diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 143063b4e9..f6293454ee 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -91,3 +91,6 @@
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
+
+#define STICKYBAN_DB_CACHE_TIME 10 SECONDS
+#define STICKYBAN_ROGUE_CHECK_TIME 5
diff --git a/code/_globalvars/admin.dm b/code/_globalvars/admin.dm
new file mode 100644
index 0000000000..81037ff3dd
--- /dev/null
+++ b/code/_globalvars/admin.dm
@@ -0,0 +1,12 @@
+GLOBAL_LIST_EMPTY(stickybanadminexemptions) //stores a list of ckeys exempted from a stickyban (workaround for a bug)
+GLOBAL_LIST_EMPTY(stickybanadmintexts) //stores the entire stickyban list temporarily
+GLOBAL_VAR(stickbanadminexemptiontimerid) //stores the timerid of the callback that restores all stickybans after an admin joins
+
+// /proc/init_smites() //todo: add on the second wave
+// var/list/smites = list()
+// for (var/_smite_path in subtypesof(/datum/smite))
+// var/datum/smite/smite_path = _smite_path
+// smites[initial(smite_path.name)] = smite_path
+// return smites
+
+// GLOBAL_LIST_INIT_TYPED(smites, /datum/smite, init_smites())
diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm
index 4eff4fbf1d..c779c9f26d 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -177,6 +177,25 @@ SUBSYSTEM_DEF(dbcore)
return FALSE
return new /datum/DBQuery(sql_query, connection)
+/datum/controller/subsystem/dbcore/proc/QuerySelect(list/querys, warn = FALSE, qdel = FALSE)
+ if (!islist(querys))
+ if (!istype(querys, /datum/DBQuery))
+ CRASH("Invalid query passed to QuerySelect: [querys]")
+ querys = list(querys)
+
+ for (var/thing in querys)
+ var/datum/DBQuery/query = thing
+ if (warn)
+ INVOKE_ASYNC(query, /datum/DBQuery.proc/warn_execute)
+ else
+ INVOKE_ASYNC(query, /datum/DBQuery.proc/Execute)
+
+ for (var/thing in querys)
+ var/datum/DBQuery/query = thing
+ UNTIL(!query.in_progress)
+ if (qdel)
+ qdel(query)
+
/*
Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query.
Rows missing columns present in other rows will resolve to SQL NULL
@@ -361,5 +380,5 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
//strip sensitive stuff
if(findtext(message, ": CreateConnection("))
message = "CreateConnection CENSORED"
-
+
log_sql("BSQL_DEBUG: [message]")
diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm
index 189efa99fe..0c71777bc0 100644
--- a/code/controllers/subsystem/stickyban.dm
+++ b/code/controllers/subsystem/stickyban.dm
@@ -1,34 +1,231 @@
SUBSYSTEM_DEF(stickyban)
- name = "Sticky Ban"
+ name = "PRISM"
init_order = INIT_ORDER_STICKY_BAN
flags = SS_NO_FIRE
var/list/cache = list()
+ var/list/dbcache = list()
+ var/list/confirmed_exempt = list()
+ var/dbcacheexpire = 0
+
/datum/controller/subsystem/stickyban/Initialize(timeofday)
- var/list/bannedkeys = world.GetConfig("ban")
+ if (length(GLOB.stickybanadminexemptions))
+ restore_stickybans()
+ var/list/bannedkeys = sticky_banned_ckeys()
//sanitize the sticky ban list
+
+ //delete db bans that no longer exist in the database and add new legacy bans to the database
+ if (SSdbcore.Connect() || length(SSstickyban.dbcache))
+ if (length(GLOB.stickybanadminexemptions))
+ restore_stickybans()
+ for (var/oldban in (world.GetConfig("ban") - bannedkeys))
+ var/ckey = ckey(oldban)
+ if (ckey != oldban && (ckey in bannedkeys))
+ continue
+
+ var/list/ban = params2list(world.GetConfig("ban", oldban))
+ if (ban && !ban["fromdb"])
+ if (!import_raw_stickyban_to_db(ckey, ban))
+ log_world("Could not import stickyban on [oldban] into the database. Ignoring")
+ continue
+ dbcacheexpire = 0
+ bannedkeys += ckey
+ world.SetConfig("ban", oldban, null)
+
+ if (length(GLOB.stickybanadminexemptions)) //the previous loop can sleep
+ restore_stickybans()
+
for (var/bannedkey in bannedkeys)
var/ckey = ckey(bannedkey)
- var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey))
+ var/list/ban = get_stickyban_from_ckey(bannedkey)
- //byond stores sticky bans by key, that can end up confusing things
- //i also remove it here so that if any stickybans cause a runtime, they just stop existing
- world.SetConfig("ban", bannedkey, null)
+ //byond stores sticky bans by key, that's lame
+ if (ckey != bannedkey)
+ world.SetConfig("ban", bannedkey, null)
if (!ban["ckey"])
ban["ckey"] = ckey
- //storing these can break things and isn't needed for sticky ban tracking
- ban -= "IP"
- ban -= "computer_id"
-
ban["matches_this_round"] = list()
ban["existing_user_matches_this_round"] = list()
ban["admin_matches_this_round"] = list()
+ ban["pending_matches_this_round"] = list()
+
cache[ckey] = ban
-
- for (var/bannedckey in cache)
- world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey]))
+ world.SetConfig("ban", ckey, list2stickyban(ban))
return ..()
+
+/datum/controller/subsystem/stickyban/proc/Populatedbcache()
+ var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache
+
+ // var/datum/db_query/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey")
+ // var/datum/db_query/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
+ // var/datum/db_query/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched")
+ // var/datum/db_query/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched")
+
+ var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey")
+ var/datum/DBQuery/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
+ var/datum/DBQuery/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched")
+ var/datum/DBQuery/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched")
+
+ SSdbcore.QuerySelect(list(query_stickybans, query_ckey_matches, query_cid_matches, query_ip_matches))
+
+ if (query_stickybans.last_error)
+ qdel(query_stickybans)
+ qdel(query_ckey_matches)
+ qdel(query_cid_matches)
+ qdel(query_ip_matches)
+ return
+
+ while (query_stickybans.NextRow())
+ var/list/ban = list()
+
+ ban["ckey"] = query_stickybans.item[1]
+ ban["message"] = query_stickybans.item[2]
+ ban["reason"] = "(InGameBan)([query_stickybans.item[3]])"
+ ban["admin"] = query_stickybans.item[3]
+ ban["datetime"] = query_stickybans.item[4]
+ ban["type"] = list("sticky")
+
+ newdbcache["[query_stickybans.item[1]]"] = ban
+
+
+ if (!query_ckey_matches.last_error)
+ while (query_ckey_matches.NextRow())
+ var/list/match = list()
+
+ match["stickyban"] = query_ckey_matches.item[1]
+ match["matched_ckey"] = query_ckey_matches.item[2]
+ match["first_matched"] = query_ckey_matches.item[3]
+ match["last_matched"] = query_ckey_matches.item[4]
+ match["exempt"] = text2num(query_ckey_matches.item[5])
+
+ var/ban = newdbcache[query_ckey_matches.item[1]]
+ if (!ban)
+ continue
+ var/keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"]
+ if (!keys)
+ keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] = list()
+ keys[query_ckey_matches.item[2]] = match
+
+ if (!query_cid_matches.last_error)
+ while (query_cid_matches.NextRow())
+ var/list/match = list()
+
+ match["stickyban"] = query_cid_matches.item[1]
+ match["matched_cid"] = query_cid_matches.item[2]
+ match["first_matched"] = query_cid_matches.item[3]
+ match["last_matched"] = query_cid_matches.item[4]
+
+ var/ban = newdbcache[query_cid_matches.item[1]]
+ if (!ban)
+ continue
+ var/computer_ids = ban["computer_id"]
+ if (!computer_ids)
+ computer_ids = ban["computer_id"] = list()
+ computer_ids[query_cid_matches.item[2]] = match
+
+
+ if (!query_ip_matches.last_error)
+ while (query_ip_matches.NextRow())
+ var/list/match = list()
+
+ match["stickyban"] = query_ip_matches.item[1]
+ match["matched_ip"] = query_ip_matches.item[2]
+ match["first_matched"] = query_ip_matches.item[3]
+ match["last_matched"] = query_ip_matches.item[4]
+
+ var/ban = newdbcache[query_ip_matches.item[1]]
+ if (!ban)
+ continue
+ var/IPs = ban["IP"]
+ if (!IPs)
+ IPs = ban["IP"] = list()
+ IPs[query_ip_matches.item[2]] = match
+
+ dbcache = newdbcache
+ dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME
+
+ qdel(query_stickybans)
+ qdel(query_ckey_matches)
+ qdel(query_cid_matches)
+ qdel(query_ip_matches)
+
+
+/datum/controller/subsystem/stickyban/proc/import_raw_stickyban_to_db(ckey, list/ban)
+ . = FALSE
+ if (!ban["admin"])
+ ban["admin"] = "LEGACY"
+ if (!ban["message"])
+ ban["message"] = "Evasion"
+
+ // TODO: USE NEW DB IMPLEMENTATION
+ var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery(
+ "INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ([ckey], [ban["message"]], ban["admin"]))"
+ )
+
+ if (query_create_stickyban.warn_execute())
+ qdel(query_create_stickyban)
+ return
+ qdel(query_create_stickyban)
+
+ // var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery(
+ // "INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES (:ckey, :message, :admin)",
+ // list("ckey" = ckey, "message" = ban["message"], "admin" = ban["admin"])
+ // )
+ // if (!query_create_stickyban.warn_execute())
+ // qdel(query_create_stickyban)
+ // return
+ // qdel(query_create_stickyban)
+
+ var/list/sqlckeys = list()
+ var/list/sqlcids = list()
+ var/list/sqlips = list()
+
+ if (ban["keys"])
+ var/list/keys = splittext(ban["keys"], ",")
+ for (var/key in keys)
+ var/list/sqlckey = list()
+ sqlckey["stickyban"] = ckey
+ sqlckey["matched_ckey"] = ckey(key)
+ sqlckey["exempt"] = FALSE
+ sqlckeys[++sqlckeys.len] = sqlckey
+
+ if (ban["whitelist"])
+ var/list/keys = splittext(ban["whitelist"], ",")
+ for (var/key in keys)
+ var/list/sqlckey = list()
+ sqlckey["stickyban"] = ckey
+ sqlckey["matched_ckey"] = ckey(key)
+ sqlckey["exempt"] = TRUE
+ sqlckeys[++sqlckeys.len] = sqlckey
+
+ if (ban["computer_id"])
+ var/list/cids = splittext(ban["computer_id"], ",")
+ for (var/cid in cids)
+ var/list/sqlcid = list()
+ sqlcid["stickyban"] = ckey
+ sqlcid["matched_cid"] = cid
+ sqlcids[++sqlcids.len] = sqlcid
+
+ if (ban["IP"])
+ var/list/ips = splittext(ban["IP"], ",")
+ for (var/ip in ips)
+ var/list/sqlip = list()
+ sqlip["stickyban"] = ckey
+ sqlip["matched_ip"] = ip
+ sqlips[++sqlips.len] = sqlip
+
+ if (length(sqlckeys))
+ SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlckeys, ignore_errors = TRUE)
+
+ if (length(sqlcids))
+ SSdbcore.MassInsert(format_table_name("stickyban_matched_cid"), sqlcids, ignore_errors = TRUE)
+
+ if (length(sqlips))
+ SSdbcore.MassInsert(format_table_name("stickyban_matched_ip"), sqlips, ignore_errors = TRUE)
+
+
+ return TRUE
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 4ddb92ab19..63facade2e 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -226,6 +226,14 @@
key_cache[key] = 0
return .
+/proc/restore_stickybans()
+ for (var/banned_ckey in GLOB.stickybanadmintexts)
+ world.SetConfig("ban", banned_ckey, GLOB.stickybanadmintexts[banned_ckey])
+ GLOB.stickybanadminexemptions = list()
+ GLOB.stickybanadmintexts = list()
+ if (GLOB.stickbanadminexemptiontimerid)
+ deltimer(GLOB.stickbanadminexemptiontimerid)
+ GLOB.stickbanadminexemptiontimerid = null
#undef STICKYBAN_MAX_MATCHES
#undef STICKYBAN_MAX_EXISTING_USER_MATCHES
diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm
index df6a9b89ad..ef0bfe8e70 100644
--- a/code/modules/admin/stickyban.dm
+++ b/code/modules/admin/stickyban.dm
@@ -7,7 +7,7 @@
if ("add")
var/list/ban = list()
var/ckey
- ban["admin"] = usr.key
+ ban["admin"] = usr.ckey
ban["type"] = list("sticky")
ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only
@@ -21,7 +21,8 @@
ban["ckey"] = ckey
if (get_stickyban_from_ckey(ckey))
- to_chat(usr, "Error: Can not add a stickyban: User already has a current sticky ban")
+ to_chat(usr, "Error: Can not add a stickyban: User already has a current sticky ban", confidential = TRUE)
+ return
if (data["reason"])
ban["message"] = data["reason"]
@@ -31,7 +32,26 @@
return
ban["message"] = "[reason]"
+ if(SSdbcore.Connect()) // todo: second wave
+ // var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({"
+ // INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
+ // VALUES (:ckey, :message, :banning_admin)
+ // "}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey))
+ var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery({"
+ INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
+ VALUES ([ckey], [ban["message"]], [usr.ckey])
+ "})
+ if (query_create_stickyban.warn_execute())
+ ban["fromdb"] = TRUE
+ qdel(query_create_stickyban)
+
world.SetConfig("ban",ckey,list2stickyban(ban))
+ ban = stickyban2list(list2stickyban(ban))
+ ban["matches_this_round"] = list()
+ ban["existing_user_matches_this_round"] = list()
+ ban["admin_matches_this_round"] = list()
+ ban["pending_matches_this_round"] = list()
+ SSstickyban.cache[ckey] = ban
log_admin_private("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]")
message_admins("[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]")
@@ -43,14 +63,29 @@
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: No sticky ban for [ckey] found!")
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
return
if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No")
return
if (!get_stickyban_from_ckey(ckey))
- to_chat(usr, "Error: The ban disappeared.")
+ to_chat(usr, "Error: The ban disappeared.", confidential = TRUE)
return
world.SetConfig("ban",ckey, null)
+ SSstickyban.cache -= ckey
+
+ if (SSdbcore.Connect())
+ // SSdbcore.QuerySelect(list(
+ // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)),
+ // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)),
+ // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)),
+ // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey))
+ // ), warn = TRUE, qdel = TRUE)
+ SSdbcore.QuerySelect(list(
+ SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = [ckey]"),
+ SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey]"),
+ SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = [ckey]"),
+ SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = [ckey]")
+ ), warn = TRUE, qdel = TRUE)
log_admin_private("[key_name(usr)] removed [ckey]'s stickyban")
message_admins("[key_name_admin(usr)] removed [ckey]'s stickyban")
@@ -64,42 +99,45 @@
var/alt = ckey(data["alt"])
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: No sticky ban for [ckey] found!")
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
return
- var/found = 0
- //we have to do it this way because byond keeps the case in its sticky ban matches WHY!!!
- for (var/key in ban["keys"])
- if (ckey(key) == alt)
- found = 1
- break
-
- if (!found)
- to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!")
+ var/key = LAZYACCESS(ban["keys"], alt)
+ if (!key)
+ to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!", confidential = TRUE)
return
- if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No")
+ if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them, Use \[E] to exempt them","Are you sure","Yes","No") == "No")
return
//we have to do this again incase something changes
ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: The ban disappeared.")
+ to_chat(usr, "Error: The ban disappeared.", confidential = TRUE)
return
- found = 0
- for (var/key in ban["keys"])
- if (ckey(key) == alt)
- ban["keys"] -= key
- found = 1
- break
+ key = LAZYACCESS(ban["keys"], alt)
- if (!found)
- to_chat(usr, "Error: [alt] link to [ckey]'s sticky ban disappeared.")
+ if (!key)
+ to_chat(usr, "Error: [alt] link to [ckey]'s sticky ban disappeared.", confidential = TRUE)
return
+ LAZYREMOVE(ban["keys"], alt)
world.SetConfig("ban",ckey,list2stickyban(ban))
+ SSstickyban.cache[ckey] = ban
+
+ if (SSdbcore.Connect())
+ // var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery(
+ // "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt",
+ // list("ckey" = ckey, "alt" = alt)
+ // )
+ var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery(
+ "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey] AND matched_ckey = [alt]"
+ )
+ query_remove_stickyban_alt.warn_execute()
+ qdel(query_remove_stickyban_alt)
+
log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban")
message_admins("[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban")
@@ -109,7 +147,7 @@
var/ckey = data["ckey"]
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: No sticky ban for [ckey] found!")
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
return
var/oldreason = ban["message"]
var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null
@@ -118,28 +156,203 @@
//we have to do this again incase something changed while we waited for input
ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: The ban disappeared.")
+ to_chat(usr, "Error: The ban disappeared.", confidential = TRUE)
return
ban["message"] = "[reason]"
world.SetConfig("ban",ckey,list2stickyban(ban))
+ SSstickyban.cache[ckey] = ban
+
+ if (SSdbcore.Connect())
+ // var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery(
+ // "UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey",
+ // list("reason" = reason, "ckey" = ckey)
+ // )
+ var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery(
+ "UPDATE [format_table_name("stickyban")] SET reason = [reason] WHERE ckey = [ckey]"
+ )
+ query_edit_stickyban.warn_execute()
+ qdel(query_edit_stickyban)
+
log_admin_private("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]")
message_admins("[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]")
+ if ("exempt")
+ if (!data["ckey"])
+ return
+ var/ckey = data["ckey"]
+ if (!data["alt"])
+ return
+ var/alt = ckey(data["alt"])
+ var/ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
+ return
+
+ var/key = LAZYACCESS(ban["keys"], alt)
+ if (!key)
+ to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!", confidential = TRUE)
+ return
+
+ if (alert("Are you sure you want to exempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
+ return
+
+ //we have to do this again incase something changes
+ ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ to_chat(usr, "Error: The ban disappeared.", confidential = TRUE)
+ return
+
+ key = LAZYACCESS(ban["keys"], alt)
+
+ if (!key)
+ to_chat(usr, "Error: [alt]'s link to [ckey]'s sticky ban disappeared.", confidential = TRUE)
+ return
+ LAZYREMOVE(ban["keys"], alt)
+ key["exempt"] = TRUE
+ LAZYSET(ban["whitelist"], alt, key)
+
+ world.SetConfig("ban",ckey,list2stickyban(ban))
+
+ SSstickyban.cache[ckey] = ban
+
+ if (SSdbcore.Connect())
+ // var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery(
+ // "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt",
+ // list("ckey" = ckey, "alt" = alt)
+ // )
+ var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery(
+ "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
+ )
+ query_exempt_stickyban_alt.warn_execute()
+ qdel(query_exempt_stickyban_alt)
+
+ log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban")
+ message_admins("[key_name_admin(usr)] has exempted [alt] from [ckey]'s sticky ban")
+
+ if ("unexempt")
+ if (!data["ckey"])
+ return
+ var/ckey = data["ckey"]
+ if (!data["alt"])
+ return
+ var/alt = ckey(data["alt"])
+ var/ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
+ return
+
+ var/key = LAZYACCESS(ban["whitelist"], alt)
+ if (!key)
+ to_chat(usr, "Error: [alt] is not exempt from [ckey]'s sticky ban!", confidential = TRUE)
+ return
+
+ if (alert("Are you sure you want to unexempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
+ return
+
+ //we have to do this again incase something changes
+ ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ to_chat(usr, "Error: The ban disappeared.", confidential = TRUE)
+ return
+
+ key = LAZYACCESS(ban["whitelist"], alt)
+ if (!key)
+ to_chat(usr, "Error: [alt]'s exemption from [ckey]'s sticky ban disappeared.", confidential = TRUE)
+ return
+
+ LAZYREMOVE(ban["whitelist"], alt)
+ key["exempt"] = FALSE
+ LAZYSET(ban["keys"], alt, key)
+
+ world.SetConfig("ban",ckey,list2stickyban(ban))
+
+ SSstickyban.cache[ckey] = ban
+
+ if (SSdbcore.Connect())
+ // var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
+ // "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt",
+ // list("ckey" = ckey, "alt" = alt)
+ // )
+ var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
+ "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
+ )
+ query_unexempt_stickyban_alt.warn_execute()
+ qdel(query_unexempt_stickyban_alt)
+
+ log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban")
+ message_admins("[key_name_admin(usr)] has unexempted [alt] from [ckey]'s sticky ban")
+
+ if ("timeout")
+ if (!data["ckey"])
+ return
+ if (!SSdbcore.Connect())
+ to_chat(usr, "No database connection!", confidential = TRUE)
+ return
+
+ var/ckey = data["ckey"]
+
+ if (alert("Are you sure you want to put [ckey]'s stickyban on timeout until next round (or removed)?","Are you sure","Yes","No") == "No")
+ return
+ var/ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
+ return
+
+ ban["timeout"] = TRUE
+
+ world.SetConfig("ban", ckey, null)
+
+ var/cachedban = SSstickyban.cache[ckey]
+ if (cachedban)
+ cachedban["timeout"] = TRUE
+
+ log_admin_private("[key_name(usr)] has put [ckey]'s sticky ban on timeout.")
+ message_admins("[key_name_admin(usr)] has put [ckey]'s sticky ban on timeout.")
+
+ if ("untimeout")
+ if (!data["ckey"])
+ return
+ if (!SSdbcore.Connect())
+ to_chat(usr, "No database connection!", confidential = TRUE)
+ return
+ var/ckey = data["ckey"]
+
+ if (alert("Are you sure you want to lift the timeout on [ckey]'s stickyban?","Are you sure","Yes","No") == "No")
+ return
+
+ var/ban = get_stickyban_from_ckey(ckey)
+ var/cachedban = SSstickyban.cache[ckey]
+ if (cachedban)
+ cachedban["timeout"] = FALSE
+ if (!ban)
+ if (!cachedban)
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
+ return
+ ban = cachedban
+
+ ban["timeout"] = FALSE
+
+ world.SetConfig("ban",ckey,list2stickyban(ban))
+
+ log_admin_private("[key_name(usr)] has taken [ckey]'s sticky ban off of timeout.")
+ message_admins("[key_name_admin(usr)] has taken [ckey]'s sticky ban off of timeout.")
+
+
if ("revert")
if (!data["ckey"])
return
var/ckey = data["ckey"]
- if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start?","Are you sure","Yes","No") == "No")
+ if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start (or last edit)?","Are you sure","Yes","No") == "No")
return
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
- to_chat(usr, "Error: No sticky ban for [ckey] found!")
+ to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE)
return
var/cached_ban = SSstickyban.cache[ckey]
if (!cached_ban)
- to_chat(usr, "Error: No cached sticky ban for [ckey] found!")
+ to_chat(usr, "Error: No cached sticky ban for [ckey] found!", confidential = TRUE)
world.SetConfig("ban",ckey,null)
log_admin_private("[key_name(usr)] has reverted [ckey]'s sticky ban to its state at round start.")
@@ -150,14 +363,22 @@
world.SetConfig("ban",ckey,list2stickyban(cached_ban))
-/datum/admins/proc/stickyban_gethtml(ckey, ban)
- . = {"
+/datum/admins/proc/stickyban_gethtml(ckey)
+ var/ban = get_stickyban_from_ckey(ckey)
+ if (!ban)
+ return
+ var/timeout
+ if (SSdbcore.Connect())
+ timeout = "\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]"
+ else
+ timeout = "\[revert\]"
+ . = list({"
\[-\]
- \[revert\]
+ [timeout]
[ckey]
"
[ban["message"]] \[Edit\]
- "}
+ "})
if (ban["admin"])
. += "[ban["admin"]]
"
else
@@ -166,19 +387,24 @@
for (var/key in ban["keys"])
if (ckey(key) == ckey)
continue
- . += "