zio fork 1.8.2b-zio10: rank tags match CS2-Tags, log rank changes to sa_rank_log
This commit is contained in:
parent
cf1090cbd2
commit
24f011cbe5
5 changed files with 100 additions and 17 deletions
|
|
@ -22,7 +22,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
||||||
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
||||||
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
||||||
public override string ModuleAuthor => "daffyy";
|
public override string ModuleAuthor => "daffyy";
|
||||||
public override string ModuleVersion => "1.8.2b-zio9";
|
public override string ModuleVersion => "1.8.2b-zio10";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,9 @@ public partial class CS2_SimpleAdmin
|
||||||
if (DatabaseProvider == null) return;
|
if (DatabaseProvider == null) return;
|
||||||
|
|
||||||
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
||||||
_ = Instance.PermissionManager.AddAdminBySteamId(steamid, name, flagsList, immunity, time, globalAdmin);
|
// zio: who did it, for the rank log (null caller is Console, which includes RCON).
|
||||||
|
_ = Instance.PermissionManager.AddAdminBySteamId(steamid, name, flagsList, immunity, time, globalAdmin,
|
||||||
|
caller?.SteamID ?? 0, caller?.PlayerName ?? "Console");
|
||||||
|
|
||||||
Helper.LogCommand(caller, $"css_addadmin {steamid} {name} {flags} {immunity} {time}");
|
Helper.LogCommand(caller, $"css_addadmin {steamid} {name} {flags} {immunity} {time}");
|
||||||
|
|
||||||
|
|
@ -331,7 +333,8 @@ public partial class CS2_SimpleAdmin
|
||||||
public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null)
|
public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null)
|
||||||
{
|
{
|
||||||
if (DatabaseProvider == null) return;
|
if (DatabaseProvider == null) return;
|
||||||
_ = PermissionManager.DeleteAdminBySteamId(steamid, globalDelete);
|
// zio: who did it, for the rank log (null caller is Console, which includes RCON).
|
||||||
|
_ = PermissionManager.DeleteAdminBySteamId(steamid, globalDelete, caller?.SteamID ?? 0, caller?.PlayerName ?? "Console");
|
||||||
|
|
||||||
AddTimer(2, () =>
|
AddTimer(2, () =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -158,21 +158,21 @@ internal static class Helper
|
||||||
return check.CanExecuteCommand(player);
|
return check.CanExecuteCommand(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
// zio: rank groups, highest first, and their chat abbreviations. Guardian (VIP) is last, so a
|
// zio: rank groups, highest first, and their chat tags (the same as CS2-Tags' chat prefixes).
|
||||||
// staff rank wins.
|
// Guardian (VIP) is last, so a staff rank wins.
|
||||||
private static readonly (string Group, string Tag)[] StaffRanks =
|
private static readonly (string Group, string Tag)[] StaffRanks =
|
||||||
[
|
[
|
||||||
("#rank/owner", "O"),
|
("#rank/owner", "O"),
|
||||||
("#rank/senioradmin", "SA"),
|
("#rank/senioradmin", "S.Admin"),
|
||||||
("#rank/admin", "A"),
|
("#rank/admin", "Admin"),
|
||||||
("#rank/trialadmin", "TA"),
|
("#rank/trialadmin", "T.Admin"),
|
||||||
("#rank/mod", "M"),
|
("#rank/mod", "Mod"),
|
||||||
("#rank/trialmod", "TM"),
|
("#rank/trialmod", "T.Mod"),
|
||||||
("#rank/helper", "H"),
|
("#rank/helper", "Helper"),
|
||||||
("#rank/guardian", "G"),
|
("#rank/guardian", "Guardian"),
|
||||||
];
|
];
|
||||||
|
|
||||||
// zio: the player's highest rank abbreviation, or null if they're in no rank group.
|
// zio: the player's highest rank tag, or null if they're in no rank group.
|
||||||
internal static string? GetStaffRankTag(CCSPlayerController player)
|
internal static string? GetStaffRankTag(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
var groups = AdminManager.GetPlayerAdminData(new SteamID(player.SteamID))?.Groups;
|
var groups = AdminManager.GetPlayerAdminData(new SteamID(player.SteamID))?.Groups;
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,9 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerSteamId">The SteamID of the admin to delete.</param>
|
/// <param name="playerSteamId">The SteamID of the admin to delete.</param>
|
||||||
/// <param name="globalDelete">Whether to delete the admin globally or only for the current server.</param>
|
/// <param name="globalDelete">Whether to delete the admin globally or only for the current server.</param>
|
||||||
public async Task DeleteAdminBySteamId(string playerSteamId, bool globalDelete = false)
|
/// <param name="adminSteamId">zio: SteamID64 of who removed them, 0 for Console, for the rank log.</param>
|
||||||
|
/// <param name="adminName">zio: name of who removed them, for the rank log.</param>
|
||||||
|
public async Task DeleteAdminBySteamId(string playerSteamId, bool globalDelete = false, ulong adminSteamId = 0, string adminName = "Console")
|
||||||
{
|
{
|
||||||
if (databaseProvider == null) return;
|
if (databaseProvider == null) return;
|
||||||
if (string.IsNullOrEmpty(playerSteamId)) return;
|
if (string.IsNullOrEmpty(playerSteamId)) return;
|
||||||
|
|
@ -255,8 +257,14 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var connection = await databaseProvider.CreateConnectionAsync();
|
await using var connection = await databaseProvider.CreateConnectionAsync();
|
||||||
|
// zio: note the rank and name before they're gone, for the rank log.
|
||||||
|
var before = await GetRank(connection, playerSteamId);
|
||||||
|
var playerName = await connection.ExecuteScalarAsync<string?>(
|
||||||
|
"SELECT player_name FROM sa_admins WHERE player_steamid = @playerSteamId ORDER BY server_id IS NULL DESC, id LIMIT 1",
|
||||||
|
new { playerSteamId }) ?? "";
|
||||||
var sql = databaseProvider.GetDeleteAdminQuery(globalDelete);
|
var sql = databaseProvider.GetDeleteAdminQuery(globalDelete);
|
||||||
await connection.ExecuteAsync(sql, new { PlayerSteamID = playerSteamId, CS2_SimpleAdmin.ServerId });
|
await connection.ExecuteAsync(sql, new { PlayerSteamID = playerSteamId, CS2_SimpleAdmin.ServerId });
|
||||||
|
await LogRankChange(connection, playerSteamId, playerName, before, await GetRank(connection, playerSteamId), adminSteamId, adminName);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -273,7 +281,9 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
/// <param name="immunity">Immunity level.</param>
|
/// <param name="immunity">Immunity level.</param>
|
||||||
/// <param name="time">Duration in minutes for admin expiration; 0 means permanent.</param>
|
/// <param name="time">Duration in minutes for admin expiration; 0 means permanent.</param>
|
||||||
/// <param name="globalAdmin">Whether the admin is global or server-specific.</param>
|
/// <param name="globalAdmin">Whether the admin is global or server-specific.</param>
|
||||||
public async Task AddAdminBySteamId(string playerSteamId, string playerName, List<string> flagsList, int immunity = 0, int time = 0, bool globalAdmin = false)
|
/// <param name="adminSteamId">zio: SteamID64 of who added them, 0 for Console, for the rank log.</param>
|
||||||
|
/// <param name="adminName">zio: name of who added them, for the rank log.</param>
|
||||||
|
public async Task AddAdminBySteamId(string playerSteamId, string playerName, List<string> flagsList, int immunity = 0, int time = 0, bool globalAdmin = false, ulong adminSteamId = 0, string adminName = "Console")
|
||||||
{
|
{
|
||||||
if (databaseProvider == null) return;
|
if (databaseProvider == null) return;
|
||||||
|
|
||||||
|
|
@ -285,6 +295,7 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var connection = await databaseProvider.CreateConnectionAsync();
|
await using var connection = await databaseProvider.CreateConnectionAsync();
|
||||||
|
var before = await GetRank(connection, playerSteamId); // zio: for the rank log
|
||||||
|
|
||||||
var insertAdminSql = databaseProvider.GetAddAdminQuery();
|
var insertAdminSql = databaseProvider.GetAddAdminQuery();
|
||||||
var adminId = await connection.ExecuteScalarAsync<int>(insertAdminSql, new
|
var adminId = await connection.ExecuteScalarAsync<int>(insertAdminSql, new
|
||||||
|
|
@ -307,6 +318,8 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await LogRankChange(connection, playerSteamId, playerName, before, await GetRank(connection, playerSteamId), adminSteamId, adminName);
|
||||||
|
|
||||||
await Server.NextWorldUpdateAsync(() =>
|
await Server.NextWorldUpdateAsync(() =>
|
||||||
{
|
{
|
||||||
CS2_SimpleAdmin.Instance.ReloadAdmins(null);
|
CS2_SimpleAdmin.Instance.ReloadAdmins(null);
|
||||||
|
|
@ -318,6 +331,69 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zio: rank history in sa_rank_log, a table owned by our web panel (simpleadmin-web's
|
||||||
|
// sql/rank-log.sql), which logs its own changes there too. A player's rank is their
|
||||||
|
// highest-immunity group; a change is only logged when that changes.
|
||||||
|
private sealed class RankRow
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public int Immunity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool _rankLogMissingWarned;
|
||||||
|
|
||||||
|
// zio: the player's current rank, or null. Only unexpired admin rows and groups that apply to
|
||||||
|
// this server count, the same set SimpleAdmin loads.
|
||||||
|
private static async Task<RankRow?> GetRank(System.Data.Common.DbConnection connection, string playerSteamId)
|
||||||
|
{
|
||||||
|
return await connection.QueryFirstOrDefaultAsync<RankRow>("""
|
||||||
|
SELECT g.name AS Name, g.immunity AS Immunity
|
||||||
|
FROM sa_admins a
|
||||||
|
JOIN sa_admins_flags f ON f.admin_id = a.id
|
||||||
|
JOIN sa_groups g ON g.name = f.flag
|
||||||
|
JOIN sa_groups_servers gs ON gs.group_id = g.id AND (gs.server_id IS NULL OR gs.server_id = @serverid)
|
||||||
|
WHERE a.player_steamid = @playerSteamId AND (a.ends IS NULL OR a.ends > @now)
|
||||||
|
AND (a.server_id IS NULL OR a.server_id = @serverid)
|
||||||
|
ORDER BY g.immunity DESC, g.id LIMIT 1
|
||||||
|
""", new { playerSteamId, now = Time.ActualDateTime(), serverid = CS2_SimpleAdmin.ServerId });
|
||||||
|
}
|
||||||
|
|
||||||
|
// zio: records a rank change in sa_rank_log. Never fails the admin change itself: if the table
|
||||||
|
// is missing (the panel hasn't created it), it warns once and carries on.
|
||||||
|
private static async Task LogRankChange(System.Data.Common.DbConnection connection, string playerSteamId, string playerName,
|
||||||
|
RankRow? before, RankRow? after, ulong adminSteamId, string adminName)
|
||||||
|
{
|
||||||
|
if (before?.Name == after?.Name) return;
|
||||||
|
var kind = before == null ? "added"
|
||||||
|
: after == null ? "removed"
|
||||||
|
: after.Immunity > before.Immunity ? "promoted"
|
||||||
|
: after.Immunity < before.Immunity ? "demoted"
|
||||||
|
: "changed";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.ExecuteAsync("""
|
||||||
|
INSERT INTO sa_rank_log (player_steamid, player_name, old_rank, new_rank, kind, admin_steamid, admin_name, source, created)
|
||||||
|
VALUES (@playerSteamId, @playerName, @oldRank, @newRank, @kind, @adminSteamId, @adminName, 'game', @created)
|
||||||
|
""", new
|
||||||
|
{
|
||||||
|
playerSteamId = ulong.Parse(playerSteamId),
|
||||||
|
playerName,
|
||||||
|
oldRank = before?.Name,
|
||||||
|
newRank = after?.Name,
|
||||||
|
kind,
|
||||||
|
adminSteamId,
|
||||||
|
adminName,
|
||||||
|
created = Time.ActualDateTime()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (_rankLogMissingWarned) return;
|
||||||
|
_rankLogMissingWarned = true;
|
||||||
|
CS2_SimpleAdmin._logger?.LogWarning($"Couldn't write sa_rank_log (the web panel creates it): {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new group with flags and immunity asynchronously.
|
/// Adds a new group with flags and immunity asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ from the `build-1.8.2b` tag). Changes, all marked `zio:` in the code:
|
||||||
- New permission `@css/bypassipban`, for players or groups: IP bans, and bans on other accounts
|
- New permission `@css/bypassipban`, for players or groups: IP bans, and bans on other accounts
|
||||||
that share their IP, don't apply to them; a ban on their own SteamID still does. `@css/root`
|
that share their IP, don't apply to them; a ban on their own SteamID still does. `@css/root`
|
||||||
has it, as it has every `@css` flag.
|
has it, as it has every `@css` flag.
|
||||||
- Staff chat shows the sender's rank, from their highest `#rank/...` group (O, SA, A, TA, M, TM,
|
- Staff chat shows the sender's rank, from their highest `#rank/...` group (O, S.Admin, Admin,
|
||||||
H for helper, G for guardian): `@message` in team chat and `css_asay` read
|
T.Admin, Mod, T.Mod, Helper, Guardian, the same as CS2-Tags' chat prefixes): `@message` in team chat and `css_asay` read
|
||||||
`>[STAFF][RANK] name: message`, and
|
`>[STAFF][RANK] name: message`, and
|
||||||
`@message` in all chat and `css_say` from a player read `[RANK] name: message` (`name: message`
|
`@message` in all chat and `css_say` from a player read `[RANK] name: message` (`name: message`
|
||||||
if they have no rank group). A non-staff player's `@message` in team chat reads
|
if they have no rank group). A non-staff player's `@message` in team chat reads
|
||||||
|
|
@ -29,6 +29,10 @@ from the `build-1.8.2b` tag). Changes, all marked `zio:` in the code:
|
||||||
as CSS checks the typed command. Upstream required every flag in the override.
|
as CSS checks the typed command. Upstream required every flag in the override.
|
||||||
- `css_penalties <player>` (someone else's penalties) needs `@zio/penalties` or `@css/root`
|
- `css_penalties <player>` (someone else's penalties) needs `@zio/penalties` or `@css/root`
|
||||||
instead of `@css/kick`.
|
instead of `@css/kick`.
|
||||||
|
- `css_addadmin`, `css_deladmin` and the admin menu's add/remove log rank changes (the player's
|
||||||
|
highest-immunity group, and who changed it) to `sa_rank_log`, the table simpleadmin-web creates
|
||||||
|
and lists as the public promotions/demotions log. If the table is missing, it warns once in the
|
||||||
|
log and the admin change goes ahead.
|
||||||
|
|
||||||
Publish with `FORGEJO_TOKEN=... ./release.sh v<ModuleVersion>` (ModuleVersion is `1.8.2b-zioN`).
|
Publish with `FORGEJO_TOKEN=... ./release.sh v<ModuleVersion>` (ModuleVersion is `1.8.2b-zioN`).
|
||||||
It rebuilds from the committed source and uploads `SimpleAdmin-<tag>.tar.gz` to git.zio.sh
|
It rebuilds from the committed source and uploads `SimpleAdmin-<tag>.tar.gz` to git.zio.sh
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue