diff --git a/SQL/migrate/V012__Deleteable_mirrors.sql b/SQL/migrate/V012__Deleteable_mirrors.sql
new file mode 100644
index 00000000000..35e9cd5c82a
--- /dev/null
+++ b/SQL/migrate/V012__Deleteable_mirrors.sql
@@ -0,0 +1,29 @@
+--
+-- Implemented in PR #4026.
+-- Adds a deleted_at column for mirrors.
+-- Also adds indexes for speeding up search queries around the ban database.
+--
+
+ALTER TABLE `ss13_ban_mirrors`
+ ADD `deleted_at` DATETIME NULL DEFAULT NULL AFTER `extra_info`;
+
+CREATE INDEX `idx_mirrors_isbanned` ON `ss13_ban_mirrors` (
+ `deleted_at`,
+ `ckey`,
+ `ip`,
+ `computerid`
+);
+
+CREATE INDEX `idx_mirrors_select` ON `ss13_ban_mirrors` (
+ `deleted_at`,
+ `ban_id`
+);
+
+CREATE INDEX `idx_ban_isbanned` ON `ss13_ban` (
+ `unbanned`,
+ `bantype`,
+ `expiration_time`,
+ `ckey`,
+ `computerid`,
+ `ip`
+);
diff --git a/code/modules/admin/DB ban/ban_mirroring.dm b/code/modules/admin/DB ban/ban_mirroring.dm
index c0d90ffdd40..ae2d7001188 100644
--- a/code/modules/admin/DB ban/ban_mirroring.dm
+++ b/code/modules/admin/DB ban/ban_mirroring.dm
@@ -30,7 +30,7 @@
bad_data &= ~BAD_CID
if (bad_data)
- var/DBQuery/mirrored_bans = dbcon.NewQuery("SELECT ckey, ip, computerid FROM ss13_ban_mirrors WHERE ban_id = :ban_id:")
+ var/DBQuery/mirrored_bans = dbcon.NewQuery("SELECT ckey, ip, computerid FROM ss13_ban_mirrors WHERE isnull(deleted_at) AND ban_id = :ban_id:")
mirrored_bans.Execute(list("ban_id" = ban_id))
while (mirrored_bans.NextRow())
@@ -66,7 +66,7 @@
log_misc("Ban database connection failure while attempting to check mirrors. Key passed for mirror checking: [ckey].")
return null
- var/DBQuery/initial_query = dbcon.NewQuery("SELECT DISTINCT ban_id FROM ss13_ban_mirrors WHERE ckey = :ckey: OR ip = :address: OR computerid = :computerid:")
+ var/DBQuery/initial_query = dbcon.NewQuery("SELECT DISTINCT ban_id FROM ss13_ban_mirrors WHERE isnull(deleted_at) AND (ckey = :ckey: OR ip = :address: OR computerid = :computerid:)")
initial_query.Execute(list("ckey" = ckey, "address" = address, "computerid" = computer_id))
var/list/ban_ids = list()
@@ -78,7 +78,7 @@
if (!ban_ids.len)
return null
- var/DBQuery/search_query = dbcon.NewQuery("SELECT id FROM ss13_ban WHERE id IN :vars: AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
+ var/DBQuery/search_query = dbcon.NewQuery("SELECT id FROM ss13_ban WHERE id IN :vars: AND isnull(unbanned) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now()))")
search_query.Execute(list("vars" = ban_ids))
var/list/active_bans = list()
@@ -116,7 +116,7 @@
if (!dbcon.IsConnected())
return null
- var/DBQuery/query = dbcon.NewQuery("SELECT id, ckey, ip, computerid, date(datetime) as datetime, source, extra_info FROM ss13_ban_mirrors WHERE ban_id = :ban_id:")
+ var/DBQuery/query = dbcon.NewQuery("SELECT id, ckey, ip, computerid, date(datetime) as datetime, source, extra_info, deleted_at FROM ss13_ban_mirrors WHERE ban_id = :ban_id:")
query.Execute(list("ban_id" = ban_id))
var/list/mirrors = list()
@@ -137,6 +137,11 @@
items["extra"] = TRUE
catch()
+ if (query.item[8])
+ items["inactive"] = TRUE
+ else
+ items["inactive"] = FALSE
+
mirrors += list(items)
return mirrors
@@ -169,18 +174,17 @@
var/static/list/bg_colors = list("#ffeeee", "#ffdddd")
var/i = 0
for (var/mirror in mirrors)
- var/bg = bg_colors[i + 1]
var/list/details = mirror
+ var/bg = details["inactive"] ? "#aaaaaa" : bg_colors[i + 1]
output += "
"
output += "| [details["source"]] | "
output += "[details["ckey"]] | "
output += "[details["date"]] | "
+ output += "[details["inactive"] ? "Reactivate" : "Deactivate"]"
if (details["extra"])
- output += " | View Ckeys | "
- else
- output += " | "
- output += "
"
+ output += " | View Ckeys"
+ output += ""
output += ""
output += "| IP: [details["ip"]] | "
@@ -227,6 +231,22 @@
output += "
Back"
user << browse(output, "window=banmirrors")
+/proc/toggle_mirror_status(mob/user, mirror_id, inactive = FALSE)
+ if (!user || !check_rights(R_MOD|R_ADMIN) || !mirror_id)
+ return
+
+ if (!establish_db_connection(dbcon))
+ to_chat(user, "Database connection failed!")
+ return
+
+ var/DBQuery/query = dbcon.NewQuery("UPDATE ss13_ban_mirrors SET deleted_at = :new_state: WHERE id = :id:")
+ query.Execute(list("new_state" = inactive ? null : "NOW()", "id" = mirror_id))
+
+ if (query.ErrorMsg())
+ to_chat(user, "An error occured while toggling mirror status!")
+ else
+ to_chat(user, "Mirror set to [inactive ? "ACTIVE" : "INACTIVE"].")
+
/proc/handle_connection_info(var/client/C, var/data)
if (!C)
return
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index bb47a240948..cd2aa4a2496 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -133,7 +133,7 @@
else
bantype_sql = "bantype = '[bantype_str]'"
- var/sql = "SELECT id FROM ss13_ban WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
+ var/sql = "SELECT id FROM ss13_ban WHERE isnull(unbanned) AND [bantype_sql] AND ckey = '[ckey]'"
if(job)
sql += " AND job = '[job]'"
@@ -437,7 +437,7 @@
if (!match)
var/DBQuery/mirror_query = dbcon.NewQuery({"SELECT DISTINCT(mirrors.ban_id), bans.ckey FROM ss13_ban_mirrors mirrors
JOIN ss13_ban bans ON mirrors.ban_id = bans.id
- WHERE (1 [mirror_player] [mirror_ip] [mirror_cid])
+ WHERE (isnull(mirrors.deleted_at) AND (1 [mirror_player] [mirror_ip] [mirror_cid]))
AND (
ISNULL(bans.unbanned) AND (
(bans.bantype = 'PERMABAN')
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 5e4ad4371d1..15a7b1a6451 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -44,10 +44,10 @@ world/IsBanned(key,address,computer_id)
var/params[] = list()
var/query_content = ""
if (pulled_ban_id)
- query_content = "SELECT id, ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM ss13_ban WHERE id = :ban_id: AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)"
+ query_content = "SELECT id, ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM ss13_ban WHERE id = :ban_id: AND isnull(unbanned) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now()))"
params["ban_id"] = pulled_ban_id
else
- query_content = "SELECT id, ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM ss13_ban WHERE (ckey = :ckey: OR computerid = :computerid: OR ip = :address:) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)"
+ query_content = "SELECT id, ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM ss13_ban WHERE isnull(unbanned) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND (ckey = :ckey: OR computerid = :computerid: OR ip = :address:)"
params["ckey"] = ckey
params["computerid"] = computer_id
params["address"] = address
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index bbe9fd8d1eb..1f0f2a70094 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -97,8 +97,13 @@
display_mirrors_panel(usr, text2num(href_list["dbbanmirrors"]))
return
- else if(href_list["dbbanmirrorckeys"])
- display_mirrors_ckeys(usr, text2num(href_list["dbbanmirrorckeys"]))
+ else if(href_list["dbbanmirroract"])
+ // Mirror act contains the ID of the mirror being acted upon.
+ var/mirror_id = text2num(href_list["dbbanmirroract"])
+ if (href_list["mirrorckeys"])
+ display_mirrors_ckeys(usr, mirror_id)
+ else if (href_list["mirrorstatus"])
+ toggle_mirror_status(usr, mirror_id, text2num(href_list["mirrorstatus"]))
return
else if(href_list["editrights"])