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);