Adds LDAP but for 2d spessmen (#9527)

This commit is contained in:
Erki
2020-08-10 14:56:39 +03:00
committed by GitHub
parent e717274903
commit 7097912fd1
20 changed files with 598 additions and 415 deletions

View File

@@ -0,0 +1,18 @@
---
--- Adds the ss13_admins SQL table again.
---
CREATE TABLE `ss13_admins` (
`ckey` VARCHAR(50) NOT NULL,
`rank` TEXT NOT NULL,
`flags` INT NOT NULL,
`status` TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY (`ckey`),
CONSTRAINT `FK_ss13_admins_ss13_player_ckey` FOREIGN KEY(`ckey`) REFERENCES `ss13_player` (`ckey`) ON UPDATE CASCADE
) ENGINE=InnoDB COLLATE='utf8mb4_unicode_ci';
ALTER TABLE `ss13_player`
DROP COLUMN `rank`,
DROP COLUMN `flags`;
DROP TABLE `ss13_admin_log`;

View File

@@ -1641,6 +1641,7 @@
#include "code\modules\holodeck\HolodeckObjects.dm"
#include "code\modules\holodeck\HolodeckPrograms.dm"
#include "code\modules\http\forum_api.dm"
#include "code\modules\http\forumuser_api.dm"
#include "code\modules\http\http.dm"
#include "code\modules\hydroponics\grown.dm"
#include "code\modules\hydroponics\grown_inedible.dm"

View File

@@ -306,9 +306,12 @@ var/list/gamemode_cache = list()
var/forum_api_path
// global.forum_api_key - see modules/http/forum_api.dm
var/news_use_forum_api = FALSE
var/forumuser_api_url
var/use_forumuser_api = FALSE
// global.forumuser_api_key - see modules/http/forumuser_api.dm
var/profiler_is_enabled = FALSE
var/profiler_restart_period = 120 SECONDS
var/profiler_timeout_threshold = 5 SECONDS
@@ -947,6 +950,13 @@ var/list/gamemode_cache = list()
if ("profiler_timeout_threshold")
profiler_timeout_threshold = text2num(value)
if ("forumuser_api_url")
forumuser_api_url = value
if ("use_forumuser_api")
use_forumuser_api = TRUE
if ("forumuser_api_key")
global.forumuser_api_key = value
else
log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -864,6 +864,5 @@
SearchVar(mark)
SearchVar(contamination_overlay)
SearchVar(vsc)
SearchVar(global_player_panel)
#endif

View File

@@ -36,6 +36,10 @@
populate_code_phrases()
if (config.use_forumuser_api)
update_admins_from_api(TRUE)
..(timeofday)
/proc/sorted_add_area(area/A)

View File

@@ -1,94 +1,97 @@
var/list/admin_ranks = list() //list of all ranks with associated rights
var/list/forum_groupids_to_ranks = list()
//load our rank - > rights associations
/proc/load_admin_ranks()
/datum/admin_rank
var/rank_name
var/group_id
var/rights
/datum/admin_rank/New(raw_data)
group_id = raw_data["role_id"]
rank_name = raw_data["name"]
rights = auths_to_rights(raw_data["auths"])
/datum/admin_rank/proc/auths_to_rights(list/auths)
. = 0
for (var/auth in auths)
switch (lowertext(auth))
if ("r_buildmode","r_build")
. |= R_BUILDMODE
if ("r_admin")
. |= R_ADMIN
if ("r_ban")
. |= R_BAN
if ("r_fun")
. |= R_FUN
if ("r_server")
. |= R_SERVER
if ("r_debug")
. |= R_DEBUG
if ("r_permissions","r_rights")
. |= R_PERMISSIONS
if ("r_possess")
. |= R_POSSESS
if ("r_stealth")
. |= R_STEALTH
if ("r_rejuv","r_rejuvinate")
. |= R_REJUVINATE
if ("r_varedit")
. |= R_VAREDIT
if ("r_sound","r_sounds")
. |= R_SOUNDS
if ("r_spawn","r_create")
. |= R_SPAWN
if ("r_moderator")
. |= R_MOD
if ("r_developer")
. |= R_DEV
if ("r_cciaa")
. |= R_CCIAA
if ("r_everything","r_host","r_all")
. |= (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_CCIAA | R_DEV)
else
crash_with("Unknown rank in file: [auth]")
/proc/load_admin_ranks(rank_file="config/admin_ranks.json")
admin_ranks.Cut()
forum_groupids_to_ranks.Cut()
var/previous_rights = 0
var/list/data = json_decode(file2text(rank_file))
//load text from file
var/list/Lines = file2list("config/admin_ranks.txt")
//process each line seperately
for(var/line in Lines)
if(!length(line)) continue
if(copytext(line,1,2) == "#") continue
var/list/List = text2list(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_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_CCIAA | R_DEV)
if("sound","sounds") rights |= R_SOUNDS
if("spawn","create") rights |= R_SPAWN
if("mod") rights |= R_MOD
if("developer") rights |= R_DEV
if("cciaa") rights |= R_CCIAA
admin_ranks[rank] = rights
previous_rights = rights
#ifdef TESTING
var/msg = "Permission Sets Built:\n"
for(var/rank in admin_ranks)
msg += "\t[rank] - [admin_ranks[rank]]\n"
testing(msg)
#endif
for (var/list/group in data)
var/datum/admin_rank/rank = new(group)
admin_ranks[rank.rank_name] = rank
forum_groupids_to_ranks["[rank.group_id]"] = rank
/hook/startup/proc/loadAdmins()
load_admin_ranks()
load_admins()
return 1
/proc/load_admins()
//clear the datums references
admin_datums.Cut()
for(var/s in staff)
var/client/C = s
C.remove_admin_verbs()
C.holder = null
staff.Cut()
// Clears admins from the world config.
for (var/A in world.GetConfig("admin"))
world.SetConfig("APP/admin", A, null)
clear_admins()
if(config.admin_legacy_system)
load_admin_ranks()
//load text from file
var/list/Lines = file2list("config/admins.txt")
//process each line seperately
for(var/line in Lines)
if(!length(line)) continue
if(copytext(line,1,2) == "#") continue
if(!length(line))
continue
if(copytext(line,1,2) == "#")
continue
//Split the line at every "-"
var/list/List = text2list(line, "-")
if(!List.len) continue
if(!List.len)
continue
//ckey is before the first "-"
var/ckey = ckey(List[1])
if(!ckey) continue
if(!ckey)
continue
//rank follows the first "-"
var/rank = ""
@@ -96,10 +99,10 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
rank = ckeyEx(List[2])
//load permissions associated with this rank
var/rights = admin_ranks[rank]
var/datum/admin_rank/rank_object = admin_ranks[rank]
//create the admin datum and store it for later use
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
var/datum/admins/D = new /datum/admins(rank, rank_object?.rights || 0, ckey)
//find the client for a ckey if they are connected and associate them with the new admin datum
D.associate(directory[ckey])
@@ -115,17 +118,19 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
load_admins()
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, (flags & 0xFFFF) as flags FROM ss13_player WHERE rank IS NOT NULL AND (flags & 0xFFFF) != 0")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, flags FROM ss13_admins;")
query.Execute()
while(query.NextRow())
var/ckey = query.item[1]
var/rank = query.item[2]
var/rights = query.item[3]
if(istext(rights)) rights = text2num(rights)
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(directory[ckey])
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.")
@@ -133,7 +138,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
load_admins()
return
#ifdef TESTING
#ifdef TESTING
var/msg = "Admins Built:\n"
for(var/ckey in admin_datums)
var/rank
@@ -141,25 +146,76 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
if(D) rank = D.rank
msg += "\t[ckey] - [rank]\n"
testing(msg)
#endif
#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)
/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)
#endif
/proc/clear_admins()
//clear the datums references
admin_datums.Cut()
for(var/s in staff)
var/client/C = s
C.remove_admin_verbs()
C.holder = null
staff.Cut()
// Clears admins from the world config.
for (var/A in world.GetConfig("admin"))
world.SetConfig("APP/admin", A, null)
/proc/update_admins_from_api(reload_once_done=FALSE)
set background = TRUE
if (!establish_db_connection(dbcon))
log_and_message_admins("Failed to connect to database in update_admins_from_api(). Carrying on with old staff lists.")
return FALSE
var/list/admins_to_push = list()
for (var/rank_name in admin_ranks)
var/datum/admin_rank/rank = admin_ranks[rank_name]
var/datum/http_request/forumuser_api/req = new()
req.prepare_roles_query(rank.group_id)
req.begin_async()
UNTIL(req.is_complete())
var/datum/http_response/resp = req.into_response()
if (resp.errored)
crash_with("Role request errored for id [rank.group_id] with: [resp.error]")
log_and_message_admins("Loading admins from forumuser API FAILED. Please alert web-service maintainers immediately!")
return FALSE
for (var/datum/forum_user/user in resp.body)
admins_to_push += user
var/DBQuery/prep_query = dbcon.NewQuery("UPDATE ss13_admins SET status = 0")
prep_query.Execute()
for (var/user in admins_to_push)
insert_user_to_admins_table(user)
var/DBQuery/del_query = dbcon.NewQuery("DELETE FROM ss13_admins WHERE status = 0")
del_query.Execute()
if (reload_once_done)
load_admins()
return TRUE
/proc/insert_user_to_admins_table(datum/forum_user/user)
var/rights = 0
for (var/group_id in (user.forum_secondary_groups + user.forum_primary_group))
var/datum/admin_rank/r = forum_groupids_to_ranks["[group_id]"]
if (r)
rights |= r.rights
var/primary_rank = "Administrator"
if (forum_groupids_to_ranks["[user.forum_primary_group]"])
var/datum/admin_rank/r = forum_groupids_to_ranks["[user.forum_primary_group]"]
primary_rank = r.rank_name
var/DBQuery/query = dbcon.NewQuery("INSERT INTO ss13_admins VALUES (:ckey:, :rank:, :flags:, 1) ON DUPLICATE KEY UPDATE rank = :rank:, flags = :flags:, status = 1")
query.Execute(list("ckey" = ckey(user.ckey), "rank" = primary_rank, "flags" = rights))

