mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
* [Ready] CDN browser assets! (#52681) Rewrites the asset_cache system to handle sending assets to a CDN via a webroot. see https://github.com/MrStonedOne/tgstation/blob/asset-cdn/code/modules/asset_cache/readme.md Fixed a lot of bugs with assets, removed some dead code. Changes: Moved asset cache code to transport datums, the currently loaded one is located at SSassets.transport, asset cache calls made before the config is loaded use the simple browse_rsc transport. Added subsystem call for when the config loads or reloads. Added a webroot CDN asset transport. assets are saved to a file in a format based on the file's hash (currently md5). Assets that don't use get_asset_url or get_url_mappings (such as browser assets referred to by static html files like changelog.html or static css files) can be saved to browse_rsc even when in cdn asset mode by setting legacy to TRUE on the datum returned by register_assets Added a system for saving assets on a cdn in a hash based namespace (folder), assets within the same namespace will always be able to refer to each other by relative names. (used to allow cdn'ing font awesome without having to make something that regenerates it's css files.). The simple/namespaced asset cache datum helper will handle generating a namespace composed of the combined md5 of everything in the same datum, as well as registering them properly. Moved external resource from a snowflake loaded file to a config entry, added it to resources.txt To ensure the system breaks in local testing in any situation that wouldn't work in cdn mode, the simple transport will mutate the filenames of non-legacy and non-namespaced assets and return this with get_asset_url. Simple transport's passive send of all roundstart assets to all clients is now a config that defaults to off. this is to break race conditions during local testings from devs accidentally relying on this instead of using send() properly. cl refactor: Interface assets (js/css/images) can now be managed using an external webserver instead of byond's one at a time file transfer queue. admin: Adds admin verb toggle-cdn that allows admins to disable the external webserver asset transport and revert to the old system. Useful if the webserver backing this goes down (thanks cloudflare). config: New config file, resources.txt, (must be loaded by an $include statement from the main config) server: The external_rsc_urls.txt config has been moved to the main config system. /cl Porting notes: Interface webpages must refer to their assets (css/js/image/etc) by a generated url, or the asset must register itself as a legacy asset. The system is designed to break in localtest (on simple/legacy mode) in most situations that would break in cdn mode. Requires latest tgui. The webserver must set the proper CORS headers for font files or font awesome (and other fonts) won't load. /tg/'s webserver config: https://gist.github.com/MrStonedOne/523388b2f161af832292d98a8aad0eae * [Ready] CDN browser assets! Co-authored-by: Kyle Spier-Swenson <kyleshome@gmail.com>
532 lines
27 KiB
Plaintext
532 lines
27 KiB
Plaintext
/client/proc/edit_admin_permissions()
|
|
set category = "Admin"
|
|
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='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
|
if(action)
|
|
output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
|
|
else
|
|
output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
|
if(action == 1)
|
|
var/logcount = 0
|
|
var/logssperpage = 20
|
|
var/pagecount = 0
|
|
page = text2num(page)
|
|
var/datum/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='?_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 byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
|
operation,
|
|
IF(ckey IS NULL, target, byond_key),
|
|
log
|
|
FROM [format_table_name("admin_log")]
|
|
LEFT JOIN [format_table_name("player")] ON target = ckey
|
|
WHERE (:target IS NULL OR ckey = :target) AND (:operation IS NULL OR operation = :operation)
|
|
ORDER BY datetime DESC
|
|
LIMIT :skip, :take
|
|
"}, list("target" = target, "operation" = operation, "skip" = logssperpage * page, "take" = logssperpage))
|
|
if(!query_search_admin_logs.warn_execute())
|
|
qdel(query_search_admin_logs)
|
|
return
|
|
while(query_search_admin_logs.NextRow())
|
|
var/datetime = query_search_admin_logs.item[1]
|
|
var/round_id = query_search_admin_logs.item[2]
|
|
var/admin_key = query_search_admin_logs.item[3]
|
|
operation = query_search_admin_logs.item[4]
|
|
target = query_search_admin_logs.item[5]
|
|
var/log = query_search_admin_logs.item[6]
|
|
output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_key] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
|
|
qdel(query_search_admin_logs)
|
|
if(action == 2)
|
|
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
|
var/datum/db_query/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("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='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>"
|
|
output += "<hr style='background:#000000; border:0; height:1px'>"
|
|
qdel(query_check_admin_errors)
|
|
output += "<h3>Unused ranks</h3>"
|
|
var/datum/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='?_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='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
|
<th style='width:125px;'>RANK</th>
|
|
<th style='width:40%;'>PERMISSIONS</th>
|
|
<th style='width:20%;'>DENIED</th>
|
|
<th style='width:40%;'>ALLOWED TO EDIT</th>
|
|
</tr>
|
|
"}
|
|
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
|
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
|
if(!D)
|
|
D = GLOB.deadmins[adm_ckey]
|
|
if (!D)
|
|
continue
|
|
var/deadminlink = ""
|
|
if(D.owner)
|
|
adm_ckey = D.owner.key
|
|
if (D.deadmined)
|
|
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
|
|
else
|
|
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
|
|
output += "<tr>"
|
|
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a></td>"
|
|
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank.name]</a></td>"
|
|
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
|
|
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
|
|
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
|
|
output += "</tr>"
|
|
output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
|
|
if(QDELETED(usr))
|
|
return
|
|
usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
|
|
|
|
/datum/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(src)
|
|
var/admin_key = href_list["key"]
|
|
var/admin_ckey = ckey(admin_key)
|
|
var/datum/admins/D = GLOB.admin_datums[admin_ckey]
|
|
var/use_db
|
|
var/task = href_list["editrights"]
|
|
var/skip
|
|
var/legacy_only
|
|
if(task == "activate" || task == "deactivate" || task == "sync")
|
|
skip = TRUE
|
|
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
|
if(admin_ckey in GLOB.protected_admins)
|
|
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential = TRUE)
|
|
return
|
|
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
|
|
if(D.rank in GLOB.protected_ranks)
|
|
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>", confidential = TRUE)
|
|
return
|
|
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions"))
|
|
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>", confidential = TRUE)
|
|
legacy_only = TRUE
|
|
if(check_rights(R_DBRANKS, FALSE))
|
|
if(!skip)
|
|
if(!SSdbcore.Connect())
|
|
to_chat(usr, "<span class='danger'>Unable to connect to database, changes are temporary only.</span>", confidential = TRUE)
|
|
use_db = FALSE
|
|
else
|
|
use_db = alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel")
|
|
if(use_db == "Cancel")
|
|
return
|
|
if(use_db == "Permanent")
|
|
use_db = TRUE
|
|
else
|
|
use_db = FALSE
|
|
if(QDELETED(usr))
|
|
return
|
|
if(task != "add")
|
|
D = GLOB.admin_datums[admin_ckey]
|
|
if(!D)
|
|
D = GLOB.deadmins[admin_ckey]
|
|
if(!D)
|
|
return
|
|
if((task != "sync") && !check_if_greater_rights_than_holder(D))
|
|
message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
|
log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
|
return
|
|
switch(task)
|
|
if("add")
|
|
admin_ckey = add_admin(admin_ckey, admin_key, use_db)
|
|
if(!admin_ckey)
|
|
return
|
|
change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only)
|
|
if("remove")
|
|
remove_admin(admin_ckey, admin_key, use_db, D)
|
|
if("rank")
|
|
change_admin_rank(admin_ckey, admin_key, use_db, D, legacy_only)
|
|
if("permissions")
|
|
change_admin_flags(admin_ckey, admin_key, use_db, D, legacy_only)
|
|
if("activate")
|
|
force_readmin(admin_key, D)
|
|
if("deactivate")
|
|
force_deadmin(admin_key, D)
|
|
if("sync")
|
|
sync_lastadminrank(admin_ckey, admin_key, D)
|
|
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 class='danger'>[admin_key] is already an admin.</span>", 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 class='danger'>[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins.</span>", 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 (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target))
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .))
|
|
if(!query_add_admin_log.warn_execute())
|
|
qdel(query_add_admin_log)
|
|
return FALSE
|
|
qdel(query_add_admin_log)
|
|
|
|
/datum/admins/proc/remove_admin(admin_ckey, admin_key, use_db, datum/admins/D)
|
|
if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
|
|
GLOB.admin_datums -= admin_ckey
|
|
GLOB.deadmins -= admin_ckey
|
|
if(D)
|
|
D.disassociate()
|
|
var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
|
var/m2 = "[key_name(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
|
if(use_db)
|
|
var/datum/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 (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey))
|
|
if(!query_add_rank_log.warn_execute())
|
|
qdel(query_add_rank_log)
|
|
return
|
|
qdel(query_add_rank_log)
|
|
sync_lastadminrank(admin_ckey, admin_key)
|
|
message_admins(m1)
|
|
log_admin(m2)
|
|
|
|
/datum/admins/proc/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.
|
|
|
|
/datum/admins/proc/auto_deadmin()
|
|
to_chat(owner, "<span class='interface'>You are now a normal player.</span>", confidential = TRUE)
|
|
var/old_owner = owner
|
|
deactivate()
|
|
message_admins("[old_owner] deadmined via auto-deadmin config.")
|
|
log_admin("[old_owner] deadmined via auto-deadmin config.")
|
|
return TRUE
|
|
|
|
/datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
|
var/datum/admin_rank/R
|
|
var/list/rank_names = list()
|
|
if(!use_db || (use_db && !legacy_only))
|
|
rank_names += "*New Rank*"
|
|
for(R in GLOB.admin_ranks)
|
|
if((R.rights & usr.client.holder.rank.can_edit_rights) == R.rights)
|
|
rank_names[R.name] = R
|
|
var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
|
if(new_rank == "*New Rank*")
|
|
new_rank = input("Please input a new rank", "New custom rank") as text|null
|
|
if(!new_rank)
|
|
return
|
|
R = rank_names[new_rank]
|
|
if(!R) //rank with that name doesn't exist yet - make it
|
|
if(D)
|
|
R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
|
|
else
|
|
R = new(new_rank) //blank new admin_rank
|
|
GLOB.admin_ranks += R
|
|
var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
|
var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
|
if(use_db)
|
|
//if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
|
|
var/old_rank
|
|
var/datum/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)
|
|
//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" = new_rank)
|
|
)
|
|
if(!query_rank_in_db.warn_execute())
|
|
qdel(query_rank_in_db)
|
|
return
|
|
if(!query_rank_in_db.NextRow())
|
|
QDEL_NULL(query_rank_in_db)
|
|
var/datum/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" = new_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 (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = new_rank))
|
|
if(!query_add_rank_log.warn_execute())
|
|
qdel(query_add_rank_log)
|
|
return
|
|
qdel(query_add_rank_log)
|
|
qdel(query_rank_in_db)
|
|
var/datum/db_query/query_change_rank = SSdbcore.NewQuery(
|
|
"UPDATE [format_table_name("admin")] SET `rank` = :new_rank WHERE ckey = :admin_ckey",
|
|
list("new_rank" = new_rank, "admin_ckey" = admin_ckey)
|
|
)
|
|
if(!query_change_rank.warn_execute())
|
|
qdel(query_change_rank)
|
|
return
|
|
qdel(query_change_rank)
|
|
var/datum/db_query/query_change_rank_log = SSdbcore.NewQuery({"
|
|
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
|
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = new_rank))
|
|
if(!query_change_rank_log.warn_execute())
|
|
qdel(query_change_rank_log)
|
|
return
|
|
qdel(query_change_rank_log)
|
|
if(D) //they were previously an admin
|
|
D.disassociate() //existing admin needs to be disassociated
|
|
D.rank = R //set the admin_rank as our rank
|
|
var/client/C = GLOB.directory[admin_ckey]
|
|
D.associate(C)
|
|
else
|
|
D = new(R, admin_ckey, TRUE) //new admin
|
|
message_admins(m1)
|
|
log_admin(m2)
|
|
|
|
/datum/admins/proc/change_admin_flags(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
|
var/new_flags = input_bitfield(usr, "Include permission flags<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.include_rights, 350, 590, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
|
if(isnull(new_flags))
|
|
return
|
|
var/new_exclude_flags = input_bitfield(usr, "Exclude permission flags<br>Flags enabled here will be removed from a rank.<br>Note these take precedence over included flags.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.exclude_rights, 350, 670, "red", usr.client.holder.rank.can_edit_rights)
|
|
if(isnull(new_exclude_flags))
|
|
return
|
|
var/new_can_edit_flags = input_bitfield(usr, "Editable permission flags<br>These are the flags this rank is allowed to edit if they have access to the permissions panel.<br>They will be unable to modify admins to a rank that has a flag not included here.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.can_edit_rights, 350, 710, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
|
if(isnull(new_can_edit_flags))
|
|
return
|
|
var/m1 = "[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
|
var/m2 = "[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
|
if(use_db || legacy_only)
|
|
var/rank_name = D.rank.name
|
|
var/old_flags
|
|
var/old_exclude_flags
|
|
var/old_can_edit_flags
|
|
var/datum/db_query/query_get_rank_flags = SSdbcore.NewQuery(
|
|
"SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE `rank` = :rank_name",
|
|
list("rank_name" = rank_name)
|
|
)
|
|
if(!query_get_rank_flags.warn_execute())
|
|
qdel(query_get_rank_flags)
|
|
return
|
|
if(query_get_rank_flags.NextRow())
|
|
old_flags = text2num(query_get_rank_flags.item[1])
|
|
old_exclude_flags = text2num(query_get_rank_flags.item[2])
|
|
old_can_edit_flags = text2num(query_get_rank_flags.item[3])
|
|
qdel(query_get_rank_flags)
|
|
var/datum/db_query/query_change_rank_flags = SSdbcore.NewQuery(
|
|
"UPDATE [format_table_name("admin_ranks")] SET flags = :new_flags, exclude_flags = :new_exclude_flags, can_edit_flags = :new_can_edit_flags WHERE `rank` = :rank_name",
|
|
list("new_flags" = new_flags, "new_exclude_flags" = new_exclude_flags, "new_can_edit_flags" = new_can_edit_flags, "rank_name" = rank_name)
|
|
)
|
|
if(!query_change_rank_flags.warn_execute())
|
|
qdel(query_change_rank_flags)
|
|
return
|
|
qdel(query_change_rank_flags)
|
|
var/log_message = "Permissions of [rank_name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]"
|
|
var/datum/db_query/query_change_rank_flags_log = SSdbcore.NewQuery({"
|
|
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
|
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change rank flags', :rank_name, :log)
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "rank_name" = rank_name, "log" = log_message))
|
|
if(!query_change_rank_flags_log.warn_execute())
|
|
qdel(query_change_rank_flags_log)
|
|
return
|
|
qdel(query_change_rank_flags_log)
|
|
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
|
if(R.name != D.rank.name)
|
|
continue
|
|
R.rights = new_flags &= ~new_exclude_flags
|
|
R.exclude_rights = new_exclude_flags
|
|
R.include_rights = new_flags
|
|
R.can_edit_rights = new_can_edit_flags
|
|
for(var/i in GLOB.admin_datums+GLOB.deadmins)
|
|
var/datum/admins/A = GLOB.admin_datums[i]
|
|
if(!A)
|
|
A = GLOB.deadmins[i]
|
|
if (!A)
|
|
continue
|
|
if(A.rank.name != D.rank.name)
|
|
continue
|
|
var/client/C = GLOB.directory[A.target]
|
|
A.disassociate()
|
|
A.associate(C)
|
|
else
|
|
D.disassociate()
|
|
if(!findtext(D.rank.name, "([admin_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
|
|
D.rank = new("[D.rank.name]([admin_ckey])", new_flags, new_exclude_flags, new_can_edit_flags) //duplicate our previous admin_rank but with a new name
|
|
//we don't add this clone to the admin_ranks list, as it is unique to that ckey
|
|
else
|
|
D.rank.rights = new_flags &= ~new_exclude_flags
|
|
D.rank.include_rights = new_flags
|
|
D.rank.exclude_rights = new_exclude_flags
|
|
D.rank.can_edit_rights = new_can_edit_flags
|
|
var/client/C = GLOB.directory[admin_ckey] //find the client with the specified ckey (if they are logged in)
|
|
D.associate(C) //link up with the client and add verbs
|
|
message_admins(m1)
|
|
log_admin(m2)
|
|
|
|
/datum/admins/proc/remove_rank(admin_rank)
|
|
if(!admin_rank)
|
|
return
|
|
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
|
if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
|
|
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>", confidential = TRUE)
|
|
return
|
|
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
|
|
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>", confidential = TRUE)
|
|
return
|
|
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
|
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>", confidential = TRUE)
|
|
return
|
|
var/datum/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 class='danger'>Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.</span>", confidential = TRUE)
|
|
return
|
|
qdel(query_admins_with_rank)
|
|
if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
|
|
var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
|
|
var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
|
|
var/datum/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 (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank))
|
|
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank))
|
|
if(!query_add_rank_log.warn_execute())
|
|
qdel(query_add_rank_log)
|
|
return
|
|
qdel(query_add_rank_log)
|
|
message_admins(m1)
|
|
log_admin(m2)
|
|
|
|
/datum/admins/proc/sync_lastadminrank(admin_ckey, admin_key, datum/admins/D)
|
|
var/sqlrank = "Player"
|
|
if (D)
|
|
sqlrank = D.rank.name
|
|
var/datum/db_query/query_sync_lastadminrank = SSdbcore.NewQuery(
|
|
"UPDATE [format_table_name("player")] SET lastadminrank = :rank WHERE ckey = :ckey",
|
|
list("rank" = sqlrank, "ckey" = admin_ckey)
|
|
)
|
|
if(!query_sync_lastadminrank.warn_execute())
|
|
qdel(query_sync_lastadminrank)
|
|
return
|
|
qdel(query_sync_lastadminrank)
|
|
to_chat(usr, "<span class='admin'>Sync of [admin_key] successful.</span>", confidential = TRUE)
|