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"