View File

@@ -196,7 +196,6 @@ var/list/admin_verbs_debug = list(
/client/proc/cmd_debug_tog_aliens,
/client/proc/air_report,
/client/proc/reload_admins,
/client/proc/reload_mentors,
/client/proc/print_random_map,
/client/proc/create_random_map,
/client/proc/apply_random_map,
@@ -374,7 +373,6 @@ var/list/admin_verbs_hideable = list(
/client/proc/cmd_debug_tog_aliens,
/client/proc/air_report,
/client/proc/reload_admins,
/client/proc/reload_mentors,
/client/proc/restart_controller,
/client/proc/print_random_map,
/client/proc/create_random_map,
@@ -608,8 +606,7 @@ var/list/admin_verbs_cciaa = list(
set name = "Player Panel"
set category = "Admin"
if(holder)
if(!global_player_panel)
global_player_panel = new()
var/static/datum/vueui_module/player_panel/global_player_panel = new()
global_player_panel.ui_interact(usr)
feedback_add_details("admin_verb","PPM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return

View File

@@ -2,153 +2,248 @@
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()
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='?src=\ref[src];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='?src=\ref[src];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
output += "<td><a href='?src=\ref[src];editrights=rank;ckey=[adm_ckey]'>[rank]</a></td>"
output += "<td><a class='small' href='?src=\ref[src];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.admin_legacy_system) return
if(!usr.client)
if(!check_rights(R_PERMISSIONS))
return
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
to_chat(usr, "<span class='danger'>You do not have permission to do this!</span>")
var/static/datum/vueui_module/permissions_panel/global_permissions_panel = new()
global_permissions_panel.ui_interact(usr)
/datum/vueui_module/permissions_panel
/datum/vueui_module/permissions_panel/ui_interact(mob/user)
if (!check_rights(R_PERMISSIONS))
return
establish_db_connection(dbcon)
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
if(!ui)
ui = new(user, src, "admin-permissions-panel", 800, 600, "Permissions panel", state = interactive_state)
ui.header = "minimal"
ui.data = vueui_data_change(list(), user, ui)
if(!dbcon.IsConnected())
to_chat(usr, "<span class='warning'>Failed to establish database connection</span>")
ui.open()
/datum/vueui_module/permissions_panel/vueui_data_change(list/data, mob/user, datum/vueui/ui)
data = list()
var/list/admins = list()
for (var/admin_ckey in admin_datums)
var/datum/admins/D = admin_datums[admin_ckey]
if(!D)
continue
var/list/d = list()
d["ckey"] = admin_ckey
d["rank"] = D?.rank || "*none*"
d["rights"] = rights2text(D.rights, " ") || "*none*"
admins += list(d)
data["admins"] = admins
data["forumuserui_enabled"] = config.use_forumuser_api
return data
/datum/vueui_module/permissions_panel/Topic(href, href_list)
if (!check_rights(R_PERMISSIONS))
log_and_message_admins("attempted to edit the admin permissions without sufficient rights.")
return
if(!adm_ckey || !new_rank)
var/admin_ckey = ckey(href_list["ckey"])
var/action = href_list["action"]
var/datum/admins/D = admin_datums[admin_ckey]
if (action != "add" && (!admin_ckey || !D))
to_chat(usr, SPAN_NOTICE("No ckey specified or no such admin found."))
return
adm_ckey = ckey(adm_ckey)
if (action == "add")
action = "rank"
admin_ckey = _get_admin_ckey()
if(!adm_ckey)
if (!admin_ckey)
return
if (action == "remove")
_remove_admin(admin_ckey, D)
else if (action == "rank")
_edit_rank(admin_ckey, D)
else if (action == "rights")
_edit_rights(admin_ckey, D)
var/list/new_data = vueui_data_change()
for (var/U in SSvueui.get_open_uis(src))
var/datum/vueui/ui = U
if (ui.status <= STATUS_DISABLED)
continue
ui.push_change(new_data.Copy())
/datum/vueui_module/permissions_panel/proc/_remove_admin(admin_ckey, datum/admins/D)
PRIVATE_PROC(TRUE)
admin_datums -= admin_ckey
D.disassociate()
log_and_message_admins("removed [admin_ckey] from the admins list.")
log_admin_rank_modification(admin_ckey, "Removed")
/datum/vueui_module/permissions_panel/proc/_edit_rank(admin_ckey, datum/admins/D)
PRIVATE_PROC(TRUE)
var/new_rank
if(admin_ranks.len)
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (admin_ranks|"*New Rank*")
else
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in list("Game Master","Game Admin", "Trial Admin", "Admin Observer","*New Rank*")
var/rights = D?.rights || 0
switch(new_rank)
if(null, "")
return
if("*New Rank*")
new_rank = input("Please input a new rank", "New custom rank", null, null) as null|text
if(config.admin_legacy_system)
new_rank = ckeyEx(new_rank)
if(!new_rank)
to_chat(usr, SPAN_ALERT("Error editing rank: invalid rank."))
return
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
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, admin_ckey)
var/client/C = 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
log_and_message_admins("edited the admin rank of [admin_ckey] to [new_rank]")
log_admin_rank_modification(admin_ckey, new_rank)
/datum/vueui_module/permissions_panel/proc/_edit_rights(datum/admins/D, admin_ckey)
PRIVATE_PROC(TRUE)
if (!D)
return
if(!istext(adm_ckey) || !istext(new_rank))
var/list/permissionlist = list()
for(var/i = 1, i <= R_MAXPERMISSION, i <<= 1)
permissionlist[rights2text(i)] = i
var/new_permission = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in permissionlist
if(!new_permission)
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM `ss13_player` WHERE ckey = '[adm_ckey]' AND rank IS NOT NULL")
select_query.Execute()
D.rights ^= permissionlist[new_permission]
var/new_admin = 1
var/admin_id
while(select_query.NextRow())
new_admin = 0
admin_id = text2num(select_query.item[1])
log_and_message_admins("toggled the [new_permission] permission of [admin_ckey]")
log_admin_permission_modification(admin_ckey, permissionlist[new_permission])
if(new_admin)
var/DBQuery/update_query = dbcon.NewQuery("UPDATE `ss13_player` SET `rank` = '[new_rank]', flags = 0 WHERE ckey = '[adm_ckey]'")
update_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `ss13_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()
to_chat(usr, "<span class='notice'>New admin added.</span>")
else if(!isnull(admin_id) && isnum(admin_id) && new_rank != "Removed")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_player` SET rank = '[new_rank]' WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `ss13_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()
to_chat(usr, "<span class='notice'>Admin rank changed.</span>")
else if(!isnull(admin_id) && isnum(admin_id) && new_rank == "Removed")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_player` SET rank = NULL, flags = 0 WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `ss13_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed the rank of [adm_ckey]');")
log_query.Execute()
to_chat(usr, "<span class='notice'>Admin rank removed.</span>")
/datum/vueui_module/permissions_panel/proc/_get_admin_ckey()
PRIVATE_PROC(TRUE)
/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission)
if(config.admin_legacy_system) return
var/new_ckey = ckey(input(usr, "New admin's ckey", "Admin ckey", null) as text|null)
if(!new_ckey)
return ""
if(!usr.client)
if(new_ckey in admin_datums)
to_chat(usr, SPAN_ALERT("[new_ckey] is already an admin."))
return ""
return new_ckey
/datum/vueui_module/permissions_panel/proc/log_admin_rank_modification(admin_ckey, new_rank)
if (config.admin_legacy_system)
return
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
to_chat(usr, "<span class='warning'>You do not have permission to do this!</span>")
if (!check_rights(R_PERMISSIONS))
to_chat(usr, SPAN_DANGER("You do not have permission to do this!"))
return
establish_db_connection(dbcon)
if(!dbcon.IsConnected())
to_chat(usr, "<span class='warning'>Failed to establish database connection</span>")
if (!establish_db_connection(dbcon))
to_chat(usr, SPAN_WARNING("Failed to establish database connection."))
return
if(!adm_ckey || !new_permission)
if (!admin_ckey || !new_rank)
return
adm_ckey = ckey(adm_ckey)
admin_ckey = ckey(admin_ckey)
if(!adm_ckey)
if (!istext(admin_ckey) || !istext(new_rank))
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT ckey FROM `ss13_admins` WHERE ckey = :ckey:")
select_query.Execute(list("ckey" = admin_ckey))
var/new_admin = TRUE
if (select_query.NextRow())
new_admin = FALSE
if (new_admin)
var/DBQuery/update_query = dbcon.NewQuery("INSERT INTO `ss13_admins` VALUES (:ckey:, :rank:, 0)")
update_query.Execute(list("ckey" = admin_ckey, "rank" = new_rank))
to_chat(usr, SPAN_NOTICE("New admin added to the DB."))
else if (new_rank != "Removed")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admins` SET rank = :rank: WHERE ckey = :ckey:")
insert_query.Execute(list("ckey" = admin_ckey, "rank" = new_rank))
to_chat(usr, SPAN_NOTICE("Admin's rank changed."))
else if (new_rank == "Removed")
var/DBQuery/insert_query = dbcon.NewQuery("DELETE FROM ss13_admins WHERE ckey = :ckey:")
insert_query.Execute(list("ckey" = admin_ckey))
to_chat(usr, SPAN_NOTICE("Admin removed."))
/datum/vueui_module/permissions_panel/proc/log_admin_permission_modification(admin_ckey, new_permission)
if (config.admin_legacy_system)
return
if (!check_rights(R_PERMISSIONS))
to_chat(usr, SPAN_DANGER("You do not have permission to do this!"))
return
if (!establish_db_connection(dbcon))
to_chat(usr, SPAN_WARNING("Failed to establish database connection."))
return
if(!admin_ckey || !new_permission)
return
admin_ckey = ckey(admin_ckey)
if(istext(new_permission))
new_permission = text2num(new_permission)
if(!istext(adm_ckey) || !isnum(new_permission))
if(!istext(admin_ckey) || !isnum(new_permission))
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM ss13_player WHERE ckey = '[adm_ckey]'")
select_query.Execute()
var/DBQuery/select_query = dbcon.NewQuery("SELECT flags FROM ss13_admins WHERE ckey = :ckey:")
select_query.Execute(list("ckey" = admin_ckey))
var/admin_id
var/admin_rights
while(select_query.NextRow())
admin_id = text2num(select_query.item[1])
admin_rights = text2num(select_query.item[2])
if(!admin_id)
var/admin_rights = 0
if (select_query.NextRow())
admin_rights = text2num(select_query.item[1])
else
return
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_player` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `ss13_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()
to_chat(usr, "<span class='notice'>Permission removed.</span>")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admins` SET flags = :flags: WHERE ckey = :ckey:")
insert_query.Execute(list("flags" = admin_rights & ~new_permission, "ckey" = admin_ckey))
to_chat(usr, SPAN_NOTICE("Permission removed."))
else //This admin doesn't have this permission, so we are adding it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_player` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `ss13_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()
to_chat(usr, "<span class='notice'>Permission added.</span>")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admins` SET flags = :flags: WHERE ckey = :ckey:")
insert_query.Execute(list("flags" = admin_rights | new_permission, "ckey" = admin_ckey))
to_chat(usr, SPAN_NOTICE("Permission added."))

View File

@@ -29,11 +29,9 @@
else
alert("The game hasn't started yet!")
var/datum/vueui_module/player_panel/global_player_panel
/datum/vueui_module/player_panel
var/something = TRUE
/datum/vueui_module/player_panel/ui_interact(var/mob/user)
/datum/vueui_module/player_panel/ui_interact(mob/user)
if (!usr.client.holder)
return
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)

View File

@@ -109,100 +109,6 @@
toggle_mirror_status(usr, mirror_id, text2num(href_list["mirrorstatus"]))
return
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.",admin_key=key_name(usr))
return
var/adm_ckey
var/task = href_list["editrights"]
if(task == "add")
var/new_ckey = ckey(input(usr,"New admin's ckey","Admin ckey", null) as text|null)
if(!new_ckey) return
if(new_ckey in admin_datums)
to_chat(usr, "<font color='red'>Error: Topic 'editrights': [new_ckey] is already an admin</font>")
return
adm_ckey = new_ckey
task = "rank"
else if(task != "show")
adm_ckey = ckey(href_list["ckey"])
if(!adm_ckey)
to_chat(usr, "<font color='red'>Error: Topic 'editrights': No valid ckey</font>")
return
var/datum/admins/D = admin_datums[adm_ckey]
if(task == "remove")
if(alert("Are you sure you want to remove [adm_ckey]?","Message","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",admin_key=key_name(usr))
log_admin_rank_modification(adm_ckey, "Removed")
else if(task == "rank")
var/new_rank
if(admin_ranks.len)
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (admin_ranks|"*New Rank*")
else
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in 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 = input("Please input a new rank", "New custom rank", null, null) as null|text
if(config.admin_legacy_system)
new_rank = ckeyEx(new_rank)
if(!new_rank)
to_chat(usr, "<font color='red'>Error: Topic 'editrights': Invalid rank</font>")
return
if(config.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.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 = 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]",admin_key=key_name(usr))
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 = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in 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]", admin_key=key_name(usr))
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
edit_admin_permissions()
else if(href_list["call_shuttle"])
if(!check_rights(R_ADMIN)) return

View File

@@ -102,22 +102,13 @@
set name = "Reload Admins"
set category = "Debug"
if(!check_rights(R_SERVER|R_DEV)) return
if(!check_rights(R_SERVER|R_DEV))
return
message_admins("[usr] manually reloaded admins")
load_admins()
feedback_add_details("admin_verb","RLDA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/reload_mentors()
set name = "Reload Mentors"
set category = "Debug"
if(!check_rights(R_SERVER)) return
message_admins("[usr] manually reloaded Mentors")
world.load_mods()
//todo:
/client/proc/jump_to_dead_group()
set name = "Jump to dead group"

View File

@@ -0,0 +1,65 @@
var/global/forumuser_api_key = null
/datum/forum_user
var/forum_member_id
var/forum_name
var/forum_primary_group
var/list/forum_secondary_groups = list()
var/discord_id
var/ckey
/datum/forum_user/New(data)
forum_member_id = data["forum_member_id"]
forum_name = data["forum_name"]
forum_primary_group = data["forum_primary_group"]
for (var/id in splittext(data["forum_secondary_groups"], ","))
forum_secondary_groups += text2num(id)
discord_id = data["discord_id"]
ckey = data["ckey"]
/datum/http_request/forumuser_api
/datum/http_request/forumuser_api/proc/prepare_roles_query(role_id)
var/url = "[config.forumuser_api_url]/staff/[role_id]"
var/list/headers = list("Authorization" = "Bearer [forumuser_api_key]")
prepare(RUSTG_HTTP_METHOD_GET, url, headers=headers)
/datum/http_request/forumuser_api/proc/prepare_user_discord(discord_id)
var/url = "[config.forumuser_api_url]/user/discord/[discord_id]"
var/list/headers = list("Authorization" = "Bearer [forumuser_api_key]")
prepare(RUSTG_HTTP_METHOD_GET, url, headers=headers)
/datum/http_request/forumuser_api/proc/prepare_user_ckey(ckey)
var/url = "[config.forumuser_api_url]/user/ckey/[ckey]"
var/list/headers = list("Authorization" = "Bearer [forumuser_api_key]")
prepare(RUSTG_HTTP_METHOD_GET, url, headers=headers)
/datum/http_request/forumuser_api/into_response()
var/datum/http_response/R = ..()
if (R.errored)
return R
try
R.body = json_decode(R.body)
catch
R.errored = TRUE
R.error = "Malformed JSON returned."
return R
var/list/users = list()
for (var/d in R.body)
users += new /datum/forum_user(d)
R.body = users
return R

View File

@@ -120,3 +120,29 @@
statuscode = 200
response = "Text sent"
return TRUE
//Reloads all admins via remote command. Updates from the forumuser API if enabled.
/datum/topic_command/admins_reload
name = "admins_reload"
description = "Reloads all admins and pulls new data from the forumuser API if it's enabled."
params = list(
"senderkey" = list("name"="senderkey","desc"="A display friendly name for the sender.","req"=1,"type"="str")
)
/datum/topic_command/broadcast_text/run_command(queryparams)
log_and_message_admins("[queryparams["senderkey"]] initiated a remote reload of the admins list.")
if (config.use_forumuser_api)
if (!update_admins_from_api(reload_once_done=FALSE))
statuscode = 500
response = "Updating admins from the forumuser API failed. Aborted."
return FALSE
else
statuscode = 201
response = "Admins updated from the forumuser API and reloaded."
else
statuscode = 200
response = "Admins reloaded."
load_admins()
return TRUE

View File

@@ -82,9 +82,6 @@ var/global/datum/global_init/init = new ()
config.server_name += " #[(world.port % 1000) / 100]"
callHook("startup")
//Emergency Fix
load_mods()
//end-emergency fix
. = ..()
@@ -294,52 +291,6 @@ var/list/world_api_rate_limit = list()
if (config.age_restrictions_from_file)
config.load("config/age_restrictions.txt", "age_restrictions")
/hook/startup/proc/loadMods()
world.load_mods()
world.load_mentors() // no need to write another hook.
return 1
/world/proc/load_mods()
if(config.admin_legacy_system)
var/text = file2text("config/moderators.txt")
if (!text)
error("Failed to load config/mods.txt")
else
var/list/lines = text2list(text, "\n")
for(var/line in lines)
if (!line)
continue
if (copytext(line, 1, 2) == ";")
continue
var/title = "Moderator"
var/rights = admin_ranks[title]
var/ckey = copytext(line, 1, length(line)+1)
var/datum/admins/D = new /datum/admins(title, rights, ckey)
D.associate(directory[ckey])
/world/proc/load_mentors()
if(config.admin_legacy_system)
var/text = file2text("config/mentors.txt")
if (!text)
error("Failed to load config/mentors.txt")
else
var/list/lines = text2list(text, "\n")
for(var/line in lines)
if (!line)
continue
if (copytext(line, 1, 2) == ";")
continue
var/title = "Mentor"
var/rights = admin_ranks[title]
var/ckey = copytext(line, 1, length(line)+1)
var/datum/admins/D = new /datum/admins(title, rights, ckey)
D.associate(directory[ckey])
/world/proc/update_status()
var/list/s = list()
@@ -349,7 +300,6 @@ var/list/world_api_rate_limit = list()
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"[config.forumurl]\">" //Change this to wherever you want the hub to link to.
// s += "[game_version]"
s += "Forums" //Replace this with something else. Or ever better, delete it and uncomment the game version.
s += "</a>"
s += ")"

View File

@@ -0,0 +1,62 @@
[
{
"role_id": 4,
"name": "Head Admin/Dev",
"auths": [
"R_ALL"
]
},
{
"role_id": 18,
"name": "Primary Administrator",
"auths": [
"R_BUILDMODE", "R_ADMIN", "R_BAN", "R_FUN", "R_STEALTH", "R_SERVER",
"R_REJUVINATE", "R_VAREDIT", "R_SOUND", "R_SPAWN", "R_PERMISSIONS",
"R_MODERATOR", "R_DEVELOPER", "R_CCIAA", "R_DEBUG"
]
},
{
"role_id": 8,
"name": "Secondary Administrator",
"auths": [
"R_BUILDMODE", "R_ADMIN", "R_BAN", "R_FUN", "R_STEALTH", "R_SERVER",
"R_REJUVINATE", "R_VAREDIT", "R_SOUND", "R_SPAWN", "R_MODERATOR",
"R_DEVELOPER", "R_CCIAA"
]
},
{
"role_id": 6,
"name": "Moderator",
"auths": [
"R_MODERATOR", "R_BAN"
]
},
{
"role_id": 22,
"name": "Trial Moderator",
"auths": [
"R_MODERATOR"
]
},
{
"role_id": 9,
"name": "Developer",
"auths": [
"R_DEVELOPER"
]
},
{
"role_id": 13,
"name": "CCIA Agent",
"auths": [
"R_CCIAA"
]
},
{
"role_id": 16,
"name": "CCIA Leader",
"auths": [
"R_CCIAA"
]
}
]

View File

@@ -1,45 +0,0 @@
########################################################################################
# ADMIN RANK DEFINES #
# The format of this is very simple. Rank name goes first. #
# Rank is CASE-SENSITIVE, all punctuation will be stripped so spaces don't matter. #
# Each rank is then followed by keywords with the prefix "+". #
# These keywords represent groups of verbs and abilities which are given to that rank. #
# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #
# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #
########################################################################################
# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!
# ALSO NOTE: this is a WorkInProgress at the moment. Most of this is just arbitrarily thrown in whatever group because LoadsaWork2Do+LittleTime.
# I'll be doing more moving around as feedback comes in. So be sure to check the notes after updates.
# KEYWORDS:
# +ADMIN = general admin tools, verbs etc
# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.
# +BAN = the ability to ban, jobban and fullban
# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins
# +POSSESS = the ability to possess objects
# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode
# +BUILD (or +BUILDMODE) = the ability to use buildmode
# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration.
# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.
# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.
# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people.
# +SOUND (or +SOUNDS) = allows you to upload and play sounds
# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too)
# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag
Admin Observer
Moderator +MOD
Mentor +MENTOR
Admin Candidate +ADMIN
Trial Admin +@ +SPAWN +REJUV +VAREDIT +BAN
Badmin +@ +POSSESS +BUILDMODE +SERVER +FUN
Game Admin +@ +STEALTH +SOUNDS +DEBUG +PERMISSIONS
Game Master +EVERYTHING
Head Admin +EVERYTHING
Retired Admin +ADMIN +STEALTH
Host +EVERYTHING
Developer +DEBUG +VAREDIT +SERVER +SPAWN +REJUV +POSSESS +BUILDMODE
Dev Mod +@ +MOD

View File

@@ -591,3 +591,14 @@ FAIL2TOPIC_ENABLED 0
## gets dumped. Time is in DECISECONDS (1/10th of a second). Might not be wise to
## use a value less than 10.
#PROFILER_TIMEOUT_THRESHOLD 20
### Forumuser API configuration
### Enables the updating of the ss13_admins table from the forumuser API.
### You can think of this as LDAP for admin ranks: a single central repo is
### used for multiple different services.
## Uncomment this to enable the use of the system. SQL admins MUST be enabled for this to work.
#USE_FORUMUSER_API
## The base URL of the API. Without a trailing slash.
#FORUMUSER_API_URL
## The API key of the system.
#FORUMUSER_API_KEY

View File

@@ -0,0 +1,6 @@
author: Skull132
delete-after: True
changes:
- backend: "Added support for an external API for updating the ingame staff list."
- refactor: "Permissions Panel is now a VueUI panel."

View File

@@ -0,0 +1,34 @@
<template>
<div>
<div v-if="forumuserui_enabled" class="notice">
<center>Modifications done do not outlast the round! Use the forums/WI to modify ranks.</center>
</div>
<table>
<tr>
<th>Ckey <vui-button :params="{ action: 'add' }">Add</vui-button></th>
<th>Rank</th>
<th>Permissions</th>
</tr>
<tr v-for="admin in admins" :key="admin.ckey">
<td>
<vui-button :params="{ action: 'remove', ckey: admin.ckey }">Edit</vui-button> {{admin.ckey}}
</td>
<td>
<vui-button :params="{ action: 'rank', ckey: admin.ckey }">Edit</vui-button> {{admin.rank}}
</td>
<td>
<vui-button :params="{ action: 'rights', ckey: admin.ckey }">Edit</vui-button> {{admin.rights}}
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
data() {
return this.$root.$data.state
}
}
</script>

View File

@@ -90,4 +90,3 @@ export default {
}
</style>