From 6519fe884a04374254604b7c5d6fd3dc76baa717 Mon Sep 17 00:00:00 2001
From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
Date: Mon, 3 Jan 2022 19:01:21 +0000
Subject: [PATCH] Ban refactor part 3 - Job bans with CDL (#17283)
---
code/game/world.dm | 8 +-
code/modules/admin/banjob.dm | 180 ++++--------------
code/modules/admin/db_ban/functions.dm | 23 ++-
code/modules/admin/topic.dm | 32 ++--
code/modules/admin/verbs/diagnostics.dm | 36 ----
code/modules/admin/verbs/toggledebugverbs.dm | 2 -
code/modules/client/client_defines.dm | 6 +
code/modules/client/jobban_holder.dm | 72 +++++++
.../login_processing/25-load_jobbans.dm | 10 +
paradise.dme | 2 +
10 files changed, 163 insertions(+), 208 deletions(-)
create mode 100644 code/modules/client/jobban_holder.dm
create mode 100644 code/modules/client/login_processing/25-load_jobbans.dm
diff --git a/code/game/world.dm b/code/game/world.dm
index b3729428119..fcbcb6d3a1c 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -54,7 +54,7 @@ GLOBAL_LIST_INIT(map_transition_config, list(CC_TRANSITION_CONFIG))
GLOB.timezoneOffset = text2num(time2text(0, "hh")) * 36000
- startup_procs() // Call procs that need to occur on startup (Generate lists, load MOTD, etc)
+ investigate_reset()
update_status()
@@ -74,12 +74,6 @@ GLOBAL_LIST_INIT(map_transition_config, list(CC_TRANSITION_CONFIG))
TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED) // creates a new TGS object
GLOB.revision_info.load_tgs_info() // Loads git and TM info from TGS itself
-// This is basically a replacement for hook/startup. Please dont shove random bullshit here
-// If it doesnt need to happen IMMEDIATELY on world load, make a subsystem for it
-/world/proc/startup_procs()
- jobban_loadbans() // Load up jobbans. Again, DO NOT PUT THIS IN A SUBSYSTEM IT WILL TAKE TOO LONG TO BE CALLED
- investigate_reset() // This is part of the admin investigate system. PLEASE DONT SS THIS EITHER
-
/// List of all world topic spam prevention handlers. See code/modules/world_topic/_spam_prevention_handler.dm
GLOBAL_LIST_EMPTY(world_topic_spam_prevention_handlers)
/// List of all world topic handler datums. Populated inside makeDatumRefLists()
diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm
index 808491d3994..7c3fefa3abc 100644
--- a/code/modules/admin/banjob.dm
+++ b/code/modules/admin/banjob.dm
@@ -1,159 +1,59 @@
-GLOBAL_VAR(jobban_runonce) // Updates legacy bans with new info
-GLOBAL_LIST_INIT(jobban_keylist, new()) // Linear list of jobban strings, kept around for the legacy system
-GLOBAL_LIST_INIT(jobban_assoclist, new()) // Associative list, for efficiency
-
-// Matches string-based jobbans into ckey, rank, and reason groups
-GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ## (.+))?"))
-
-/proc/jobban_assoc_insert(ckey, rank, reason)
- if(!ckey || !rank)
- return
- if(!GLOB.jobban_assoclist[ckey])
- GLOB.jobban_assoclist[ckey] = list()
- GLOB.jobban_assoclist[ckey][rank] = reason || "Reason Unspecified"
-
-/proc/jobban_fullban(mob/M, rank, reason)
- if(!M || !M.key)
- return
- GLOB.jobban_keylist.Add(text("[M.ckey] - [rank] ## [reason]"))
- jobban_assoc_insert(M.ckey, rank, reason)
-
-/proc/jobban_client_fullban(ckey, rank)
- if(!ckey || !rank)
- return
- GLOB.jobban_keylist.Add(text("[ckey] - [rank]"))
- jobban_assoc_insert(ckey, rank)
-
-//returns a reason if M is banned from rank, returns 0 otherwise
+// Returns a reason if M is banned from rank, returns null otherwise
/proc/jobban_isbanned(mob/M, rank)
- if(!M || !rank)
- return 0
-
- if(GLOB.configuration.jobs.guest_job_ban && check_job_karma(rank))
- if(IsGuestKey(M.key))
- return "Guest Job-ban"
-
- if(GLOB.jobban_assoclist[M.ckey])
- return GLOB.jobban_assoclist[M.ckey][rank]
- else
- return 0
-
-/proc/jobban_isbanned_ckey(ckey, rank)
- if(!ckey || !rank)
+ if(!M || !M.client || !rank)
return null
- if(GLOB.configuration.jobs.guest_job_ban && check_job_karma(rank))
- if(IsGuestKey(ckey))
- return "Guest Job-ban"
+ if(GLOB.configuration.jobs.guest_job_ban && IsGuestKey(M.key))
+ return "Guest Job-ban"
- if(GLOB.jobban_assoclist[ckey])
- return GLOB.jobban_assoclist[ckey][rank]
+ if(rank in M.client.jbh.job_bans)
+ var/datum/job_ban/JB = M.client.jbh.job_bans[rank]
+ return JB.reason
return null
-/proc/jobban_loadbans()
- if(!SSdbcore.IsConnected())
- log_world("Database connection failed. Job bans not loaded.")
- return
-
- //Job permabans
- var/datum/db_query/permabans = SSdbcore.NewQuery("SELECT ckey, job FROM ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
-
- if(!permabans.warn_execute(async=FALSE))
- qdel(permabans)
- return FALSE
-
- while(permabans.NextRow())
- var/ckey = permabans.item[1]
- var/job = permabans.item[2]
- GLOB.jobban_keylist.Add("[ckey] - [job]")
- jobban_assoc_insert(ckey, job)
-
- qdel(permabans)
-
- // Job tempbans
- var/datum/db_query/tempbans = SSdbcore.NewQuery("SELECT ckey, job FROM ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
-
- if(!tempbans.warn_execute(async=FALSE))
- qdel(tempbans)
- return FALSE
-
- while(tempbans.NextRow())
- var/ckey = tempbans.item[1]
- var/job = tempbans.item[2]
- GLOB.jobban_keylist.Add("[ckey] - [job]")
- jobban_assoc_insert(ckey, job)
-
- qdel(tempbans)
-
-/proc/jobban_savebanfile()
- var/savefile/S=new("data/job_full.ban")
- S["keys[0]"] << GLOB.jobban_keylist
-
-/proc/jobban_unban(mob/M, rank)
- jobban_remove("[M.ckey] - [rank]")
-
-/proc/jobban_unban_client(ckey, rank)
- jobban_remove("[ckey] - [rank]")
-
-/proc/jobban_remove(X)
- for(var/i = 1; i <= length(GLOB.jobban_keylist); i++)
- if( findtext(GLOB.jobban_keylist[i], "[X]") )
- // This need to be here, instead of jobban_unban, due to direct calls to jobban_remove
- if(GLOB.jobban_regex.Find(X))
- var/ckey = GLOB.jobban_regex.group[1]
- var/rank = GLOB.jobban_regex.group[2]
- if(GLOB.jobban_assoclist[ckey] && GLOB.jobban_assoclist[ckey][rank])
- GLOB.jobban_assoclist[ckey] -= rank
- else
- log_runtime(EXCEPTION("Attempted to remove non-existent job ban: [X]"))
- else
- log_runtime(EXCEPTION("Failed to remove malformed job ban from associative list: [X]"))
- GLOB.jobban_keylist.Remove(GLOB.jobban_keylist[i])
- return 1
- return 0
-
-/mob/verb/displayjobbans()
- set category = "OOC"
- set name = "Display Current Jobbans"
- set desc = "Displays all of your current jobbans."
-
- if(!client || !ckey)
- return
-
- var/is_actually_banned = FALSE
- var/datum/db_query/select_query = SSdbcore.NewQuery({"
- SELECT bantime, bantype, reason, job, duration, expiration_time, a_ckey FROM ban
- WHERE ckey LIKE :ckey AND ((bantype like 'JOB_TEMPBAN' AND expiration_time > Now()) OR (bantype like 'JOB_PERMABAN')) AND isnull(unbanned)
+// Gets all the job bans for a ckey incase they are offline
+/proc/get_jobbans_for_offline_ckey(ckey)
+ var/datum/db_query/query = SSdbcore.NewQuery({"
+ SELECT job FROM ban
+ WHERE ckey LIKE :ckey AND ((bantype LIKE 'JOB_TEMPBAN' AND expiration_time > NOW()) OR (bantype LIKE 'JOB_PERMABAN')) AND ISNULL(unbanned)
ORDER BY bantime DESC LIMIT 100"},
list("ckey" = ckey)
)
- if(!select_query.warn_execute())
- qdel(select_query)
+ if(!query.warn_execute())
+ qdel(query)
return FALSE
- while(select_query.NextRow())
+ var/list/jobs = list()
- var/bantime = select_query.item[1]
- var/bantype = select_query.item[2]
- var/reason = select_query.item[3]
- var/job = select_query.item[4]
- var/duration = select_query.item[5]
- var/expiration = select_query.item[6]
- var/ackey = select_query.item[7]
+ while(query.NextRow())
+ jobs += query.item[1]
- if(bantype == "JOB_PERMABAN")
- to_chat(src, "[bantype]: [job] - REASON: [reason], by [ackey]; [bantime]")
- else if(bantype == "JOB_TEMPBAN")
- to_chat(src, "[bantype]: [job] - REASON: [reason], by [ackey]; [bantime]; [duration]; expires [expiration]")
+ return jobs
- is_actually_banned = TRUE
+/client/verb/displayjobbans()
+ set category = "OOC"
+ set name = "Display Current Jobbans"
+ set desc = "Displays all of your current jobbans."
- qdel(select_query)
+ // Ok. I know this verb here is scoped to client, I know.
+ // But sometimes when executing, the src will be a mob
+ // I have no idea why, but this is a workaround.
+ jbh.reload_jobbans(usr.client)
- if(is_actually_banned)
- if(GLOB.configuration.url.banappeals_url)
- to_chat(src, "You can appeal the bans at: [GLOB.configuration.url.banappeals_url]")
- else
+ if(!length(jbh.job_bans))
to_chat(src, "You have no active jobbans!")
+ return
+
+ for(var/ban in jbh.job_bans)
+ var/datum/job_ban/JB = jbh.job_bans[ban] // Remember. Its assoc.
+ switch(JB.bantype)
+ if("JOB_PERMABAN")
+ to_chat(src, "[JB.bantype]: [JB.job] - REASON: [JB.reason], by [JB.a_ckey]; [JB.bantime]")
+ if("JOB_TEMPBAN")
+ to_chat(src, "[JB.bantype]: [JB.job] - REASON: [JB.reason], by [JB.a_ckey]; [JB.bantime]; [JB.duration]; expires [JB.expiration_time]")
+
+ if(GLOB.configuration.url.banappeals_url)
+ to_chat(src, "You can appeal the bans at: [GLOB.configuration.url.banappeals_url]")
+
diff --git a/code/modules/admin/db_ban/functions.dm b/code/modules/admin/db_ban/functions.dm
index b83bc4ec028..44b27afb2e6 100644
--- a/code/modules/admin/db_ban/functions.dm
+++ b/code/modules/admin/db_ban/functions.dm
@@ -179,7 +179,11 @@
qdel(banned_mob.client)
if(isjobban)
- jobban_client_fullban(ckey, job)
+ // See if they are online
+ var/client/C = GLOB.directory[ckey(ckey)]
+ if(C)
+ // Reload their job ban holder
+ C.jbh.reload_jobbans(C)
else
flag_account_for_forum_sync(ckey)
@@ -265,7 +269,11 @@
DB_ban_unban_by_id(ban_id)
if(isjobban)
- jobban_unban_client(ckey, job)
+ // See if they are online
+ var/client/C = GLOB.directory[ckey(ckey)]
+ if(C)
+ // Reload their job ban holder
+ C.jbh.reload_jobbans(C)
else
flag_account_for_forum_sync(ckey)
@@ -346,7 +354,11 @@
if(alert("Unban [pckey]?", "Unban?", "Yes", "No") == "Yes")
DB_ban_unban_by_id(banid)
if(job && length(job))
- jobban_unban_client(pckey, job)
+ // See if they are online
+ var/client/C = GLOB.directory[ckey(pckey)]
+ if(C)
+ // Reload their job ban holder
+ C.jbh.reload_jobbans(C)
return
else
to_chat(usr, "Cancelled")
@@ -410,6 +422,11 @@
message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.")
log_admin("[key_name(usr)] has lifted [pckey]'s ban.")
flag_account_for_forum_sync(pckey)
+ // See if they are online
+ var/client/C = GLOB.directory[ckey(pckey)]
+ if(C)
+ // Reload their job ban holder
+ C.jbh.reload_jobbans(C)
/datum/admins/proc/DB_ban_panel(playerckey = null, adminckey = null, playerip = null, playercid = null, dbbantype = null, match = null)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index a63bb54264b..23bb2600d98 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -219,8 +219,9 @@
if(multi_job)
//Create a list of unbanned jobs within joblist
var/list/notbannedlist = list()
+ var/list/banned_list = get_jobbans_for_offline_ckey(banckey) // They might be offline, you never know
for(var/job in jobs_to_ban)
- if(!jobban_isbanned_ckey(banckey, job))
+ if(!(job in banned_list))
notbannedlist += job
for(var/job in notbannedlist)
@@ -773,11 +774,13 @@
for(var/job in notbannedlist)
log_admin("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes")
DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job)
- jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") //Legacy banning does not support temporary jobbans.
if(!msg)
msg = job
else
msg += ", [job]"
+
+ // Reload their job ban holder (refresh this round)
+ M.client.jbh.reload_jobbans(M.client)
add_note(M.ckey, "Banned from [msg] - [reason]", null, usr.ckey, 0)
message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1)
to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
@@ -793,9 +796,13 @@
for(var/job in notbannedlist)
log_admin("[key_name(usr)] perma-banned [key_name(M)] from [job]")
DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, job)
- jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
- if(!msg) msg = job
- else msg += ", [job]"
+ if(!msg)
+ msg = job
+ else
+ msg += ", [job]"
+
+ // Reload their job ban holder (refresh this round)
+ M.client.jbh.reload_jobbans(M.client)
add_note(M.ckey, "Banned from [msg] - [reason]", null, usr.ckey, 0)
message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1)
to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
@@ -883,21 +890,6 @@
usr << browse(edit_log,"window=noteedits")
qdel(query_noteedits)
- else if(href_list["removejobban"])
- if(!check_rights(R_BAN)) return
-
- var/t = href_list["removejobban"]
- if(t)
- if((alert("Do you want to unjobban [t]?","Unjobban confirmation", "Yes", "No") == "Yes") && t) //No more misclicks! Unless you do it twice.
- log_admin("[key_name(usr)] removed [t]")
- message_admins("[key_name_admin(usr)] removed [t]", 1)
- jobban_remove(t)
- href_list["ban"] = 1 // lets it fall through and refresh
- var/t_split = splittext(t, " - ")
- var/key = t_split[1]
- var/job = t_split[2]
- DB_ban_unban(ckey(key), BANTYPE_JOB_PERMA, job)
-
else if(href_list["newban"])
if(!check_rights(R_BAN)) return
diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm
index f57d2871b02..08ddadc3f3a 100644
--- a/code/modules/admin/verbs/diagnostics.dm
+++ b/code/modules/admin/verbs/diagnostics.dm
@@ -119,42 +119,6 @@
load_admins(run_async=TRUE)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reload Admins") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/print_jobban_old()
- set name = "Print Jobban Log"
- set desc = "This spams all the active jobban entries for the current round to standard output."
- set category = "Debug"
-
- if(!check_rights(R_DEBUG))
- return
-
- to_chat(usr, "Jobbans active in this round.")
- for(var/t in GLOB.jobban_keylist)
- to_chat(usr, "[t]")
-
- message_admins("[key_name_admin(usr)] has printed the jobban log")
- log_admin("[key_name(usr)] has printed the jobban log")
-
-/client/proc/print_jobban_old_filter()
- set name = "Search Jobban Log"
- set desc = "This searches all the active jobban entries for the current round and outputs the results to standard output."
- set category = "Debug"
-
- if(!check_rights(R_DEBUG))
- return
-
- var/filter = clean_input("Contains what?","Filter")
- if(!filter)
- return
-
- to_chat(usr, "Jobbans active in this round.")
- for(var/t in GLOB.jobban_keylist)
- if(findtext(t, filter))
- to_chat(usr, "[t]")
-
- message_admins("[key_name_admin(usr)] has searched the jobban log for [filter]")
- log_admin("[key_name(usr)] has searched the jobban log for [filter]")
-
/client/proc/vv_by_ref()
set name = "VV by Ref"
set desc = "Give this a ref string, and you will see its corresponding VV panel if it exists"
diff --git a/code/modules/admin/verbs/toggledebugverbs.dm b/code/modules/admin/verbs/toggledebugverbs.dm
index e82da39558a..cded94b4caa 100644
--- a/code/modules/admin/verbs/toggledebugverbs.dm
+++ b/code/modules/admin/verbs/toggledebugverbs.dm
@@ -14,8 +14,6 @@ GLOBAL_LIST_INIT(admin_verbs_show_debug_verbs, list(
/client/proc/cmd_admin_areatest,
/client/proc/cmd_admin_rejuvenate,
/datum/admins/proc/show_traitor_panel,
- /client/proc/print_jobban_old,
- /client/proc/print_jobban_old_filter,
/client/proc/forceEvent,
/client/proc/admin_redo_space_transitions,
/client/proc/make_turf_space_map,
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index a31bb348820..2d0ffc409e1 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -120,6 +120,9 @@
/// The client's karma holder
var/datum/karma_holder/karmaholder
+ /// The client's job ban holder
+ var/datum/job_ban_holder/jbh = new()
+
/client/vv_edit_var(var_name, var_value)
switch(var_name)
// I know we will never be in a world where admins are editing client vars to let people bypass TOS
@@ -132,4 +135,7 @@
// or this
if("karmaholder")
return FALSE
+ // or this
+ if("jbh")
+ return FALSE
return ..()
diff --git a/code/modules/client/jobban_holder.dm b/code/modules/client/jobban_holder.dm
new file mode 100644
index 00000000000..0f6c86aea22
--- /dev/null
+++ b/code/modules/client/jobban_holder.dm
@@ -0,0 +1,72 @@
+/// Holder for job bans
+/datum/job_ban_holder
+ /// Assoc list of job banned:ban holder
+ var/list/datum/job_ban/job_bans = list()
+
+// Get us a query
+/datum/job_ban_holder/proc/get_query(client/C)
+ var/datum/db_query/query = SSdbcore.NewQuery({"
+ SELECT bantime, bantype, reason, job, duration, expiration_time, a_ckey FROM ban
+ WHERE ckey LIKE :ckey AND ((bantype LIKE 'JOB_TEMPBAN' AND expiration_time > NOW()) OR (bantype LIKE 'JOB_PERMABAN')) AND ISNULL(unbanned)
+ ORDER BY bantime DESC LIMIT 100"}, // If someone has 100 job bans we have bigger problems
+ list("ckey" = C.ckey)
+ )
+ return query
+
+// Uses the query from above
+/datum/job_ban_holder/proc/process_query(datum/db_query/Q)
+ while(Q.NextRow())
+ var/datum/job_ban/JB = new()
+ JB.bantime = Q.item[1]
+ JB.bantype = Q.item[2]
+ JB.reason = Q.item[3]
+ JB.job = Q.item[4]
+ JB.duration = Q.item[5]
+ JB.expiration_time = Q.item[6]
+ JB.a_ckey = Q.item[7]
+ job_bans[JB.job] = JB // Save it assoc
+
+// Check if someone is job banned
+/datum/job_ban_holder/proc/is_banned(job)
+ if(job in job_bans)
+ return TRUE
+ return FALSE
+
+// Reload the job bans
+/datum/job_ban_holder/proc/reload_jobbans(client/C)
+ var/datum/db_query/data = get_query(C)
+ if(!data.warn_execute())
+ qdel(data)
+ return
+
+ job_bans.Cut() // Empty it
+ process_query(data)
+ qdel(data)
+
+// dont mess with this
+/datum/job_ban_holder/vv_edit_var(var_name, var_value)
+ return FALSE
+
+/datum/job_ban_holder/CanProcCall(procname)
+ return FALSE
+
+// Job ban data "model"
+/datum/job_ban
+ /// Time of ban
+ var/bantime
+ /// Type of ban
+ var/bantype
+ /// Reason for ban
+ var/reason
+ /// Job banned itself
+ var/job
+ /// Duration (if temp)
+ var/duration
+ /// Expiry time (if temp)
+ var/expiration_time
+ /// Admin who did it
+ var/a_ckey
+
+// or this
+/datum/job_ban/vv_edit_var(var_name, var_value)
+ return FALSE
diff --git a/code/modules/client/login_processing/25-load_jobbans.dm b/code/modules/client/login_processing/25-load_jobbans.dm
new file mode 100644
index 00000000000..3825e01f223
--- /dev/null
+++ b/code/modules/client/login_processing/25-load_jobbans.dm
@@ -0,0 +1,10 @@
+/datum/client_login_processor/load_jobbans
+ priority = 25
+
+// These look pretty useless, but it allows the client jobban holder to reload bans without proc calling here,
+// and we can re-use the same queries and handlers
+/datum/client_login_processor/load_jobbans/get_query(client/C)
+ return C.jbh.get_query(C)
+
+/datum/client_login_processor/load_jobbans/process_result(datum/db_query/Q, client/C)
+ C.jbh.process_query(Q)
diff --git a/paradise.dme b/paradise.dme
index fca4ac6d8a3..5faf4da8fb6 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1409,10 +1409,12 @@
#include "code\modules\client\asset_cache.dm"
#include "code\modules\client\client_defines.dm"
#include "code\modules\client\client_procs.dm"
+#include "code\modules\client\jobban_holder.dm"
#include "code\modules\client\message.dm"
#include "code\modules\client\view.dm"
#include "code\modules\client\login_processing\10-load_preferences.dm"
#include "code\modules\client\login_processing\20-load_characters.dm"
+#include "code\modules\client\login_processing\25-load_jobbans.dm"
#include "code\modules\client\login_processing\30-tos_consent.dm"
#include "code\modules\client\login_processing\35-donator_check.dm"
#include "code\modules\client\login_processing\36-watchlist.dm"