mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
[ADMIN] Chganges auth backend to use the forums instead of the DB (#15195)
* [ADMIN] Chganges auth backend to use the forums instead of the DB * Remove dbranks flag * I'm dumb * re-promotes myself * Re-use datums, rather than continually re-making them * Delete the datum instead, easier to manage * Moved to an inhertiance based system for permissions management * Proccall protection and logging * Linter * Update config * Fixes pp I hope * Two letters made it do a bad, I am sad * Clears forums admins when reloading * Adds db support * Update config * Re-enables forum integration * No editing the funny datum * Allow me to do the funny during the test merge * Didn't commit the changes * Copying and pasting hard * Sanitize ckey * Var is unnecessary * Small debug log to debug dono chat * Fixes wrong proc call * Move log, will be a bit much, but is fine because its temporary * Made better log message * Fixed reload admins, added debug log to json_decode that was erroring * Expanded forums integration error handling * Fully protects funny lists
This commit is contained in:
@@ -37,8 +37,8 @@
|
||||
#define R_SOUNDS (1<<11)
|
||||
#define R_SPAWN (1<<12)
|
||||
#define R_AUTOLOGIN (1<<13)
|
||||
#define R_DBRANKS (1<<14)
|
||||
#define R_DEV (1<<15) // Stuff NOONE should be touching except for head-dev/maints, I guess council too..
|
||||
#define R_DEV (1<<14) // Stuff NOONE should be touching except for head-dev/maints, I guess council too..
|
||||
#define R_PERSIST_PERMS (1<<15) // Allow modification of persistent perms
|
||||
#define R_EVERYTHING (1<<16)-1 //the sum of all other rank permissions, used for +EVERYTHING
|
||||
|
||||
#define R_DEFAULT R_AUTOLOGIN
|
||||
|
||||
@@ -294,7 +294,7 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE))
|
||||
#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, \
|
||||
type = MESSAGE_TYPE_DEBUG, \
|
||||
text = "DEBUG: [msg]")
|
||||
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, \
|
||||
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.permissions.admins, \
|
||||
type = MESSAGE_TYPE_DEBUG, \
|
||||
text = "DEBUG: [msg]")
|
||||
#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
|
||||
|
||||
@@ -622,76 +622,6 @@
|
||||
count++
|
||||
return objective_parts.Join("<br>")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/save_admin_data()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
else if(load_admins(TRUE)) //returns true if there was a database failure and the backup was loaded from
|
||||
return
|
||||
sync_ranks_with_db()
|
||||
var/list/sql_admins = list()
|
||||
for(var/i in GLOB.protected_admins)
|
||||
var/datum/admins/A = GLOB.protected_admins[i]
|
||||
sql_admins += list(list("ckey" = A.target, "rank" = A.rank.name))
|
||||
SSdbcore.MassInsert(format_table_name("admin"), sql_admins, duplicate_key = TRUE)
|
||||
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] p INNER JOIN [format_table_name("admin")] a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
|
||||
query_admin_rank_update.Execute()
|
||||
qdel(query_admin_rank_update)
|
||||
|
||||
//json format backup file generation stored per server
|
||||
var/json_file = file("data/admins_backup.json")
|
||||
var/list/file_data = list("ranks" = list(), "admins" = list())
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
file_data["ranks"]["[R.name]"] = list()
|
||||
file_data["ranks"]["[R.name]"]["include rights"] = R.include_rights
|
||||
file_data["ranks"]["[R.name]"]["exclude rights"] = R.exclude_rights
|
||||
file_data["ranks"]["[R.name]"]["can edit rights"] = R.can_edit_rights
|
||||
for(var/i in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/A = GLOB.admin_datums[i]
|
||||
if(!A)
|
||||
A = GLOB.deadmins[i]
|
||||
if (!A)
|
||||
continue
|
||||
file_data["admins"]["[i]"] = list()
|
||||
file_data["admins"]["[i]"]["rank"] = A.rank.name
|
||||
file_data["admins"]["[i]"]["ip_cache"] = A.ip_cache
|
||||
file_data["admins"]["[i]"]["cid_cache"] = A.cid_cache
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/update_everything_flag_in_db()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
var/list/flags = list()
|
||||
if(R.include_rights == R_EVERYTHING)
|
||||
flags += "flags"
|
||||
if(R.exclude_rights == R_EVERYTHING)
|
||||
flags += "exclude_flags"
|
||||
if(R.can_edit_rights == R_EVERYTHING)
|
||||
flags += "can_edit_flags"
|
||||
if(!flags.len)
|
||||
continue
|
||||
var/flags_to_check = flags.Join(" != [R_EVERYTHING] AND ") + " != [R_EVERYTHING]"
|
||||
var/datum/DBQuery/query_check_everything_ranks = SSdbcore.NewQuery(
|
||||
"SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = :rank AND ([flags_to_check])",
|
||||
list("rank" = R.name)
|
||||
)
|
||||
if(!query_check_everything_ranks.Execute())
|
||||
qdel(query_check_everything_ranks)
|
||||
return
|
||||
if(query_check_everything_ranks.NextRow()) //no row is returned if the rank already has the correct flag value
|
||||
var/flags_to_update = flags.Join(" = [R_EVERYTHING], ") + " = [R_EVERYTHING]"
|
||||
var/datum/DBQuery/query_update_everything_ranks = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin_ranks")] SET [flags_to_update] WHERE rank = :rank",
|
||||
list("rank" = R.name)
|
||||
)
|
||||
if(!query_update_everything_ranks.Execute())
|
||||
qdel(query_update_everything_ranks)
|
||||
return
|
||||
qdel(query_update_everything_ranks)
|
||||
qdel(query_check_everything_ranks)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/cargoking()
|
||||
var/datum/achievement/cargoking/CK = SSachievements.get_achievement(/datum/achievement/cargoking)
|
||||
var/cargoking = FALSE
|
||||
|
||||
@@ -195,38 +195,38 @@
|
||||
//Converts a rights bitfield into a string
|
||||
/proc/rights2text(rights, seperator="", prefix = "+")
|
||||
seperator += prefix
|
||||
if(rights & R_BUILDMODE)
|
||||
. += "[seperator]BUILDMODE"
|
||||
if(rights & R_ADMIN)
|
||||
. += "[seperator]ADMIN"
|
||||
if(rights & R_AUTOLOGIN)
|
||||
. += "[seperator]AUTOLOGIN"
|
||||
if(rights & R_BAN)
|
||||
. += "[seperator]BAN"
|
||||
if(rights & R_FUN)
|
||||
. += "[seperator]FUN"
|
||||
if(rights & R_SERVER)
|
||||
. += "[seperator]SERVER"
|
||||
if(rights & R_BUILDMODE)
|
||||
. += "[seperator]BUILDMODE"
|
||||
if(rights & R_DEBUG)
|
||||
. += "[seperator]DEBUG"
|
||||
if(rights & R_POSSESS)
|
||||
. += "[seperator]POSSESS"
|
||||
if(rights & R_DEV)
|
||||
. += "[seperator]DEV"
|
||||
if(rights & R_FUN)
|
||||
. += "[seperator]FUN"
|
||||
if(rights & R_PERMISSIONS)
|
||||
. += "[seperator]PERMISSIONS"
|
||||
if(rights & R_STEALTH)
|
||||
. += "[seperator]STEALTH"
|
||||
if(rights & R_PERSIST_PERMS)
|
||||
. += "[seperator]PERSISTPERMS"
|
||||
if(rights & R_POLL)
|
||||
. += "[seperator]POLL"
|
||||
if(rights & R_VAREDIT)
|
||||
. += "[seperator]VAREDIT"
|
||||
if(rights & R_POSSESS)
|
||||
. += "[seperator]POSSESS"
|
||||
if(rights & R_SERVER)
|
||||
. += "[seperator]SERVER"
|
||||
if(rights & R_SOUNDS)
|
||||
. += "[seperator]SOUND"
|
||||
if(rights & R_SPAWN)
|
||||
. += "[seperator]SPAWN"
|
||||
if(rights & R_AUTOLOGIN)
|
||||
. += "[seperator]AUTOLOGIN"
|
||||
if(rights & R_DBRANKS)
|
||||
. += "[seperator]DBRANKS"
|
||||
if(rights & R_DEV)
|
||||
. += "[seperator]DEV"
|
||||
if(rights & R_STEALTH)
|
||||
. += "[seperator]STEALTH"
|
||||
if(rights & R_VAREDIT)
|
||||
. += "[seperator]VAREDIT"
|
||||
if(!.)
|
||||
. = "NONE"
|
||||
return .
|
||||
|
||||
@@ -68,8 +68,8 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"SOUNDS" = R_SOUNDS,
|
||||
"SPAWN" = R_SPAWN,
|
||||
"AUTOLOGIN" = R_AUTOLOGIN,
|
||||
"DBRANKS" = R_DBRANKS,
|
||||
"DEV" = R_DEV
|
||||
"DEV" = R_DEV,
|
||||
"PERSISTPERMS" = R_PERSIST_PERMS
|
||||
),
|
||||
"interaction_flags_atom" = list(
|
||||
"INTERACT_ATOM_REQUIRES_ANCHORED" = INTERACT_ATOM_REQUIRES_ANCHORED,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
GLOBAL_LIST_EMPTY(clients) //all clients
|
||||
GLOBAL_LIST_EMPTY(admins) //all clients whom are admins
|
||||
GLOBAL_PROTECT(admins)
|
||||
GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb.
|
||||
|
||||
GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client
|
||||
GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys, for stealthmins
|
||||
|
||||
@@ -161,9 +161,6 @@
|
||||
min_val = 0 //oranges warned us
|
||||
integer = FALSE
|
||||
|
||||
/datum/config_entry/flag/admin_legacy_system //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/protect_legacy_admins //Stops any admins loaded by the legacy system from having their rank edited by the permissions panel
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
@@ -173,7 +170,7 @@
|
||||
/datum/config_entry/flag/enable_localhost_rank //Gives the !localhost! rank to any client connecting from 127.0.0.1 or ::1
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/load_legacy_ranks_only //Loads admin ranks only from legacy admin_ranks.txt, while enabled ranks are mirrored to the database
|
||||
/datum/config_entry/string/permissions_backend // Sets the permissions backend to use
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/string/hostedby
|
||||
|
||||
@@ -59,20 +59,20 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
message_admins(span_adminnotice("Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks."))
|
||||
--defcon
|
||||
if(2)
|
||||
to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks."))
|
||||
to_chat(GLOB.permissions.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks."))
|
||||
--defcon
|
||||
if(1)
|
||||
|
||||
to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting..."))
|
||||
to_chat(GLOB.permissions.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting..."))
|
||||
--defcon
|
||||
var/rtn = Recreate_MC()
|
||||
if(rtn > 0)
|
||||
defcon = 4
|
||||
master_iteration = 0
|
||||
to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
|
||||
to_chat(GLOB.permissions.admins, span_adminnotice("MC restarted successfully"))
|
||||
else if(rtn < 0)
|
||||
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
|
||||
to_chat(GLOB.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
|
||||
to_chat(GLOB.permissions.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
|
||||
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
|
||||
//no need to handle that specially when defcon 0 can handle it
|
||||
if(0) //DEFCON 0! (mc failed to restart)
|
||||
@@ -80,7 +80,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
if(rtn > 0)
|
||||
defcon = 4
|
||||
master_iteration = 0
|
||||
to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
|
||||
to_chat(GLOB.permissions.admins, span_adminnotice("MC restarted successfully"))
|
||||
else
|
||||
defcon = min(defcon + 1,5)
|
||||
master_iteration = Master.iteration
|
||||
|
||||
@@ -152,7 +152,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined."
|
||||
BadBoy.flags |= SS_NO_FIRE
|
||||
if(msg)
|
||||
to_chat(GLOB.admins, span_boldannounce("[msg]"))
|
||||
to_chat(GLOB.permissions.admins, span_boldannounce("[msg]"))
|
||||
log_world(msg)
|
||||
|
||||
if (istype(Master.subsystems))
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
SEND_SIGNAL(src, COMSIG_SUBSYSTEM_POST_INITIALIZE, start_timeofday)
|
||||
var/time = (REALTIMEOFDAY - start_timeofday)/10
|
||||
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!" // Yogs -- quieter subsystem initialization
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_DEBUG,
|
||||
html = span_notice(msg),
|
||||
confidential = FALSE)
|
||||
|
||||
@@ -395,7 +395,7 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
//Yogs start -- prettier atmos notices
|
||||
var/msg = "HEY! LISTEN! [(world.timeofday - timer)/10] seconds were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_DEBUG,
|
||||
html = span_notice(msg),
|
||||
confidential = FALSE)
|
||||
|
||||
@@ -738,5 +738,3 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
/datum/controller/subsystem/ticker/Shutdown()
|
||||
gather_newscaster() //called here so we ensure the log is created even upon admin reboot
|
||||
save_admin_data()
|
||||
update_everything_flag_in_db()
|
||||
|
||||
@@ -134,7 +134,7 @@ SUBSYSTEM_DEF(vote)
|
||||
SSmapping.map_voted = TRUE
|
||||
if(restart)
|
||||
var/active_admins = FALSE
|
||||
for(var/client/C in GLOB.admins + GLOB.deadmins)
|
||||
for(var/client/C in GLOB.permissions.admins + GLOB.permissions.deadmins)
|
||||
if(!C.is_afk() && check_rights_for(C, R_SERVER))
|
||||
active_admins = TRUE
|
||||
break
|
||||
@@ -170,7 +170,7 @@ SUBSYSTEM_DEF(vote)
|
||||
return FALSE
|
||||
var/lower_admin = FALSE
|
||||
var/ckey = ckey(initiator_key)
|
||||
if(GLOB.admin_datums[ckey])
|
||||
if(GLOB.permissions.admin_datums[ckey])
|
||||
lower_admin = TRUE
|
||||
|
||||
if(!mode)
|
||||
|
||||
@@ -610,7 +610,7 @@
|
||||
continue //Ghosted while alive
|
||||
|
||||
|
||||
for (var/C in GLOB.admins)
|
||||
for (var/C in GLOB.permissions.admins)
|
||||
to_chat(C, msg.Join())
|
||||
log_admin(msg.Join())
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
// Autoapproves after a certain time
|
||||
rename_callback = CALLBACK(src, .proc/rename_station, new_name, user.name, user.real_name, key_name(user))
|
||||
response_timer_id = addtimer(rename_callback, approval_time, TIMER_STOPPABLE)
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
span_adminnotice("<b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will auto-approve in [DisplayTimeText(approval_time)]).\
|
||||
(<a HREF='?_src_=holder;[HrefToken(TRUE)];accept_custom_name=[REF(src)]'>ACCEPT</a> or <a HREF='?_src_=holder;[HrefToken(TRUE)];reject_custom_name=[REF(src)]'>REJECT</a>) [ADMIN_SMITE(user)] [ADMIN_CENTCOM_REPLY(user)]"))
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ GLOBAL_VAR(restart_counter)
|
||||
|
||||
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
|
||||
|
||||
load_admins()
|
||||
init_permissions()
|
||||
|
||||
GLOB.permissions.start()
|
||||
|
||||
//SetupLogs depends on the RoundID, so lets check
|
||||
//DB schema and set RoundID if we can
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
//magic voodo to check for a key in a list while also adding that key to the list without having to do two associated lookups
|
||||
var/message = !checkedckeys[ckey]++
|
||||
|
||||
if(GLOB.admin_datums[ckey] || GLOB.deadmins[ckey])
|
||||
if(GLOB.permissions.admin_datums[ckey] || GLOB.permissions.deadmins[ckey])
|
||||
admin = TRUE
|
||||
|
||||
var/client/C = GLOB.directory[ckey]
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
////////////////////////////////
|
||||
/proc/message_admins(msg)
|
||||
msg = span_admin("<span class=\"prefix\">ADMIN LOG:</span> <span class=\"message\">[msg]</span>")
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
html = msg,
|
||||
confidential = TRUE)
|
||||
|
||||
/proc/relay_msg_admins(msg)
|
||||
msg = span_admin("<span class=\"prefix\">RELAY:</span> <span class=\"message\">[msg]</span>")
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
html = msg,
|
||||
confidential = TRUE)
|
||||
@@ -42,7 +42,7 @@
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[M.client.ckey] || GLOB.deadmins[M.client.ckey]) ? "rank" : "add"];key=[M.key]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.permissions.admin_datums[M.client.ckey] || GLOB.permissions.deadmins[M.client.ckey]) ? "rank" : "add"];key=[M.key]'>[M.client.holder ? M.client.holder.rank_name() : "Player"]</A>\]"
|
||||
if(CONFIG_GET(flag/use_exp_tracking))
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(M)]'>" + M.client.get_exp_living() + "</a> | "
|
||||
body += " <A href='?_src_=holder;[HrefToken()];toggleexempt=[REF(M)]'>Toggle Exempt</a>\]"
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
GLOBAL_LIST_EMPTY(admin_ranks) //list of all admin_rank datums
|
||||
GLOBAL_PROTECT(admin_ranks)
|
||||
|
||||
GLOBAL_LIST_EMPTY(protected_ranks) //admin ranks loaded from txt
|
||||
GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
/datum/admin_rank
|
||||
var/name = "NoRank"
|
||||
var/rights = R_DEFAULT
|
||||
var/exclude_rights = 0
|
||||
var/include_rights = 0
|
||||
var/can_edit_rights = 0
|
||||
|
||||
/datum/admin_rank/New(init_name, init_rights, init_exclude_rights, init_edit_rights)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
if (name == "NoRank") //only del if this is a true creation (and not just a New() proc call), other wise trialmins/coders could abuse this to deadmin other admins
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
return
|
||||
name = init_name
|
||||
if(!name)
|
||||
qdel(src)
|
||||
CRASH("Admin rank created without name.")
|
||||
if(init_rights)
|
||||
rights = init_rights
|
||||
include_rights = rights
|
||||
if(init_exclude_rights)
|
||||
exclude_rights = init_exclude_rights
|
||||
rights &= ~exclude_rights
|
||||
if(init_edit_rights)
|
||||
can_edit_rights = init_edit_rights
|
||||
|
||||
/datum/admin_rank/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/proc/admin_keyword_to_flag(word, previous_rights=0)
|
||||
var/flag = 0
|
||||
switch(ckey(word))
|
||||
if("buildmode","build")
|
||||
flag = R_BUILDMODE
|
||||
if("admin")
|
||||
flag = R_ADMIN
|
||||
if("ban")
|
||||
flag = R_BAN
|
||||
if("fun")
|
||||
flag = R_FUN
|
||||
if("server")
|
||||
flag = R_SERVER
|
||||
if("debug")
|
||||
flag = R_DEBUG
|
||||
if("permissions","rights")
|
||||
flag = R_PERMISSIONS
|
||||
if("possess")
|
||||
flag = R_POSSESS
|
||||
if("stealth")
|
||||
flag = R_STEALTH
|
||||
if("poll")
|
||||
flag = R_POLL
|
||||
if("varedit")
|
||||
flag = R_VAREDIT
|
||||
if("everything","host","all")
|
||||
flag = R_EVERYTHING
|
||||
if("sound","sounds")
|
||||
flag = R_SOUNDS
|
||||
if("spawn","create")
|
||||
flag = R_SPAWN
|
||||
if("autologin", "autoadmin")
|
||||
flag = R_AUTOLOGIN
|
||||
if("dbranks")
|
||||
flag = R_DBRANKS
|
||||
if("dev")
|
||||
flag = R_DEV
|
||||
if("@","prev")
|
||||
flag = previous_rights
|
||||
return flag
|
||||
|
||||
// Adds/removes rights to this admin_rank
|
||||
/datum/admin_rank/proc/process_keyword(word, previous_rights=0)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
var/flag = admin_keyword_to_flag(word, previous_rights)
|
||||
if(flag)
|
||||
switch(text2ascii(word,1))
|
||||
if(43)
|
||||
rights |= flag //+
|
||||
include_rights |= flag
|
||||
if(45)
|
||||
rights &= ~flag //-
|
||||
exclude_rights |= flag
|
||||
if(42)
|
||||
can_edit_rights |= flag //*
|
||||
|
||||
// Checks for (keyword-formatted) rights on this admin
|
||||
/datum/admins/proc/check_keyword(word)
|
||||
var/flag = admin_keyword_to_flag(word)
|
||||
if(flag)
|
||||
return ((rank.rights & flag) == flag) //true only if right has everything in flag
|
||||
|
||||
/proc/sync_ranks_with_db()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>", confidential=TRUE)
|
||||
return
|
||||
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.protected_ranks)
|
||||
sql_ranks += list(list("rank" = R.name, "flags" = R.include_rights, "exclude_flags" = R.exclude_rights, "can_edit_flags" = R.can_edit_rights))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks(dbfail, no_update)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Reload blocked: Advanced ProcCall detected.</span>", confidential=TRUE)
|
||||
return
|
||||
GLOB.admin_ranks.Cut()
|
||||
GLOB.protected_ranks.Cut()
|
||||
var/previous_rights = 0
|
||||
//load text from file and process each line separately
|
||||
for(var/line in world.file2list("[global.config.directory]/admin_ranks.txt"))
|
||||
if(!line || findtextEx(line,"#",1,2) || line == " ") //YOGS - added our DB support
|
||||
continue
|
||||
var/next = findtext(line, "=")
|
||||
var/datum/admin_rank/R = new(trim(copytext(line, 1, next)))
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
GLOB.protected_ranks += R
|
||||
var/prev = findchar(line, "+-*", next, 0)
|
||||
while(prev)
|
||||
next = findchar(line, "+-*", prev + 1, 0)
|
||||
R.process_keyword(copytext(line, prev, next), previous_rights)
|
||||
prev = next
|
||||
previous_rights = R.rights
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
if(!no_update)
|
||||
sync_ranks_with_db()
|
||||
else
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = trim(query_load_admin_ranks.item[1])
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
qdel(query_load_admin_ranks)
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return FALSE
|
||||
var/list/json = json_decode(backup_file)
|
||||
for(var/J in json["ranks"])
|
||||
var/skip
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == "[J]") //this rank was already loaded from txt override
|
||||
skip = TRUE
|
||||
if(skip)
|
||||
continue
|
||||
var/datum/admin_rank/R = new("[J]", json["ranks"]["[J]"]["include rights"], json["ranks"]["[J]"]["exclude rights"], json["ranks"]["[J]"]["can edit rights"])
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
return json
|
||||
#ifdef TESTING
|
||||
var/msg = "Permission Sets Built:\n"
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
msg += "\t[R.name]"
|
||||
var/rights = rights2text(R.rights,"\n\t\t")
|
||||
if(rights)
|
||||
msg += "\t\t[rights]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
/proc/load_admins(no_update)
|
||||
var/dbfail
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database while loading admins. Loading from backup.")
|
||||
log_sql("Failed to connect to database while loading admins. Loading from backup.")
|
||||
dbfail = 1
|
||||
//clear the datums references
|
||||
GLOB.admin_datums.Cut()
|
||||
for(var/client/C in GLOB.admins)
|
||||
C.remove_admin_verbs()
|
||||
C.holder = null
|
||||
GLOB.admins.Cut()
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
var/list/backup_file_json = load_admin_ranks(dbfail, no_update)
|
||||
dbfail = backup_file_json != null
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
var/list/rank_names = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
rank_names[R.name] = R
|
||||
//ckeys listed in admins.txt are always made admins before sql loading is attempted
|
||||
var/list/lines = world.file2list("[global.config.directory]/admins.txt")
|
||||
for(var/line in lines)
|
||||
if(!length(line) || findtextEx(line, "#", 1, 2) || line == " ") //yogs - added our DB support
|
||||
continue
|
||||
var/list/entry = splittext(line, "=")
|
||||
if(entry.len < 2)
|
||||
continue
|
||||
var/ckey = ckey(entry[1])
|
||||
var/rank = trim(entry[2])
|
||||
if(!ckey || !rank)
|
||||
continue
|
||||
new /datum/admins(rank_names[rank], ckey, 0, 1)
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, rank FROM [format_table_name("admin")] ORDER BY rank")
|
||||
if(!query_load_admins.Execute())
|
||||
message_admins("Error loading admins from database. Loading from backup.")
|
||||
log_sql("Error loading admins from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admins.NextRow())
|
||||
var/admin_ckey = ckey(query_load_admins.item[1])
|
||||
var/admin_rank = trim(query_load_admins.item[2])
|
||||
var/skip
|
||||
if(rank_names[admin_rank] == null)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
skip = 1
|
||||
if(GLOB.admin_datums[admin_ckey] || GLOB.deadmins[admin_ckey])
|
||||
skip = 1
|
||||
if(!skip)
|
||||
new /datum/admins(rank_names[admin_rank], admin_ckey)
|
||||
qdel(query_load_admins)
|
||||
//load admins from backup file
|
||||
if(dbfail)
|
||||
if(!backup_file_json)
|
||||
if(backup_file_json != null)
|
||||
//already tried
|
||||
return
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
backup_file_json = json_decode(backup_file)
|
||||
for(var/J in backup_file_json["admins"])
|
||||
var/skip
|
||||
for(var/A in GLOB.admin_datums + GLOB.deadmins)
|
||||
if(A == "[J]") //this admin was already loaded from txt override
|
||||
skip = TRUE
|
||||
if(skip)
|
||||
continue
|
||||
var/datum/admins/A = new /datum/admins(trim(rank_names[backup_file_json["admins"]["[J]"]["rank"]]), ckey("[J]"))
|
||||
A.ip_cache = backup_file_json["admins"]["[J]"]["ip_cache"]
|
||||
A.cid_cache = backup_file_json["admins"]["[J]"]["cid_cache"]
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
msg += "\t[ckey] - [D.rank.name]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
return dbfail
|
||||
|
||||
#ifdef TESTING
|
||||
/client/verb/changerank(newrank in GLOB.admin_ranks)
|
||||
if(holder)
|
||||
holder.rank = newrank
|
||||
else
|
||||
holder = new /datum/admins(newrank, ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
|
||||
/client/verb/changerights(newrights as num)
|
||||
if(holder)
|
||||
holder.rank.rights = newrights
|
||||
else
|
||||
holder = new /datum/admins("testing", newrights, ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
#endif
|
||||
@@ -262,7 +262,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if(holder)
|
||||
control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS
|
||||
|
||||
var/rights = holder.rank.rights
|
||||
var/rights = GLOB.permissions.get_rights_for(src)
|
||||
add_verb(src, GLOB.admin_verbs_default)
|
||||
add_verb(src, GLOB.mentor_verbs) // yogs - give admins mentor verbs
|
||||
if(rights & R_BUILDMODE)
|
||||
@@ -650,7 +650,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
/client/proc/togglebuildmodeself()
|
||||
set name = "Toggle Build Mode Self"
|
||||
set category = "Admin.Round Interaction"
|
||||
if (!(holder.rank.rights & R_BUILDMODE))
|
||||
if (!(check_rights(R_BUILDMODE)))
|
||||
return
|
||||
if(src.mob)
|
||||
togglebuildmode(src.mob)
|
||||
@@ -703,10 +703,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set category = "Admin"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
var/datum/admins/A = GLOB.deadmins[ckey]
|
||||
var/datum/admins/A = GLOB.permissions.deadmins[ckey]
|
||||
|
||||
if(!A)
|
||||
A = GLOB.admin_datums[ckey]
|
||||
A = GLOB.permissions.admin_datums[ckey]
|
||||
if (!A)
|
||||
var/msg = " is trying to readmin but they have no deadmin entry"
|
||||
message_admins("[key_name_admin(src)][msg]")
|
||||
|
||||
@@ -116,8 +116,7 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/tgs_chat_command/reload_admins/proc/ReloadAsync()
|
||||
set waitfor = FALSE
|
||||
refresh_admin_files() //yogs - DB support
|
||||
load_admins()
|
||||
GLOB.permissions.start()
|
||||
|
||||
/datum/tgs_chat_command/reload_mentors
|
||||
name = "reload_mentors"
|
||||
@@ -131,4 +130,4 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/tgs_chat_command/reload_mentors/proc/ReloadAsync()
|
||||
set waitfor = FALSE
|
||||
load_mentors()
|
||||
load_mentors()
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
GLOBAL_LIST_EMPTY(admin_datums)
|
||||
GLOBAL_PROTECT(admin_datums)
|
||||
GLOBAL_LIST_EMPTY(protected_admins)
|
||||
GLOBAL_PROTECT(protected_admins)
|
||||
|
||||
GLOBAL_VAR_INIT(href_token, GenerateToken())
|
||||
GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins
|
||||
var/datum/admin_rank/rank
|
||||
|
||||
var/target
|
||||
var/name = "nobody's admin datum (no rank)" //Makes for better runtimes
|
||||
@@ -33,7 +27,7 @@ GLOBAL_PROTECT(href_token)
|
||||
var/cid_cache
|
||||
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected)
|
||||
/datum/admins/New(ckey, rights, force_active = FALSE)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
@@ -45,20 +39,13 @@ GLOBAL_PROTECT(href_token)
|
||||
if(!ckey)
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created without a ckey")
|
||||
if(!istype(R))
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created without a rank")
|
||||
target = ckey
|
||||
name = "[ckey]'s admin datum ([R])"
|
||||
rank = R
|
||||
name = "[ckey]'s admin datum"
|
||||
admin_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
|
||||
href_token = GenerateToken()
|
||||
if(R.rights & R_DEBUG) //grant profile access
|
||||
if(rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
//only admins with +ADMIN start admined
|
||||
if(protected)
|
||||
GLOB.protected_admins[target] = src
|
||||
if (force_active || (R.rights & R_AUTOLOGIN))
|
||||
if (force_active || (rights & R_AUTOLOGIN))
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
@@ -69,6 +56,12 @@ GLOBAL_PROTECT(href_token)
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return QDEL_HINT_LETMELIVE
|
||||
var/client/C = owner
|
||||
deactivate()
|
||||
if(GLOB.permissions.deadmins[target] == src)
|
||||
GLOB.permissions.deadmins -= target
|
||||
if(C)
|
||||
remove_verb(C, /client/proc/readmin)
|
||||
. = ..()
|
||||
|
||||
/datum/admins/proc/activate()
|
||||
@@ -77,8 +70,8 @@ GLOBAL_PROTECT(href_token)
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
GLOB.deadmins -= target
|
||||
GLOB.admin_datums[target] = src
|
||||
GLOB.permissions.deadmins -= target
|
||||
GLOB.permissions.admin_datums[target] = src
|
||||
deadmined = FALSE
|
||||
if (GLOB.directory[target])
|
||||
associate(GLOB.directory[target]) //find the client for a ckey if they are connected and associate them with us
|
||||
@@ -90,8 +83,8 @@ GLOBAL_PROTECT(href_token)
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
GLOB.deadmins[target] = src
|
||||
GLOB.admin_datums -= target
|
||||
GLOB.permissions.deadmins[target] = src
|
||||
GLOB.permissions.admin_datums -= target
|
||||
deadmined = TRUE
|
||||
var/client/C
|
||||
if ((C = owner) || (C = GLOB.directory[target]))
|
||||
@@ -126,7 +119,7 @@ GLOBAL_PROTECT(href_token)
|
||||
owner.add_admin_verbs() //TODO <--- todo what? the proc clearly exists and works since its the backbone to our entire admin system
|
||||
remove_verb(owner, /client/proc/readmin)
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
GLOB.admins |= C
|
||||
GLOB.permissions.admins |= C
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/disassociate()
|
||||
@@ -136,71 +129,20 @@ GLOBAL_PROTECT(href_token)
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(owner)
|
||||
GLOB.admins -= owner
|
||||
GLOB.permissions.admins -= owner
|
||||
owner.remove_admin_verbs()
|
||||
owner.init_verbs()
|
||||
owner.holder = null
|
||||
owner = null
|
||||
|
||||
/datum/admins/proc/check_for_rights(rights_required)
|
||||
if(rights_required && !(rights_required & rank.rights))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other)
|
||||
if(!other)
|
||||
return 1 //they have no rights
|
||||
if(rank.rights == R_EVERYTHING)
|
||||
return 1 //we have all the rights
|
||||
if(src == other)
|
||||
return 1 //you always have more rights than yourself
|
||||
if(rank.rights != other.rank.rights)
|
||||
if( (rank.rights & other.rank.rights) == other.rank.rights )
|
||||
return 1 //we have all the rights they have and more
|
||||
return 0
|
||||
/datum/admins/proc/rank_name()
|
||||
if(owner)
|
||||
return GLOB.permissions.get_rank_name(owner)
|
||||
return "Unknown"
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
/*
|
||||
checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags)
|
||||
if rights_required == 0, then it simply checks if they are an admin.
|
||||
if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed
|
||||
generally it would be used like so:
|
||||
|
||||
/proc/admin_proc()
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
to_chat(world, "you have enough rights!")
|
||||
|
||||
NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call
|
||||
you will have to do something like if(client.rights & R_ADMIN) yourself.
|
||||
*/
|
||||
/proc/check_rights(rights_required, show_msg=1)
|
||||
if(usr && usr.client)
|
||||
if (check_rights_for(usr.client, rights_required))
|
||||
return 1
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(usr, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>", confidential=TRUE)
|
||||
return 0
|
||||
|
||||
//probably a bit iffy - will hopefully figure out a better solution
|
||||
/proc/check_if_greater_rights_than(client/other)
|
||||
if(usr && usr.client)
|
||||
if(usr.client.holder)
|
||||
if(!other || !other.holder)
|
||||
return 1
|
||||
return usr.client.holder.check_if_greater_rights_than_holder(other.holder)
|
||||
return 0
|
||||
|
||||
//This proc checks whether subject has at least ONE of the rights specified in rights_required.
|
||||
/proc/check_rights_for(client/subject, rights_required)
|
||||
if(subject && subject.holder)
|
||||
return subject.holder.check_for_rights(rights_required)
|
||||
return 0
|
||||
|
||||
/proc/GenerateToken()
|
||||
. = ""
|
||||
for(var/I in 1 to 32)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/client/proc/mfa_check_cache()
|
||||
CHECK_MFA_ENABLED
|
||||
|
||||
var/datum/admins/tmp_holder = GLOB.admin_datums[ckey] || GLOB.deadmins[ckey]
|
||||
var/datum/admins/tmp_holder = GLOB.permissions.admin_datums[ckey] || GLOB.permissions.deadmins[ckey]
|
||||
if(tmp_holder && tmp_holder.cid_cache == computer_id && tmp_holder.ip_cache == address)
|
||||
return TRUE
|
||||
|
||||
@@ -282,7 +282,7 @@
|
||||
|
||||
qdel(mfa_addverify)
|
||||
|
||||
var/datum/admins/tmp_holder = GLOB.admin_datums[ckey] || GLOB.deadmins[ckey]
|
||||
var/datum/admins/tmp_holder = GLOB.permissions.admin_datums[ckey] || GLOB.permissions.deadmins[ckey]
|
||||
if(tmp_holder)
|
||||
// These values are cached even if the user says not to remember the session, but are only used if the DB is down during admin loading
|
||||
tmp_holder.cid_cache = computer_id
|
||||
|
||||
@@ -4,296 +4,251 @@
|
||||
set desc = "Edit admin permissions"
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
new /datum/permissions_panel(usr)
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions(action, target, operation, page)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/group/permissions)
|
||||
asset_cache_datum.send(usr)
|
||||
var/list/output = list("<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'><a href='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
||||
if(action)
|
||||
output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
|
||||
else
|
||||
output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
||||
if(action == 1)
|
||||
var/logcount = 0
|
||||
var/logssperpage = 20
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery(
|
||||
"SELECT COUNT(id) FROM [format_table_name("admin_log")] WHERE (:target IS NULL OR adminckey = :target) AND (:operation IS NULL OR operation = :operation)",
|
||||
list("target" = target, "operation" = operation)
|
||||
)
|
||||
if(!query_count_admin_logs.warn_execute())
|
||||
qdel(query_count_admin_logs)
|
||||
return
|
||||
if(query_count_admin_logs.NextRow())
|
||||
logcount = text2num(query_count_admin_logs.item[1])
|
||||
qdel(query_count_admin_logs)
|
||||
if(logcount > logssperpage)
|
||||
output += "<br><b>Page: </b>"
|
||||
while(logcount > 0)
|
||||
output += "|<a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
logcount -= logssperpage
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
datetime,
|
||||
round_id,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
operation,
|
||||
IF(ckey IS NULL, target, byond_key),
|
||||
log
|
||||
FROM [format_table_name("admin_log")]
|
||||
LEFT JOIN [format_table_name("player")] ON target = ckey
|
||||
WHERE (:target IS NULL OR ckey = :target) AND (:operation IS NULL OR operation = :operation)
|
||||
ORDER BY datetime DESC
|
||||
LIMIT :skip, :take
|
||||
"}, list("target" = target, "operation" = operation, "skip" = logssperpage * page, "take" = logssperpage))
|
||||
if(!query_search_admin_logs.warn_execute())
|
||||
qdel(query_search_admin_logs)
|
||||
return
|
||||
while(query_search_admin_logs.NextRow())
|
||||
var/datetime = query_search_admin_logs.item[1]
|
||||
var/round_id = query_search_admin_logs.item[2]
|
||||
var/admin_key = query_search_admin_logs.item[3]
|
||||
operation = query_search_admin_logs.item[4]
|
||||
target = query_search_admin_logs.item[5]
|
||||
var/log = query_search_admin_logs.item[6]
|
||||
output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_key] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
|
||||
qdel(query_search_admin_logs)
|
||||
if(action == 2)
|
||||
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
||||
var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
|
||||
if(!query_check_admin_errors.warn_execute())
|
||||
qdel(query_check_admin_errors)
|
||||
return
|
||||
while(query_check_admin_errors.NextRow())
|
||||
var/admin_key = query_check_admin_errors.item[1]
|
||||
var/admin_rank = query_check_admin_errors.item[2]
|
||||
output += "[admin_key] has non-existent rank [admin_rank] | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>"
|
||||
output += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
qdel(query_check_admin_errors)
|
||||
output += "<h3>Unused ranks</h3>"
|
||||
var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].rank = [format_table_name("admin_ranks")].rank WHERE [format_table_name("admin")].rank IS NULL")
|
||||
if(!query_check_unused_rank.warn_execute())
|
||||
qdel(query_check_unused_rank)
|
||||
return
|
||||
while(query_check_unused_rank.NextRow())
|
||||
var/admin_rank = query_check_unused_rank.item[1]
|
||||
output += {"Rank [admin_rank] is not held by any admin | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a>
|
||||
<br>Permissions: [rights2text(text2num(query_check_unused_rank.item[2])," ")]
|
||||
<br>Denied: [rights2text(text2num(query_check_unused_rank.item[3])," ", "-")]
|
||||
<br>Allowed to edit: [rights2text(text2num(query_check_unused_rank.item[4])," ", "*")]
|
||||
<hr style='background:#000000; border:0; height:1px'>"}
|
||||
qdel(query_check_unused_rank)
|
||||
else if(!action)
|
||||
output += {"<head>
|
||||
<meta charset='UTF-8'>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='[SSassets.transport.get_asset_url("search.js")]'></script>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:150px;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th style='width:40%;'>PERMISSIONS</th>
|
||||
<th style='width:20%;'>DENIED</th>
|
||||
<th style='width:40%;'>ALLOWED TO EDIT</th>
|
||||
</tr>
|
||||
"}
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
var/deadminlink = ""
|
||||
if(D.owner)
|
||||
adm_ckey = D.owner.key
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=mfareset;key=[adm_ckey]'>\[2FA\]</a><br><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a></td>"
|
||||
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank.name]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
|
||||
output += "</tr>"
|
||||
output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
|
||||
/datum/permissions_panel/New(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
/datum/permissions_panel/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
// Open UI
|
||||
ui = new(user, src, "PermissionsPanel")
|
||||
ui.open()
|
||||
|
||||
/datum/permissions_panel/ui_data(mob/user)
|
||||
. = GLOB.permissions.pp_data(user)
|
||||
|
||||
/datum/permissions_panel/ui_state(mob/user)
|
||||
return GLOB.permissions_state
|
||||
|
||||
/datum/permissions_panel/ui_act(action, list/params)
|
||||
if(..())
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>", confidential=TRUE)
|
||||
return
|
||||
if(!owner.mfa_query())
|
||||
return
|
||||
var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/namespaced/common)
|
||||
permissions_assets.send(src)
|
||||
var/admin_key = href_list["key"]
|
||||
var/admin_ckey = ckey(admin_key)
|
||||
var/datum/admins/D = GLOB.admin_datums[admin_ckey]
|
||||
var/use_db
|
||||
var/task = href_list["editrights"]
|
||||
var/skip
|
||||
var/legacy_only
|
||||
if(task == "activate" || task == "deactivate" || task == "sync" || task == "mfareset")
|
||||
skip = TRUE
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
||||
if(admin_ckey in GLOB.protected_admins)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential=TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
|
||||
if(D.rank in GLOB.protected_ranks)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>", confidential=TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions"))
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>", confidential=TRUE)
|
||||
legacy_only = TRUE
|
||||
if(check_rights(R_DBRANKS, FALSE))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, span_danger("Unable to connect to database, changes are temporary only."), confidential=TRUE)
|
||||
use_db = FALSE
|
||||
else
|
||||
use_db = alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel")
|
||||
if(use_db == "Cancel")
|
||||
return
|
||||
if(use_db == "Permanent")
|
||||
use_db = TRUE
|
||||
else
|
||||
use_db = FALSE
|
||||
if(QDELETED(usr))
|
||||
switch(action)
|
||||
if("addNewAdmin")
|
||||
GLOB.permissions.add_admin()
|
||||
return TRUE
|
||||
if("forceSwapAdmin")
|
||||
var/ckey = params["ckey"]
|
||||
var/adminned_datum = GLOB.permissions.admin_datums[ckey]
|
||||
var/deadminned_datum = GLOB.permissions.deadmins[ckey]
|
||||
if(adminned_datum)
|
||||
force_deadmin(ckey, adminned_datum)
|
||||
if(deadminned_datum)
|
||||
force_readmin(ckey, deadminned_datum)
|
||||
return TRUE
|
||||
if("resetMFA")
|
||||
var/admin_ckey = params["ckey"]
|
||||
if(alert("WARNING! This will reset the 2FA code and backup for [admin_ckey], possibly comprimising the security of the server. Are you sure you wish to continue?", "Confirmation", "Cancel", "Continue") != "Continue")
|
||||
return
|
||||
if(task != "add")
|
||||
D = GLOB.admin_datums[admin_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[admin_ckey]
|
||||
if(!D)
|
||||
return
|
||||
if((task != "sync") && !check_if_greater_rights_than_holder(D))
|
||||
message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
||||
return
|
||||
switch(task)
|
||||
if("add")
|
||||
admin_ckey = add_admin(admin_ckey, admin_key, use_db)
|
||||
if(!admin_ckey)
|
||||
return
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only)
|
||||
if("remove")
|
||||
remove_admin(admin_ckey, admin_key, use_db, D)
|
||||
if("rank")
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, D, legacy_only)
|
||||
if("permissions")
|
||||
change_admin_flags(admin_ckey, admin_key, use_db, D, legacy_only)
|
||||
if("activate")
|
||||
force_readmin(admin_key, D)
|
||||
if("deactivate")
|
||||
force_deadmin(admin_key, D)
|
||||
if("sync")
|
||||
sync_lastadminrank(admin_ckey, admin_key, D)
|
||||
if("mfareset")
|
||||
if(alert("WARNING! This will reset the 2FA code and backup for [admin_key], possibly comprimising the security of the server. Are you sure you wish to continue?", "Confirmation", "Cancel", "Continue") != "Continue")
|
||||
return
|
||||
if(alert("If you have been requested to reset the MFA credentials for someone, please confirm that you have verified their identity. Resetting MFA for an unverified person can result in a break of server security.", "Confirmation", "I Understand", "Cancel") != "I Understand")
|
||||
if(alert("If you have been requested to reset the MFA credentials for someone, please confirm that you have verified their identity. Resetting MFA for an unverified person can result in a breach of server security.", "Confirmation", "I Understand", "Cancel") != "I Understand")
|
||||
return
|
||||
message_admins("MFA for [admin_ckey] has been reset by [usr]!")
|
||||
log_admin("MFA Reset for [admin_ckey] by [usr]!")
|
||||
mfa_reset(admin_ckey)
|
||||
edit_admin_permissions()
|
||||
return TRUE
|
||||
if("editRank")
|
||||
GLOB.permissions.edit_rank(params["ckey"])
|
||||
return TRUE
|
||||
if("editPerms")
|
||||
GLOB.permissions.edit_perms(params["ckey"])
|
||||
return TRUE
|
||||
if("removeAdmin")
|
||||
GLOB.permissions.remove_admin(params["ckey"])
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/admins/proc/add_admin(admin_ckey, admin_key, use_db)
|
||||
if(admin_ckey)
|
||||
. = admin_ckey
|
||||
else
|
||||
admin_key = input("New admin's key","Admin key") as text|null
|
||||
. = ckey(admin_key)
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!admin_ckey && (. in GLOB.admin_datums+GLOB.deadmins))
|
||||
to_chat(usr, span_danger("[admin_key] is already an admin."), confidential=TRUE)
|
||||
return FALSE
|
||||
if(use_db)
|
||||
//if an admin exists without a datum they won't be caught by the above
|
||||
var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return FALSE
|
||||
if(query_admin_in_db.NextRow())
|
||||
qdel(query_admin_in_db)
|
||||
to_chat(usr, span_danger("[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins."), confidential=TRUE)
|
||||
return FALSE
|
||||
qdel(query_admin_in_db)
|
||||
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("admin")] (ckey, `rank`) VALUES (:ckey, 'NEW ADMIN')",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_add_admin.warn_execute())
|
||||
qdel(query_add_admin)
|
||||
return FALSE
|
||||
qdel(query_add_admin)
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .))
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
qdel(query_add_admin_log)
|
||||
return FALSE
|
||||
qdel(query_add_admin_log)
|
||||
// /datum/admins/proc/edit_admin_permissions(action, target, operation, page)
|
||||
// if(!check_rights(R_PERMISSIONS))
|
||||
// return
|
||||
// var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/group/permissions)
|
||||
// asset_cache_datum.send(usr)
|
||||
// var/list/output = list("<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'><a href='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
||||
// if(action)
|
||||
// output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><hr style='background:#000000; border:0; height:3px'>"
|
||||
// else
|
||||
// output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a>"
|
||||
// if(action == 1)
|
||||
// var/logcount = 0
|
||||
// var/logssperpage = 20
|
||||
// var/pagecount = 0
|
||||
// page = text2num(page)
|
||||
// var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery(
|
||||
// "SELECT COUNT(id) FROM [format_table_name("admin_log")] WHERE (:target IS NULL OR adminckey = :target) AND (:operation IS NULL OR operation = :operation)",
|
||||
// list("target" = target, "operation" = operation)
|
||||
// )
|
||||
// if(!query_count_admin_logs.warn_execute())
|
||||
// qdel(query_count_admin_logs)
|
||||
// return
|
||||
// if(query_count_admin_logs.NextRow())
|
||||
// logcount = text2num(query_count_admin_logs.item[1])
|
||||
// qdel(query_count_admin_logs)
|
||||
// if(logcount > logssperpage)
|
||||
// output += "<br><b>Page: </b>"
|
||||
// while(logcount > 0)
|
||||
// output += "|<a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
// logcount -= logssperpage
|
||||
// pagecount++
|
||||
// output += "|"
|
||||
// var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery({"
|
||||
// SELECT
|
||||
// datetime,
|
||||
// round_id,
|
||||
// IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
// operation,
|
||||
// IF(ckey IS NULL, target, byond_key),
|
||||
// log
|
||||
// FROM [format_table_name("admin_log")]
|
||||
// LEFT JOIN [format_table_name("player")] ON target = ckey
|
||||
// WHERE (:target IS NULL OR ckey = :target) AND (:operation IS NULL OR operation = :operation)
|
||||
// ORDER BY datetime DESC
|
||||
// LIMIT :skip, :take
|
||||
// "}, list("target" = target, "operation" = operation, "skip" = logssperpage * page, "take" = logssperpage))
|
||||
// if(!query_search_admin_logs.warn_execute())
|
||||
// qdel(query_search_admin_logs)
|
||||
// return
|
||||
// while(query_search_admin_logs.NextRow())
|
||||
// var/datetime = query_search_admin_logs.item[1]
|
||||
// var/round_id = query_search_admin_logs.item[2]
|
||||
// var/admin_key = query_search_admin_logs.item[3]
|
||||
// operation = query_search_admin_logs.item[4]
|
||||
// target = query_search_admin_logs.item[5]
|
||||
// var/log = query_search_admin_logs.item[6]
|
||||
// output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_key] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
|
||||
// qdel(query_search_admin_logs)
|
||||
// else if(!action)
|
||||
// output += {"<head>
|
||||
// <meta charset='UTF-8'>
|
||||
// <title>Permissions Panel</title>
|
||||
// <script type='text/javascript' src='[SSassets.transport.get_asset_url("search.js")]'></script>
|
||||
// </head>
|
||||
// <body onload='selectTextField();updateSearch();'>
|
||||
// <div id='main'><table id='searchable' cellspacing='0'>
|
||||
// <tr class='title'>
|
||||
// <th style='width:150px;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
// <th style='width:125px;'>RANK</th>
|
||||
// <th style='width:40%;'>PERMISSIONS</th>
|
||||
// </tr>
|
||||
// "}
|
||||
// for(var/adm_ckey in GLOB.permissions.admin_datums+GLOB.permissions.deadmins)
|
||||
// var/datum/admins/D = GLOB.permissions.admin_datums[adm_ckey]
|
||||
// if(!D)
|
||||
// D = GLOB.permissions.deadmins[adm_ckey]
|
||||
// if (!D)
|
||||
// continue
|
||||
// var/deadminlink = ""
|
||||
// if(D.owner)
|
||||
// adm_ckey = D.owner.key
|
||||
// if (D.deadmined)
|
||||
// deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
|
||||
// else
|
||||
// deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
|
||||
// output += "<tr>"
|
||||
// output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=mfareset;key=[adm_ckey]'>\[2FA\]</a></td>"
|
||||
// output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank_name()]</a></td>"
|
||||
// output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rights," ")]</a></td>"
|
||||
// output += "</tr>"
|
||||
// output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
|
||||
// if(QDELETED(usr))
|
||||
// return
|
||||
// usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
|
||||
|
||||
/datum/admins/proc/remove_admin(admin_ckey, admin_key, use_db, datum/admins/D)
|
||||
if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
GLOB.admin_datums -= admin_ckey
|
||||
GLOB.deadmins -= admin_ckey
|
||||
if(D)
|
||||
D.disassociate()
|
||||
var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
sync_lastadminrank(admin_ckey, admin_key)
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
// /datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
// if(!check_rights(R_PERMISSIONS))
|
||||
// message_admins("[key_name_admin(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
// log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
// return
|
||||
// if(IsAdminAdvancedProcCall())
|
||||
// to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>", confidential=TRUE)
|
||||
// return
|
||||
// if(!owner.mfa_query())
|
||||
// return
|
||||
// var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/namespaced/common)
|
||||
// permissions_assets.send(owner)
|
||||
// var/admin_key = href_list["key"]
|
||||
// var/admin_ckey = ckey(admin_key)
|
||||
// var/datum/admins/D = GLOB.permissions.admin_datums[admin_ckey]
|
||||
// var/task = href_list["editrights"]
|
||||
// if(CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
||||
// if(admin_ckey in GLOB.protected_admins)
|
||||
// to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential=TRUE)
|
||||
// return
|
||||
// if(task != "add")
|
||||
// D = GLOB.permissions.admin_datums[admin_ckey]
|
||||
// if(!D)
|
||||
// D = GLOB.permissions.deadmins[admin_ckey]
|
||||
// if(!D)
|
||||
// return
|
||||
// switch(task)
|
||||
// if("add")
|
||||
// admin_key = input("New admin's key","Admin key") as text|null
|
||||
// admin_ckey = ckey(admin_key)
|
||||
// if(admin_ckey in GLOB.permissions.admin_datums+GLOB.permissions.deadmins)
|
||||
// to_chat(usr, span_danger("[admin_key] is already an admin."), confidential=TRUE)
|
||||
// return
|
||||
// change_admin_rank(admin_ckey, admin_key, null)
|
||||
// if("remove")
|
||||
// remove_admin(admin_ckey, admin_key, D)
|
||||
// if("rank")
|
||||
// change_admin_rank(admin_ckey, admin_key, D)
|
||||
// if("permissions")
|
||||
// change_admin_flags(admin_ckey, admin_key, D)
|
||||
// if("activate")
|
||||
// force_readmin(admin_key, D)
|
||||
// if("deactivate")
|
||||
// force_deadmin(admin_key, D)
|
||||
// if("mfareset")
|
||||
// if(alert("WARNING! This will reset the 2FA code and backup for [admin_key], possibly comprimising the security of the server. Are you sure you wish to continue?", "Confirmation", "Cancel", "Continue") != "Continue")
|
||||
// return
|
||||
// if(alert("If you have been requested to reset the MFA credentials for someone, please confirm that you have verified their identity. Resetting MFA for an unverified person can result in a break of server security.", "Confirmation", "I Understand", "Cancel") != "I Understand")
|
||||
// return
|
||||
// message_admins("MFA for [admin_ckey] has been reset by [usr]!")
|
||||
// log_admin("MFA Reset for [admin_ckey] by [usr]!")
|
||||
// mfa_reset(admin_ckey)
|
||||
// edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/force_readmin(admin_key, datum/admins/D)
|
||||
// /datum/admins/proc/add_admin(admin_ckey, admin_key)
|
||||
// if(admin_ckey)
|
||||
// . = admin_ckey
|
||||
// else
|
||||
// admin_key = input("New admin's key","Admin key") as text|null
|
||||
// . = ckey(admin_key)
|
||||
// if(!.)
|
||||
// return FALSE
|
||||
// if(!admin_ckey && (. in GLOB.permissions.admin_datums+GLOB.permissions.deadmins))
|
||||
// to_chat(usr, span_danger("[admin_key] is already an admin."), confidential=TRUE)
|
||||
// return FALSE
|
||||
|
||||
// /datum/admins/proc/remove_admin(admin_ckey, admin_key, datum/admins/D)
|
||||
// if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
// GLOB.permissions.admin_datums -= admin_ckey
|
||||
// GLOB.permissions.deadmins -= admin_ckey
|
||||
// if(D)
|
||||
// D.disassociate()
|
||||
// var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list temporarily"
|
||||
// var/m2 = "[key_name(usr)] removed [admin_key] from the admins list temporarily"
|
||||
// message_admins(m1)
|
||||
// log_admin(m2)
|
||||
|
||||
/datum/permissions_panel/proc/force_readmin(admin_key, datum/admins/D)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!D || !D.deadmined)
|
||||
return
|
||||
D.activate()
|
||||
message_admins("[key_name_admin(usr)] forcefully readmined [admin_key]")
|
||||
log_admin("[key_name(usr)] forcefully readmined [admin_key]")
|
||||
|
||||
/datum/admins/proc/force_deadmin(admin_key, datum/admins/D)
|
||||
/datum/permissions_panel/proc/force_deadmin(admin_key, datum/admins/D)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!D || D.deadmined)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] forcefully deadmined [admin_key]")
|
||||
@@ -301,7 +256,12 @@
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
/datum/admins/proc/auto_deadmin()
|
||||
if(GLOB.admins.len < CONFIG_GET(number/auto_deadmin_threshold))
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(GLOB.permissions.admins.len < CONFIG_GET(number/auto_deadmin_threshold))
|
||||
log_admin("[owner] auto-deadmin failed due to low admin count.")
|
||||
to_chat(owner, span_userdanger("You have not be auto-deadminned due to lack of admins on the server, you can still deadmin manually."))
|
||||
return FALSE
|
||||
@@ -312,238 +272,38 @@
|
||||
log_admin("[old_owner] deadmined via auto-deadmin config.")
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
var/datum/admin_rank/R
|
||||
var/list/rank_names = list()
|
||||
if(!use_db || (use_db && !legacy_only))
|
||||
rank_names += "*New Rank*"
|
||||
for(R in GLOB.admin_ranks)
|
||||
if((R.rights & usr.client.holder.rank.can_edit_rights) == R.rights)
|
||||
rank_names[R.name] = R
|
||||
var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
||||
if(new_rank == "*New Rank*")
|
||||
new_rank = trim(input("Please input a new rank", "New custom rank") as text|null)
|
||||
if(!new_rank)
|
||||
if(!D)
|
||||
remove_admin(admin_ckey, admin_key, use_db, null)
|
||||
return
|
||||
R = rank_names[new_rank]
|
||||
if(!R) //rank with that name doesn't exist yet - make it
|
||||
if(D)
|
||||
R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
|
||||
else
|
||||
R = new(new_rank) //blank new admin_rank
|
||||
GLOB.admin_ranks += R
|
||||
var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
//if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
|
||||
var/old_rank
|
||||
var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT `rank` FROM [format_table_name("admin")] WHERE ckey = :admin_ckey",
|
||||
list("admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return
|
||||
if(!query_admin_in_db.NextRow())
|
||||
add_admin(admin_ckey, admin_key, TRUE)
|
||||
old_rank = "NEW ADMIN"
|
||||
else
|
||||
old_rank = query_admin_in_db.item[1]
|
||||
qdel(query_admin_in_db)
|
||||
//similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
|
||||
// /datum/admins/proc/change_admin_rank(admin_ckey, admin_key, datum/admins/D)
|
||||
// if(!check_rights(R_PERMISSIONS))
|
||||
// return
|
||||
// var/list/rank_names = list()
|
||||
// rank_names += "*New Rank*"
|
||||
// for(var/R in GLOB.legacy_ranks)
|
||||
// rank_names += R
|
||||
// var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
||||
// if(new_rank == "*New Rank*")
|
||||
// new_rank = trim(input("Please input a new rank", "New custom rank") as text|null)
|
||||
// if(!new_rank)
|
||||
// return
|
||||
// D.rank_name = new_rank
|
||||
// if(new_rank in GLOB.legacy_ranks)
|
||||
// D.rights = GLOB.legacy_ranks[new_rank]
|
||||
// var/client/C = D.owner
|
||||
// D.disassociate()
|
||||
// D.associate(C)
|
||||
// var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [new_rank] temporarily"
|
||||
// var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [new_rank] temporarily"
|
||||
// message_admins(m1)
|
||||
// log_admin(m2)
|
||||
|
||||
var/datum/DBQuery/query_rank_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = :new_rank",
|
||||
list("new_rank" = new_rank)
|
||||
)
|
||||
if(!query_rank_in_db.warn_execute())
|
||||
qdel(query_rank_in_db)
|
||||
return
|
||||
if(!query_rank_in_db.NextRow())
|
||||
QDEL_NULL(query_rank_in_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags)
|
||||
VALUES (:new_rank, '0', '0', '0')
|
||||
"}, list("new_rank" = new_rank))
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = new_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
qdel(query_rank_in_db)
|
||||
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin")] SET `rank` = :new_rank WHERE ckey = :admin_ckey",
|
||||
list("new_rank" = new_rank, "admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_change_rank.warn_execute())
|
||||
qdel(query_change_rank)
|
||||
return
|
||||
qdel(query_change_rank)
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = new_rank))
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
qdel(query_change_rank_log)
|
||||
return
|
||||
qdel(query_change_rank_log)
|
||||
if(D) //they were previously an admin
|
||||
D.disassociate() //existing admin needs to be disassociated
|
||||
D.rank = R //set the admin_rank as our rank
|
||||
var/client/C = GLOB.directory[admin_ckey]
|
||||
D.associate(C)
|
||||
else
|
||||
D = new(R, admin_ckey, TRUE) //new admin
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
/datum/admins/proc/change_admin_flags(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
||||
var/new_flags = input_bitfield(usr, "Include permission flags<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.include_rights, 350, 590, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_flags))
|
||||
return
|
||||
var/new_exclude_flags = input_bitfield(usr, "Exclude permission flags<br>Flags enabled here will be removed from a rank.<br>Note these take precedence over included flags.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.exclude_rights, 350, 670, "red", usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_exclude_flags))
|
||||
return
|
||||
var/new_can_edit_flags = input_bitfield(usr, "Editable permission flags<br>These are the flags this rank is allowed to edit if they have access to the permissions panel.<br>They will be unable to modify admins to a rank that has a flag not included here.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.can_edit_rights, 350, 710, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_can_edit_flags))
|
||||
return
|
||||
var/m1 = "[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
||||
if(use_db || legacy_only)
|
||||
var/rank_name = D.rank.name
|
||||
var/old_flags
|
||||
var/old_exclude_flags
|
||||
var/old_can_edit_flags
|
||||
var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery(
|
||||
"SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE `rank` = :rank_name",
|
||||
list("rank_name" = rank_name)
|
||||
)
|
||||
if(!query_get_rank_flags.warn_execute())
|
||||
qdel(query_get_rank_flags)
|
||||
return
|
||||
if(query_get_rank_flags.NextRow())
|
||||
old_flags = text2num(query_get_rank_flags.item[1])
|
||||
old_exclude_flags = text2num(query_get_rank_flags.item[2])
|
||||
old_can_edit_flags = text2num(query_get_rank_flags.item[3])
|
||||
qdel(query_get_rank_flags)
|
||||
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin_ranks")] SET flags = :new_flags, exclude_flags = :new_exclude_flags, can_edit_flags = :new_can_edit_flags WHERE `rank` = :rank_name",
|
||||
list("new_flags" = new_flags, "new_exclude_flags" = new_exclude_flags, "new_can_edit_flags" = new_can_edit_flags, "rank_name" = rank_name)
|
||||
)
|
||||
if(!query_change_rank_flags.warn_execute())
|
||||
qdel(query_change_rank_flags)
|
||||
return
|
||||
qdel(query_change_rank_flags)
|
||||
var/log_message = "Permissions of [rank_name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]"
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change rank flags', :rank_name, :log)
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "rank_name" = rank_name, "log" = log_message))
|
||||
if(!query_change_rank_flags_log.warn_execute())
|
||||
qdel(query_change_rank_flags_log)
|
||||
return
|
||||
qdel(query_change_rank_flags_log)
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name != D.rank.name)
|
||||
continue
|
||||
R.rights = new_flags &= ~new_exclude_flags
|
||||
R.exclude_rights = new_exclude_flags
|
||||
R.include_rights = new_flags
|
||||
R.can_edit_rights = new_can_edit_flags
|
||||
for(var/i in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/A = GLOB.admin_datums[i]
|
||||
if(!A)
|
||||
A = GLOB.deadmins[i]
|
||||
if (!A)
|
||||
continue
|
||||
if(A.rank.name != D.rank.name)
|
||||
continue
|
||||
var/client/C = GLOB.directory[A.target]
|
||||
A.disassociate()
|
||||
A.associate(C)
|
||||
else
|
||||
D.disassociate()
|
||||
if(!findtext(D.rank.name, "([admin_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
|
||||
D.rank = new("[D.rank.name]([admin_ckey])", new_flags, new_exclude_flags, new_can_edit_flags) //duplicate our previous admin_rank but with a new name
|
||||
//we don't add this clone to the admin_ranks list, as it is unique to that ckey
|
||||
else
|
||||
D.rank.rights = new_flags &= ~new_exclude_flags
|
||||
D.rank.include_rights = new_flags
|
||||
D.rank.exclude_rights = new_exclude_flags
|
||||
D.rank.can_edit_rights = new_can_edit_flags
|
||||
var/client/C = GLOB.directory[admin_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
D.associate(C) //link up with the client and add verbs
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
/datum/admins/proc/remove_rank(admin_rank)
|
||||
if(!admin_rank)
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
|
||||
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>", confidential=TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
|
||||
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>", confidential=TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>", confidential=TRUE)
|
||||
return
|
||||
var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_admins_with_rank.warn_execute())
|
||||
qdel(query_admins_with_rank)
|
||||
return
|
||||
if(query_admins_with_rank.NextRow())
|
||||
qdel(query_admins_with_rank)
|
||||
to_chat(usr, span_danger("Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen."), confidential=TRUE)
|
||||
return
|
||||
qdel(query_admins_with_rank)
|
||||
if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
|
||||
var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin_ranks")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
/datum/admins/proc/sync_lastadminrank(admin_ckey, admin_key, datum/admins/D)
|
||||
var/sqlrank = "Player"
|
||||
if (D)
|
||||
sqlrank = D.rank.name
|
||||
var/datum/DBQuery/query_sync_lastadminrank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET lastadminrank = :rank WHERE ckey = :ckey",
|
||||
list("rank" = sqlrank, "ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_sync_lastadminrank.warn_execute())
|
||||
qdel(query_sync_lastadminrank)
|
||||
return
|
||||
qdel(query_sync_lastadminrank)
|
||||
to_chat(usr, span_admin("Sync of [admin_key] successful."), confidential=TRUE)
|
||||
// /datum/admins/proc/change_admin_flags(admin_ckey, admin_key, datum/admins/D)
|
||||
// var/new_flags = input_bitfield(usr, "Permission flags<br>This will affect only the current admin [admin_key]", "admin_flags", D.rights, 350, 590)
|
||||
// if(isnull(new_flags))
|
||||
// return
|
||||
// var/m1 = "[key_name_admin(usr)] edited the permissions of [admin_key] temporarily"
|
||||
// var/m2 = "[key_name(usr)] edited the permissions of [admin_key] temporarily"
|
||||
// D.rights = new_flags
|
||||
// var/client/C = D.owner
|
||||
// D.disassociate()
|
||||
// D.associate(C)
|
||||
// message_admins(m1)
|
||||
// log_admin(m2)
|
||||
|
||||
375
code/modules/admin/permissions/database.dm
Normal file
375
code/modules/admin/permissions/database.dm
Normal file
@@ -0,0 +1,375 @@
|
||||
/datum/permissions_controller/db
|
||||
var/list/dbranks = list()
|
||||
var/list/dbadmins = list()
|
||||
|
||||
/datum/permissions_controller/db/clear_admins()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
..()
|
||||
dbranks.Cut()
|
||||
dbadmins.Cut()
|
||||
|
||||
/datum/permissions_controller/db/load_admins()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database to load admins.")
|
||||
log_sql("Failed to connect to database to load admins")
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database.")
|
||||
log_sql("Error loading admin ranks from database.")
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/rank_name = trim(query_load_admin_ranks.item[1])
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
dbranks[rank_name] = list("flags" = rank_flags & (~rank_exclude_flags), "can_edit_flags" = rank_can_edit_flags)
|
||||
qdel(query_load_admin_ranks)
|
||||
|
||||
var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, rank FROM [format_table_name("admin")] ORDER BY rank")
|
||||
if(!query_load_admins.Execute())
|
||||
message_admins("Error loading admins from database. Loading from backup.")
|
||||
log_sql("Error loading admins from database. Loading from backup.")
|
||||
else
|
||||
while(query_load_admins.NextRow())
|
||||
var/admin_ckey = ckey(query_load_admins.item[1])
|
||||
var/admin_rank = trim(query_load_admins.item[2])
|
||||
if(dbranks[admin_rank] == null)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
continue
|
||||
if(admin_ckey in legacy_admins)
|
||||
continue
|
||||
dbadmins[admin_ckey] = admin_rank
|
||||
qdel(query_load_admins)
|
||||
|
||||
/datum/permissions_controller/db/_load_permissions_for(var/client/C)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/rank = dbadmins[C.ckey]
|
||||
if(!rank)
|
||||
return FALSE
|
||||
var/rights = dbranks[rank]
|
||||
if(!rights)
|
||||
return FALSE
|
||||
new /datum/admins(C.ckey, rights["flags"])
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/db/get_rights_for_ckey(ckey)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/rank = dbadmins[ckey]
|
||||
if(!rank)
|
||||
return
|
||||
var/rights = dbranks[rank]
|
||||
if(!rights)
|
||||
return
|
||||
else
|
||||
return rights["flags"]
|
||||
|
||||
/datum/permissions_controller/db/get_rank_name(client/subject)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(subject.ckey in dbadmins)
|
||||
return dbadmins[subject.ckey]
|
||||
|
||||
/datum/permissions_controller/db/pp_data(mob/user)
|
||||
. = ..()
|
||||
var/perm_rights = check_rights_for(user.client, R_PERSIST_PERMS)
|
||||
var/grant_flags = 0
|
||||
if(user.ckey in legacy_admins)
|
||||
grant_flags = legacy_ranks[legacy_admins[user.ckey]] || 0
|
||||
else if(user.ckey in dbadmins)
|
||||
var/dbrank = dbadmins[user.ckey]
|
||||
if(dbranks[dbrank])
|
||||
grant_flags = dbranks[dbrank]["can_edit_flags"]
|
||||
for(var/admin in dbadmins)
|
||||
var/data = list()
|
||||
data["ckey"] = admin
|
||||
data["rank"] = dbadmins[admin]
|
||||
var/rights_text = "Rights: [rights2text(dbranks[data["rank"]]["flags"], " ")]\nGrant Rights: [rights2text(dbranks[data["rank"]]["can_edit_flags"], " ", "*")]"
|
||||
data["rights"] = rights_text
|
||||
data["deadminned"] = (admin in deadmins)
|
||||
data["protected_admin"] = (dbranks[data["rank"]]["flags"] & grant_flags) != dbranks[data["rank"]]["flags"]
|
||||
data["protected_rank"] = !perm_rights || data["protected_admin"]
|
||||
.["admins"] |= list(data)
|
||||
|
||||
/datum/permissions_controller/db/should_add_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!..())
|
||||
return FALSE
|
||||
return !(ckey in dbadmins)
|
||||
|
||||
/// Sets a rank in the DB
|
||||
/// Returns true of the rank was set
|
||||
/datum/permissions_controller/db/proc/set_db_rank(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
var/grant_flags = 0
|
||||
if(usr.ckey in legacy_admins)
|
||||
grant_flags = legacy_ranks[legacy_admins[usr.ckey]] || 0
|
||||
else if(usr.ckey in dbadmins)
|
||||
var/dbrank = dbadmins[usr.ckey]
|
||||
if(dbranks[dbrank])
|
||||
grant_flags = dbranks[dbrank]["can_edit_flags"]
|
||||
|
||||
if((ckey in dbadmins) && (dbadmins[ckey] in dbranks) && (dbranks[dbadmins[ckey]]["flags"] & grant_flags) != dbranks[dbadmins[ckey]]["flags"])
|
||||
return FALSE
|
||||
|
||||
var/list/ranks = list()
|
||||
ranks += "*New Rank*"
|
||||
for(var/rank in dbranks)
|
||||
var/flags = dbranks[rank]["flags"]
|
||||
if((flags & grant_flags) == flags)
|
||||
ranks += rank
|
||||
|
||||
var/new_rank = input("Please select a rank", "New rank") as null|anything in ranks
|
||||
if(new_rank == "*New Rank*")
|
||||
new_rank = trim(input("Please input a new rank", "New custom rank") as text|null)
|
||||
if(!new_rank)
|
||||
return FALSE
|
||||
|
||||
if(!(new_rank in dbranks))
|
||||
var/current_flags = list("flags" = 0, "can_edit_flags" = 0)
|
||||
if((ckey in dbadmins) && (dbadmins[ckey] in dbranks))
|
||||
current_flags = dbranks[dbadmins[ckey]]
|
||||
dbranks[new_rank] = current_flags
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags)
|
||||
VALUES (:new_rank, :flags, '0', :edit_flags) ON DUPLICATE KEY UPDATE
|
||||
"}, list("new_rank" = new_rank, "flags" = current_flags["flags"], "edit_flags" = current_flags["can_edit_flags"]))
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = new_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
var/old_rank = dbadmins[ckey] || "NEW ADMIN"
|
||||
dbadmins[ckey] = new_rank
|
||||
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("admin")] (`rank`, ckey) VALUES(:new_rank, :admin_ckey)",
|
||||
list("new_rank" = new_rank, "admin_ckey" = ckey)
|
||||
)
|
||||
if(!query_change_rank.warn_execute())
|
||||
qdel(query_change_rank)
|
||||
return
|
||||
qdel(query_change_rank)
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = ckey, "old_rank" = old_rank, "new_rank" = new_rank))
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
qdel(query_change_rank_log)
|
||||
return
|
||||
qdel(query_change_rank_log)
|
||||
var/datum/admins/holder = admin_datums[ckey]
|
||||
if(holder)
|
||||
holder.deactivate()
|
||||
holder.activate()
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/db/make_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
var/permanent = (SSdbcore.Connect() && check_rights(R_PERSIST_PERMS, FALSE) && (alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel") == "Permanent"))
|
||||
if(!permanent)
|
||||
return ..()
|
||||
|
||||
set_db_rank(ckey)
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/db/edit_rank(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(!(ckey in dbadmins))
|
||||
return FALSE
|
||||
|
||||
var/permanent = ((ckey in dbadmins) && SSdbcore.Connect() && check_rights(R_PERSIST_PERMS, FALSE) && (alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel") == "Permanent"))
|
||||
if(!permanent)
|
||||
if(set_legacy_rank(ckey))
|
||||
dbadmins -= ckey
|
||||
return TRUE
|
||||
|
||||
set_db_rank(ckey)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/db/edit_perms(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(!(ckey in dbadmins))
|
||||
return FALSE
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "Cannot connect to database to edit rank [dbadmins[ckey]]", confidential = TRUE)
|
||||
return TRUE
|
||||
|
||||
if(!check_rights(R_PERSIST_PERMS, FALSE))
|
||||
to_chat(usr, "You do not have access to modify this rank.")
|
||||
return TRUE
|
||||
|
||||
var/grant_flags = 0
|
||||
if(usr.ckey in legacy_admins)
|
||||
grant_flags = legacy_ranks[legacy_admins[usr.ckey]] || 0
|
||||
else if(usr.ckey in dbadmins)
|
||||
var/dbrank = dbadmins[usr.ckey]
|
||||
if(dbranks[dbrank])
|
||||
grant_flags = dbranks[dbrank]["can_edit_flags"]
|
||||
|
||||
if(!((dbadmins[ckey] in dbranks) && (dbranks[dbadmins[ckey]]["flags"] & grant_flags) == dbranks[dbadmins[ckey]]["flags"]))
|
||||
to_chat(usr, "You do not have access to modify this rank.")
|
||||
return TRUE
|
||||
|
||||
if(alert(usr, "This rank cannot be modified temporarily, and modifying it will change all admins using this rank. Do you wish to continue?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
|
||||
var/rank = dbranks[dbadmins[ckey]]
|
||||
|
||||
var/new_flags = input_bitfield(usr, "Permission flags<br>This will affect ALL admins with this rank.", "admin_flags", rank["flags"], 350, 590, allowed_edit_list = grant_flags)
|
||||
if(isnull(new_flags))
|
||||
return
|
||||
|
||||
var/new_can_edit_flags = input_bitfield(usr, "Editable permission flags<br>These are the flags this rank is allowed to edit if they have access to the permissions panel.<br>They will be unable to modify admins to a rank that has a flag not included here.<br>This will affect ALL admins with this rank.", "admin_flags", rank["can_edit_flags"], 350, 710, grant_flags)
|
||||
if(isnull(new_can_edit_flags))
|
||||
return
|
||||
|
||||
var/rank_name = dbadmins[ckey]
|
||||
var/m = "edited the permissions of rank [rank_name] permanently"
|
||||
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin_ranks")] SET flags = :new_flags, exclude_flags = :new_exclude_flags, can_edit_flags = :new_can_edit_flags WHERE `rank` = :rank_name",
|
||||
list("new_flags" = new_flags, "new_exclude_flags" = 0, "new_can_edit_flags" = new_can_edit_flags, "rank_name" = rank_name)
|
||||
)
|
||||
if(!query_change_rank_flags.warn_execute())
|
||||
qdel(query_change_rank_flags)
|
||||
return
|
||||
qdel(query_change_rank_flags)
|
||||
var/log_message = "Permissions of [rank_name] changed from[rights2text(rank["flags"]," ")][rights2text(rank["can_edit_flags"]," ", "*")] to[rights2text(new_flags," ")][rights2text(new_can_edit_flags," ", "*")]"
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change rank flags', :rank_name, :log)
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "rank_name" = rank_name, "log" = log_message))
|
||||
if(!query_change_rank_flags_log.warn_execute())
|
||||
qdel(query_change_rank_flags_log)
|
||||
return
|
||||
qdel(query_change_rank_flags_log)
|
||||
rank["flags"] = new_flags
|
||||
rank["can_edit_flags"] = new_can_edit_flags
|
||||
|
||||
for(var/admin in admin_datums)
|
||||
if(dbadmins[admin] == rank_name)
|
||||
var/datum/admins/holder = admin_datums[admin]
|
||||
holder.deactivate()
|
||||
holder.activate()
|
||||
|
||||
message_admins("[key_name_admin(usr)] [m]")
|
||||
log_admin("[key_name(usr)] [m]")
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/db/remove_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(!(ckey in dbadmins))
|
||||
return FALSE
|
||||
|
||||
var/grant_flags = 0
|
||||
if(usr.ckey in legacy_admins)
|
||||
grant_flags = legacy_ranks[legacy_admins[usr.ckey]] || 0
|
||||
else if(usr.ckey in dbadmins)
|
||||
var/dbrank = dbadmins[usr.ckey]
|
||||
if(dbranks[dbrank])
|
||||
grant_flags = dbranks[dbrank]["can_edit_flags"]
|
||||
|
||||
if(!((dbadmins[ckey] in dbranks) && (dbranks[dbadmins[ckey]]["flags"] & grant_flags) == dbranks[dbadmins[ckey]]["flags"]))
|
||||
to_chat(usr, "You do not have access to delete this admin")
|
||||
return TRUE
|
||||
|
||||
var/permanent = ((ckey in dbadmins) && SSdbcore.Connect() && check_rights(R_PERSIST_PERMS, FALSE) && (alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel") == "Permanent"))
|
||||
|
||||
if(permanent)
|
||||
if(alert(usr, "Are you sure you wish to permanently remove [ckey] from the admins list?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = ckey))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
else
|
||||
if(alert(usr, "Are you sure you wish to temporarily remove [ckey] from the admins list?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
|
||||
var/datum/admins/holder = admin_datums[ckey] || deadmins[ckey]
|
||||
if(holder)
|
||||
qdel(holder)
|
||||
|
||||
dbadmins -= ckey
|
||||
return TRUE
|
||||
|
||||
171
code/modules/admin/permissions/forums.dm
Normal file
171
code/modules/admin/permissions/forums.dm
Normal file
@@ -0,0 +1,171 @@
|
||||
/datum/permissions_controller/forums
|
||||
/// Admins from the forums
|
||||
var/list/forums_admins = list()
|
||||
|
||||
/// Admins who are overriden for this round
|
||||
var/list/overrides = list()
|
||||
|
||||
/datum/permissions_controller/forums/clear_admins()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
..()
|
||||
forums_admins.Cut()
|
||||
overrides.Cut()
|
||||
|
||||
/datum/permissions_controller/forums/_load_permissions_for(client/C)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(C.ckey in overrides)
|
||||
return ..()
|
||||
|
||||
forums_admins -= C.ckey // In case they have been demoted since last login
|
||||
|
||||
var/permissions = query_permissions_for(C.ckey)
|
||||
|
||||
if(permissions)
|
||||
forums_admins[C.ckey] = permissions
|
||||
new /datum/admins(C.ckey, permissions["rights"])
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
/// Queries forums to find permissions
|
||||
/datum/permissions_controller/forums/proc/query_permissions_for(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
if(!CONFIG_GET(string/xenforo_key))
|
||||
CRASH("Trying to load forums permisisons without xenforo key")
|
||||
|
||||
var/datum/http_request/req = new()
|
||||
req.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/apiurl)]/linking/byond/[ckey(ckey)]", "", list("XF-Api-Key" = CONFIG_GET(string/xenforo_key)))
|
||||
req.begin_async()
|
||||
|
||||
UNTIL(req.is_complete())
|
||||
|
||||
var/datum/http_response/response = req.into_response()
|
||||
if(response.errored)
|
||||
CRASH("Errored loading forums rank: [response.error]")
|
||||
var/list/body
|
||||
try
|
||||
body = json_decode(response.body)
|
||||
catch
|
||||
CRASH("Malformed JSON from forums permssions endpoint. [response.body]")
|
||||
if(!body["success"])
|
||||
return FALSE
|
||||
|
||||
var/flags = 0
|
||||
var/list/permissions = body["user"]["permissions"]
|
||||
for(var/permission in permissions)
|
||||
var/list/parts = splittext(permission, ".")
|
||||
if(parts[1] != "ingame")
|
||||
continue
|
||||
var/newflag = admin_keyword_to_flag(parts[2])
|
||||
if(!newflag)
|
||||
stack_trace("WARNING: Permission \"[parts[2]]\" not found.")
|
||||
flags |= newflag
|
||||
if(flags)
|
||||
return list("rank" = body["display_group"]["title"], "rights" = flags)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/datum/permissions_controller/forums/get_rights_for_ckey(ckey)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!(ckey in overrides) && (ckey in forums_admins))
|
||||
return forums_admins[ckey]["rights"]
|
||||
|
||||
/datum/permissions_controller/forums/get_rank_name(client/subject)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!(subject.ckey in overrides) && (subject.ckey in forums_admins))
|
||||
return forums_admins[subject.ckey]["rank"]
|
||||
|
||||
/datum/permissions_controller/forums/pp_data(mob/user)
|
||||
. = ..()
|
||||
for(var/admin in forums_admins)
|
||||
if(admin in overrides)
|
||||
continue
|
||||
var/data = list()
|
||||
data["ckey"] = admin
|
||||
data["rank"] = forums_admins[admin]["rank"]
|
||||
data["rights"] = rights2text(forums_admins[admin]["rights"], seperator = " ")
|
||||
data["deadminned"] = (admin in deadmins)
|
||||
data["protected_rank"] = TRUE
|
||||
.["admins"] |= list(data)
|
||||
|
||||
/datum/permissions_controller/forums/should_add_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(ckey in overrides)
|
||||
return TRUE
|
||||
return !query_permissions_for(ckey)
|
||||
|
||||
/datum/permissions_controller/forums/edit_rank(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if((ckey in forums_admins) && !(ckey in overrides))
|
||||
if(alert("Forums permissions cannot be edited from this panel. Would you like to add an override for this round?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
if(set_legacy_rank(ckey))
|
||||
overrides += ckey
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/permissions_controller/forums/edit_perms(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if((ckey in forums_admins) && !(ckey in overrides))
|
||||
to_chat(usr, "Permissions for forums ranks cannot be edited in game. To temporarily modify a users permissions first give them a temporary rank.", confidential = TRUE)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/permissions_controller/forums/remove_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if((ckey in forums_admins) && !(ckey in overrides))
|
||||
if(alert("Forums permissions cannot be edited from this panel. Would you like to demote for this round?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
overrides += ckey
|
||||
forums_admins -= ckey
|
||||
if(ckey in admin_datums)
|
||||
qdel(admin_datums[ckey])
|
||||
if(ckey in deadmins)
|
||||
qdel(deadmins[ckey])
|
||||
return TRUE
|
||||
return FALSE
|
||||
454
code/modules/admin/permissions/permissions.dm
Normal file
454
code/modules/admin/permissions/permissions.dm
Normal file
@@ -0,0 +1,454 @@
|
||||
GLOBAL_DATUM(permissions, /datum/permissions_controller)
|
||||
GENERAL_PROTECT_DATUM(/datum/permissions_controller)
|
||||
|
||||
// Creates permissions controller based on the config
|
||||
/proc/init_permissions()
|
||||
if(GLOB.permissions != null)
|
||||
CRASH("Permissions controller loaded twice")
|
||||
|
||||
var/controller_type = /datum/permissions_controller
|
||||
switch(ckey(CONFIG_GET(string/permissions_backend)))
|
||||
if("database")
|
||||
if(CONFIG_GET(flag/sql_enabled))
|
||||
controller_type = /datum/permissions_controller/db
|
||||
else
|
||||
stack_trace("Attempted to load database permissions with sql disabled.")
|
||||
if("forums")
|
||||
if(CONFIG_GET(string/xenforo_key))
|
||||
controller_type = /datum/permissions_controller/forums
|
||||
else
|
||||
stack_trace("Attempted to load forums permissions without a xenforo api key")
|
||||
GLOB.permissions = new controller_type()
|
||||
|
||||
// Handles admin permissions management, overriden to support external backends
|
||||
// Base datum supports legacy file based admin loading
|
||||
/datum/permissions_controller
|
||||
/// Admins that should not be allowed to be modified by the permissions panel
|
||||
var/list/protected_admins = list()
|
||||
|
||||
/// Ranks that should not be allowed to be modified by the permissions panel
|
||||
var/list/protected_ranks = list()
|
||||
|
||||
/// Admins loaded with the legacy system
|
||||
var/list/legacy_admins = list()
|
||||
|
||||
/// Ranks loaded with the legacy system
|
||||
var/list/legacy_ranks = list()
|
||||
|
||||
// These lists are mostly handled by the datums themselves
|
||||
/// Associated list of ckey -> admin datums
|
||||
var/list/admin_datums = list()
|
||||
|
||||
/// List of all admin clients
|
||||
var/list/admins = list()
|
||||
|
||||
/// List of all deadmins
|
||||
var/list/deadmins = list()
|
||||
|
||||
/// Clears any existing stored admins and (re) loads the data from the backend
|
||||
/datum/permissions_controller/proc/start()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
|
||||
clear_admins()
|
||||
load_admins()
|
||||
for(var/client/C in GLOB.clients)
|
||||
load_permissions_for(C)
|
||||
|
||||
/// Removes all admin status from everyone
|
||||
/datum/permissions_controller/proc/clear_admins()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
//clear the datums references
|
||||
admin_datums.Cut()
|
||||
for(var/client/C in GLOB.permissions.admins)
|
||||
C.remove_admin_verbs()
|
||||
C.holder = null
|
||||
admins.Cut()
|
||||
protected_admins.Cut()
|
||||
protected_ranks.Cut()
|
||||
legacy_admins.Cut()
|
||||
legacy_ranks.Cut()
|
||||
deadmins.Cut()
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
/// Pulls in admin data, for if the backend caches the admin data
|
||||
/datum/permissions_controller/proc/load_admins()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
var/previous_rights = 0
|
||||
for(var/line in world.file2list("[global.config.directory]/admin_ranks.txt"))
|
||||
if(!line || findtextEx(line,"#",1,2) || line == " ") //YOGS - added our DB support
|
||||
continue
|
||||
var/next = findtext(line, "=")
|
||||
var/prev = findchar(line, "+-*", next, 0)
|
||||
var/rank_name = trim(copytext(line, 1, next))
|
||||
if(!rank_name) continue
|
||||
var/rights = 0
|
||||
while(prev)
|
||||
next = findchar(line, "+-*", prev + 1, 0)
|
||||
rights |= admin_keyword_to_flag(copytext(line, prev, next), previous_rights)
|
||||
prev = next
|
||||
previous_rights = rights
|
||||
legacy_ranks[rank_name] = rights
|
||||
if(CONFIG_GET(flag/protect_legacy_ranks))
|
||||
protected_ranks |= rank_name
|
||||
|
||||
//ckeys listed in admins.txt are always made admins before sql loading is attempted
|
||||
var/list/lines = world.file2list("[global.config.directory]/admins.txt")
|
||||
for(var/line in lines)
|
||||
if(!length(line) || findtextEx(line, "#", 1, 2) || line == " ") //yogs - added our DB support
|
||||
continue
|
||||
var/list/entry = splittext(line, "=")
|
||||
if(entry.len < 2)
|
||||
continue
|
||||
var/ckey = ckey(entry[1])
|
||||
var/rank = trim(entry[2])
|
||||
if(!ckey || !rank)
|
||||
continue
|
||||
if(rank in legacy_ranks)
|
||||
legacy_admins[ckey] = rank
|
||||
if(CONFIG_GET(flag/protect_legacy_admins))
|
||||
protected_admins |= ckey
|
||||
|
||||
/// Queries the backend permissions system then creates their datum if they should have one
|
||||
/// Returns true if a datum was created
|
||||
/datum/permissions_controller/proc/load_permissions_for(client/C)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(C.ckey in legacy_admins)
|
||||
new /datum/admins(C.ckey, legacy_ranks[legacy_admins[C.ckey]])
|
||||
return TRUE
|
||||
|
||||
if(_load_permissions_for(C))
|
||||
return TRUE
|
||||
|
||||
if(CONFIG_GET(flag/autoadmin))
|
||||
var/auto_rank = CONFIG_GET(string/autoadmin_rank)
|
||||
if(auto_rank in legacy_ranks)
|
||||
legacy_admins[C.ckey] = auto_rank
|
||||
new /datum/admins(C.ckey, legacy_ranks[C.ckey])
|
||||
return TRUE
|
||||
|
||||
if(CONFIG_GET(flag/enable_localhost_rank))
|
||||
var/localhost_addresses = list("127.0.0.1", "::1")
|
||||
if(isnull(C.address) || (C.address in localhost_addresses))
|
||||
legacy_ranks["!localhost!"] = R_EVERYTHING - R_PERSIST_PERMS
|
||||
legacy_admins[C.ckey] = "!localhost!"
|
||||
new /datum/admins(C.ckey, R_EVERYTHING - R_PERSIST_PERMS)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/// Most backends probably want to override this one
|
||||
/// Loads after legacy but before autoadmin/localhost
|
||||
/// If you woud like your backend to load before legacy, or after autoadmin/localhost
|
||||
/// Override the above function instead
|
||||
/datum/permissions_controller/proc/_load_permissions_for(client/C)
|
||||
PROTECTED_PROC(TRUE)
|
||||
return FALSE
|
||||
|
||||
/datum/permissions_controller/proc/check_for_rights(client/subject, rights_required)
|
||||
if(!subject || !subject.holder) // Null and deadmins have no rights
|
||||
return FALSE
|
||||
if(rights_required)
|
||||
return !!(get_rights_for(subject) & rights_required)
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/proc/get_rights_for(client/subject)
|
||||
. = 0
|
||||
if(!subject || !subject.holder)
|
||||
return
|
||||
return get_rights_for_ckey(subject.ckey)
|
||||
|
||||
/datum/permissions_controller/proc/get_rights_for_ckey(ckey)
|
||||
if(ckey in legacy_admins)
|
||||
if(legacy_admins[ckey] in legacy_ranks)
|
||||
return legacy_ranks[legacy_admins[ckey]]
|
||||
|
||||
/// Returns -1 if fewer, 0 if same, 1 if more
|
||||
/datum/permissions_controller/proc/compare_rights(client/A, client/B)
|
||||
if(!A && !B) // If both null, same
|
||||
return 0
|
||||
if(!A)
|
||||
return -1
|
||||
if(!B)
|
||||
return 1
|
||||
|
||||
if(!A.holder && !B.holder)
|
||||
return 0
|
||||
if(!A.holder)
|
||||
return -1
|
||||
if(!B.holder)
|
||||
return 1
|
||||
|
||||
var/A_rights = get_rights_for(A)
|
||||
var/B_rights = get_rights_for(B)
|
||||
if(A_rights == B_rights)
|
||||
return 0
|
||||
if(A_rights > B_rights)
|
||||
return 1
|
||||
return -1
|
||||
|
||||
|
||||
/datum/permissions_controller/proc/get_rank_name(client/subject)
|
||||
var/ckey = subject.ckey
|
||||
if(ckey in legacy_admins)
|
||||
return legacy_admins[ckey]
|
||||
|
||||
/datum/permissions_controller/proc/pp_data(mob/user)
|
||||
var/user_rights = get_rights_for(user.client)
|
||||
. = list()
|
||||
.["admins"] = list()
|
||||
for(var/legmin in legacy_admins)
|
||||
var/data = list()
|
||||
data["ckey"] = legmin
|
||||
data["rank"] = legacy_admins[legmin]
|
||||
var/rights = legacy_ranks[data["rank"]]
|
||||
data["rights"] = rights2text(rights, seperator = " ")
|
||||
var/can_edit = (rights & user_rights) == rights
|
||||
data["protected_admin"] = (legmin in protected_admins) || !can_edit
|
||||
data["protected_rank"] = (data["rank"] in protected_ranks) || !can_edit
|
||||
data["deadminned"] = (legmin in deadmins)
|
||||
.["admins"] |= list(data)
|
||||
|
||||
// Functions used to modify permissions
|
||||
// Returns true if permissions modification was handled
|
||||
|
||||
/// This proc prompts the user for the name that want to add
|
||||
/// Then uses should_add_admin(ckey) to determine if there is a reason
|
||||
/// that ckey shouldn't be added (usually due to already being adminned)
|
||||
/// make_admin(ckey) is then called to handle the actual adding
|
||||
/datum/permissions_controller/proc/add_admin()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
var/ckey = ckey(input("New admin's key","Admin key") as text|null)
|
||||
if(!ckey)
|
||||
return FALSE
|
||||
|
||||
if(!should_add_admin(ckey))
|
||||
to_chat(usr, span_warning("Unable to admin [ckey]. Do they already hold a rank?"), confidential = TRUE)
|
||||
return FALSE
|
||||
|
||||
return make_admin(ckey)
|
||||
|
||||
/datum/permissions_controller/proc/should_add_admin(ckey)
|
||||
return !(ckey in legacy_admins)
|
||||
|
||||
/// Returns true if the rank was changed
|
||||
/datum/permissions_controller/proc/set_legacy_rank(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
var/list/rank_names = list()
|
||||
var/usr_rights = get_rights_for(usr.client)
|
||||
|
||||
rank_names += "*New Rank*"
|
||||
for(var/R in legacy_ranks)
|
||||
if((usr_rights & legacy_ranks[R]) == legacy_ranks[R]) // Cannot grant permissions you do not have
|
||||
rank_names += R
|
||||
var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
||||
if(new_rank == "*New Rank*")
|
||||
new_rank = trim(input("Please input a new rank", "New custom rank") as text|null)
|
||||
if(!new_rank)
|
||||
return FALSE
|
||||
var/old_rights = 0
|
||||
if(ckey in legacy_admins)
|
||||
if(legacy_admins[ckey] in legacy_ranks)
|
||||
old_rights = legacy_ranks[legacy_admins[ckey]]
|
||||
if(!(new_rank in legacy_ranks))
|
||||
legacy_ranks[new_rank] = old_rights
|
||||
legacy_admins[ckey] = new_rank
|
||||
|
||||
var/m = "edited the admin rank of [ckey] to [new_rank] temporarily"
|
||||
message_admins("[key_name_admin(usr)] [m]")
|
||||
log_admin("[key_name(usr)] [m]")
|
||||
|
||||
if(ckey in admin_datums)
|
||||
var/datum/admins/holder = admin_datums[ckey]
|
||||
holder.deactivate()
|
||||
holder.activate()
|
||||
return TRUE
|
||||
if(ckey in deadmins)
|
||||
return TRUE
|
||||
if(ckey in GLOB.directory)
|
||||
new /datum/admins(ckey, legacy_ranks[new_rank])
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/proc/make_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
set_legacy_rank(ckey)
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/proc/edit_rank(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(ckey in protected_admins)
|
||||
to_chat(usr, span_warning("Editing this admin blocked by config"), confidential = TRUE)
|
||||
return TRUE // Nothing was changed, but nothing should be changed
|
||||
|
||||
if(!(ckey in legacy_admins))
|
||||
return FALSE
|
||||
|
||||
set_legacy_rank(ckey)
|
||||
return TRUE
|
||||
|
||||
/datum/permissions_controller/proc/edit_perms(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!(ckey in legacy_admins))
|
||||
return FALSE
|
||||
var/rank = legacy_admins[ckey]
|
||||
if(rank in protected_ranks)
|
||||
to_chat(usr, span_warning("Editing this rank blocked by config"), confidential = TRUE)
|
||||
return TRUE // Nothing was changed, but nothing should be changed
|
||||
|
||||
if(alert("This will modify all admins with the same rank, are you sure you wish to continue?", "Confirmation", "Yes", "No") != "Yes")
|
||||
return TRUE
|
||||
|
||||
var/new_flags = input_bitfield(usr, "Permission flags<br>This will affect all admins with rank [rank]", "admin_flags", legacy_ranks[rank], 350, 590)
|
||||
if(isnull(new_flags))
|
||||
return
|
||||
legacy_ranks[rank] = new_flags
|
||||
|
||||
var/m = "edited the admin rank of [rank] temporarily"
|
||||
message_admins("[key_name_admin(usr)] [m]")
|
||||
log_admin("[key_name(usr)] [m]")
|
||||
|
||||
for(var/admin in admin_datums)
|
||||
if((admin in legacy_admins) && legacy_admins[admin] == rank)
|
||||
var/datum/admins/holder = admin_datums[ckey]
|
||||
holder.deactivate()
|
||||
holder.activate()
|
||||
|
||||
/datum/permissions_controller/proc/remove_admin(ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
return
|
||||
if(!(ckey in legacy_admins))
|
||||
return FALSE
|
||||
if(ckey in protected_admins)
|
||||
to_chat(usr, span_warning("Editing this admin blocked by config"), confidential = TRUE)
|
||||
return TRUE // Nothing was changed, but nothing should be changed
|
||||
|
||||
if(alert("This will remove all admin access for the rest of the round. Are you sure?", "Confirmation", "Yes", "No", "Cancel") != "Yes")
|
||||
return TRUE
|
||||
|
||||
var/m = "removed [ckey] from the admin list temporarily"
|
||||
message_admins("[key_name_admin(usr)] [m]")
|
||||
log_admin("[key_name(usr)] [m]")
|
||||
|
||||
legacy_admins[ckey] = null
|
||||
if(ckey in admin_datums)
|
||||
qdel(admin_datums[ckey])
|
||||
if(ckey in deadmins)
|
||||
qdel(deadmins[ckey])
|
||||
|
||||
/*
|
||||
checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags)
|
||||
if rights_required == 0, then it simply checks if they are an admin.
|
||||
if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed
|
||||
generally it would be used like so:
|
||||
|
||||
/proc/admin_proc()
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
to_chat(world, "you have enough rights!")
|
||||
|
||||
NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call
|
||||
use check_rights_for
|
||||
*/
|
||||
/proc/check_rights(rights_required, show_msg=TRUE)
|
||||
if(usr && usr.client)
|
||||
if (check_rights_for(usr.client, rights_required))
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(usr, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>", confidential=TRUE)
|
||||
return FALSE
|
||||
|
||||
//This proc checks whether subject has at least ONE of the rights specified in rights_required.
|
||||
/proc/check_rights_for(client/subject, rights_required)
|
||||
return GLOB.permissions.check_for_rights(subject, rights_required)
|
||||
|
||||
//probably a bit iffy - will hopefully figure out a better solution
|
||||
/proc/check_if_greater_rights_than(client/other)
|
||||
if(usr && usr.client)
|
||||
if(usr.client.holder)
|
||||
if(!other || !other.holder)
|
||||
return TRUE
|
||||
return GLOB.permissions.compare_rights(usr.client, other) > 0
|
||||
return FALSE
|
||||
|
||||
/proc/admin_keyword_to_flag(word, previous_rights=0)
|
||||
var/flag = 0
|
||||
switch(ckey(word))
|
||||
if("buildmode","build")
|
||||
flag = R_BUILDMODE
|
||||
if("admin")
|
||||
flag = R_ADMIN
|
||||
if("ban")
|
||||
flag = R_BAN
|
||||
if("fun")
|
||||
flag = R_FUN
|
||||
if("server")
|
||||
flag = R_SERVER
|
||||
if("debug")
|
||||
flag = R_DEBUG
|
||||
if("permissions","rights")
|
||||
flag = R_PERMISSIONS
|
||||
if("possess")
|
||||
flag = R_POSSESS
|
||||
if("stealth")
|
||||
flag = R_STEALTH
|
||||
if("poll")
|
||||
flag = R_POLL
|
||||
if("varedit")
|
||||
flag = R_VAREDIT
|
||||
if("everything","host","all")
|
||||
flag = R_EVERYTHING
|
||||
if("sound","sounds")
|
||||
flag = R_SOUNDS
|
||||
if("spawn","create")
|
||||
flag = R_SPAWN
|
||||
if("autologin", "autoadmin")
|
||||
flag = R_AUTOLOGIN
|
||||
if("dev")
|
||||
flag = R_DEV
|
||||
if("dbranks", "persistperms")
|
||||
flag = R_PERSIST_PERMS
|
||||
if("@","prev")
|
||||
flag = previous_rights
|
||||
return flag
|
||||
@@ -115,10 +115,10 @@
|
||||
|
||||
if("show_admins")
|
||||
var/dat = "<HTML><HEAD><meta charset='UTF-8'></HEAD><BODY><B>Current admins:</B><HR>"
|
||||
if(GLOB.admin_datums)
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
dat += "[ckey] - [D.rank.name]<br>"
|
||||
if(GLOB.permissions.admin_datums)
|
||||
for(var/ckey in GLOB.permissions.admin_datums)
|
||||
var/datum/admins/D = GLOB.permissions.admin_datums[ckey]
|
||||
dat += "[ckey] - [D.rank_name()]<br>"
|
||||
dat += "</BODY></HTML>"
|
||||
usr << browse(dat, "window=showadmins;size=600x500")
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
else
|
||||
var/values = list(
|
||||
"player_ckey" = player_ckey,
|
||||
"must_apply_to_admins" = !!(GLOB.admin_datums[player_ckey] || GLOB.deadmins[player_ckey]),
|
||||
"must_apply_to_admins" = !!(GLOB.permissions.admin_datums[player_ckey] || GLOB.permissions.deadmins[player_ckey]),
|
||||
)
|
||||
var/sql_roles
|
||||
if(islist(roles))
|
||||
@@ -113,7 +113,7 @@
|
||||
if(C && istype(C))
|
||||
C.ban_cache = list()
|
||||
var/is_admin = FALSE
|
||||
if(GLOB.admin_datums[C.ckey] || GLOB.deadmins[C.ckey])
|
||||
if(GLOB.permissions.admin_datums[C.ckey] || GLOB.permissions.deadmins[C.ckey])
|
||||
is_admin = TRUE
|
||||
var/datum/DBQuery/query_build_ban_cache = SSdbcore.NewQuery(
|
||||
"SELECT [format_table_name("ban")].role, applies_to_admins FROM [format_table_name("ban")] WHERE ckey = :ckey AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW())",
|
||||
@@ -487,7 +487,7 @@
|
||||
if(query_check_adminban_count.NextRow())
|
||||
var/adminban_count = text2num(query_check_adminban_count.item[1])
|
||||
var/max_adminbans = MAX_ADMINBANS_PER_ADMIN
|
||||
if(R_EVERYTHING && !(R_EVERYTHING & rank.can_edit_rights)) //edit rights are a more effective way to check hierarchical rank since many non-headmins have R_PERMISSIONS now
|
||||
if(check_rights(R_PERMISSIONS, FALSE)) //edit rights are a more effective way to check hierarchical rank since many non-headmins have R_PERMISSIONS now
|
||||
max_adminbans = MAX_ADMINBANS_PER_HEADMIN
|
||||
if(adminban_count >= max_adminbans)
|
||||
to_chat(usr, span_danger("You've already logged [max_adminbans] admin ban(s) or more. Do not abuse this function!"), confidential=TRUE)
|
||||
@@ -557,7 +557,7 @@
|
||||
if(C)
|
||||
build_ban_cache(C)
|
||||
to_chat(C, "[span_boldannounce("You have been [applies_to_admins ? "admin " : ""]banned by [usr.client.key] from [roles_to_ban[1] == "Server" ? "the server" : " Roles: [roles_to_ban.Join(", ")]"].\nReason: [reason]")]<br>[span_danger("This ban is [isnull(duration) ? "permanent." : "temporary, it will be removed in [time_message]."] The round ID is [GLOB.round_id].")]<br>[span_danger("To appeal this ban go to [appeal_url]")]", confidential=TRUE)
|
||||
if(GLOB.admin_datums[C.ckey] || GLOB.deadmins[C.ckey])
|
||||
if(GLOB.permissions.admin_datums[C.ckey] || GLOB.permissions.deadmins[C.ckey])
|
||||
is_admin = TRUE
|
||||
if(roles_to_ban[1] == "Server" && (!is_admin || (is_admin && applies_to_admins)))
|
||||
qdel(C)
|
||||
@@ -567,7 +567,7 @@
|
||||
if(i.address == player_ip || i.computer_id == player_cid)
|
||||
build_ban_cache(i)
|
||||
to_chat(i, "[span_boldannounce("You have been [applies_to_admins ? "admin " : ""]banned by [usr.client.key] from [roles_to_ban[1] == "Server" ? "the server" : " Roles: [roles_to_ban.Join(", ")]"].\nReason: [reason]")]<br>[span_danger("This ban is [isnull(duration) ? "permanent." : "temporary, it will be removed in [time_message]."] The round ID is [GLOB.round_id].")]<br>[span_danger("To appeal this ban go to [appeal_url]")]")
|
||||
if(GLOB.admin_datums[i.ckey] || GLOB.deadmins[i.ckey])
|
||||
if(GLOB.permissions.admin_datums[i.ckey] || GLOB.permissions.deadmins[i.ckey])
|
||||
is_admin = TRUE
|
||||
if(roles_to_ban[1] == "Server" && (!is_admin || (is_admin && applies_to_admins)))
|
||||
qdel(i)
|
||||
@@ -805,7 +805,7 @@
|
||||
if(query_check_adminban_count.NextRow())
|
||||
var/adminban_count = text2num(query_check_adminban_count.item[1])
|
||||
var/max_adminbans = MAX_ADMINBANS_PER_ADMIN
|
||||
if(R_EVERYTHING && !(R_EVERYTHING & rank.can_edit_rights)) //edit rights are a more effective way to check hierarchical rank since many non-headmins have R_PERMISSIONS now
|
||||
if(check_rights(R_PERMISSIONS, FALSE)) //edit rights are a more effective way to check hierarchical rank since many non-headmins have R_PERMISSIONS now
|
||||
max_adminbans = MAX_ADMINBANS_PER_HEADMIN
|
||||
if(adminban_count >= max_adminbans)
|
||||
to_chat(usr, span_danger("You've already logged [max_adminbans] admin ban(s) or more. Do not abuse this function!"), confidential=TRUE)
|
||||
|
||||
@@ -240,23 +240,14 @@
|
||||
log_admin("[key_name(usr)] has triggered an event. ([E.name])")
|
||||
return
|
||||
|
||||
else if(href_list["editrightsbrowser"])
|
||||
edit_admin_permissions(0)
|
||||
// else if(href_list["editrightsbrowser"])
|
||||
// edit_admin_permissions(0)
|
||||
|
||||
else if(href_list["editrightsbrowserlog"])
|
||||
edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"])
|
||||
// else if(href_list["editrightsbrowserlog"])
|
||||
// edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"])
|
||||
|
||||
if(href_list["editrightsbrowsermanage"])
|
||||
if(href_list["editrightschange"])
|
||||
change_admin_rank(ckey(href_list["editrightschange"]), href_list["editrightschange"], TRUE)
|
||||
else if(href_list["editrightsremove"])
|
||||
remove_admin(ckey(href_list["editrightsremove"]), href_list["editrightsremove"], TRUE)
|
||||
else if(href_list["editrightsremoverank"])
|
||||
remove_rank(href_list["editrightsremoverank"])
|
||||
edit_admin_permissions(2)
|
||||
|
||||
else if(href_list["editrights"])
|
||||
edit_rights_topic(href_list)
|
||||
// else if(href_list["editrights"])
|
||||
// edit_rights_topic(href_list)
|
||||
|
||||
else if(href_list["gamemode_panel"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
|
||||
if(irc)
|
||||
log_admin_private("PM: [key_name(src)]->IRC: [rawmsg]")
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
to_chat(X,
|
||||
type = MESSAGE_TYPE_ADMINPM,
|
||||
html = span_notice("<B>PM: [key_name(src, X, 0)]->External:</B> [keywordparsedmsg]"),
|
||||
@@ -269,7 +269,7 @@
|
||||
window_flash(recipient, ignorepref = TRUE)
|
||||
log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
|
||||
//we don't use message_admins here because the sender/receiver might get it too
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipientD
|
||||
to_chat(X,
|
||||
type = MESSAGE_TYPE_ADMINPM,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
msg = keywords_lookup(msg)
|
||||
var/custom_asay_color = (CONFIG_GET(flag/allow_admin_asaycolor) && prefs.asaycolor) ? "<font color=[prefs.asaycolor]>" : null // Yogs -- yogs asay
|
||||
msg = "<span class='adminsay'>[span_prefix("ADMIN:")] <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: [custom_asay_color]<span class='message linkify'>[msg]</span></span>[custom_asay_color ? "</font>":null]"
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_ADMINCHAT,
|
||||
html = msg,
|
||||
confidential = TRUE)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
if (!msg)
|
||||
return
|
||||
var/rank_name = holder.rank
|
||||
var/rank_name = holder.rank_name()
|
||||
var/admin_name = key
|
||||
var/follow_link = ""
|
||||
if(holder.fakekey)
|
||||
|
||||
@@ -894,7 +894,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
if("Players")
|
||||
to_chat(usr, jointext(GLOB.player_list,","), confidential=TRUE)
|
||||
if("Admins")
|
||||
to_chat(usr, jointext(GLOB.admins,","), confidential=TRUE)
|
||||
to_chat(usr, jointext(GLOB.permissions.admins,","), confidential=TRUE)
|
||||
if("Mobs")
|
||||
to_chat(usr, jointext(GLOB.mob_list,","), confidential=TRUE)
|
||||
if("Living Mobs")
|
||||
|
||||
@@ -92,8 +92,7 @@
|
||||
if(confirm !="Yes")
|
||||
return
|
||||
|
||||
refresh_admin_files() //yogs - DB support
|
||||
load_admins()
|
||||
GLOB.permissions.start()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reload All Admins") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
message_admins("[key_name_admin(usr)] manually reloaded admins")
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
prayer_type = "SPIRITUAL PRAYER"
|
||||
|
||||
var/msg_tmp = msg
|
||||
msg = span_adminnotice("[icon2html(cross, GLOB.admins)]<b><font color=[font_color]>[prayer_type][deity ? " (to [deity])" : ""]: </font>[ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]:</b> [msg]")
|
||||
msg = span_adminnotice("[icon2html(cross, GLOB.permissions.admins)]<b><font color=[font_color]>[prayer_type][deity ? " (to [deity])" : ""]: </font>[ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]:</b> [msg]")
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
for(var/client/C in GLOB.permissions.admins)
|
||||
if(C.prefs.chat_toggles & CHAT_PRAYER)
|
||||
to_chat(C, msg, confidential=TRUE)
|
||||
if(C.prefs.toggles & SOUND_PRAYERS)
|
||||
@@ -57,7 +57,7 @@
|
||||
/proc/message_centcom(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = span_adminnotice("<b><font color=orange>CENTCOM:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)]:</b> [msg]")
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
/proc/message_syndicate(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = span_adminnotice("<b><font color=crimson>SYNDICATE:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_SYNDICATE_REPLY(sender)]:</b> [msg]")
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
@@ -73,13 +73,13 @@
|
||||
/proc/nuke_request(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = span_adminnotice("<b><font color=orange>NUKE CODE REQUEST:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)] [ADMIN_SET_SD_CODE] [ADMIN_SET_BC_CODE]:</b> [msg]")
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
/proc/Clown_announce(text , mob/Sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = span_adminnotice("<b><font color=violet>CLOWN PLANET:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]:</b> [msg]")
|
||||
to_chat(GLOB.admins, msg, confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential=TRUE)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.override_cooldown()
|
||||
|
||||
@@ -241,32 +241,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
tgui_panel.send_connected()
|
||||
|
||||
GLOB.ahelp_tickets.ClientLogin(src)
|
||||
var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins.
|
||||
//Admin Authorisation
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
if(holder)
|
||||
if(!holder.associate(src, FALSE)) // Prevent asking for MFA at this point, it likely won't work
|
||||
holder = null
|
||||
connecting_admin = TRUE
|
||||
else if(GLOB.deadmins[ckey])
|
||||
add_verb(src, /client/proc/readmin)
|
||||
connecting_admin = TRUE
|
||||
if(CONFIG_GET(flag/autoadmin))
|
||||
if(!GLOB.admin_datums[ckey])
|
||||
var/datum/admin_rank/autorank
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == CONFIG_GET(string/autoadmin_rank))
|
||||
autorank = R
|
||||
break
|
||||
if(!autorank)
|
||||
to_chat(world, "Autoadmin rank not found")
|
||||
else
|
||||
new /datum/admins(autorank, ckey)
|
||||
if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin)
|
||||
var/localhost_addresses = list("127.0.0.1", "::1")
|
||||
if(isnull(address) || (address in localhost_addresses))
|
||||
var/datum/admin_rank/localhost_rank = new("!localhost!", R_EVERYTHING, R_DBRANKS, R_EVERYTHING) //+EVERYTHING -DBRANKS *EVERYTHING
|
||||
new /datum/admins(localhost_rank, ckey, 1, 1)
|
||||
var/connecting_admin = GLOB.permissions.load_permissions_for(src) //because de-admined admins connecting should be treated like admins.
|
||||
if(connecting_admin && !holder)
|
||||
stack_trace("[ckey] is an admin but has no holder")
|
||||
|
||||
// yogs start - mentor stuff
|
||||
if(ckey in GLOB.mentor_datums)
|
||||
@@ -523,8 +500,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(holder)
|
||||
adminGreet(1)
|
||||
holder.owner = null
|
||||
GLOB.admins -= src
|
||||
if (!GLOB.admins.len && SSticker.IsRoundInProgress()) //Only report this stuff if we are currently playing.
|
||||
GLOB.permissions.admins -= src
|
||||
if (!GLOB.permissions.admins.len && SSticker.IsRoundInProgress()) //Only report this stuff if we are currently playing.
|
||||
var/cheesy_message = pick(
|
||||
"I have no admins online!",\
|
||||
"I'm all alone :(",\
|
||||
@@ -541,6 +518,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
)
|
||||
|
||||
send2irc("Server", "[cheesy_message] (No admins online)")
|
||||
qdel(holder)
|
||||
if(ckey in GLOB.permissions.deadmins)
|
||||
qdel(GLOB.permissions.deadmins[ckey])
|
||||
|
||||
GLOB.ahelp_tickets.ClientLogout(src)
|
||||
GLOB.directory -= ckey
|
||||
@@ -588,10 +568,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
related_accounts_cid += "[query_get_related_cid.item[1]], "
|
||||
qdel(query_get_related_cid)
|
||||
var/admin_rank = "Player"
|
||||
if (src.holder && src.holder.rank)
|
||||
admin_rank = src.holder.rank.name
|
||||
if (src.holder)
|
||||
admin_rank = src.holder.rank_name()
|
||||
else
|
||||
if (!GLOB.deadmins[ckey] && check_randomizer(connectiontopic))
|
||||
if (!GLOB.permissions.deadmins[ckey] && check_randomizer(connectiontopic))
|
||||
return
|
||||
var/new_player
|
||||
var/datum/DBQuery/query_client_in_db = SSdbcore.NewQuery(
|
||||
@@ -602,7 +582,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
qdel(query_client_in_db)
|
||||
return
|
||||
if(!query_client_in_db.NextRow())
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey])
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.permissions.deadmins[ckey])
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins(span_adminnotice("Failed Login: [key] - New account attempting to connect during panic bunker"))
|
||||
to_chat(src, CONFIG_GET(string/panic_bunker_message))
|
||||
|
||||
@@ -1355,7 +1355,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(href_list["bancheck"])
|
||||
var/list/ban_details = is_banned_from_with_details(user.ckey, user.client.address, user.client.computer_id, href_list["bancheck"])
|
||||
var/admin = FALSE
|
||||
if(GLOB.admin_datums[user.ckey] || GLOB.deadmins[user.ckey])
|
||||
if(GLOB.permissions.admin_datums[user.ckey] || GLOB.permissions.deadmins[user.ckey])
|
||||
admin = TRUE
|
||||
for(var/i in ban_details)
|
||||
if(admin && !text2num(i["applies_to_admins"]))
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
|
||||
var/msg = "<b>Current Admins:</b>\n"
|
||||
if(holder)
|
||||
for(var/client/C in GLOB.admins)
|
||||
msg += "\t[C] is a [C.holder.rank]"
|
||||
for(var/client/C in GLOB.permissions.admins)
|
||||
msg += "\t[C] is a [C.holder.rank_name()]"
|
||||
|
||||
if(C.holder.fakekey)
|
||||
msg += " <i>(as [C.holder.fakekey])</i>"
|
||||
@@ -79,11 +79,11 @@
|
||||
msg += " (AFK)"
|
||||
msg += "\n"
|
||||
else
|
||||
for(var/client/C in GLOB.admins)
|
||||
for(var/client/C in GLOB.permissions.admins)
|
||||
if(C.is_afk())
|
||||
continue //Don't show afk admins to adminwho
|
||||
if(!C.holder.fakekey)
|
||||
msg += "\t[C] is a [C.holder.rank]\n"
|
||||
msg += "\t[C] is a [C.holder.rank_name()]\n"
|
||||
msg += span_info("Adminhelps are also sent to Discord. If no admins are available in game adminhelp anyways and an admin on Discord will see it and respond.") //yogs - IRC -> discord
|
||||
to_chat(src, msg)
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
LateChoices()
|
||||
return
|
||||
|
||||
if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
|
||||
if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.permissions.admin_datums)))
|
||||
//yogs start -- donors bypassing the queue
|
||||
if(ckey(key) in get_donators())
|
||||
to_chat(usr, span_notice("Because you are a donator, you have bypassed the queue! Thank you for donating!"))
|
||||
@@ -176,7 +176,7 @@
|
||||
to_chat(usr, span_notice("There is an administrative lock on entering the game!"))
|
||||
return
|
||||
|
||||
if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
|
||||
if(SSticker.queued_players.len && !(ckey(key) in GLOB.permissions.admin_datums))
|
||||
if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
|
||||
to_chat(usr, span_warning("Server is full."))
|
||||
return
|
||||
|
||||
@@ -373,7 +373,7 @@
|
||||
/mob/dead/new_player/proc/poll_rank()
|
||||
. = "Player"
|
||||
if(client.holder)
|
||||
. = client.holder.rank.name
|
||||
. = client.holder.rank_name()
|
||||
|
||||
|
||||
/mob/dead/new_player/proc/vote_rig_check()
|
||||
@@ -423,7 +423,7 @@
|
||||
var/datum/admins/holder = client.holder
|
||||
var/rank = "Player"
|
||||
if (holder)
|
||||
rank = holder.rank.name
|
||||
rank = holder.rank_name()
|
||||
var/ckey = client.ckey
|
||||
var/address = client.address
|
||||
|
||||
@@ -566,7 +566,7 @@
|
||||
qdel(query_numval_hasvoted)
|
||||
var/adminrank = "Player"
|
||||
if(client.holder)
|
||||
adminrank = client.holder.rank.name
|
||||
adminrank = client.holder.rank_name()
|
||||
if(isnull(rating))
|
||||
rating = "null"
|
||||
var/datum/DBQuery/query_numval_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (Now(), :pollid, :optionid, :ckey, INET_ATON(:address), :adminrank, :rating", list("pollid" = pollid, "optionid" = optionid, "ckey" = ckey, "address" = client.address, "adminrank" = adminrank, "rating" = rating))
|
||||
@@ -611,7 +611,7 @@
|
||||
return 2
|
||||
var/adminrank = "Player"
|
||||
if(!QDELETED(client) && client.holder)
|
||||
adminrank = client.holder.rank.name
|
||||
adminrank = client.holder.rank_name()
|
||||
var/datum/DBQuery/query_multi_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank) VALUES (Now(), :pollid, :optionid, :ckey, INET_ATON(:address), :adminrank)", list("pollid" = pollid, "optionid" = optionid, "ckey" = ckey, "address" = client.address, "adminrank" = adminrank))
|
||||
if(!query_multi_vote.warn_execute())
|
||||
qdel(query_multi_vote)
|
||||
@@ -619,4 +619,4 @@
|
||||
qdel(query_multi_vote)
|
||||
if(!QDELETED(usr))
|
||||
usr << browse(null,"window=playerpoll")
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -168,7 +168,7 @@ GLOBAL_LIST_EMPTY(adminfaxes)
|
||||
/obj/machinery/photocopier/faxmachine/proc/send_adminmessage(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100")
|
||||
var/msg = "<b><font color='[font_colour]'>[faxname]: </font>[key_name(sender, 1)] (<A HREF='?_src_=holder;[HrefToken(TRUE)];adminplayeropts=\ref[sender]'>PP</A>) (<A HREF='?_src_=vars;[HrefToken(TRUE)];Vars=\ref[sender]'>VV</A>) (<A HREF='?_src_=holder;[HrefToken(TRUE)];subtlemessage=\ref[sender]'>SM</A>) (<A HREF='?_src_=holder;[HrefToken(TRUE)];adminplayerobservefollow=\ref[sender]'>JMP</A>) (<a href='?_src_=holder;[HrefToken(TRUE)];[reply_type]=\ref[sender];originfax=\ref[src]'>REPLY</a>)</b>: Receiving '[sent.name]' via secure connection ... <a href='?_src_=holder;[HrefToken(TRUE)];AdminFaxView=\ref[sent]'>view message</a>"
|
||||
msg = span_admin("<span class=\"message\">[msg]</span>")
|
||||
to_chat(GLOB.admins,
|
||||
to_chat(GLOB.permissions.admins,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
html = msg,
|
||||
confidential = TRUE)
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
return
|
||||
COOLDOWN_START(src, request_cooldown, 1 MINUTES)
|
||||
to_chat(usr, span_notice("Your request has been received by CentCom."))
|
||||
to_chat(GLOB.admins, "<b>FERRY: <font color='#3d5bc3'>[ADMIN_LOOKUPFLW(usr)] (<A HREF='?_src_=holder;[HrefToken()];secrets=moveferry'>Move Ferry</a>)</b> is requesting to move the transport ferry to CentCom.</font>")
|
||||
to_chat(GLOB.permissions.admins, "<b>FERRY: <font color='#3d5bc3'>[ADMIN_LOOKUPFLW(usr)] (<A HREF='?_src_=holder;[HrefToken()];secrets=moveferry'>Move Ferry</a>)</b> is requesting to move the transport ferry to CentCom.</font>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/shuttle/emag_act(mob/user)
|
||||
|
||||
15
code/modules/tgui/states/permissions.dm
Normal file
15
code/modules/tgui/states/permissions.dm
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* tgui state: admin_state
|
||||
*
|
||||
* Checks that the user is an admin, end-of-story.
|
||||
*
|
||||
* Copyright (c) 2020 Aleksej Komarov
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
GLOBAL_DATUM_INIT(permissions_state, /datum/ui_state/permissions_state, new)
|
||||
|
||||
/datum/ui_state/permissions_state/can_use_topic(src_object, mob/user)
|
||||
if(check_rights_for(user.client, R_PERMISSIONS))
|
||||
return UI_INTERACTIVE
|
||||
return UI_CLOSE
|
||||
@@ -4,13 +4,12 @@
|
||||
# Rank is CASE-SENSITIVE, all punctuation save for '-', '_' and '@' will be stripped so spaces don't matter. #
|
||||
# You can then define permissions for each rank by adding a '=' followed by keywords #
|
||||
# These keywords represent groups of verbs and abilities. #
|
||||
# keywords are preceded by a '+', '-' or '*' + adds permissions, - takes them away. #
|
||||
# * is used only with SQL-based admin loading to denote what permissions the rank is allowed to edit #
|
||||
# keywords are preceded by a '+'. #
|
||||
# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #
|
||||
# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #
|
||||
##############################################################################################################
|
||||
# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!
|
||||
# If SQL-based admin loading is enabled, ranks and their keywords listed here will be loaded first and override any with the same name loaded from the database.
|
||||
# If network-based admin loading is enabled, ranks and their keywords listed here will be used for protected admins and temporary rank changes
|
||||
|
||||
# Follow the format below when documenting new keywords so the server tools may parse it
|
||||
|
||||
@@ -35,37 +34,16 @@
|
||||
# END_KEYWORDS
|
||||
|
||||
|
||||
Host = +EVERYTHING *EVERYTHING
|
||||
Host = +EVERYTHING
|
||||
|
||||
Council Member = +EVERYTHING *EVERYTHING
|
||||
Council Member = +EVERYTHING
|
||||
|
||||
Head Developer = +EVERYTHING *EVERYTHING
|
||||
Head Developer = +EVERYTHING
|
||||
|
||||
SysOp = +EVERYTHING *EVERYTHING
|
||||
|
||||
#Senior Admin = +EVERYTHING *EVERYTHING -DEV
|
||||
|
||||
#Community Manager = +EVERYTHING *EVERYTHING -DEV
|
||||
|
||||
#Primary Admin = +STEALTH +ADMIN +BASIC +BAN +SPAWN +VAREDIT +DEBUG +SERVER +FUN +POSSESS +BUILD +TICKET +SOUND
|
||||
|
||||
#Administrator-Mainterino = +STEALTH +ADMIN +BASIC +BAN +SPAWN +VAREDIT +DEBUG +SERVER +FUN +TICKET +BUILD +POLL +DEV
|
||||
|
||||
#Administrator = +STEALTH +ADMIN +BASIC +BAN +SPAWN +VAREDIT +DEBUG +SERVER +FUN +TICKET +BUILD
|
||||
|
||||
#Moderator-Mainterino = +STEALTH +ADMIN +VAREDIT +DEBUG +SERVER +BASIC +SPAWN +POLL +BAN +DEV
|
||||
|
||||
#Moderator = +STEALTH +ADMIN +BASIC +BAN +TICKET
|
||||
|
||||
#Retired Admin = +ADMIN +STEALTH +BASIC +SERVER +BAN +TICKET +VAREDIT
|
||||
|
||||
#Admin Observer = +STEALTH
|
||||
|
||||
#Maintainer = +STEALTH +ADMIN +VAREDIT +DEBUG +SERVER +BASIC +SPAWN +POLL -AUTOLOGIN +DEV
|
||||
|
||||
#LogDiver =
|
||||
|
||||
#Forum Mod =
|
||||
|
||||
#Bot = +EVERYTHING *EVERYTHING
|
||||
SysOp = +EVERYTHING
|
||||
|
||||
Administrator = +STEALTH +ADMIN +BASIC +BAN +SPAWN +VAREDIT +DEBUG +SERVER +FUN +TICKET +BUILD +AUTOLOGIN
|
||||
|
||||
Admin Observer = +STEALTH +AUTOLOGIN
|
||||
|
||||
Maintainer = +STEALTH +ADMIN +VAREDIT +DEBUG +SERVER +BASIC +SPAWN +POLL +DEV
|
||||
|
||||
@@ -25,10 +25,6 @@ ROUND_END_COUNTDOWN 90
|
||||
##Uncomment this to stop any admins loaded by the legacy system from having their rank edited by the permissions panel
|
||||
PROTECT_LEGACY_ADMINS
|
||||
|
||||
##Uncomment this to have admin ranks only loaded from the legacy admin_ranks.txt
|
||||
##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags
|
||||
#LOAD_LEGACY_RANKS_ONLY
|
||||
|
||||
## Uncomment this entry to have certain jobs require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different jobs by editing
|
||||
## the minimal_player_age variable in the files in folder /code/game/jobs/job/.. for the job you want to edit. Set minimal_player_age to 0 to disable age requirement for that job.
|
||||
## REQUIRES the database set up to work. Keep it hashed if you don't have a database set up.
|
||||
|
||||
@@ -19,10 +19,11 @@ SERVERSQLNAME yogstation
|
||||
## Put on byond hub: Uncomment this to put your server on the byond hub.
|
||||
#HUB
|
||||
|
||||
## Comment this out if you want to use the SQL based admin system, the legacy system uses admins.txt.
|
||||
## You need to set up your database to use the SQL based system.
|
||||
## This flag is automatically enabled if SQL_ENABLED isn't
|
||||
ADMIN_LEGACY_SYSTEM
|
||||
## Determines the backend provider of admin rank data
|
||||
# Use 'database' to load from an SQL database, requires SQL_ENABLED
|
||||
# Use 'forums' to load from the Xenforo plugin, requires XENFORO_KEY
|
||||
# Any other value, or missing the required configuration settings will use the legacy system only
|
||||
PERMISSIONS_BACKEND none
|
||||
|
||||
##Uncomment this to stop any ranks loaded by the legacy system from having their flags edited by the permissions panel
|
||||
# PROTECT_LEGACY_RANKS
|
||||
|
||||
@@ -19,10 +19,11 @@ SERVERSQLNAME yogstation
|
||||
## Put on byond hub: Uncomment this to put your server on the byond hub.
|
||||
HUB
|
||||
|
||||
## Comment this out if you want to use the SQL based admin system, the legacy system uses admins.txt.
|
||||
## You need to set up your database to use the SQL based system.
|
||||
## This flag is automatically enabled if SQL_ENABLED isn't
|
||||
# ADMIN_LEGACY_SYSTEM
|
||||
## Determines the backend provider of admin rank data
|
||||
# Use 'database' to load from an SQL database, requires SQL_ENABLED
|
||||
# Use 'forums' to load from the Xenforo plugin, requires XENFORO_KEY
|
||||
# Any other value, or missing the required configuration settings will use the legacy system only
|
||||
PERMISSIONS_BACKEND forums
|
||||
|
||||
##Uncomment this to stop any ranks loaded by the legacy system from having their flags edited by the permissions panel
|
||||
PROTECT_LEGACY_RANKS
|
||||
|
||||
88
tgui/packages/tgui/interfaces/PermissionsPanel.js
Normal file
88
tgui/packages/tgui/interfaces/PermissionsPanel.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Box, Button, Collapsible, Flex, Section, Tabs } from "../components";
|
||||
import { Layout, Window } from "../layouts";
|
||||
import { createLogger } from "../logging";
|
||||
|
||||
const logger = createLogger('PermissionsPanel');
|
||||
|
||||
export const PermissionsPanel = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
return (
|
||||
<Window
|
||||
title="Permissions Panel"
|
||||
width={600}
|
||||
height={500}
|
||||
resizable >
|
||||
<Window.Content scrollable>
|
||||
<Button
|
||||
icon="plus"
|
||||
color="green"
|
||||
mb={1}
|
||||
onClick={() => act('addNewAdmin')}>
|
||||
Add New
|
||||
</Button>
|
||||
{data.admins.map((admin, i) => (
|
||||
<AdminDisplay
|
||||
key={i}
|
||||
data={admin}
|
||||
act={act} />
|
||||
))}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
export const AdminDisplay = props => {
|
||||
const { data, act } = props;
|
||||
const {
|
||||
ckey,
|
||||
rank,
|
||||
protected_admin,
|
||||
protected_rank,
|
||||
rights,
|
||||
deadminned,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title={`${ckey} - ${rank}`}
|
||||
buttons={(
|
||||
<Button
|
||||
icon="trash"
|
||||
color="bad"
|
||||
onClick={() => act('removeAdmin', {
|
||||
ckey: ckey,
|
||||
})} />
|
||||
)} >
|
||||
<Button onClick={() => act('forceSwapAdmin', {
|
||||
ckey: ckey,
|
||||
})}>
|
||||
Force { deadminned ? "Re" : "De" }admin
|
||||
</Button>
|
||||
<Button onClick={() => act('resetMFA', {
|
||||
ckey: ckey,
|
||||
})}>
|
||||
Reset MFA
|
||||
</Button>
|
||||
<Button
|
||||
disabled={protected_admin}
|
||||
onClick={() => act('editRank', {
|
||||
ckey: ckey,
|
||||
})}>
|
||||
Change Rank
|
||||
</Button>
|
||||
<Collapsible
|
||||
title="Permissions"
|
||||
buttons={(
|
||||
<Button
|
||||
icon="edit"
|
||||
content="Edit"
|
||||
disabled={protected_rank}
|
||||
onClick={() => act('editPerms', {
|
||||
ckey: ckey,
|
||||
})} />
|
||||
)}>
|
||||
{ rights }
|
||||
</Collapsible>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -1301,7 +1301,6 @@
|
||||
#include "code\game\turfs\space\transit.dm"
|
||||
#include "code\modules\admin\admin.dm"
|
||||
#include "code\modules\admin\admin_investigate.dm"
|
||||
#include "code\modules\admin\admin_ranks.dm"
|
||||
#include "code\modules\admin\admin_verbs.dm"
|
||||
#include "code\modules\admin\adminmenu.dm"
|
||||
#include "code\modules\admin\antag_panel.dm"
|
||||
@@ -1327,6 +1326,9 @@
|
||||
#include "code\modules\admin\team_panel.dm"
|
||||
#include "code\modules\admin\topic.dm"
|
||||
#include "code\modules\admin\whitelist.dm"
|
||||
#include "code\modules\admin\permissions\database.dm"
|
||||
#include "code\modules\admin\permissions\forums.dm"
|
||||
#include "code\modules\admin\permissions\permissions.dm"
|
||||
#include "code\modules\admin\verbs\adminjump.dm"
|
||||
#include "code\modules\admin\verbs\adminpm.dm"
|
||||
#include "code\modules\admin\verbs\atmosdebug.dm"
|
||||
@@ -3248,6 +3250,7 @@
|
||||
#include "code\modules\tgui\states\not_incapacitated.dm"
|
||||
#include "code\modules\tgui\states\notcontained.dm"
|
||||
#include "code\modules\tgui\states\observer.dm"
|
||||
#include "code\modules\tgui\states\permissions.dm"
|
||||
#include "code\modules\tgui\states\physical.dm"
|
||||
#include "code\modules\tgui\states\self.dm"
|
||||
#include "code\modules\tgui\states\zlevel.dm"
|
||||
@@ -3507,7 +3510,6 @@
|
||||
#include "yogstation\code\game\turfs\simulated\minerals.dm"
|
||||
#include "yogstation\code\game\turfs\simulated\floor\fancy_floor.dm"
|
||||
#include "yogstation\code\modules\admin\admin.dm"
|
||||
#include "yogstation\code\modules\admin\admin_ranks.dm"
|
||||
#include "yogstation\code\modules\admin\admin_verbs.dm"
|
||||
#include "yogstation\code\modules\admin\holder2.dm"
|
||||
#include "yogstation\code\modules\admin\moja.dm"
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
if(ismob(user))
|
||||
var/mob/temp = user
|
||||
if(temp)
|
||||
return (temp.ckey in GLOB.deadmins)
|
||||
return (temp.ckey in GLOB.permissions.deadmins)
|
||||
|
||||
if(istype(user, /client))
|
||||
var/client/temp = user
|
||||
if(temp)
|
||||
return (temp.ckey in GLOB.deadmins)
|
||||
return (temp.ckey in GLOB.permissions.deadmins)
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ GLOBAL_VAR_INIT(mentornoot, FALSE)
|
||||
require_comms_key = TRUE
|
||||
|
||||
/datum/world_topic/asay/Run(list/input)
|
||||
to_chat(GLOB.admins, span_adminsay("[span_prefix("DISCORD:")] <EM>[input["admin"]]</EM>: [span_message("[input["asay"]]")]"), confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, span_adminsay("[span_prefix("DISCORD:")] <EM>[input["admin"]]</EM>: [span_message("[input["asay"]]")]"), confidential=TRUE)
|
||||
|
||||
/datum/world_topic/ooc
|
||||
keyword = "ooc"
|
||||
@@ -29,7 +29,7 @@ GLOBAL_VAR_INIT(mentornoot, FALSE)
|
||||
/datum/world_topic/adminwho/Run(list/input)
|
||||
var/list/message = list("Admins: ")
|
||||
var/list/admin_keys = list()
|
||||
for(var/adm in GLOB.admins)
|
||||
for(var/adm in GLOB.permissions.admins)
|
||||
var/client/C = adm
|
||||
if(input["adminchannel"])
|
||||
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
|
||||
@@ -66,7 +66,7 @@ GLOBAL_VAR_INIT(mentornoot, FALSE)
|
||||
require_comms_key = TRUE
|
||||
|
||||
/datum/world_topic/msay/Run(list/input)
|
||||
to_chat(GLOB.admins | GLOB.mentors, "<b><font color ='#8A2BE2'>[span_prefix("DISCORD MENTOR:")]</span> <EM>[input["admin"]]</EM>: [span_message("[input["msay"]]")]</span>")
|
||||
to_chat(GLOB.permissions.admins | GLOB.mentors, "<b><font color ='#8A2BE2'>[span_prefix("DISCORD MENTOR:")]</span> <EM>[input["admin"]]</EM>: [span_message("[input["msay"]]")]</span>")
|
||||
|
||||
/datum/world_topic/mhelp
|
||||
keyword = "mhelp"
|
||||
@@ -86,7 +86,7 @@ GLOBAL_VAR_INIT(mentornoot, FALSE)
|
||||
SEND_SOUND(C, sound('sound/items/bikehorn.ogg'))
|
||||
to_chat(C, "<font color='purple'>Mentor PM from-<b>[discord_mentor_link(from, from_id)]</b>: [msg]</font>")
|
||||
var/show_char_recip = !C.is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
|
||||
for(var/client/X in GLOB.mentors | GLOB.admins)
|
||||
for(var/client/X in GLOB.mentors | GLOB.permissions.admins)
|
||||
if(X != C)
|
||||
to_chat(X, "<B><font color='green'>Mentor PM: [discord_mentor_link(from, from_id)]->[key_name_mentor(C, X, 0, 0, show_char_recip)]:</B> <font color ='cyan'> [msg]</font>")
|
||||
return 1
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Kn0ss0s: This proc allows your to use a database for admin ranks, whilst immediately providing a functioning actual fallback in the case of failure
|
||||
/proc/refresh_admin_files()
|
||||
return //this is a stupid system
|
||||
/*
|
||||
// Generate the Admins and Admins Ranks config files
|
||||
if(SSdbcore.IsConnected())
|
||||
var/datum/DBQuery/query_ranks = SSdbcore.NewQuery("SELECT `name`, `byond`, `rank_group` FROM `web_groups` ORDER BY `web_groups`.`rank_group` ASC, `web_groups`.`name` DESC")
|
||||
if(query_ranks.Execute())
|
||||
fdel("config/admin_ranks.txt")
|
||||
var/ranksFile = file("config/admin_ranks.txt")
|
||||
WRITE_FILE(ranksFile, "##############################################################################################################\n# ADMIN RANK DEFINES #\n# The format of this is very simple. Rank name goes first. #\n# Rank is CASE-SENSITIVE, all punctuation save for '-', '_' and '@' will be stripped so spaces don't matter. #\n# You can then define permissions for each rank by adding a '=' followed by keywords #\n# These keywords represent groups of verbs and abilities. #\n# keywords are preceded by either a '+' or a '-', + adds permissions, - takes them away. #\n# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #\n# You can also specify verbs like so +/client/proc/some_added_verb or -/client/proc/some_restricted_verb #\n# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #\n##############################################################################################################\n# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!\n\n# KEYWORDS:\n# +ADMIN = general admin tools, verbs etc\n# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.\n# +BAN = the ability to ban, jobban and fullban\n# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins\n# +POSSESS = the ability to possess objects\n# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode\n# +BUILD (or +BUILDMODE) = the ability to use buildmode\n# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration.\n# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.\n# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.\n# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people.\n# +SOUND (or +SOUNDS) = allows you to upload and play sounds\n# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too)\n# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag\n\n# DO NOT EDIT THIS FILE DIRECTLY\n# IT IS AUTOMATICALLY GENERATED FROM THE SERVER DATABASE\n")
|
||||
|
||||
var/lastGroup = 1
|
||||
// Write out each rank to the rank file
|
||||
while(query_ranks.NextRow())
|
||||
var/rank_name = query_ranks.item[1]
|
||||
var/rank_byond = query_ranks.item[2]
|
||||
var/rank_group = text2num(query_ranks.item[3])
|
||||
if(lastGroup != rank_group)
|
||||
lastGroup = rank_group
|
||||
WRITE_FILE(ranksFile, " ")
|
||||
WRITE_FILE(ranksFile, "[rank_name]\t=\t[rank_byond]")
|
||||
|
||||
qdel(query_ranks)
|
||||
|
||||
var/datum/DBQuery/query_admin = SSdbcore.NewQuery("SELECT `web_admins`.`username` AS admin, `web_groups`.`name` AS adminrank, `web_groups`.`rank_group` AS rank_group FROM `web_admins`, `web_groups` WHERE `web_admins`.`rank` = `web_groups`.`rankid` ORDER BY `web_groups`.`rank_group` ASC, adminrank DESC")
|
||||
if(query_admin.Execute())
|
||||
fdel("config/admins.txt")
|
||||
var/adminsFile = file("config/admins.txt")
|
||||
WRITE_FILE(adminsFile, "###############################################################################################\n# Basically, ckey goes first. Rank goes after the '=' #\n# Case is not important for ckey. #\n# Case IS important for the rank. #\n# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. #\n# Ranks can be anything defined in admin_ranks.txt #\n# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn #\n# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. #\n###############################################################################################\n\n# DO NOT EDIT THIS FILE DIRECTLY\n# IT IS AUTOMATICALLY GENERATED FROM THE SERVER DATABASE\n")
|
||||
|
||||
var/lastGroup = 1
|
||||
// Write out each admin to the admins file
|
||||
while(query_admin.NextRow())
|
||||
var/name = query_admin.item[1]
|
||||
var/adminrank = query_admin.item[2]
|
||||
var/rank_group = text2num(query_admin.item[3])
|
||||
if(lastGroup != rank_group)
|
||||
lastGroup = rank_group
|
||||
WRITE_FILE(adminsFile, " ")
|
||||
WRITE_FILE(adminsFile, "[name]\t=\t[adminrank]")
|
||||
|
||||
qdel(query_admin)
|
||||
*/
|
||||
@@ -203,10 +203,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
return
|
||||
// There are no admins online, try deadmins
|
||||
var/found_deadmin = FALSE
|
||||
if(GLOB.deadmins.len > 0)
|
||||
for(var/deadmin_ckey in GLOB.deadmins)
|
||||
var/datum/admins/A = GLOB.deadmins[deadmin_ckey]
|
||||
if(!A.check_for_rights(R_BAN))
|
||||
if(GLOB.permissions.deadmins.len > 0)
|
||||
for(var/deadmin_ckey in GLOB.permissions.deadmins)
|
||||
var/datum/admins/A = GLOB.permissions.deadmins[deadmin_ckey]
|
||||
if(!check_rights_for(A.owner, R_BAN))
|
||||
continue
|
||||
var/client/client = GLOB.directory[deadmin_ckey]
|
||||
if(!client)
|
||||
@@ -231,7 +231,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/datum/admin_help/proc/check_owner() // Handles unclaimed tickets; returns TRUE if no longer unclaimed
|
||||
if(!handling_admin && state == AHELP_ACTIVE)
|
||||
var/msg = span_admin("<span class=\"prefix\">ADMIN LOG:</span> <span class=\"message linkify\"><font color='blue'>Ticket [TicketHref("#[id]")] Unclaimed!</font></span>")
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
if(check_rights_for(X,R_BAN))
|
||||
to_chat(X,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
@@ -248,7 +248,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
|
||||
if(world.time > last_bwoinking)
|
||||
last_bwoinking = world.time + 1 SECONDS
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
if(check_rights_for(X,R_BAN) && (X.prefs.toggles & SOUND_ADMINHELP)) // Can't use check_rights here since it's dependent on $usr
|
||||
SEND_SOUND(X, sound('sound/effects/adminhelp.ogg'))
|
||||
return FALSE
|
||||
@@ -304,7 +304,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
AddInteraction(msg)
|
||||
|
||||
//send this msg to all admins
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
if(X.prefs.toggles & SOUND_ADMINHELP)
|
||||
SEND_SOUND(X, sound('sound/effects/adminhelp.ogg'))
|
||||
window_flash(X, ignorepref = TRUE)
|
||||
@@ -945,7 +945,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
|
||||
/proc/get_admin_counts(requiredflags = R_BAN)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
for(var/client/X in GLOB.permissions.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
@@ -999,7 +999,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/proc/ircadminwho()
|
||||
var/list/message = list("Admins: ")
|
||||
var/list/admin_keys = list()
|
||||
for(var/adm in GLOB.admins)
|
||||
for(var/adm in GLOB.permissions.admins)
|
||||
var/client/C = adm
|
||||
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
msg = keywords_lookup(msg)
|
||||
if(check_rights(R_ADMIN,0))
|
||||
msg = span_adminsay("[span_prefix("ADMIN:")] <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: [span_message("[msg]")]")
|
||||
to_chat(GLOB.admins, msg, confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential=TRUE)
|
||||
else
|
||||
msg = span_adminsay("[span_prefix("OBSERVER:")] <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: [span_message("[msg]")]")
|
||||
to_chat(GLOB.admins, msg, confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, msg, confidential=TRUE)
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Asay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ GLOBAL_LIST_EMPTY(antag_token_users)
|
||||
return
|
||||
to_chat(src, span_userdanger("You will be notified if your antag token is used"))
|
||||
C.antag_token_timer = addtimer(CALLBACK(src, .proc/deny_antag_token_request), 45 SECONDS, TIMER_STOPPABLE)
|
||||
to_chat(GLOB.admins, span_adminnotice("<b><font color=orange>ANTAG TOKEN REQUEST:</font></b>[ADMIN_LOOKUPFLW(usr)] wants to use their antag token! (will auto-DENY in [DisplayTimeText(45 SECONDS)]). (<A HREF='?_src_=holder;[HrefToken(TRUE)];approve_antag_token=[REF(C)]'>APPROVE</A>)"))
|
||||
for(var/client/A in GLOB.admins)
|
||||
to_chat(GLOB.permissions.admins, span_adminnotice("<b><font color=orange>ANTAG TOKEN REQUEST:</font></b>[ADMIN_LOOKUPFLW(usr)] wants to use their antag token! (will auto-DENY in [DisplayTimeText(45 SECONDS)]). (<A HREF='?_src_=holder;[HrefToken(TRUE)];approve_antag_token=[REF(C)]'>APPROVE</A>)"))
|
||||
for(var/client/A in GLOB.permissions.admins)
|
||||
if(check_rights_for(A, R_ADMIN) && (A.prefs.toggles & SOUND_ADMINHELP)) // Can't use check_rights here since it's dependent on $usr
|
||||
SEND_SOUND(A, sound('sound/effects/adminhelp.ogg'))
|
||||
else
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
for(var/T in GLOB.clients)
|
||||
var/client/C = T
|
||||
if(C in GLOB.admins)
|
||||
if(C in GLOB.permissions.admins)
|
||||
if(C in clients_to_hear)
|
||||
to_chat(C, message_admin)
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/client/proc/find_admin_rank(client)
|
||||
var/client/C = client
|
||||
|
||||
switch(C.holder.rank.name)
|
||||
switch(C.holder.rank_name())
|
||||
|
||||
if("CouncilMember")
|
||||
return "\[Council\]"
|
||||
@@ -31,7 +31,7 @@
|
||||
return "\[Retmin-tainer\]"
|
||||
|
||||
else
|
||||
return "\[[C.holder.rank.name]\]"
|
||||
return "\[[C.holder.rank_name()]\]"
|
||||
|
||||
/client/verb/give_tip()
|
||||
set name = "Give Random Tip"
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
var/msg = ""
|
||||
|
||||
var/list/Lines = list()
|
||||
if(length(GLOB.admins))
|
||||
if(length(GLOB.permissions.admins))
|
||||
Lines += "<b>Admins:</b>"
|
||||
for(var/X in GLOB.admins)
|
||||
for(var/X in GLOB.permissions.admins)
|
||||
var/client/C = X
|
||||
if(C && C.holder && !C.holder.fakekey)
|
||||
Lines += "\t <font color='#FF0000'>[C.key]</font>[show_admin_info(C)] ([round(C.avgping, 1)]ms)"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
if(mentor_datum)
|
||||
mentor_datum.following = M
|
||||
|
||||
to_chat(GLOB.admins, span_mentor("[span_prefix("MENTOR:")] <EM>[key_name(usr)]</EM> is now following <EM>[key_name(M)]"), confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, span_mentor("[span_prefix("MENTOR:")] <EM>[key_name(usr)]</EM> is now following <EM>[key_name(M)]"), confidential=TRUE)
|
||||
to_chat(usr, span_info("Click the \"Stop Following\" button in the Mentor tab to stop following [key_name(M)]."), confidential=TRUE)
|
||||
log_mentor("[key_name(usr)] began following [key_name(M)]")
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
usr.reset_perspective()
|
||||
remove_verb(src, /client/proc/mentor_unfollow)
|
||||
if(mentor_datum)
|
||||
to_chat(GLOB.admins, span_mentor("[span_prefix("MENTOR:")] <EM>[key_name(usr)]</EM> is no longer following <EM>[key_name(mentor_datum.following)]"), confidential=TRUE)
|
||||
to_chat(GLOB.permissions.admins, span_mentor("[span_prefix("MENTOR:")] <EM>[key_name(usr)]</EM> is no longer following <EM>[key_name(mentor_datum.following)]"), confidential=TRUE)
|
||||
log_mentor("[key_name(usr)] stopped following [key_name(mentor_datum.following)]")
|
||||
|
||||
mentor_datum.following = null
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
var/mentor_msg = "<span class='mentornotice purple'><b>[admininfo]</b> <b>[key_name_mentor(src, 1, 0, 1, show_char)]</b>: [msg]</span>"
|
||||
log_mentor("[admininfo] [key_name_mentor(src, 0, 0, 0, 0)]: [msg]")
|
||||
|
||||
for(var/client/X in GLOB.mentors | GLOB.admins)
|
||||
for(var/client/X in GLOB.mentors | GLOB.permissions.admins)
|
||||
if(X.prefs.toggles & SOUND_ADMINHELP)
|
||||
send_mentor_sound(X)
|
||||
to_chat(X, mentor_msg, confidential=TRUE)
|
||||
|
||||
@@ -54,12 +54,12 @@
|
||||
//get message text, limit it's length.and clean/escape html
|
||||
if(!msg)
|
||||
if(is_mentor())
|
||||
to_chat((GLOB.admins - GLOB.deadmins) | GLOB.mentors, "<b><span class='purple mentor'>[key_name_mentor(src)] has started answering [key_name_mentor(C)]'s mentorhelp.</span></b>", confidential=TRUE)
|
||||
to_chat((GLOB.permissions.admins - GLOB.permissions.deadmins) | GLOB.mentors, "<b><span class='purple mentor'>[key_name_mentor(src)] has started answering [key_name_mentor(C)]'s mentorhelp.</span></b>", confidential=TRUE)
|
||||
msg = input(src,"Message:", "Private message") as text|null
|
||||
|
||||
if(!msg)
|
||||
if(is_mentor())
|
||||
to_chat((GLOB.admins - GLOB.deadmins) | GLOB.mentors, "<b><span class='purple mentor'>[key_name_mentor(src)] has decided not to answer [key_name_mentor(C)]'s mentorhelp.</span></b>", confidential=TRUE)
|
||||
to_chat((GLOB.permissions.admins - GLOB.permissions.deadmins) | GLOB.mentors, "<b><span class='purple mentor'>[key_name_mentor(src)] has decided not to answer [key_name_mentor(C)]'s mentorhelp.</span></b>", confidential=TRUE)
|
||||
return
|
||||
|
||||
// Neither party is a mentor, they shouldn't be PMing!
|
||||
@@ -112,7 +112,7 @@
|
||||
//we don't use message_Mentors here because the sender/receiver might get it too
|
||||
var/show_char_sender = !is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
|
||||
var/show_char_recip = C && !C.is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
|
||||
for(var/client/X in GLOB.mentors | (GLOB.admins - GLOB.deadmins))
|
||||
for(var/client/X in GLOB.mentors | (GLOB.permissions.admins - GLOB.permissions.deadmins))
|
||||
if(X.key != key && (!C || X.key != C.key)) //check client/X is an Mentor and isn't the sender or recipient
|
||||
if(discord_id)
|
||||
to_chat(X, "<B><font color='green mentor'>Mentor PM: [key_name_mentor(src, X, 0, 0, show_char_sender)]->[discord_mentor_link(whom, discord_id)]:</B> <span class='blueteamradio mentor'> [msg]</span>", confidential=TRUE) //inform X
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
else
|
||||
msg = "<b><font color ='#E236D8'><span class='prefix mentor'>MENTOR:</span> <EM>[key_name(src, 0, 0)]</EM>: <span class='message mentor'>[msg]</span></font></b>"
|
||||
|
||||
to_chat((GLOB.admins - GLOB.deadmins) | GLOB.mentors, msg, confidential=TRUE)
|
||||
to_chat((GLOB.permissions.admins - GLOB.permissions.deadmins) | GLOB.mentors, msg, confidential=TRUE)
|
||||
|
||||
/client/proc/get_mentor_say()
|
||||
var/msg = input(src, null, "msay \"text\"") as text|null
|
||||
|
||||
Reference in New Issue
Block a user