mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-12 07:35:31 +01:00
[MAJOR CHANGE] Admin rank datum (#17133)
* Admin ranks update * Permissions fix * One missing thing * Further rework to make database also fully work * Adds admin rank bitflag calculator to tools * ZA WARUDO --------- Co-authored-by: C.L. <killer65311@gmail.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#ifndef OVERRIDE_BAN_SYSTEM
|
||||
//Blocks an attempt to connect before even creating our client datum thing.
|
||||
/world/IsBanned(key,address,computer_id)
|
||||
if(ckey(key) in admin_datums)
|
||||
if(ckey(key) in GLOB.admin_datums)
|
||||
return ..()
|
||||
|
||||
//Guest Checking
|
||||
|
||||
@@ -7,7 +7,7 @@ var/global/floorIsLava = 0
|
||||
//log_adminwarn(msg) //log_and_message_admins is for this
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN|R_MOD|R_SERVER)))
|
||||
to_chat(C,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
html = msg,
|
||||
@@ -16,7 +16,7 @@ var/global/floorIsLava = 0
|
||||
/proc/msg_admin_attack(var/text) //Toggleable Attack Messages
|
||||
var/rendered = span_filter_attacklog(span_log_message(span_prefix("ATTACK:") + span_message("[text]")))
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN|R_MOD)))
|
||||
if(C.prefs?.read_preference(/datum/preference/toggle/show_attack_logs))
|
||||
var/msg = rendered
|
||||
to_chat(C,
|
||||
@@ -26,8 +26,16 @@ var/global/floorIsLava = 0
|
||||
|
||||
/proc/admin_notice(var/message, var/rights)
|
||||
for(var/mob/M in mob_list)
|
||||
if(check_rights(rights, 0, M))
|
||||
to_chat(M,message)
|
||||
var/C = M.client
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
if(!(istype(C, /client)))
|
||||
return
|
||||
|
||||
if(check_rights_for(C, rights))
|
||||
to_chat(C, message)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
||||
|
||||
@@ -49,7 +57,7 @@ var/global/floorIsLava = 0
|
||||
body += "<body>Options panel for" + span_bold("[M]")
|
||||
if(M.client)
|
||||
body += " played by " + span_bold("[M.client]")
|
||||
body += "\[<A href='byond://?src=\ref[src];[HrefToken()];editrights=show'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='byond://?src=\ref[src];[HrefToken()];editrights=show'>[M.client.holder ? M.client.holder.rank_names() : "Player"]</A>\]"
|
||||
|
||||
if(isnewplayer(M))
|
||||
body += span_bold(" Hasn't Entered Game")
|
||||
@@ -1353,7 +1361,7 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
if(istype(whom, /mob))
|
||||
M = whom
|
||||
C = M.client
|
||||
if(R_HOST & C.holder.rights)
|
||||
if(check_rights_for(C, R_HOST))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -1562,12 +1570,12 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
if(P.sender) // sent as a reply
|
||||
log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
else
|
||||
log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] has sent a fax message to [destination.department] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
|
||||
var/plaintext_title = P.sender ? "replied to [key_name(P.sender)]'s fax" : "sent a fax message to [destination.department]"
|
||||
@@ -1590,3 +1598,18 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
qdel(P)
|
||||
faxreply = null
|
||||
return
|
||||
|
||||
/datum/admins/proc/set_uplink(mob/living/carbon/human/H as mob)
|
||||
set category = "Debug.Events"
|
||||
set name = "Set Uplink"
|
||||
set desc = "Allows admins to set up an uplink on a character. This will be required for a character to use telecrystals."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(check_rights(R_ADMIN|R_DEBUG))
|
||||
traitors.spawn_uplink(H)
|
||||
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
|
||||
H.mind.accept_tcrystals = 1
|
||||
var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
|
||||
message_admins(msg)
|
||||
else
|
||||
to_chat(usr, "You do not have access to this command.")
|
||||
|
||||
+368
-136
@@ -1,166 +1,398 @@
|
||||
var/list/admin_ranks = list() //list of all ranks with associated rights
|
||||
GLOBAL_LIST_EMPTY(admin_ranks) //list of all admin_rank datums
|
||||
GLOBAL_PROTECT(admin_ranks)
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks()
|
||||
admin_ranks.Cut()
|
||||
GLOBAL_LIST_EMPTY(protected_ranks) //admin ranks loaded from txt
|
||||
GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
var/previous_rights = 0
|
||||
/datum/admin_rank
|
||||
var/name = "NoRank"
|
||||
var/rights = R_DEFAULT
|
||||
var/exclude_rights = NONE
|
||||
var/include_rights = NONE
|
||||
var/can_edit_rights = NONE
|
||||
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
/datum/admin_rank/New(init_name, init_rights, init_exclude_rights, init_edit_rights)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
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
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admin_ranks.txt")
|
||||
/datum/admin_rank/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
var/list/List = splittext(line,"+")
|
||||
if(!List.len) continue
|
||||
|
||||
var/rank = ckeyEx(List[1])
|
||||
switch(rank)
|
||||
if(null,"") continue
|
||||
if("Removed") continue //Reserved
|
||||
|
||||
var/rights = 0
|
||||
for(var/i=2, i<=List.len, i++)
|
||||
switch(ckey(List[i]))
|
||||
if("@","prev") rights |= previous_rights
|
||||
if("buildmode","build") rights |= R_BUILDMODE
|
||||
if("admin") rights |= R_ADMIN
|
||||
if("ban") rights |= R_BAN
|
||||
if("fun") rights |= R_FUN
|
||||
if("server") rights |= R_SERVER
|
||||
if("debug") rights |= R_DEBUG
|
||||
if("permissions","rights") rights |= R_PERMISSIONS
|
||||
if("possess") rights |= R_POSSESS
|
||||
if("stealth") rights |= R_STEALTH
|
||||
if("rejuv","rejuvinate") rights |= R_REJUVINATE
|
||||
if("varedit") rights |= R_VAREDIT
|
||||
if("everything","host","all") rights |= (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVINATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD| R_EVENT)
|
||||
if("sound","sounds") rights |= R_SOUNDS
|
||||
if("spawn","create") rights |= R_SPAWN
|
||||
if("mod") rights |= R_MOD
|
||||
if("event") rights |= R_EVENT
|
||||
|
||||
admin_ranks[rank] = rights
|
||||
previous_rights = rights
|
||||
// Adds/removes rights to this admin_rank
|
||||
/datum/admin_rank/proc/process_keyword(group, group_count, datum/admin_rank/previous_rank)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
var/list/keywords = splittext(group, " ")
|
||||
var/flag = 0
|
||||
for(var/k in keywords)
|
||||
switch(k)
|
||||
if("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")
|
||||
flag = R_PERMISSIONS
|
||||
if("POSSESS")
|
||||
flag = R_POSSESS
|
||||
if("STEALTH")
|
||||
flag = R_STEALTH
|
||||
if("REJUVINATE")
|
||||
flag = R_REJUVINATE
|
||||
if("VAREDIT")
|
||||
flag = R_VAREDIT
|
||||
if("EVERYTHING")
|
||||
flag = R_EVERYTHING
|
||||
if("SOUND")
|
||||
flag = R_SOUNDS
|
||||
if("SPAWN")
|
||||
flag = R_SPAWN
|
||||
if("MOD")
|
||||
flag = R_MOD
|
||||
if("EVENT")
|
||||
flag = R_EVENT
|
||||
if("@")
|
||||
if(previous_rank)
|
||||
switch(group_count)
|
||||
if(1)
|
||||
flag = previous_rank.include_rights
|
||||
if(2)
|
||||
flag = previous_rank.exclude_rights
|
||||
if(3)
|
||||
flag = previous_rank.can_edit_rights
|
||||
else
|
||||
continue
|
||||
switch(group_count)
|
||||
if(1)
|
||||
rights |= flag
|
||||
include_rights |= flag
|
||||
if(2)
|
||||
rights &= ~flag
|
||||
exclude_rights |= flag
|
||||
if(3)
|
||||
can_edit_rights |= flag
|
||||
|
||||
/// Loads admin ranks.
|
||||
/// Return a list containing the backup data if they were loaded from the database backup json
|
||||
/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()
|
||||
//load text from file and process each entry
|
||||
var/ranks_text = file2text("[global.config.directory]/admin_ranks.txt")
|
||||
var/datum/admin_rank/previous_rank
|
||||
var/regex/admin_ranks_regex = new(@"^Name\s*=\s*(.+?)\s*\n+Include\s*=\s*([\l @]*?)\s*\n+Exclude\s*=\s*([\l @]*?)\s*\n+Edit\s*=\s*([\l @]*?)\s*\n*$", "gm")
|
||||
while(admin_ranks_regex.Find(ranks_text))
|
||||
var/datum/admin_rank/R = new(admin_ranks_regex.group[1])
|
||||
if(!R)
|
||||
continue
|
||||
var/count = 1
|
||||
for(var/i in admin_ranks_regex.group - admin_ranks_regex.group[1])
|
||||
if(i)
|
||||
R.process_keyword(i, count, previous_rank)
|
||||
count++
|
||||
GLOB.admin_ranks += R
|
||||
GLOB.protected_ranks += R
|
||||
previous_rank = R
|
||||
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/db_query/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 = TRUE
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = 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/rank in admin_ranks)
|
||||
msg += "\t[rank] - [admin_ranks[rank]]\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
|
||||
|
||||
/hook/startup/proc/loadAdmins()
|
||||
load_admins()
|
||||
return 1
|
||||
/// Converts a rank name (such as "Coder+Moth") into a list of /datum/admin_rank
|
||||
/proc/ranks_from_rank_name(rank_name)
|
||||
var/list/rank_names = splittext(rank_name, "+")
|
||||
var/list/ranks = list()
|
||||
|
||||
/proc/load_admins()
|
||||
for (var/datum/admin_rank/rank as anything in GLOB.admin_ranks)
|
||||
if (rank.name in rank_names)
|
||||
rank_names -= rank.name
|
||||
ranks += rank
|
||||
|
||||
if (rank_names.len == 0)
|
||||
break
|
||||
|
||||
if (rank_names.len > 0)
|
||||
log_config("Admin rank names were invalid: [jointext(ranks, ", ")]")
|
||||
|
||||
return ranks
|
||||
|
||||
/// Takes a list of rank names and joins them with +
|
||||
/proc/join_admin_ranks(list/datum/admin_rank/ranks)
|
||||
var/list/names = list()
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
names += rank.name
|
||||
|
||||
return jointext(names, "+")
|
||||
|
||||
/// (Re)Loads the admin list.
|
||||
/// returns TRUE if database admins had to be loaded from the backup json
|
||||
/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 = TRUE
|
||||
//clear the datums references
|
||||
admin_datums.Cut()
|
||||
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/admins_text = file2text("[global.config.directory]/admins.txt")
|
||||
var/regex/admins_regex = new(@"^(?!#)(.+?)\s+=\s+(.+)", "gm")
|
||||
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
load_admin_ranks()
|
||||
while(admins_regex.Find(admins_text))
|
||||
var/admin_key = admins_regex.group[1]
|
||||
var/admin_rank = admins_regex.group[2]
|
||||
new /datum/admins(ranks_from_rank_name(admin_rank), ckey(admin_key), force_active = FALSE, protected = TRUE)
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admins.txt")
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !dbfail)
|
||||
var/datum/db_query/query_load_admins = SSdbcore.NewQuery("SELECT ckey, `rank`, feedback 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 = query_load_admins.item[2]
|
||||
var/admin_feedback = query_load_admins.item[3]
|
||||
var/skip
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
|
||||
//Split the line at every "-"
|
||||
var/list/List = splittext(line, "-")
|
||||
if(!List.len) continue
|
||||
|
||||
//ckey is before the first "-"
|
||||
var/ckey = ckey(List[1])
|
||||
if(!ckey) continue
|
||||
|
||||
//rank follows the first "-"
|
||||
var/rank = ""
|
||||
if(List.len >= 2)
|
||||
rank = ckeyEx(List[2])
|
||||
|
||||
//load permissions associated with this rank
|
||||
var/rights = admin_ranks[rank]
|
||||
|
||||
//create the admin datum and store it for later use
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(GLOB.directory[ckey])
|
||||
|
||||
else
|
||||
//The current admin system uses SQL
|
||||
|
||||
establish_db_connection()
|
||||
if(!SSdbcore.IsConnected())
|
||||
error("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
CONFIG_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admins()
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin")
|
||||
query.Execute()
|
||||
while(query.NextRow())
|
||||
var/ckey = query.item[1]
|
||||
var/rank = query.item[2]
|
||||
if(rank == "Removed") continue //This person was de-adminned. They are only in the admin list for archive purposes.
|
||||
|
||||
var/rights = query.item[4]
|
||||
if(istext(rights)) rights = text2num(rights)
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(GLOB.directory[ckey])
|
||||
qdel(query)
|
||||
if(!admin_datums)
|
||||
error("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
log_misc("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
CONFIG_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admins()
|
||||
return
|
||||
var/list/admin_ranks = ranks_from_rank_name(admin_rank)
|
||||
|
||||
if(admin_ranks.len == 0)
|
||||
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)
|
||||
var/datum/admins/admin_holder = new(admin_ranks, admin_ckey)
|
||||
admin_holder.cached_feedback_link = admin_feedback || NO_FEEDBACK_LINK
|
||||
qdel(query_load_admins)
|
||||
if (!no_update)
|
||||
save_admin_backup()
|
||||
sync_admins_with_db()
|
||||
//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/backup_admin_ckey in backup_file_json["admins"])
|
||||
var/skip
|
||||
for(var/admin_ckey in GLOB.admin_datums + GLOB.deadmins)
|
||||
if(ckey(admin_ckey) == ckey("[backup_admin_ckey]")) //this admin was already loaded from txt override
|
||||
skip = TRUE
|
||||
break
|
||||
if(skip)
|
||||
continue
|
||||
new /datum/admins(ranks_from_rank_name(backup_file_json["admins"]["[backup_admin_ckey]"]), ckey("[backup_admin_ckey]"))
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in admin_datums)
|
||||
var/rank
|
||||
var/datum/admins/D = admin_datums[ckey]
|
||||
if(D) rank = D.rank
|
||||
msg += "\t[ckey] - [rank]\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
msg += "\t[ckey] - [D.rank_names()]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
return dbfail
|
||||
|
||||
|
||||
#ifdef TESTING
|
||||
/client/verb/changerank(newrank in admin_ranks)
|
||||
if(holder)
|
||||
holder.rank = newrank
|
||||
holder.rights = admin_ranks[newrank]
|
||||
else
|
||||
holder = new /datum/admins(newrank,admin_ranks[newrank],ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
/proc/sync_ranks_with_db()
|
||||
set waitfor = FALSE
|
||||
|
||||
/client/verb/changerights(newrights as num)
|
||||
if(holder)
|
||||
holder.rights = newrights
|
||||
else
|
||||
holder = new /datum/admins("testing",newrights,ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
#endif
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R as anything 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)
|
||||
update_everything_flag_in_db()
|
||||
|
||||
|
||||
/proc/update_everything_flag_in_db()
|
||||
for(var/datum/admin_rank/R as anything 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/db_query/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/db_query/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)
|
||||
|
||||
|
||||
/proc/sync_admins_with_db()
|
||||
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) || !SSdbcore.IsConnected()) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
sync_ranks_with_db()
|
||||
var/list/sql_admins = list()
|
||||
for(var/holder_ckey in GLOB.protected_admins)
|
||||
var/datum/admins/holder = GLOB.protected_admins[holder_ckey]
|
||||
sql_admins += list(list("ckey" = holder.target, "rank" = holder.rank_names()))
|
||||
SSdbcore.MassInsert(format_table_name("admin"), sql_admins, duplicate_key = TRUE)
|
||||
var/datum/db_query/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] AS p INNER JOIN [format_table_name("admin")] AS a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
|
||||
query_admin_rank_update.Execute()
|
||||
qdel(query_admin_rank_update)
|
||||
|
||||
/proc/save_admin_backup()
|
||||
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
|
||||
|
||||
//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 as anything 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/admin_ckey in GLOB.admin_datums + GLOB.deadmins)
|
||||
var/datum/admins/admin = GLOB.admin_datums[admin_ckey]
|
||||
|
||||
if(!admin)
|
||||
admin = GLOB.deadmins[admin_ckey]
|
||||
if (!admin)
|
||||
continue
|
||||
|
||||
file_data["admins"][admin_ckey] = admin.rank_names()
|
||||
|
||||
//admin.backup_connections()
|
||||
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data, JSON_PRETTY_PRINT))
|
||||
|
||||
@@ -55,7 +55,7 @@ var/datum/admin_secrets/admin_secrets = new()
|
||||
return name
|
||||
|
||||
/datum/admin_secret_item/proc/can_view(var/mob/user)
|
||||
return check_rights(permissions, 0, user)
|
||||
return check_rights_for(user.client, permissions)
|
||||
|
||||
/datum/admin_secret_item/proc/can_execute(var/mob/user)
|
||||
if(can_view(user))
|
||||
|
||||
@@ -3,7 +3,7 @@ var/list/admin_verbs_default = list(
|
||||
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags,
|
||||
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels,
|
||||
/client/proc/player_panel,
|
||||
/client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/deadmin, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/hide_verbs, //hides all our adminverbs,
|
||||
/client/proc/hide_most_verbs, //hides all our hideable adminverbs,
|
||||
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify,
|
||||
@@ -268,7 +268,7 @@ var/list/admin_verbs_rejuv = list(
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
var/list/admin_verbs_hideable = list(
|
||||
/client/proc/deadmin_self,
|
||||
/client/proc/deadmin,
|
||||
// /client/proc/deadchat,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
|
||||
@@ -3,7 +3,7 @@ var/list/admin_verbs_default = list(
|
||||
// /datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Remove,
|
||||
// /client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Remove,
|
||||
// /client/proc/player_panel, //VOREStation Remove,
|
||||
/client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/deadmin, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/cmd_admin_say, //VOREStation Add,
|
||||
/client/proc/cmd_mod_say, //VOREStation Add,
|
||||
/client/proc/cmd_event_say, //VOREStation Add,
|
||||
@@ -311,7 +311,7 @@ var/list/admin_verbs_rejuv = list(
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
var/list/admin_verbs_hideable = list(
|
||||
/client/proc/deadmin_self,
|
||||
/client/proc/deadmin,
|
||||
// /client/proc/deadchat,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
@@ -580,24 +580,25 @@ var/list/admin_verbs_event_manager = list(
|
||||
|
||||
/client/proc/add_admin_verbs()
|
||||
if(holder)
|
||||
var/rights = holder.rank_flags()
|
||||
add_verb(src, admin_verbs_default)
|
||||
if(holder.rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
|
||||
if(holder.rights & R_ADMIN) add_verb(src, admin_verbs_admin)
|
||||
if(holder.rights & R_BAN) add_verb(src, admin_verbs_ban)
|
||||
if(holder.rights & R_FUN) add_verb(src, admin_verbs_fun)
|
||||
if(holder.rights & R_SERVER) add_verb(src, admin_verbs_server)
|
||||
if(holder.rights & R_DEBUG)
|
||||
if(rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
|
||||
if(rights & R_ADMIN) add_verb(src, admin_verbs_admin)
|
||||
if(rights & R_BAN) add_verb(src, admin_verbs_ban)
|
||||
if(rights & R_FUN) add_verb(src, admin_verbs_fun)
|
||||
if(rights & R_SERVER) add_verb(src, admin_verbs_server)
|
||||
if(rights & R_DEBUG)
|
||||
add_verb(src, admin_verbs_debug)
|
||||
if(CONFIG_GET(flag/debugparanoid) && !(holder.rights & R_ADMIN))
|
||||
if(CONFIG_GET(flag/debugparanoid) && !(rights & R_ADMIN))
|
||||
remove_verb(src, admin_verbs_paranoid_debug) //Right now it's just callproc but we can easily add others later on.
|
||||
if(holder.rights & R_POSSESS) add_verb(src, admin_verbs_possess)
|
||||
if(holder.rights & R_PERMISSIONS) add_verb(src, admin_verbs_permissions)
|
||||
if(holder.rights & R_STEALTH) add_verb(src, /client/proc/stealth)
|
||||
if(holder.rights & R_REJUVINATE) add_verb(src, admin_verbs_rejuv)
|
||||
if(holder.rights & R_SOUNDS) add_verb(src, admin_verbs_sounds)
|
||||
if(holder.rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
|
||||
if(holder.rights & R_MOD) add_verb(src, admin_verbs_mod)
|
||||
if(holder.rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
|
||||
if(rights & R_POSSESS) add_verb(src, admin_verbs_possess)
|
||||
if(rights & R_PERMISSIONS) add_verb(src, admin_verbs_permissions)
|
||||
if(rights & R_STEALTH) add_verb(src, /client/proc/stealth)
|
||||
if(rights & R_REJUVINATE) add_verb(src, admin_verbs_rejuv)
|
||||
if(rights & R_SOUNDS) add_verb(src, admin_verbs_sounds)
|
||||
if(rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
|
||||
if(rights & R_MOD) add_verb(src, admin_verbs_mod)
|
||||
if(rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
|
||||
|
||||
/client/proc/remove_admin_verbs()
|
||||
remove_verb(src, list(
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
if(!warned_ckey || !istext(warned_ckey)) return
|
||||
if(warned_ckey in admin_datums)
|
||||
if(warned_ckey in GLOB.admin_datums)
|
||||
to_chat(usr, span_warning("Error: warn(): You can't warn admins."))
|
||||
return
|
||||
|
||||
@@ -333,36 +333,22 @@
|
||||
log_admin("[key_name(usr)] used 'kill air'.")
|
||||
message_admins(span_blue("[key_name_admin(usr)] used 'kill air'."), 1)
|
||||
|
||||
/client/proc/readmin_self()
|
||||
set name = "Re-Admin self"
|
||||
/client/proc/deadmin()
|
||||
set name = "DeAdmin"
|
||||
set category = "Admin.Misc"
|
||||
set desc = "Shed your admin powers."
|
||||
|
||||
if(deadmin_holder)
|
||||
deadmin_holder.reassociate()
|
||||
log_admin("[src] re-admined themself.")
|
||||
message_admins("[src] re-admined themself.", 1)
|
||||
to_chat(src, span_filter_system(span_interface("You now have the keys to control the planet, or at least a small space station")))
|
||||
remove_verb(src, /client/proc/readmin_self)
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.addVisibility(our_mob, src)
|
||||
|
||||
/client/proc/deadmin_self()
|
||||
set name = "De-admin self"
|
||||
set category = "Admin.Misc"
|
||||
|
||||
if(holder)
|
||||
if(tgui_alert(usr, "Confirm self-deadmin for the round? You can't re-admin yourself without someone promoting you.","Deadmin",list("Yes","No")) == "Yes")
|
||||
log_admin("[src] deadmined themself.")
|
||||
message_admins("[src] deadmined themself.", 1)
|
||||
deadmin()
|
||||
to_chat(src, span_filter_system(span_interface("You are now a normal player.")))
|
||||
add_verb(src, /client/proc/readmin_self)
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.removeVisibility(our_mob, src)
|
||||
src.holder.deactivate()
|
||||
to_chat(src, span_interface("You are now a normal player."))
|
||||
log_admin("[key_name(src)] deadminned themselves.")
|
||||
message_admins("[key_name_admin(src)] deadminned themselves.")
|
||||
//BLACKBOX_LOG_ADMIN_VERB("Deadmin")
|
||||
feedback_add_details("admin_verb","DAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.removeVisibility(our_mob, src)
|
||||
|
||||
/client/proc/toggle_log_hrefs()
|
||||
set name = "Toggle href logging"
|
||||
set category = "Server.Config"
|
||||
@@ -582,3 +568,144 @@
|
||||
return
|
||||
SSmotiontracker.hide_all = !SSmotiontracker.hide_all
|
||||
log_admin("[key_name(usr)] changed the motion echo visibility to [SSmotiontracker.hide_all ? "hidden" : "visible"].")
|
||||
|
||||
/client/proc/adminorbit()
|
||||
set category = "Fun.Event Kit"
|
||||
set name = "Orbit Things"
|
||||
set desc = "Makes something orbit around something else."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/center
|
||||
var/atom/movable/orbiter
|
||||
var/input
|
||||
|
||||
if(holder.marked_datum)
|
||||
input = tgui_alert(usr, "You have \n[holder.marked_datum] marked, should this be the center of the orbit, or the orbiter?", "Orbit", list("Center", "Orbiter", "Neither"))
|
||||
switch(input)
|
||||
if("Center")
|
||||
center = holder.marked_datum
|
||||
if("Orbiter")
|
||||
orbiter = holder.marked_datum
|
||||
var/list/possible_things = list()
|
||||
for(var/T as mob in view(view)) //Let's do mobs before objects
|
||||
if(ismob(T))
|
||||
possible_things |= T
|
||||
for(var/T as obj in view(view))
|
||||
if(isobj(T))
|
||||
possible_things |= T
|
||||
if(!center)
|
||||
center = tgui_input_list(src, "What should act as the center of the orbit?", "Center", possible_things)
|
||||
possible_things -= center
|
||||
if(!orbiter)
|
||||
orbiter = tgui_input_list(src, "What should act as the orbiter of the orbit?", "Orbiter", possible_things)
|
||||
if(!center || !orbiter)
|
||||
to_chat(usr, span_warning("A center of orbit and an orbiter must be configured. You can also do this by marking a target."))
|
||||
return
|
||||
if(center == orbiter)
|
||||
to_chat(usr, span_warning("The center of the orbit cannot also be the orbiter."))
|
||||
return
|
||||
if(isturf(orbiter))
|
||||
to_chat(usr, span_warning("The orbiter cannot be a turf. It can only be used as a center."))
|
||||
return
|
||||
var/distance = tgui_input_number(usr, "How large will their orbit radius be? (In pixels. 32 is 'near around a character)", "Orbit Radius", 32)
|
||||
var/speed = tgui_input_number(usr, "How fast will they orbit (negative numbers spin clockwise)", "Orbit Speed", 20)
|
||||
var/segments = tgui_input_number(usr, "How many segments will they have in their orbit? (3 is a triangle, 36 is a circle, etc)", "Orbit Segments", 36)
|
||||
var/clock = FALSE
|
||||
if(!distance)
|
||||
distance = 32
|
||||
if(!speed)
|
||||
speed = 20
|
||||
else if (speed < 0)
|
||||
clock = TRUE
|
||||
speed *= -1
|
||||
if(!segments)
|
||||
segments = 36
|
||||
if(tgui_alert(usr, "\The [orbiter] will orbit around [center]. Is this okay?", "Confirm Orbit", list("Yes", "No")) == "Yes")
|
||||
orbiter.orbit(center, distance, clock, speed, segments)
|
||||
|
||||
/client/proc/removetickets()
|
||||
set name = "Security Tickets"
|
||||
set category = "Admin.Investigate"
|
||||
set desc = "Allows one to remove tickets from the global list."
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(security_printer_tickets.len >= 1)
|
||||
var/input = tgui_input_list(usr, "Which message?", "Security Tickets", security_printer_tickets)
|
||||
if(!input)
|
||||
return
|
||||
if(tgui_alert(usr, "Do you want to remove the following message from the global list? \"[input]\"", "Remove Ticket", list("Yes", "No")) == "Yes")
|
||||
security_printer_tickets -= input
|
||||
log_and_message_admins("removed a security ticket from the global list: \"[input]\"", usr)
|
||||
|
||||
else
|
||||
tgui_alert_async(usr, "The ticket list is empty.","Empty")
|
||||
|
||||
/client/proc/delbook()
|
||||
set name = "Delete Book"
|
||||
set desc = "Permamently deletes a book from the database."
|
||||
set category = "Admin.Game"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
var/obj/machinery/librarycomp/our_comp
|
||||
for(var/obj/machinery/librarycomp/l in world)
|
||||
if(istype(l, /obj/machinery/librarycomp))
|
||||
our_comp = l
|
||||
break
|
||||
|
||||
if(!our_comp)
|
||||
to_chat(usr, span_warning("Unable to locate a library computer to use for book deleting."))
|
||||
return
|
||||
|
||||
var/dat = "<HEAD><TITLE>Book Inventory Management</TITLE></HEAD><BODY>\n"
|
||||
dat += "<h3>ADMINISTRATIVE MANAGEMENT</h3>"
|
||||
establish_db_connection()
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.")
|
||||
else
|
||||
dat += {"<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];orderbyid=1'>(Order book by SS<sup>13</sup>BN)</A><BR><BR>
|
||||
<table>
|
||||
<tr><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=author>AUTHOR</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=title>TITLE</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=category>CATEGORY</A></td><td></td></tr>"}
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category FROM library ORDER BY [our_comp.sortby]")
|
||||
query.Execute()
|
||||
|
||||
var/show_admin_options = check_rights(R_ADMIN, show_msg = FALSE)
|
||||
|
||||
while(query.NextRow())
|
||||
var/id = query.item[1]
|
||||
var/author = query.item[2]
|
||||
var/title = query.item[3]
|
||||
var/category = query.item[4]
|
||||
dat += "<tr><td>[author]</td><td>[title]</td><td>[category]</td><td>"
|
||||
if(show_admin_options) // This isn't the only check, since you can just href-spoof press this button. Just to tidy things up.
|
||||
dat += "<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];delid=[id]'>\[Del\]</A>"
|
||||
dat += "</td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
qdel(query)
|
||||
usr << browse("<html>[dat]</html>", "window=library")
|
||||
onclose(usr, "library")
|
||||
|
||||
/client/proc/toggle_spawning_with_recolour()
|
||||
set name = "Toggle Simple/Robot recolour verb"
|
||||
set desc = "Makes it so new robots/simple_mobs spawn with a verb to recolour themselves for this round. You must set them separately."
|
||||
set category = "Server.Game"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_EVENT|R_FUN))
|
||||
return
|
||||
|
||||
var/which = tgui_alert(usr, "Which do you want to toggle?", "Choose Recolour Toggle", list("Robot", "Simple Mob"))
|
||||
switch(which)
|
||||
if("Robot")
|
||||
CONFIG_SET(flag/allow_robot_recolor, !CONFIG_GET(flag/allow_robot_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_robot_recolor) ? "enabled" : "disabled"] newly spawned cyborgs to spawn with the recolour verb")
|
||||
if("Simple Mob")
|
||||
CONFIG_SET(flag/allow_simple_mob_recolor, !CONFIG_GET(flag/allow_simple_mob_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_simple_mob_recolor) ? "enabled" : "disabled"] newly spawned simple mobs to spawn with the recolour verb")
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/client/proc/adminorbit()
|
||||
set category = "Fun.Event Kit"
|
||||
set name = "Orbit Things"
|
||||
set desc = "Makes something orbit around something else."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/center
|
||||
var/atom/movable/orbiter
|
||||
var/input
|
||||
|
||||
if(holder.marked_datum)
|
||||
input = tgui_alert(usr, "You have \n[holder.marked_datum] marked, should this be the center of the orbit, or the orbiter?", "Orbit", list("Center", "Orbiter", "Neither"))
|
||||
switch(input)
|
||||
if("Center")
|
||||
center = holder.marked_datum
|
||||
if("Orbiter")
|
||||
orbiter = holder.marked_datum
|
||||
var/list/possible_things = list()
|
||||
for(var/T as mob in view(view)) //Let's do mobs before objects
|
||||
if(ismob(T))
|
||||
possible_things |= T
|
||||
for(var/T as obj in view(view))
|
||||
if(isobj(T))
|
||||
possible_things |= T
|
||||
if(!center)
|
||||
center = tgui_input_list(src, "What should act as the center of the orbit?", "Center", possible_things)
|
||||
possible_things -= center
|
||||
if(!orbiter)
|
||||
orbiter = tgui_input_list(src, "What should act as the orbiter of the orbit?", "Orbiter", possible_things)
|
||||
if(!center || !orbiter)
|
||||
to_chat(usr, span_warning("A center of orbit and an orbiter must be configured. You can also do this by marking a target."))
|
||||
return
|
||||
if(center == orbiter)
|
||||
to_chat(usr, span_warning("The center of the orbit cannot also be the orbiter."))
|
||||
return
|
||||
if(isturf(orbiter))
|
||||
to_chat(usr, span_warning("The orbiter cannot be a turf. It can only be used as a center."))
|
||||
return
|
||||
var/distance = tgui_input_number(usr, "How large will their orbit radius be? (In pixels. 32 is 'near around a character)", "Orbit Radius", 32)
|
||||
var/speed = tgui_input_number(usr, "How fast will they orbit (negative numbers spin clockwise)", "Orbit Speed", 20)
|
||||
var/segments = tgui_input_number(usr, "How many segments will they have in their orbit? (3 is a triangle, 36 is a circle, etc)", "Orbit Segments", 36)
|
||||
var/clock = FALSE
|
||||
if(!distance)
|
||||
distance = 32
|
||||
if(!speed)
|
||||
speed = 20
|
||||
else if (speed < 0)
|
||||
clock = TRUE
|
||||
speed *= -1
|
||||
if(!segments)
|
||||
segments = 36
|
||||
if(tgui_alert(usr, "\The [orbiter] will orbit around [center]. Is this okay?", "Confirm Orbit", list("Yes", "No")) == "Yes")
|
||||
orbiter.orbit(center, distance, clock, speed, segments)
|
||||
|
||||
/client/proc/removetickets()
|
||||
set name = "Security Tickets"
|
||||
set category = "Admin.Investigate"
|
||||
set desc = "Allows one to remove tickets from the global list."
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(security_printer_tickets.len >= 1)
|
||||
var/input = tgui_input_list(usr, "Which message?", "Security Tickets", security_printer_tickets)
|
||||
if(!input)
|
||||
return
|
||||
if(tgui_alert(usr, "Do you want to remove the following message from the global list? \"[input]\"", "Remove Ticket", list("Yes", "No")) == "Yes")
|
||||
security_printer_tickets -= input
|
||||
log_and_message_admins("removed a security ticket from the global list: \"[input]\"", usr)
|
||||
|
||||
else
|
||||
tgui_alert_async(usr, "The ticket list is empty.","Empty")
|
||||
|
||||
/client/proc/delbook()
|
||||
set name = "Delete Book"
|
||||
set desc = "Permamently deletes a book from the database."
|
||||
set category = "Admin.Game"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
var/obj/machinery/librarycomp/our_comp
|
||||
for(var/obj/machinery/librarycomp/l in world)
|
||||
if(istype(l, /obj/machinery/librarycomp))
|
||||
our_comp = l
|
||||
break
|
||||
|
||||
if(!our_comp)
|
||||
to_chat(usr, span_warning("Unable to locate a library computer to use for book deleting."))
|
||||
return
|
||||
|
||||
var/dat = "<HEAD><TITLE>Book Inventory Management</TITLE></HEAD><BODY>\n"
|
||||
dat += "<h3>ADMINISTRATIVE MANAGEMENT</h3>"
|
||||
establish_db_connection()
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.")
|
||||
else
|
||||
dat += {"<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];orderbyid=1'>(Order book by SS<sup>13</sup>BN)</A><BR><BR>
|
||||
<table>
|
||||
<tr><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=author>AUTHOR</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=title>TITLE</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=category>CATEGORY</A></td><td></td></tr>"}
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category FROM library ORDER BY [our_comp.sortby]")
|
||||
query.Execute()
|
||||
|
||||
var/show_admin_options = check_rights(R_ADMIN, show_msg = FALSE)
|
||||
|
||||
while(query.NextRow())
|
||||
var/id = query.item[1]
|
||||
var/author = query.item[2]
|
||||
var/title = query.item[3]
|
||||
var/category = query.item[4]
|
||||
dat += "<tr><td>[author]</td><td>[title]</td><td>[category]</td><td>"
|
||||
if(show_admin_options) // This isn't the only check, since you can just href-spoof press this button. Just to tidy things up.
|
||||
dat += "<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];delid=[id]'>\[Del\]</A>"
|
||||
dat += "</td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
qdel(query)
|
||||
usr << browse("<html>[dat]</html>", "window=library")
|
||||
onclose(usr, "library")
|
||||
|
||||
/client/proc/toggle_spawning_with_recolour()
|
||||
set name = "Toggle Simple/Robot recolour verb"
|
||||
set desc = "Makes it so new robots/simple_mobs spawn with a verb to recolour themselves for this round. You must set them separately."
|
||||
set category = "Server.Game"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_EVENT|R_FUN))
|
||||
return
|
||||
|
||||
var/which = tgui_alert(usr, "Which do you want to toggle?", "Choose Recolour Toggle", list("Robot", "Simple Mob"))
|
||||
switch(which)
|
||||
if("Robot")
|
||||
CONFIG_SET(flag/allow_robot_recolor, !CONFIG_GET(flag/allow_robot_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_robot_recolor) ? "enabled" : "disabled"] newly spawned cyborgs to spawn with the recolour verb")
|
||||
if("Simple Mob")
|
||||
CONFIG_SET(flag/allow_simple_mob_recolor, !CONFIG_GET(flag/allow_simple_mob_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_simple_mob_recolor) ? "enabled" : "disabled"] newly spawned simple mobs to spawn with the recolour verb")
|
||||
@@ -1,14 +0,0 @@
|
||||
/datum/admins/proc/set_uplink(mob/living/carbon/human/H as mob)
|
||||
set category = "Debug.Events"
|
||||
set name = "Set Uplink"
|
||||
set desc = "Allows admins to set up an uplink on a character. This will be required for a character to use telecrystals."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(check_rights(R_ADMIN|R_DEBUG))
|
||||
traitors.spawn_uplink(H)
|
||||
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
|
||||
H.mind.accept_tcrystals = 1
|
||||
var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
|
||||
message_admins(msg)
|
||||
else
|
||||
to_chat(usr, "You do not have access to this command.")
|
||||
+205
-78
@@ -1,13 +1,18 @@
|
||||
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)
|
||||
|
||||
var/list/admin_datums = list()
|
||||
|
||||
/datum/admins
|
||||
var/rank = "Temporary Admin"
|
||||
var/client/owner = null
|
||||
var/rights = 0
|
||||
var/fakekey = null
|
||||
var/list/datum/admin_rank/ranks
|
||||
|
||||
var/target
|
||||
var/name = "nobody's admin datum (no rank)" //Makes for better runtimes
|
||||
var/client/owner = null
|
||||
var/fakekey = null
|
||||
|
||||
var/datum/marked_datum
|
||||
|
||||
@@ -18,49 +23,194 @@ var/list/admin_datums = list()
|
||||
|
||||
var/href_token
|
||||
|
||||
/// Link from the database pointing to the admin's feedback forum
|
||||
var/cached_feedback_link
|
||||
|
||||
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
|
||||
if(!ckey)
|
||||
error("Admin datum created without a ckey argument. Datum has been deleted")
|
||||
qdel(src)
|
||||
var/deadmined
|
||||
|
||||
var/given_profiling = FALSE
|
||||
|
||||
|
||||
/datum/admins/New(list/datum/admin_rank/ranks, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
if (!target) //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
|
||||
if(!ckey)
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created without a ckey")
|
||||
if(!istype(ranks))
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created with invalid ranks: [ranks] ([json_encode(ranks)])")
|
||||
target = ckey
|
||||
name = "[ckey]'s admin datum ([join_admin_ranks(ranks)])"
|
||||
src.ranks = ranks
|
||||
admincaster_signature = "[using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
|
||||
href_token = GenerateToken()
|
||||
rank = initial_rank
|
||||
rights = initial_rights
|
||||
admin_datums[ckey] = src
|
||||
if(rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
if(protected)
|
||||
GLOB.protected_admins[target] = src
|
||||
activate()
|
||||
|
||||
/datum/admins/proc/associate(client/C)
|
||||
if(istype(C))
|
||||
owner = C
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs() //TODO
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
GLOB.admins |= C
|
||||
/datum/admins/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admins/proc/activate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins -= target
|
||||
GLOB.admin_datums[target] = src
|
||||
deadmined = FALSE
|
||||
//plane_debug = new(src)
|
||||
if (GLOB.directory[target])
|
||||
associate(GLOB.directory[target]) //find the client for a ckey if they are connected and associate them with us
|
||||
|
||||
/datum/admins/proc/deactivate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins[target] = src
|
||||
GLOB.admin_datums -= target
|
||||
//QDEL_NULL(plane_debug)
|
||||
deadmined = TRUE
|
||||
|
||||
var/client/client = owner || GLOB.directory[target]
|
||||
|
||||
if (!isnull(client))
|
||||
disassociate()
|
||||
add_verb(client, /client/proc/readmin)
|
||||
//client.disable_combo_hud()
|
||||
//client.update_special_keybinds()
|
||||
|
||||
/datum/admins/proc/associate(client/client)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
|
||||
if(!istype(client))
|
||||
return
|
||||
|
||||
if(client?.ckey != target)
|
||||
var/msg = " has attempted to associate with [target]'s admin datum"
|
||||
message_admins("[key_name_admin(client)][msg]")
|
||||
log_admin("[key_name(client)][msg]")
|
||||
return
|
||||
|
||||
if (deadmined)
|
||||
activate()
|
||||
|
||||
owner = client
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs()
|
||||
remove_verb(owner, /client/proc/readmin)
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
//owner.update_special_keybinds()
|
||||
GLOB.admins |= client
|
||||
|
||||
try_give_profiling()
|
||||
|
||||
/datum/admins/proc/disassociate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
if(owner)
|
||||
GLOB.admins -= owner
|
||||
owner.remove_admin_verbs()
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
owner.deadmin_holder = owner.holder
|
||||
// owner.init_verbs() //re-initialize the verb list
|
||||
owner.holder = null
|
||||
owner = null
|
||||
|
||||
/datum/admins/proc/reassociate()
|
||||
if(owner)
|
||||
GLOB.admins += owner
|
||||
owner.holder = src
|
||||
owner.deadmin_holder = null
|
||||
owner.add_admin_verbs()
|
||||
/// Returns the feedback forum thread for the admin holder's owner, as according to DB.
|
||||
/datum/admins/proc/feedback_link()
|
||||
// This intentionally does not follow the 10-second maximum TTL rule,
|
||||
// as this can be reloaded through the Reload-Admins verb.
|
||||
if (cached_feedback_link == NO_FEEDBACK_LINK)
|
||||
return null
|
||||
|
||||
if (!isnull(cached_feedback_link))
|
||||
return cached_feedback_link
|
||||
|
||||
if (!SSdbcore.IsConnected())
|
||||
return FALSE
|
||||
|
||||
var/datum/db_query/feedback_query = SSdbcore.NewQuery("SELECT feedback FROM [format_table_name("admin")] WHERE ckey = '[owner.ckey]'")
|
||||
|
||||
if(!feedback_query.Execute())
|
||||
log_sql("Error retrieving feedback link for [src]")
|
||||
qdel(feedback_query)
|
||||
return FALSE
|
||||
|
||||
if(!feedback_query.NextRow())
|
||||
qdel(feedback_query)
|
||||
return FALSE // no feedback link exists
|
||||
|
||||
cached_feedback_link = feedback_query.item[1] || NO_FEEDBACK_LINK
|
||||
qdel(feedback_query)
|
||||
|
||||
if (cached_feedback_link == NO_FEEDBACK_LINK) // Because we don't want to send fake clickable links.
|
||||
return null
|
||||
|
||||
return cached_feedback_link
|
||||
|
||||
/datum/admins/proc/check_for_rights(rights_required)
|
||||
if(rights_required && !(rights_required & rank_flags()))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other)
|
||||
if(!other)
|
||||
return TRUE //they have no rights
|
||||
if(rank_flags() == R_EVERYTHING)
|
||||
return TRUE //we have all the rights
|
||||
if(src == other)
|
||||
return TRUE //you always have more rights than yourself
|
||||
if(rank_flags() != other.rank_flags())
|
||||
if( (rank_flags() & other.rank_flags()) == other.rank_flags() )
|
||||
return TRUE //we have all the rights they have and more
|
||||
return FALSE
|
||||
|
||||
/// Get the rank name of the admin
|
||||
/datum/admins/proc/rank_names()
|
||||
return join_admin_ranks(ranks)
|
||||
|
||||
/// Get the rank flags of the admin
|
||||
/datum/admins/proc/rank_flags()
|
||||
var/combined_flags = NONE
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
combined_flags |= rank.rights
|
||||
|
||||
return combined_flags
|
||||
|
||||
/// Get the permissions this admin is allowed to edit on other ranks
|
||||
/datum/admins/proc/can_edit_rights_flags()
|
||||
var/combined_flags = NONE
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
combined_flags |= rank.can_edit_rights
|
||||
|
||||
return combined_flags
|
||||
|
||||
/datum/admins/proc/try_give_profiling()
|
||||
if (CONFIG_GET(flag/forbid_admin_profiling))
|
||||
return
|
||||
|
||||
if (given_profiling)
|
||||
return
|
||||
|
||||
if (!(rank_flags() & R_DEBUG))
|
||||
return
|
||||
|
||||
given_profiling = TRUE
|
||||
world.SetConfig("APP/admin", owner.ckey, "role=admin")
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, rights) || var_name == NAMEOF(src, owner) || var_name == NAMEOF(src, rank))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//TODO: Proccall guard, when all try/catch are removed and WrapAdminProccall is ported.
|
||||
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)
|
||||
@@ -69,45 +219,36 @@ if it doesn't return 1 and show_msg=1 it will prints a message explaining why th
|
||||
generally it would be used like so:
|
||||
|
||||
/proc/admin_proc()
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
to_world("you have enough rights!")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
to_chat(world, "you have enough rights!", confidential = TRUE)
|
||||
|
||||
NOTE: It checks usr by default. Supply the "user" argument if you wish to check for a specific mob.
|
||||
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, var/client/C = usr)
|
||||
if(ismob(C))
|
||||
var/mob/M = C
|
||||
C = M.client
|
||||
if(!C)
|
||||
return FALSE
|
||||
if(!(istype(C, /client))) // If we still didn't find a client, something is wrong.
|
||||
return FALSE
|
||||
if(!C.holder)
|
||||
if(show_msg)
|
||||
to_chat(C, span_filter_adminlog(span_warning("Error: You are not an admin.")))
|
||||
return FALSE
|
||||
|
||||
if(rights_required)
|
||||
if(rights_required & C.holder.rights)
|
||||
/proc/check_rights(rights_required, show_msg=1)
|
||||
if(usr?.client)
|
||||
if (check_rights_for(usr.client, rights_required))
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, span_filter_adminlog(span_warning("Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].")))
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
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
|
||||
|
||||
//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)
|
||||
if(usr.client.holder)
|
||||
if(!other || !other.holder)
|
||||
return 1
|
||||
if(usr.client.holder.rights != other.holder.rights)
|
||||
if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights )
|
||||
return 1 //we have all the rights they have and more
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Cannot proceed. They have more or equal rights to us.")))
|
||||
return 0
|
||||
return TRUE
|
||||
return usr.client.holder.check_if_greater_rights_than_holder(other.holder)
|
||||
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)
|
||||
if(subject?.holder)
|
||||
return subject.holder.check_for_rights(rights_required)
|
||||
return FALSE
|
||||
|
||||
/client/proc/mark_datum(datum/D)
|
||||
if(!holder)
|
||||
@@ -122,20 +263,6 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check
|
||||
set name = "Mark Object"
|
||||
mark_datum(D)
|
||||
|
||||
/client/proc/deadmin()
|
||||
if(holder)
|
||||
holder.disassociate()
|
||||
//qdel(holder)
|
||||
return 1
|
||||
|
||||
//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)
|
||||
if(rights_required && !(rights_required & subject.holder.rights))
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/GenerateToken()
|
||||
. = ""
|
||||
for(var/I in 1 to 32)
|
||||
|
||||
@@ -0,0 +1,561 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin.Secrets"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/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='byond://?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
||||
if(action)
|
||||
output += " | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
|
||||
else
|
||||
output += "<br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
||||
if(action == 1)
|
||||
var/logcount = 0
|
||||
var/logssperpage = 20
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/db_query/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='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
logcount -= logssperpage
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/datum/db_query/query_search_admin_logs = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
datetime,
|
||||
round_id,
|
||||
IFNULL((SELECT ckey FROM [format_table_name("erro_player")] WHERE ckey = adminckey), adminckey),
|
||||
operation,
|
||||
IF(ckey IS NULL, target, ckey),
|
||||
log
|
||||
FROM [format_table_name("admin_log")]
|
||||
LEFT JOIN [format_table_name("erro_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/db_query/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT ckey FROM [format_table_name("erro_player")] WHERE [format_table_name("erro_player")].ckey = [format_table_name("admin")].ckey), 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='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='byond://?_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/db_query/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='byond://?_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 http-equiv='Content-Type' content='text/html; 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='byond://?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th>PERMISSIONS</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='byond://?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
|
||||
|
||||
var/verify_link = ""
|
||||
//if (D.blocked_by_2fa)
|
||||
// verify_link += " | <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=verify;key=[adm_ckey]'>\[2FA VERIFY\]</a>"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a>[verify_link]</td>"
|
||||
output += "<td><a href='byond://?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank_names()]</a></td>"
|
||||
output += "<td><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank_flags(), " ")]</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/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
|
||||
var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/namespaced/common)
|
||||
permissions_assets.send(usr.client)
|
||||
var/admin_key = href_list["key"]
|
||||
var/admin_ckey = ckey(admin_key)
|
||||
|
||||
var/task = href_list["editrights"]
|
||||
var/datum/admins/target_admin_datum = GLOB.admin_datums[admin_ckey]
|
||||
if(!target_admin_datum)
|
||||
target_admin_datum = GLOB.deadmins[admin_ckey]
|
||||
if (!target_admin_datum && task != "add")
|
||||
return
|
||||
var/use_db
|
||||
var/skip
|
||||
var/legacy_only
|
||||
if(task == "activate" || task == "deactivate" || task == "sync" || task == "verify")
|
||||
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((target_admin_datum.ranks & GLOB.protected_ranks).len > 0)
|
||||
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 = tgui_alert(usr,"Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", list("Permanent", "Temporary", "Cancel"))
|
||||
if(use_db == "Cancel")
|
||||
return
|
||||
if(use_db == "Permanent")
|
||||
use_db = TRUE
|
||||
else
|
||||
use_db = FALSE
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
|
||||
if(target_admin_datum && (task != "sync" && task != "verify") && !check_if_greater_rights_than_holder(target_admin_datum))
|
||||
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
|
||||
|
||||
if(!admin_key) // Prevents failures in logging admin rank changes.
|
||||
admin_key = admin_ckey
|
||||
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only)
|
||||
if("remove")
|
||||
remove_admin(admin_ckey, admin_key, use_db, target_admin_datum)
|
||||
if("rank")
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, target_admin_datum, legacy_only)
|
||||
if("permissions")
|
||||
change_admin_flags(admin_ckey, admin_key, target_admin_datum)
|
||||
if("activate")
|
||||
force_readmin(admin_key, target_admin_datum)
|
||||
if("deactivate")
|
||||
force_deadmin(admin_key, target_admin_datum)
|
||||
if("sync")
|
||||
sync_lastadminrank(admin_ckey, admin_key, target_admin_datum)
|
||||
/*
|
||||
if("verify")
|
||||
var/msg = "has authenticated [admin_ckey]"
|
||||
message_admins("[key_name_admin(usr)] [msg]")
|
||||
log_admin("[key_name(usr)] [msg]")
|
||||
|
||||
target_admin_datum.bypass_2fa = TRUE
|
||||
target_admin_datum.associate(GLOB.directory[admin_ckey])
|
||||
*/
|
||||
edit_admin_permissions()
|
||||
|
||||
/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/db_query/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/db_query/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/db_query/query_add_admin_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target))
|
||||
"}, list("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/remove_admin(admin_ckey, admin_key, use_db, datum/admins/D)
|
||||
if(tgui_alert(usr,"Are you sure you want to remove [admin_ckey]?","Confirm Removal",list("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/db_query/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/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
||||
"}, list("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/force_readmin(admin_key, datum/admins/D)
|
||||
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)
|
||||
if(!D || D.deadmined)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] forcefully deadmined [admin_key]")
|
||||
log_admin("[key_name(usr)] forcefully deadmined [admin_key]")
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
#define RANK_DONE ":) I'm Done"
|
||||
|
||||
/datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/list/rank_names = list()
|
||||
if(!use_db || (use_db && !legacy_only))
|
||||
rank_names += "*New Rank*"
|
||||
for(var/datum/admin_rank/admin_rank as anything in GLOB.admin_ranks)
|
||||
if((admin_rank.rights & usr.client.holder.can_edit_rights_flags()) == admin_rank.rights)
|
||||
rank_names[admin_rank.name] = admin_rank
|
||||
|
||||
var/list/new_rank_names = list()
|
||||
var/list/custom_ranks = list()
|
||||
|
||||
while (TRUE)
|
||||
var/list/display_rank_names = list(RANK_DONE)
|
||||
|
||||
if (new_rank_names.len > 0)
|
||||
display_rank_names += "** SELECTED **"
|
||||
for (var/rank_name in new_rank_names)
|
||||
display_rank_names += rank_name
|
||||
display_rank_names += "---------"
|
||||
|
||||
for (var/rank_name in rank_names)
|
||||
if (!(rank_name in display_rank_names))
|
||||
display_rank_names += rank_name
|
||||
|
||||
var/next_rank = input("Please select a rank, or select [RANK_DONE] if you are finished.") as null|anything in display_rank_names
|
||||
|
||||
if (isnull(next_rank))
|
||||
return
|
||||
|
||||
if (next_rank == RANK_DONE)
|
||||
break
|
||||
|
||||
// They clicked "** SELECTED **" or something silly.
|
||||
if (!(next_rank in rank_names))
|
||||
continue
|
||||
|
||||
if (next_rank in new_rank_names)
|
||||
new_rank_names -= next_rank
|
||||
continue
|
||||
|
||||
if (next_rank == "*New Rank*")
|
||||
var/new_rank_name = input("Please input a new rank", "New custom rank") as text|null
|
||||
if (!new_rank_name)
|
||||
return
|
||||
|
||||
var/datum/admin_rank/custom_rank = rank_names[new_rank_name]
|
||||
if (isnull(custom_rank))
|
||||
if (D)
|
||||
custom_rank = new(new_rank_name, D.rank_flags())
|
||||
else
|
||||
custom_rank = new(new_rank_name)
|
||||
|
||||
GLOB.admin_ranks += custom_rank
|
||||
custom_ranks += custom_rank
|
||||
new_rank_names += new_rank_name
|
||||
|
||||
new_rank_names += next_rank
|
||||
|
||||
var/list/new_ranks = list()
|
||||
for (var/datum/admin_rank/admin_rank as anything in GLOB.admin_ranks)
|
||||
if (admin_rank.name in new_rank_names)
|
||||
new_ranks += admin_rank
|
||||
new_rank_names -= admin_rank.name
|
||||
|
||||
if (new_rank_names.len == 0)
|
||||
break
|
||||
|
||||
var/joined_rank = join_admin_ranks(new_ranks)
|
||||
var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [joined_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [joined_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/db_query/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)
|
||||
|
||||
for (var/datum/admin_rank/custom_rank in custom_ranks)
|
||||
//similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
|
||||
var/datum/db_query/query_rank_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = :new_rank",
|
||||
list("new_rank" = custom_rank.name)
|
||||
)
|
||||
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/db_query/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" = custom_rank.name))
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = custom_rank.name))
|
||||
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/db_query/query_change_rank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin")] SET `rank` = :new_rank WHERE ckey = :admin_ckey",
|
||||
list("new_rank" = joined_rank, "admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_change_rank.warn_execute())
|
||||
qdel(query_change_rank)
|
||||
return
|
||||
qdel(query_change_rank)
|
||||
var/datum/db_query/query_change_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = joined_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.ranks = new_ranks //set the admin_rank as our rank
|
||||
//D.bypass_2fa = TRUE // Another admin has cleared us
|
||||
var/client/C = GLOB.directory[admin_ckey]
|
||||
D.associate(C)
|
||||
else
|
||||
D = new(new_ranks, admin_ckey) //new admin
|
||||
//D.bypass_2fa = TRUE // Another admin has cleared us
|
||||
D.activate()
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
#undef RANK_DONE
|
||||
|
||||
/datum/admins/proc/change_admin_flags(admin_ckey, admin_key, datum/admins/admin_holder)
|
||||
var/new_flags = input_bitfield(
|
||||
usr,
|
||||
"Admin rights<br>This will affect only the current admin [admin_key]",
|
||||
"admin_flags",
|
||||
admin_holder.rank_flags(),
|
||||
350,
|
||||
590,
|
||||
allowed_edit_list = usr.client.holder.can_edit_rights_flags(),
|
||||
)
|
||||
|
||||
admin_holder.disassociate()
|
||||
|
||||
if (findtext(admin_holder.rank_names(), "([admin_ckey])"))
|
||||
var/datum/admin_rank/rank = admin_holder.ranks[1]
|
||||
rank.rights = new_flags
|
||||
rank.include_rights = new_flags
|
||||
rank.exclude_rights = NONE
|
||||
rank.can_edit_rights = rank.can_edit_rights
|
||||
else
|
||||
// Not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too.
|
||||
var/datum/admin_rank/new_admin_rank = new(
|
||||
/* init_name = */ "[admin_holder.rank_names()]([admin_ckey])",
|
||||
/* init_rights = */ new_flags,
|
||||
|
||||
// rank_flags() includes the exclude rights, so we no longer need to handle them separately.
|
||||
/* init_exclude_rights = */ NONE,
|
||||
|
||||
/* init_edit_rights = */ admin_holder.can_edit_rights_flags(),
|
||||
)
|
||||
|
||||
admin_holder.ranks = list(new_admin_rank)
|
||||
|
||||
var/log = "[key_name(usr)] has updated the admin rights of [admin_ckey] into [rights2text(new_flags)]"
|
||||
message_admins(log)
|
||||
log_admin(log)
|
||||
|
||||
var/client/admin_client = GLOB.directory[admin_ckey]
|
||||
admin_holder.associate(admin_client)
|
||||
|
||||
/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.can_edit_rights_flags()) == 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/db_query/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(tgui_alert(usr,"Are you sure you want to remove [admin_rank]?","Confirm Removal",list("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/db_query/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/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank))
|
||||
"}, list("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_names()
|
||||
var/datum/db_query/query_sync_lastadminrank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("erro_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)
|
||||
@@ -1,158 +0,0 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin.Secrets"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
if(!check_rights(R_PERMISSIONS)) return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions()
|
||||
if(!check_rights(R_PERMISSIONS)) return
|
||||
|
||||
var/output = {"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='panels.css'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:125px;text-align:right;'>CKEY <a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th><th style='width:100%;'>PERMISSIONS</th>
|
||||
</tr>
|
||||
"}
|
||||
|
||||
for(var/adm_ckey in admin_datums)
|
||||
var/datum/admins/D = admin_datums[adm_ckey]
|
||||
if(!D) continue
|
||||
var/rank = D.rank ? D.rank : "*none*"
|
||||
var/rights = rights2text(D.rights," ")
|
||||
if(!rights) rights = "*none*"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:right;'>[adm_ckey] <a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
|
||||
output += "<td><a href='byond://?src=\ref[src];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[rank]</a></td>"
|
||||
output += "<td><a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[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>
|
||||
</html>"}
|
||||
|
||||
usr << browse(output,"window=editrights;size=600x500")
|
||||
|
||||
/datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank)
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
|
||||
to_chat(usr, span_filter_adminlog("[span_red("You do not have permission to do this!")]"))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]"))
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_rank)
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
return
|
||||
|
||||
if(!istext(adm_ckey) || !istext(new_rank))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'")
|
||||
select_query.Execute()
|
||||
|
||||
var/new_admin = 1
|
||||
var/admin_id
|
||||
while(select_query.NextRow())
|
||||
new_admin = 0
|
||||
admin_id = text2num(select_query.item[1])
|
||||
|
||||
qdel(select_query)
|
||||
if(new_admin)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("New admin added.")]"))
|
||||
else
|
||||
if(!isnull(admin_id) && isnum(admin_id))
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Admin rank changed.")]"))
|
||||
|
||||
/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission)
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
|
||||
to_chat(usr, span_filter_adminlog("[span_red(">You do not have permission to do this!")]"))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection!")]"))
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_permission)
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
return
|
||||
|
||||
if(istext(new_permission))
|
||||
new_permission = text2num(new_permission)
|
||||
|
||||
if(!istext(adm_ckey) || !isnum(new_permission))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'")
|
||||
select_query.Execute()
|
||||
|
||||
var/admin_id
|
||||
var/admin_rights
|
||||
while(select_query.NextRow())
|
||||
admin_id = text2num(select_query.item[1])
|
||||
admin_rights = text2num(select_query.item[2])
|
||||
qdel(select_query)
|
||||
if(!admin_id)
|
||||
return
|
||||
|
||||
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Permission removed.")]"))
|
||||
else //This admin doesn't have this permission, so we are adding it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Permission added.")]"))
|
||||
@@ -27,7 +27,7 @@
|
||||
var/datum/player_info/P = new
|
||||
if (user)
|
||||
P.author = user.key
|
||||
P.rank = user.client.holder.rank
|
||||
P.rank = user.client.holder.rank_names()
|
||||
else
|
||||
P.author = "Adminbot"
|
||||
P.rank = "Friendly Robot"
|
||||
|
||||
+18
-94
@@ -126,99 +126,23 @@
|
||||
if((bantype == BANTYPE_PERMA || bantype == BANTYPE_TEMP) && playermob.client)
|
||||
qdel(playermob.client)
|
||||
|
||||
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"])
|
||||
|
||||
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"])
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
return
|
||||
|
||||
var/adm_ckey
|
||||
|
||||
var/task = href_list["editrights"]
|
||||
if(task == "add")
|
||||
var/new_ckey = ckey(tgui_input_text(usr,"New admin's ckey","Admin ckey", null))
|
||||
if(!new_ckey) return
|
||||
if(new_ckey in admin_datums)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': [new_ckey] is already an admin")))
|
||||
return
|
||||
adm_ckey = new_ckey
|
||||
task = "rank"
|
||||
else if(task != "show")
|
||||
adm_ckey = ckey(href_list["ckey"])
|
||||
if(!adm_ckey)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': No valid ckey")))
|
||||
return
|
||||
|
||||
var/datum/admins/D = admin_datums[adm_ckey]
|
||||
|
||||
if(task == "remove")
|
||||
if(tgui_alert(usr, "Are you sure you want to remove [adm_ckey]?","Message",list("Yes","Cancel")) == "Yes")
|
||||
if(!D) return
|
||||
admin_datums -= adm_ckey
|
||||
D.disassociate()
|
||||
|
||||
message_admins("[key_name_admin(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin("[key_name(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin_rank_modification(adm_ckey, "Removed")
|
||||
|
||||
else if(task == "rank")
|
||||
var/new_rank
|
||||
if(admin_ranks.len)
|
||||
new_rank = tgui_input_list(usr, "Please select a rank", "New rank", (admin_ranks|"*New Rank*"))
|
||||
else
|
||||
new_rank = tgui_input_list(usr, "Please select a rank", "New rank", list("Game Master","Game Admin", "Trial Admin", "Admin Observer","*New Rank*"))
|
||||
|
||||
var/rights = 0
|
||||
if(D)
|
||||
rights = D.rights
|
||||
switch(new_rank)
|
||||
if(null,"") return
|
||||
if("*New Rank*")
|
||||
new_rank = tgui_input_text(usr, "Please input a new rank", "New custom rank")
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
new_rank = ckeyEx(new_rank)
|
||||
if(!new_rank)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': Invalid rank")))
|
||||
return
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
if(admin_ranks.len)
|
||||
if(new_rank in admin_ranks)
|
||||
rights = admin_ranks[new_rank] //we typed a rank which already exists, use its rights
|
||||
else
|
||||
admin_ranks[new_rank] = 0 //add the new rank to admin_ranks
|
||||
else
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
new_rank = ckeyEx(new_rank)
|
||||
rights = admin_ranks[new_rank] //we input an existing rank, use its rights
|
||||
|
||||
if(D)
|
||||
D.disassociate() //remove adminverbs and unlink from client
|
||||
D.rank = new_rank //update the rank
|
||||
D.rights = rights //update the rights based on admin_ranks (default: 0)
|
||||
else
|
||||
D = new /datum/admins(new_rank, rights, adm_ckey)
|
||||
|
||||
var/client/C = GLOB.directory[adm_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("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin("[key_name(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin_rank_modification(adm_ckey, new_rank)
|
||||
|
||||
else if(task == "permissions")
|
||||
if(!D) return
|
||||
var/list/permissionlist = list()
|
||||
for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left bitshift
|
||||
permissionlist[rights2text(i)] = i
|
||||
var/new_permission = tgui_input_list(usr, "Select a permission to turn on/off", "Permission toggle", permissionlist)
|
||||
if(!new_permission) return
|
||||
D.rights ^= permissionlist[new_permission]
|
||||
|
||||
message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey]")
|
||||
log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey]")
|
||||
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
|
||||
|
||||
edit_admin_permissions()
|
||||
edit_rights_topic(href_list)
|
||||
|
||||
else if(href_list["call_shuttle"])
|
||||
if(!check_rights(R_ADMIN|R_EVENT)) return
|
||||
@@ -689,7 +613,7 @@
|
||||
return
|
||||
|
||||
if(M != usr) //we can jobban ourselves
|
||||
if(M.client && M.client.holder && (M.client.holder.rights & R_BAN)) //they can ban too. So we can't ban them
|
||||
if(M.client && M.client.holder && (check_rights_for(M.client, R_BAN))) //they can ban too. So we can't ban them
|
||||
tgui_alert_async(usr, "You cannot perform this action. You must be of a higher administrative rank!")
|
||||
return
|
||||
|
||||
@@ -1357,7 +1281,7 @@
|
||||
if(ismob(M))
|
||||
var/take_msg = span_notice("<b>ADMINHELP</b>: <b>[key_name(usr.client)]</b> is attending to <b>[key_name(M)]'s</b> adminhelp, please don't dogpile them.")
|
||||
for(var/client/X in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD|R_SERVER) & X.holder.rights) //VOREStation Edit
|
||||
if(check_rights_for(X, (R_ADMIN|R_MOD|R_SERVER)))
|
||||
to_chat(X, take_msg)
|
||||
to_chat(M, span_filter_pm(span_boldnotice("Your adminhelp is being attended to by [usr.client]. Thanks for your patience!")))
|
||||
// VoreStation Edit Start
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
GENERAL_PROTECT_DATUM(/datum/admin_verb)
|
||||
|
||||
/**
|
||||
* This is the admin verb datum. It is used to store the verb's information and handle the verb's functionality.
|
||||
* All of this is setup for you, and you should not be defining this manually.
|
||||
* That means you reader.
|
||||
*/
|
||||
/datum/admin_verb
|
||||
var/name //! The name of the verb.
|
||||
var/description //! The description of the verb.
|
||||
var/category //! The category of the verb.
|
||||
var/permissions //! The permissions required to use the verb.
|
||||
var/visibility_flag //! The flag that determines if the verb is visible.
|
||||
VAR_PROTECTED/verb_path //! The path to the verb proc.
|
||||
|
||||
/datum/admin_verb/Destroy(force)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
return ..()
|
||||
|
||||
/// Assigns the verb to the admin.
|
||||
/datum/admin_verb/proc/assign_to_client(client/admin)
|
||||
add_verb(admin, verb_path)
|
||||
|
||||
/// Unassigns the verb from the admin.
|
||||
/datum/admin_verb/proc/unassign_from_client(client/admin)
|
||||
remove_verb(admin, verb_path)
|
||||
@@ -257,7 +257,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//send this msg to all admins
|
||||
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN, 0, X))
|
||||
if(!check_rights_for(X, R_ADMIN))
|
||||
continue
|
||||
if(X.prefs?.read_preference(/datum/preference/toggle/holder/play_adminhelp_ping))
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
@@ -684,7 +684,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights(rights_required = requiredflags, show_msg = FALSE, C = X))
|
||||
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
|
||||
@@ -203,14 +203,14 @@
|
||||
if(irc)
|
||||
log_admin("PM: [key_name(src)]->IRC: [rawmsg]")
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN, 0, X))
|
||||
if(!check_rights_for(X, R_ADMIN))
|
||||
continue
|
||||
to_chat(X, span_admin_pm_notice(span_bold("PM: [key_name(src, X, 0)]->IRC:") + " [keywordparsedmsg]"))
|
||||
else
|
||||
log_admin("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)
|
||||
if(!check_rights(R_ADMIN, 0, X))
|
||||
if(!check_rights_for(X, R_ADMIN))
|
||||
continue
|
||||
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
|
||||
to_chat(X, span_admin_pm_notice(span_bold("PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]:") + " [keywordparsedmsg]"))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
log_adminsay(msg,src)
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(check_rights(R_ADMIN, 0, C))
|
||||
if(check_rights_for(C, R_ADMIN))
|
||||
to_chat(C, span_admin_channel(create_text_tag("admin", "ADMIN:", C) + " " + span_name("[key_name(usr, 1)]") + "([admin_jump_link(mob, src)]): " + span_name("[msg]") ))
|
||||
|
||||
feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
display_name = usr.client.holder.fakekey
|
||||
|
||||
// Name shown to other players. Admins whom are not also antags have their rank displayed.
|
||||
var/player_display = (is_admin && !is_antag) ? "[display_name]([usr.client.holder.rank])" : display_name
|
||||
var/player_display = (is_admin && !is_antag) ? "[display_name]([usr.client.holder.rank_names()])" : display_name
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(check_rights(R_ADMIN|R_MOD|R_EVENT, 0, M)) // Staff can see AOOC unconditionally, and with more details.
|
||||
if(check_rights_for(M.client, R_ADMIN|R_MOD|R_EVENT)) // Staff can see AOOC unconditionally, and with more details.
|
||||
to_chat(M, span_ooc(span_aooc("[create_text_tag("aooc", "Antag-OOC:", M.client)] <EM>[get_options_bar(src, 0, 1, 1)]([admin_jump_link(usr, M.client.holder)]):</EM> " + span_message("[msg]"))))
|
||||
else if(M.client) // Players can only see AOOC if observing, or if they are an antag type allowed to use AOOC.
|
||||
var/datum/antagonist/A = null
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
to_chat(src, span_warning("You have deadchat muted."))
|
||||
return
|
||||
|
||||
var/stafftype = uppertext(holder.rank)
|
||||
var/stafftype = uppertext(holder.rank_names())
|
||||
|
||||
msg = sanitize(msg)
|
||||
log_admin("DSAY: [key_name(src)] : [msg]")
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
var/msg = span_filter_pray(span_blue("[icon2html(cross, GLOB.admins)] <b>" + span_purple("PRAY: ") + "[key_name(src, 1)] [ADMIN_QUE(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] ([admin_jump_link(src, src)]) [ADMIN_CA(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]:</b> [raw_msg]"))
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN, 0, C))
|
||||
if(!check_rights_for(C, R_ADMIN))
|
||||
continue
|
||||
if(C.prefs?.read_preference(/datum/preference/toggle/show_chat_prayers))
|
||||
to_chat(C, msg, type = MESSAGE_TYPE_PRAYER, confidential = TRUE)
|
||||
@@ -29,7 +29,7 @@
|
||||
/proc/CentCom_announce(var/msg, var/mob/Sender, var/iamessage)
|
||||
msg = span_blue(span_bold(span_orange("[uppertext(using_map.boss_short)]M[iamessage ? " IA" : ""]:") + "[key_name(Sender, 1)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] ([admin_jump_link(Sender)]) [ADMIN_CA(Sender)] [ADMIN_BSA(Sender)] [ADMIN_CENTCOM_REPLY(Sender)]:") + " [msg]")
|
||||
for(var/client/C in GLOB.admins) //VOREStation Edit - GLOB admins
|
||||
if(!check_rights(R_ADMIN, 0, C))
|
||||
if(!check_rights_for(C, R_ADMIN))
|
||||
continue
|
||||
to_chat(C,msg)
|
||||
C << 'sound/machines/signal.ogg'
|
||||
@@ -37,7 +37,7 @@
|
||||
/proc/Syndicate_announce(var/msg, var/mob/Sender)
|
||||
msg = span_blue(span_bold(span_crimson("ILLEGAL:") + "[key_name(Sender, 1)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] ([admin_jump_link(Sender)]) [ADMIN_CA(Sender)] [ADMIN_BSA(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]:") + " [msg]")
|
||||
for(var/client/C in GLOB.admins) //VOREStation Edit - GLOB admins
|
||||
if(!check_rights(R_ADMIN, 0, C))
|
||||
if(!check_rights_for(C, R_ADMIN))
|
||||
continue
|
||||
to_chat(C,msg)
|
||||
C << 'sound/machines/signal.ogg'
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Admin Verbs in this file are special and cannot use the AVD system for some reason or another.
|
||||
|
||||
/client/proc/readmin()
|
||||
set name = "Readmin"
|
||||
set category = "Admin.Misc"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
var/datum/admins/A = GLOB.deadmins[ckey]
|
||||
|
||||
if(!A)
|
||||
A = GLOB.admin_datums[ckey]
|
||||
if (!A)
|
||||
var/msg = " is trying to readmin but they have no deadmin entry"
|
||||
message_admins("[key_name_admin(src)][msg]")
|
||||
log_admin_private("[key_name(src)][msg]")
|
||||
return
|
||||
|
||||
A.associate(src)
|
||||
|
||||
if(!holder)
|
||||
return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force
|
||||
|
||||
to_chat(src, span_interface("You are now an admin."), confidential = TRUE)
|
||||
message_admins("[src] re-adminned themselves.")
|
||||
log_admin("[src] re-adminned themselves.")
|
||||
//BLACKBOX_LOG_ADMIN_VERB("Readmin")
|
||||
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.addVisibility(our_mob, src)
|
||||
@@ -172,21 +172,24 @@
|
||||
/client/VV_ckey_edit()
|
||||
return list("key", "ckey")
|
||||
|
||||
/datum/proc/may_edit_var(var/user, var/var_to_edit)
|
||||
/datum/proc/may_edit_var(var/user, var/var_to_edit) //User must be a CLIENT that is passed to this.
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(ismob(user)) //Failsafe catch in case someone feeds a mob into us.
|
||||
var/mob/living = user
|
||||
user = living.client
|
||||
if(!(var_to_edit in vars))
|
||||
to_chat(user, span_warning("\The [src] does not have a var '[var_to_edit]'"))
|
||||
return FALSE
|
||||
if(var_to_edit in VV_static())
|
||||
return FALSE
|
||||
if((var_to_edit in VV_secluded()) && !check_rights(R_ADMIN|R_DEBUG, FALSE, C = user))
|
||||
if((var_to_edit in VV_secluded()) && !check_rights_for(user, R_ADMIN|R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_locked()) && !check_rights(R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_locked()) && !check_rights_for(user, R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_ckey_edit()) && !check_rights(R_SPAWN|R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_ckey_edit()) && !check_rights_for(user, R_SPAWN|R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_icon_edit_lock()) && !check_rights(R_FUN|R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_icon_edit_lock()) && !check_rights_for(user, R_FUN|R_DEBUG))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user