diff --git a/CS2-SimpleAdmin/CS2-SimpleAdmin.csproj b/CS2-SimpleAdmin/CS2-SimpleAdmin.csproj index fe752ef..2af4159 100644 --- a/CS2-SimpleAdmin/CS2-SimpleAdmin.csproj +++ b/CS2-SimpleAdmin/CS2-SimpleAdmin.csproj @@ -84,6 +84,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -132,6 +135,9 @@ PreserveNewest + + PreserveNewest + diff --git a/CS2-SimpleAdmin/Database/IDatabaseProvider.cs b/CS2-SimpleAdmin/Database/IDatabaseProvider.cs index e2a4ae4..c847245 100644 --- a/CS2-SimpleAdmin/Database/IDatabaseProvider.cs +++ b/CS2-SimpleAdmin/Database/IDatabaseProvider.cs @@ -21,6 +21,7 @@ public interface IDatabaseProvider string GetDeleteAdminQuery(bool globalDelete); string GetAddAdminQuery(); string GetAddAdminFlagsQuery(); + string GetAddAdminServerQuery(); string GetUpdateAdminGroupQuery(); string GetGroupsQuery(); string GetGroupIdByNameQuery(); @@ -29,6 +30,7 @@ public interface IDatabaseProvider string GetAddGroupServerQuery(); string GetDeleteGroupQuery(); string GetDeleteOldAdminsQuery(); + string GetDeleteOrphanedAdminsQuery(); // BanManager string GetAddBanQuery(); diff --git a/CS2-SimpleAdmin/Database/Migrations/Mysql/017_CreateAdminsServersTable.sql b/CS2-SimpleAdmin/Database/Migrations/Mysql/017_CreateAdminsServersTable.sql new file mode 100644 index 0000000..c243415 --- /dev/null +++ b/CS2-SimpleAdmin/Database/Migrations/Mysql/017_CreateAdminsServersTable.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS `sa_admins_servers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `admin_id` int(11) NOT NULL, + `server_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`admin_id`) REFERENCES `sa_admins` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +ALTER TABLE `sa_admins` ADD `global` TINYINT(1) NOT NULL DEFAULT 0; + +INSERT INTO `sa_admins_servers` (`admin_id`, `server_id`) +SELECT `id`, `server_id` FROM `sa_admins` WHERE `server_id` IS NOT NULL; + +UPDATE `sa_admins` SET `global` = 1 WHERE `server_id` IS NULL; + +ALTER TABLE `sa_admins` DROP COLUMN `server_id`; diff --git a/CS2-SimpleAdmin/Database/Migrations/Sqlite/017_CreateAdminsServersTable.sql b/CS2-SimpleAdmin/Database/Migrations/Sqlite/017_CreateAdminsServersTable.sql new file mode 100644 index 0000000..0c0155f --- /dev/null +++ b/CS2-SimpleAdmin/Database/Migrations/Sqlite/017_CreateAdminsServersTable.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS `sa_admins_servers` ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `admin_id` INTEGER NOT NULL, + `server_id` INTEGER NOT NULL, + FOREIGN KEY (`admin_id`) REFERENCES `sa_admins` (`id`) ON DELETE CASCADE +); + +ALTER TABLE `sa_admins` ADD `global` INTEGER NOT NULL DEFAULT 0; + +INSERT INTO `sa_admins_servers` (`admin_id`, `server_id`) +SELECT `id`, `server_id` FROM `sa_admins` WHERE `server_id` IS NOT NULL; + +UPDATE `sa_admins` SET `global` = 1 WHERE `server_id` IS NULL; + +ALTER TABLE `sa_admins` DROP COLUMN `server_id`; diff --git a/CS2-SimpleAdmin/Database/MysqlDatabaseProvider.cs b/CS2-SimpleAdmin/Database/MysqlDatabaseProvider.cs index fa9a27e..6edaa36 100644 --- a/CS2-SimpleAdmin/Database/MysqlDatabaseProvider.cs +++ b/CS2-SimpleAdmin/Database/MysqlDatabaseProvider.cs @@ -127,7 +127,10 @@ public string GetAdminsQuery() FROM sa_admins_flags JOIN sa_admins ON sa_admins_flags.admin_id = sa_admins.id WHERE (sa_admins.ends IS NULL OR sa_admins.ends > @CurrentTime) - AND (sa_admins.server_id IS NULL OR sa_admins.server_id = @serverid) + AND (sa_admins.`global` = 1 + OR EXISTS (SELECT 1 FROM sa_admins_servers + WHERE sa_admins_servers.admin_id = sa_admins.id + AND sa_admins_servers.server_id = @serverid)) ORDER BY sa_admins.player_steamid """; } @@ -135,11 +138,14 @@ ORDER BY sa_admins.player_steamid public string GetDeleteAdminQuery(bool globalDelete) => globalDelete ? "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID" - : "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID AND server_id = @ServerId"; - + : "DELETE FROM sa_admins_servers WHERE server_id = @ServerId AND admin_id IN (SELECT id FROM sa_admins WHERE player_steamid = @PlayerSteamID)"; + public string GetAddAdminQuery() => - "INSERT INTO sa_admins (player_steamid, player_name, immunity, ends, created, server_id) " + - "VALUES (@playerSteamId, @playerName, @immunity, @ends, @created, @serverid); SELECT LAST_INSERT_ID();"; + "INSERT INTO sa_admins (player_steamid, player_name, immunity, ends, created, `global`) " + + "VALUES (@playerSteamId, @playerName, @immunity, @ends, @created, @isGlobal); SELECT LAST_INSERT_ID();"; + + public string GetAddAdminServerQuery() => + "INSERT INTO sa_admins_servers (admin_id, server_id) VALUES (@adminId, @server_id);"; public string GetGroupsQuery() { @@ -181,6 +187,9 @@ public string GetDeleteGroupQuery() => public string GetDeleteOldAdminsQuery() => "DELETE FROM sa_admins WHERE ends IS NOT NULL AND ends <= @CurrentTime;"; + + public string GetDeleteOrphanedAdminsQuery() => + "DELETE FROM sa_admins WHERE `global` = 0 AND id NOT IN (SELECT admin_id FROM sa_admins_servers);"; public string GetAddBanQuery() { diff --git a/CS2-SimpleAdmin/Database/SqliteDatabaseProvider.cs b/CS2-SimpleAdmin/Database/SqliteDatabaseProvider.cs index d6186fb..b226451 100644 --- a/CS2-SimpleAdmin/Database/SqliteDatabaseProvider.cs +++ b/CS2-SimpleAdmin/Database/SqliteDatabaseProvider.cs @@ -176,22 +176,28 @@ public string GetAdminsQuery() => FROM sa_admins_flags JOIN sa_admins ON sa_admins_flags.admin_id = sa_admins.id WHERE (sa_admins.ends IS NULL OR sa_admins.ends > @CurrentTime) - AND (sa_admins.server_id IS NULL OR sa_admins.server_id = @serverid) + AND (sa_admins.`global` = 1 + OR EXISTS (SELECT 1 FROM sa_admins_servers + WHERE sa_admins_servers.admin_id = sa_admins.id + AND sa_admins_servers.server_id = @serverid)) ORDER BY sa_admins.player_steamid """; public string GetDeleteAdminQuery(bool globalDelete) => globalDelete ? "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID" - : "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID AND server_id = @ServerId"; + : "DELETE FROM sa_admins_servers WHERE server_id = @ServerId AND admin_id IN (SELECT id FROM sa_admins WHERE player_steamid = @PlayerSteamID)"; public string GetAddAdminQuery() => """ - INSERT INTO sa_admins (player_steamid, player_name, immunity, ends, created, server_id) - VALUES (@playerSteamId, @playerName, @immunity, @ends, @created, @serverid); + INSERT INTO sa_admins (player_steamid, player_name, immunity, ends, created, `global`) + VALUES (@playerSteamId, @playerName, @immunity, @ends, @created, @isGlobal); SELECT last_insert_rowid(); """; + public string GetAddAdminServerQuery() => + "INSERT INTO sa_admins_servers (admin_id, server_id) VALUES (@adminId, @server_id);"; + public string GetGroupsQuery() => """ SELECT g.group_id, sg.name AS group_name, sg.immunity, f.flag @@ -234,6 +240,9 @@ public string GetDeleteGroupQuery() => public string GetDeleteOldAdminsQuery() => "DELETE FROM sa_admins WHERE ends IS NOT NULL AND ends <= @CurrentTime;"; + + public string GetDeleteOrphanedAdminsQuery() => + "DELETE FROM sa_admins WHERE `global` = 0 AND id NOT IN (SELECT admin_id FROM sa_admins_servers);"; public string GetAddMuteQuery(bool includePlayerName) => includePlayerName diff --git a/CS2-SimpleAdmin/Managers/PermissionManager.cs b/CS2-SimpleAdmin/Managers/PermissionManager.cs index c9f2b41..34a26ba 100644 --- a/CS2-SimpleAdmin/Managers/PermissionManager.cs +++ b/CS2-SimpleAdmin/Managers/PermissionManager.cs @@ -530,7 +530,7 @@ public async Task AddAdminBySteamId(string playerSteamId, string playerName, Lis immunity, ends = futureTime, created = now, - serverid = globalAdmin ? null : CS2_SimpleAdmin.ServerId + isGlobal = globalAdmin ? 1 : 0 }); // Insert flags into sa_admins_flags table @@ -563,6 +563,18 @@ public async Task AddAdminBySteamId(string playerSteamId, string playerName, Lis }); } + // Global admins apply to every server and need no per-server link row. + // Server-specific admins are linked to the current server. + if (!globalAdmin) + { + var insertAdminServerSql = databaseProvider.GetAddAdminServerQuery(); + await connection.ExecuteAsync(insertAdminServerSql, new + { + adminId, + server_id = CS2_SimpleAdmin.ServerId + }); + } + await Server.NextWorldUpdateAsync(() => { CS2_SimpleAdmin.Instance.ReloadAdmins(null); @@ -665,4 +677,24 @@ public async Task DeleteOldAdmins() CS2_SimpleAdmin._logger?.LogCritical("Unable to remove expired admins"); } } + + /// + /// Deletes orphaned admins that are not global and have no server assignments left. + /// + public async Task DeleteOrphanedAdmins() + { + if (databaseProvider == null) return; + + try + { + await using var connection = await databaseProvider.CreateConnectionAsync(); + + var sql = databaseProvider.GetDeleteOrphanedAdminsQuery(); + await connection.ExecuteAsync(sql); + } + catch (Exception) + { + CS2_SimpleAdmin._logger?.LogCritical("Unable to remove orphaned admins"); + } + } } \ No newline at end of file diff --git a/CS2-SimpleAdmin/Managers/PlayerManager.cs b/CS2-SimpleAdmin/Managers/PlayerManager.cs index 2f08393..c3132b1 100644 --- a/CS2-SimpleAdmin/Managers/PlayerManager.cs +++ b/CS2-SimpleAdmin/Managers/PlayerManager.cs @@ -306,7 +306,8 @@ public void CheckPlayersTimer() pluginInstance.MuteManager.ExpireOldMutes(), pluginInstance.WarnManager.ExpireOldWarns(), pluginInstance.CacheManager?.RefreshCacheAsync() ?? Task.CompletedTask, - pluginInstance.PermissionManager.DeleteOldAdmins() + pluginInstance.PermissionManager.DeleteOldAdmins(), + pluginInstance.PermissionManager.DeleteOrphanedAdmins() }; await Task.WhenAll(expireTasks);