mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 03:57:13 +01:00
Make DB admin ranks more useful (#29906)
* Make DB admin ranks more useful * Avoid error message when cancelling permission toggle, allow adding localhost admins as real admins. * Lint. * Don't SQL error when a previously-unseen player connects. * Use ckey of permission editor, not mob name. * Strikethrough * Order in the list. * Deadmin, readmin, and 2fa. * Correct merge error --------- Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
+21
-4
@@ -171,14 +171,32 @@ DROP TABLE IF EXISTS `admin`;
|
||||
CREATE TABLE `admin` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`ckey` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`admin_rank` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Administrator',
|
||||
`level` int(2) NOT NULL DEFAULT '0',
|
||||
`flags` int(16) NOT NULL DEFAULT '0',
|
||||
`display_rank` varchar(32) COLLATE utf8mb4_unicode_ci,
|
||||
`permissions_rank` int(11) COMMENT 'Foreign key for admin_ranks.id',
|
||||
`extra_permissions` int(16) NOT NULL DEFAULT '0',
|
||||
`removed_permissions` int(16) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ckey` (`ckey`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=99 DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
|
||||
--
|
||||
-- Table structure for table `admin_ranks`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `admin_ranks`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `admin_ranks` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`default_permissions` int(16) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=99 DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `admin_log`
|
||||
--
|
||||
@@ -273,7 +291,6 @@ CREATE TABLE `player` (
|
||||
`lastseen` datetime NOT NULL,
|
||||
`ip` varchar(18) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`computerid` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`lastadminrank` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Player',
|
||||
`ooccolor` varchar(7) COLLATE utf8mb4_unicode_ci DEFAULT '#b82e00',
|
||||
`UI_style` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT 'Midnight',
|
||||
`UI_style_color` varchar(7) COLLATE utf8mb4_unicode_ci DEFAULT '#ffffff',
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Updating DB from 69-70 -FunnyMan3595
|
||||
# Adds the admin_ranks table
|
||||
|
||||
# Create the new table.
|
||||
CREATE TABLE `admin_ranks` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`default_permissions` int(16) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=99 DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
# Create official ranks for every existing display rank, with the minimum common permissions.
|
||||
INSERT INTO admin_ranks (name, default_permissions)
|
||||
SELECT admin_rank, BIT_AND(flags) FROM admin GROUP BY admin_rank;
|
||||
|
||||
# Add new columns to admin table.
|
||||
ALTER TABLE admin
|
||||
ADD COLUMN `display_rank` varchar(32) COLLATE utf8mb4_unicode_ci,
|
||||
ADD COLUMN `permissions_rank` int(11) COMMENT 'Foreign key for admin_ranks.id',
|
||||
ADD COLUMN `extra_permissions` int(16) NOT NULL DEFAULT '0',
|
||||
ADD COLUMN `removed_permissions` int(16) NOT NULL DEFAULT '0';
|
||||
|
||||
# Set the rank and any extra_permissions for each admin.
|
||||
# There won't be any removed_permissions because we took the minimum common permissions earlier.
|
||||
# We also leave display_rank blank, since admin_ranks.name matches their old admin_rank.
|
||||
UPDATE admin JOIN admin_ranks ON admin.admin_rank = admin_ranks.name
|
||||
SET
|
||||
admin.permissions_rank = admin_ranks.id,
|
||||
admin.extra_permissions = admin.flags & ~admin_ranks.default_permissions;
|
||||
|
||||
# Drop the old columns from the admin table.
|
||||
ALTER TABLE admin
|
||||
DROP COLUMN admin_rank,
|
||||
DROP COLUMN level,
|
||||
DROP COLUMN flags;
|
||||
|
||||
# Drop the lastadminrank column from the player table.
|
||||
ALTER TABLE player DROP COLUMN lastadminrank;
|
||||
@@ -41,7 +41,7 @@
|
||||
#define R_MAINTAINER (1<<17)
|
||||
#define R_DEV_TEAM (1<<18)
|
||||
#define R_VIEWLOGS (1<<19)
|
||||
// Update the following two defines if you add more
|
||||
// Update the following two defines and GLOB.admin_permission_names if you add more
|
||||
|
||||
#define R_MAXPERMISSION (1<<19) // This holds the maximum value for a permission. It is used in iteration, so keep it updated.
|
||||
|
||||
|
||||
@@ -438,7 +438,7 @@
|
||||
#define INVESTIGATE_DEATHS "deaths"
|
||||
|
||||
// The SQL version required by this version of the code
|
||||
#define SQL_VERSION 69
|
||||
#define SQL_VERSION 70
|
||||
|
||||
// Vending machine stuff
|
||||
#define CAT_NORMAL (1<<0)
|
||||
|
||||
+18
-23
@@ -34,7 +34,7 @@
|
||||
num_list += text2num(x)
|
||||
return num_list
|
||||
|
||||
//Splits the text of a file at seperator and returns them in a list.
|
||||
//Splits the text of a file at separator and returns them in a list.
|
||||
/proc/file2list(filename, separator = "\n", no_empty = TRUE)
|
||||
var/list/result = list()
|
||||
for(var/line in splittext(return_file_text(filename), separator))
|
||||
@@ -132,28 +132,23 @@
|
||||
if(BLEND_SUBTRACT) return ICON_SUBTRACT
|
||||
else return ICON_OVERLAY
|
||||
|
||||
//Converts a rights bitfield into a string
|
||||
/proc/rights2text(rights,seperator="")
|
||||
if(rights & R_BUILDMODE) . += "[seperator]+BUILDMODE"
|
||||
if(rights & R_ADMIN) . += "[seperator]+ADMIN"
|
||||
if(rights & R_BAN) . += "[seperator]+BAN"
|
||||
if(rights & R_EVENT) . += "[seperator]+EVENT"
|
||||
if(rights & R_SERVER) . += "[seperator]+SERVER"
|
||||
if(rights & R_DEBUG) . += "[seperator]+DEBUG"
|
||||
if(rights & R_POSSESS) . += "[seperator]+POSSESS"
|
||||
if(rights & R_PERMISSIONS) . += "[seperator]+PERMISSIONS"
|
||||
if(rights & R_STEALTH) . += "[seperator]+STEALTH"
|
||||
if(rights & R_REJUVINATE) . += "[seperator]+REJUVINATE"
|
||||
if(rights & R_VAREDIT) . += "[seperator]+VAREDIT"
|
||||
if(rights & R_SOUNDS) . += "[seperator]+SOUND"
|
||||
if(rights & R_SPAWN) . += "[seperator]+SPAWN"
|
||||
if(rights & R_PROCCALL) . += "[seperator]+PROCCALL"
|
||||
if(rights & R_MOD) . += "[seperator]+MODERATOR"
|
||||
if(rights & R_MENTOR) . += "[seperator]+MENTOR"
|
||||
if(rights & R_VIEWRUNTIMES) . += "[seperator]+VIEWRUNTIMES"
|
||||
if(rights & R_MAINTAINER) . += "[seperator]+MAINTAINER"
|
||||
if(rights & R_DEV_TEAM) . += "[seperator]+DEV_TEAM"
|
||||
if(rights & R_VIEWLOGS) . += "[seperator]+VIEWLOGS"
|
||||
///Converts a rights bitfield into a string
|
||||
/proc/rights2text(rights,separator="")
|
||||
. = ""
|
||||
for(var/bit in GLOB.admin_permission_names)
|
||||
if(rights & bit)
|
||||
. += "[separator]+[GLOB.admin_permission_names[bit]]"
|
||||
|
||||
///Converts the full permissions details of a DB-ranked admin to a HTML-colored string
|
||||
/proc/ranked_rights2text(rank_rights, extra_rights, removed_rights, separator="")
|
||||
. = ""
|
||||
for(var/bit in GLOB.admin_permission_names)
|
||||
if(removed_rights & bit)
|
||||
. += "[separator]<span style='color: #FF5555'><s>-[GLOB.admin_permission_names[bit]]</s></span>"
|
||||
else if(extra_rights & bit)
|
||||
. += "[separator]<span style='color: #5555FF'>+[GLOB.admin_permission_names[bit]]</span>"
|
||||
else if(rank_rights & bit)
|
||||
. += "[separator]<span style='color: #FF55FF'>+[GLOB.admin_permission_names[bit]]</span>"
|
||||
|
||||
/proc/ui_style2icon(ui_style)
|
||||
switch(ui_style)
|
||||
|
||||
@@ -73,3 +73,28 @@ GLOBAL_LIST_EMPTY(rnd_tech_id_to_name)
|
||||
|
||||
/// List of things that restrain teslas.
|
||||
GLOBAL_LIST_EMPTY(tesla_containment)
|
||||
|
||||
/// Assoc list of admin permission names
|
||||
GLOBAL_LIST_INIT(admin_permission_names, alist(
|
||||
R_BUILDMODE = "BUILDMODE",
|
||||
R_ADMIN = "ADMIN",
|
||||
R_BAN = "BAN",
|
||||
R_EVENT = "EVENT",
|
||||
R_SERVER = "SERVER",
|
||||
R_DEBUG = "DEBUG",
|
||||
R_POSSESS = "POSSESS",
|
||||
R_PERMISSIONS = "PERMISSIONS",
|
||||
R_STEALTH = "STEALTH",
|
||||
R_REJUVINATE = "REJUVINATE",
|
||||
R_VAREDIT = "VAREDIT",
|
||||
R_SOUNDS = "SOUNDS",
|
||||
R_SPAWN = "SPAWN",
|
||||
R_MOD = "MOD",
|
||||
R_MENTOR = "MENTOR",
|
||||
R_PROCCALL = "PROCCALL",
|
||||
R_VIEWRUNTIMES = "VIEWRUNTIMES",
|
||||
R_MAINTAINER = "MAINTAINER",
|
||||
R_DEV_TEAM = "DEV_TEAM",
|
||||
R_VIEWLOGS = "VIEWLOGS",
|
||||
))
|
||||
GLOBAL_PROTECT(admin_permission_names)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
if(islist(data["admin_assignments"]))
|
||||
ckey_rank_map.Cut()
|
||||
for(var/list/kvset in data["admin_assignments"])
|
||||
ckey_rank_map[kvset["ckey"]] = kvset["rank"]
|
||||
ckey_rank_map[ckey(kvset["ckey"])] = kvset["rank"]
|
||||
|
||||
// Load admin colours
|
||||
if(islist(data["admin_rank_colour_map"]))
|
||||
|
||||
@@ -585,7 +585,7 @@ UI STUFF
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(ckey(X.ckey) == ckey(T.client_ckey))
|
||||
continue
|
||||
if(!check_rights_for(X, rights_needed))
|
||||
if(!check_rights_client(rights_needed, FALSE, X))
|
||||
continue
|
||||
for(var/key in X.pm_tracker.pms)
|
||||
if(ckey(key) != ckey(T.client_ckey))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#define COMM_MSGLEN_MINIMUM 6
|
||||
#define COMM_CCMSGLEN_MINIMUM 20
|
||||
|
||||
#define ADMIN_CHECK(user) (check_rights_all(R_ADMIN|R_EVENT, FALSE, user) && (authenticated >= COMM_AUTHENTICATION_CENTCOM || user.can_admin_interact()))
|
||||
#define ADMIN_CHECK(user) (check_rights(R_ADMIN|R_EVENT, FALSE, user, all = TRUE) && (authenticated >= COMM_AUTHENTICATION_CENTCOM || user.can_admin_interact()))
|
||||
|
||||
// The communications computer
|
||||
/obj/machinery/computer/communications
|
||||
@@ -56,7 +56,7 @@
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/communications/proc/is_authenticated(mob/user, message = 1)
|
||||
if(check_rights_all(R_ADMIN|R_EVENT, FALSE, user))
|
||||
if(check_rights(R_ADMIN|R_EVENT, FALSE, user, all = TRUE))
|
||||
if(user.can_admin_interact())
|
||||
return COMM_AUTHENTICATION_AGHOST
|
||||
if(authenticated == COMM_AUTHENTICATION_CENTCOM)
|
||||
@@ -109,7 +109,7 @@
|
||||
if(ACCESS_CAPTAIN in access)
|
||||
authenticated = COMM_AUTHENTICATION_CAPT
|
||||
if(ACCESS_CENT_COMMANDER in access)
|
||||
if(!check_rights_all(R_ADMIN|R_EVENT, FALSE, ui.user))
|
||||
if(!check_rights(R_ADMIN|R_EVENT, FALSE, ui.user, all = TRUE))
|
||||
to_chat(ui.user, "<span class='warning'>[src] buzzes, invalid central command clearance.</span>")
|
||||
return
|
||||
authenticated = COMM_AUTHENTICATION_CENTCOM
|
||||
|
||||
@@ -48,41 +48,119 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
/proc/reload_one_admin(admin_ckey, silent = FALSE)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounce'>Admin reload blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to reload an admin via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to reload an admin via advanced proc-call")
|
||||
return
|
||||
|
||||
// Make sure it's actually in ckey format.
|
||||
admin_ckey = ckey(admin_ckey)
|
||||
|
||||
// Remove any existing permissions.
|
||||
var/datum/admins/admin_datum = GLOB.admin_datums[admin_ckey]
|
||||
if(admin_datum)
|
||||
qdel(admin_datum)
|
||||
|
||||
if(admin_ckey in (GLOB.de_admins + GLOB.de_mentors))
|
||||
if(!silent)
|
||||
message_admins("<span class='notice'>Admin permissions for [admin_ckey] will reload when they re-admin.</span>")
|
||||
return
|
||||
|
||||
if(admin_ckey in GLOB.directory)
|
||||
var/client/admin = GLOB.directory[admin_ckey]
|
||||
var/localhosted = admin.try_localhost_autoadmin()
|
||||
if(localhosted)
|
||||
if(!silent)
|
||||
message_admins("<span class='notice'>Admin permissions for [admin_ckey] reloaded. Full permissions granted as they are currently connected from localhost.</span>")
|
||||
return
|
||||
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
var/datum/db_query/get_admin = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
-- Use the display_rank if set, otherwise the name of their permissions_rank.
|
||||
IFNULL(admin.display_rank, admin_ranks.name),
|
||||
-- Permissions start with their admin rank permissions (if any)
|
||||
(IFNULL(admin_ranks.default_permissions, 0)
|
||||
-- Then add in any extra permissions they've been granted.
|
||||
| admin.extra_permissions)
|
||||
-- And exclude any permissions they've had removed.
|
||||
& ~admin.removed_permissions
|
||||
FROM admin
|
||||
-- We want all admins, and admin_ranks where available.
|
||||
LEFT OUTER JOIN admin_ranks
|
||||
ON admin.permissions_rank = admin_ranks.id
|
||||
WHERE admin.ckey=:admin_ckey"}, list(
|
||||
"admin_ckey" = admin_ckey
|
||||
))
|
||||
if(!get_admin.warn_execute())
|
||||
qdel(get_admin)
|
||||
return
|
||||
|
||||
if(get_admin.NextRow())
|
||||
var/rank = get_admin.item[1]
|
||||
var/rights = get_admin.item[2]
|
||||
if(rights == 0)
|
||||
// If you have no rights, you don't get an admin datum.
|
||||
qdel(get_admin)
|
||||
if(!silent)
|
||||
message_admins("<span class='notice'>Admin permissions for [admin_ckey] have been reloaded.</span>")
|
||||
return
|
||||
admin_datum = new(rank, rights, admin_ckey)
|
||||
qdel(get_admin)
|
||||
else
|
||||
var/rank = GLOB.configuration.admin.ckey_rank_map[admin_ckey]
|
||||
|
||||
// Load permissions associated with this rank
|
||||
var/rights = GLOB.admin_ranks[rank]
|
||||
|
||||
// Create their admin datum.
|
||||
admin_datum = new /datum/admins(rank, rights, admin_ckey)
|
||||
|
||||
// Set up their permissions.
|
||||
if(admin_datum)
|
||||
admin_datum.associate(GLOB.directory[admin_ckey])
|
||||
|
||||
if(admin_ckey in GLOB.directory)
|
||||
var/client/admin = GLOB.directory[admin_ckey]
|
||||
to_chat(admin, "Holder? [admin.holder] Permissions? [admin.holder?.rights]")
|
||||
if(!silent)
|
||||
message_admins("<span class='notice'>Admin permissions for [admin_ckey] have been reloaded.</span>")
|
||||
|
||||
/proc/load_admins(run_async = FALSE)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounce'>Admin reload blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to reload admins via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to reload admins via advanced proc-call")
|
||||
return
|
||||
//clear the datums references
|
||||
|
||||
// Revoke all permissions.
|
||||
var/list/localhost_admins = list()
|
||||
for(var/datum/admins/admin_datum in GLOB.admin_datums)
|
||||
if(admin_datum.is_localhost_autoadmin && admin_datum.owner)
|
||||
localhost_admins += admin_datum.owner
|
||||
qdel(admin_datum)
|
||||
GLOB.admin_datums.Cut()
|
||||
for(var/client/C in GLOB.admins)
|
||||
C.hide_verbs()
|
||||
C.holder = null
|
||||
GLOB.admins.Cut()
|
||||
|
||||
// Remove all profiler access
|
||||
// Just to be double-sure, revoke all profiler access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
load_admin_ranks()
|
||||
|
||||
//process each line seperately
|
||||
for(var/iterator_key in GLOB.configuration.admin.ckey_rank_map)
|
||||
var/ckey = ckey(iterator_key) // Snip out formatting
|
||||
var/rank = GLOB.configuration.admin.ckey_rank_map[iterator_key]
|
||||
for(var/ckey in GLOB.configuration.admin.ckey_rank_map)
|
||||
var/rank = GLOB.configuration.admin.ckey_rank_map[ckey]
|
||||
|
||||
//load permissions associated with this rank
|
||||
// Load permissions associated with this rank
|
||||
var/rights = GLOB.admin_ranks[rank]
|
||||
|
||||
//create the admin datum and store it for later use
|
||||
// Create their admin datum.
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
if(D.rights & R_DEBUG || D.rights & R_VIEWRUNTIMES) // Grants profiler access to anyone with R_DEBUG or R_VIEWRUNTIMES
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
// Set up their admin permissions.
|
||||
D.associate(GLOB.directory[ckey])
|
||||
|
||||
else
|
||||
@@ -93,34 +171,47 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
load_admins()
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, admin_rank, level, flags FROM admin")
|
||||
if(!query.warn_execute(async=run_async))
|
||||
qdel(query)
|
||||
var/datum/db_query/get_admins = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
admin.ckey,
|
||||
-- Use the display_rank if set, otherwise the name of their permissions_rank.
|
||||
IFNULL(admin.display_rank, admin_ranks.name),
|
||||
-- Permissions start with their admin rank permissions (if any)
|
||||
(IFNULL(admin_ranks.default_permissions, 0)
|
||||
-- Then add in any extra permissions they've been granted.
|
||||
| admin.extra_permissions)
|
||||
-- And exclude any permissions they've had removed.
|
||||
& ~admin.removed_permissions
|
||||
FROM admin
|
||||
-- We want all admins, and admin_ranks where available.
|
||||
LEFT OUTER JOIN admin_ranks
|
||||
ON admin.permissions_rank = admin_ranks.id"})
|
||||
if(!get_admins.warn_execute(async=run_async))
|
||||
qdel(get_admins)
|
||||
return
|
||||
|
||||
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)
|
||||
while(get_admins.NextRow())
|
||||
var/ckey = get_admins.item[1]
|
||||
var/rank = get_admins.item[2]
|
||||
var/rights = get_admins.item[3]
|
||||
if(rights == 0)
|
||||
// If you have no rights, you don't get an admin datum.
|
||||
continue
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
if(D.rights & R_DEBUG || D.rights & R_VIEWRUNTIMES) // Grants profiler access to anyone with R_DEBUG or R_VIEWRUNTIMES
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
// Set up their admin permissions.
|
||||
D.associate(GLOB.directory[ckey])
|
||||
qdel(get_admins)
|
||||
|
||||
qdel(query)
|
||||
|
||||
if(!GLOB.admin_datums)
|
||||
if(!length(GLOB.admin_datums))
|
||||
log_world("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
GLOB.configuration.admin.use_database_admins = FALSE
|
||||
load_admins()
|
||||
return
|
||||
|
||||
for(var/client/localhost_admin in localhost_admins)
|
||||
localhost_admin.try_localhost_autoadmin()
|
||||
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
|
||||
@@ -879,119 +879,10 @@ GLOBAL_LIST_INIT(view_logs_verbs, list(
|
||||
|
||||
log_admin("[key_name(usr)] deadmined themself.")
|
||||
message_admins("[key_name_admin(usr)] deadmined themself.")
|
||||
if(check_rights(R_ADMIN, FALSE))
|
||||
GLOB.de_admins += ckey
|
||||
else
|
||||
GLOB.de_mentors += ckey
|
||||
deadmin()
|
||||
add_verb(src, /client/proc/readmin)
|
||||
update_active_keybindings()
|
||||
to_chat(src, "<span class='interface'>You are now a normal player.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "De-admin") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/readmin()
|
||||
set name = "Re-admin self"
|
||||
set category = "Admin"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
var/rank = null
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
for(var/iterator_key in GLOB.configuration.admin.ckey_rank_map)
|
||||
var/_ckey = ckey(iterator_key) // Snip out formatting
|
||||
if(ckey != _ckey)
|
||||
continue
|
||||
rank = GLOB.configuration.admin.ckey_rank_map[iterator_key]
|
||||
break
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(src, "Warning, MYSQL database is not connected.")
|
||||
return
|
||||
|
||||
var/datum/db_query/rank_read = SSdbcore.NewQuery(
|
||||
"SELECT admin_rank FROM admin WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
if(!rank_read.warn_execute())
|
||||
qdel(rank_read)
|
||||
return FALSE
|
||||
|
||||
while(rank_read.NextRow())
|
||||
rank = ckeyEx(rank_read.item[1])
|
||||
|
||||
qdel(rank_read)
|
||||
if(!D)
|
||||
D = try_localhost_autoadmin()
|
||||
if(!D)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
if(GLOB.admin_ranks[rank] == null)
|
||||
error("Error while re-adminning [src], admin rank ([rank]) does not exist.")
|
||||
to_chat(src, "Error while re-adminning, admin rank ([rank]) does not exist.")
|
||||
return
|
||||
|
||||
// Do a little check here
|
||||
if(GLOB.configuration.system.is_production && (GLOB.admin_ranks[rank] & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
to_chat(src,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
return
|
||||
D = new(rank, GLOB.admin_ranks[rank], ckey)
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(src, "Warning, MYSQL database is not connected.")
|
||||
return
|
||||
|
||||
var/datum/db_query/admin_read = SSdbcore.NewQuery(
|
||||
"SELECT ckey, admin_rank, flags FROM admin WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
if(!admin_read.warn_execute())
|
||||
qdel(admin_read)
|
||||
return FALSE
|
||||
|
||||
while(admin_read.NextRow())
|
||||
var/admin_ckey = admin_read.item[1]
|
||||
var/admin_rank = admin_read.item[2]
|
||||
var/flags = admin_read.item[3]
|
||||
if(!admin_ckey)
|
||||
to_chat(src, "Error while re-adminning, ckey [admin_ckey] was not found in the admin database.")
|
||||
qdel(admin_read)
|
||||
return
|
||||
if(admin_rank == "Removed") //This person was de-adminned. They are only in the admin list for archive purposes.
|
||||
to_chat(src, "Error while re-adminning, ckey [admin_ckey] is not an admin.")
|
||||
qdel(admin_read)
|
||||
return
|
||||
|
||||
if(istext(flags))
|
||||
flags = text2num(flags)
|
||||
var/client/check_client = GLOB.directory[ckey]
|
||||
// Do a little check here
|
||||
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && check_client.prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
to_chat(src,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
qdel(admin_read)
|
||||
return
|
||||
D = new(admin_rank, flags, ckey)
|
||||
qdel(admin_read)
|
||||
|
||||
var/client/C = GLOB.directory[ckey]
|
||||
D.associate(C)
|
||||
update_active_keybindings()
|
||||
message_admins("[key_name_admin(usr)] re-adminned themselves.")
|
||||
log_admin("[key_name(usr)] re-adminned themselves.")
|
||||
GLOB.de_admins -= ckey
|
||||
GLOB.de_mentors -= ckey
|
||||
if(istype(mob, /mob/dead/observer))
|
||||
var/mob/dead/observer/O = mob
|
||||
O.update_admin_actions()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Re-admin")
|
||||
return
|
||||
else
|
||||
to_chat(src, "You are already an admin.")
|
||||
remove_verb(src, /client/proc/readmin)
|
||||
GLOB.de_admins -= ckey
|
||||
GLOB.de_mentors -= ckey
|
||||
return
|
||||
|
||||
/client/proc/toggle_log_hrefs()
|
||||
set name = "Toggle href logging"
|
||||
set category = "Server"
|
||||
|
||||
+148
-98
@@ -10,10 +10,15 @@ GLOBAL_PROTECT(href_token)
|
||||
. += "[rand(10)]"
|
||||
|
||||
/datum/admins
|
||||
var/rank = "Temporary Admin"
|
||||
var/rank = "No Rank"
|
||||
var/ckey
|
||||
var/client/owner
|
||||
/// Bitflag containing the current rights this admin holder is assigned to
|
||||
var/rights = 0
|
||||
/// Tracks if their permissions have been reduced due to a lack of 2fa.
|
||||
var/restricted_by_2fa = FALSE
|
||||
/// Was this auto-created for someone connecting from localhost?
|
||||
var/is_localhost_autoadmin = FALSE
|
||||
var/fakekey
|
||||
var/big_brother = FALSE
|
||||
var/current_tab = 0
|
||||
@@ -27,7 +32,7 @@ GLOBAL_PROTECT(href_token)
|
||||
/// Our index into GLOB.antagonist_teams, so that admins can have pretty tabs in the Check Teams menu.
|
||||
var/team_switch_tab_index = 1
|
||||
|
||||
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
|
||||
/datum/admins/New(initial_rank, initial_rights, ckey)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounceooc'>Admin rank creation blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to create a new admin rank via advanced proc-call")
|
||||
@@ -37,8 +42,11 @@ GLOBAL_PROTECT(href_token)
|
||||
error("Admin datum created without a ckey argument. Datum has been deleted")
|
||||
qdel(src)
|
||||
return
|
||||
rank = initial_rank
|
||||
rights = initial_rights
|
||||
src.ckey = ckey
|
||||
if(initial_rank)
|
||||
rank = initial_rank
|
||||
if(initial_rights)
|
||||
rights = initial_rights
|
||||
href_token = GenerateToken()
|
||||
GLOB.admin_datums[ckey] = src
|
||||
|
||||
@@ -48,22 +56,68 @@ GLOBAL_PROTECT(href_token)
|
||||
message_admins("[key_name(usr)] attempted to delete an admin rank via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to delete an admin rank via advanced proc-call")
|
||||
return
|
||||
disassociate()
|
||||
..()
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
/datum/admins/proc/associate(client/C)
|
||||
/datum/admins/proc/associate(client/C, delay_2fa_complaint = FALSE)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounceooc'>Rank association blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to associate an admin rank to a new client via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to associate an admin rank to a new client via advanced proc-call")
|
||||
return
|
||||
if(istype(C))
|
||||
owner = C
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs() //TODO
|
||||
remove_verb(owner, /client/proc/readmin)
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
GLOB.admins |= C
|
||||
|
||||
if(istype(C) && C.ckey != ckey)
|
||||
CRASH("Admin datum belonging to [ckey] was asked to associate to client belonging to [C.ckey].")
|
||||
|
||||
owner = C
|
||||
|
||||
// Check for 2fa, if required.
|
||||
if(needs_2fa() && istype(owner) && !owner.has_2fa())
|
||||
// Disable most permissions.
|
||||
rights = rights & (R_MENTOR | R_VIEWRUNTIMES)
|
||||
restricted_by_2fa = TRUE
|
||||
if(!delay_2fa_complaint)
|
||||
// And tell them about it.
|
||||
to_chat(owner,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
|
||||
// Regardless of client, tell BYOND if they should have profiler access.
|
||||
if(rights & (R_DEBUG | R_VIEWRUNTIMES))
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
if(!istype(owner))
|
||||
return
|
||||
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs()
|
||||
if(istype(owner.mob, /mob/dead/observer))
|
||||
var/mob/dead/observer/ghost = owner.mob
|
||||
ghost.update_admin_actions()
|
||||
remove_verb(owner, /client/proc/readmin)
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
owner.update_active_keybindings()
|
||||
if(rights & (R_DEBUG | R_VIEWRUNTIMES))
|
||||
// Enable the buttons they should have.
|
||||
winset(owner, "debugmcbutton", "is-disabled=true")
|
||||
winset(owner, "profilecode", "is-disabled=true")
|
||||
GLOB.admins |= owner
|
||||
GLOB.de_admins -= ckey
|
||||
GLOB.de_mentors -= ckey
|
||||
|
||||
/datum/admins/proc/needs_2fa()
|
||||
if((rights & (R_MENTOR | R_VIEWRUNTIMES)) == rights)
|
||||
// No significant permissions.
|
||||
return FALSE
|
||||
|
||||
if(GLOB.configuration.admin.enable_localhost_autoadmin && owner && owner.is_connecting_from_localhost())
|
||||
// Localhost connections are immune.
|
||||
return FALSE
|
||||
|
||||
if(!GLOB.configuration.system.is_production)
|
||||
// 2fa isn't required for anyone.
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/disassociate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -71,72 +125,74 @@ GLOBAL_PROTECT(href_token)
|
||||
message_admins("[key_name(usr)] attempted to disassociate an admin rank from a client via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to disassociate an admin rank from a client via advanced proc-call")
|
||||
return
|
||||
|
||||
GLOB.admin_datums -= ckey
|
||||
|
||||
// Regardless of client, tell BYOND they shouldn't have access to the profiler.
|
||||
world.SetConfig("APP/admin", ckey, null)
|
||||
|
||||
if(owner)
|
||||
GLOB.admins -= owner
|
||||
owner.hide_verbs()
|
||||
owner.init_verbs()
|
||||
owner.holder = null
|
||||
owner.init_verbs()
|
||||
if(istype(owner.mob, /mob/dead/observer))
|
||||
var/mob/dead/observer/ghost = owner.mob
|
||||
ghost.update_admin_actions()
|
||||
owner.update_active_keybindings()
|
||||
// Disable buttons they should no longer have.
|
||||
winset(owner, "debugmcbutton", "is-disabled=true")
|
||||
winset(owner, "profilecode", "is-disabled=true")
|
||||
owner = null
|
||||
|
||||
/*
|
||||
checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags)
|
||||
if rights_required == 0, then it simply checks if they are an admin.
|
||||
if it doesn't return 1 and show_msg=1 it will prints a message explaining why the check has failed
|
||||
generally it would be used like so:
|
||||
Checks if usr is an admin.
|
||||
If rights_required == 0, then it simply checks if they are an admin.
|
||||
If all is set, requires all the rights listed. Otherwise, any matching right is sufficient.
|
||||
With show_msg, if the check fails, prints a message explaining why.
|
||||
|
||||
proc/admin_proc()
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
Usage:
|
||||
/some/proc()
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
to_chat(world, "you have enough rights!")
|
||||
|
||||
NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call
|
||||
you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
|
||||
NOTE: checks usr by default, not src
|
||||
*/
|
||||
/proc/check_rights(rights_required, show_msg = TRUE, mob/user = usr)
|
||||
/proc/check_rights(rights_required, show_msg = TRUE, mob/user = usr, all = FALSE)
|
||||
if(user && user.client)
|
||||
if(rights_required)
|
||||
if(user.client.holder)
|
||||
if(rights_required & user.client.holder.rights)
|
||||
return 1
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(user, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>")
|
||||
else
|
||||
if(user.client.holder)
|
||||
return 1
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(user, "<font color='red'>Error: You are not an admin.</font>")
|
||||
return 0
|
||||
|
||||
// Basically the above proc but checks at a /client level
|
||||
/proc/check_rights_client(rights_required, show_msg = TRUE, client/C)
|
||||
if(C)
|
||||
if(rights_required)
|
||||
if(C.holder)
|
||||
if(rights_required & C.holder.rights)
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>")
|
||||
else
|
||||
if(C.holder)
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, "<font color='red'>Error: You are not an admin.</font>")
|
||||
return check_rights_ckey(rights_required, show_msg, user.ckey, all)
|
||||
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.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, "<font color='red'>Error: Cannot proceed. They have more or equal rights to us.</font>")
|
||||
return 0
|
||||
// As above, for a /client
|
||||
/proc/check_rights_client(rights_required, show_msg, client/C, all = FALSE)
|
||||
if(C)
|
||||
return check_rights_ckey(rights_required, show_msg, C.ckey, all)
|
||||
return FALSE
|
||||
|
||||
// As above, for a ckey
|
||||
/proc/check_rights_ckey(rights_required, show_msg, ckey, all)
|
||||
var/datum/admins/holder = GLOB.admin_datums[ckey]
|
||||
if(!holder)
|
||||
if(show_msg)
|
||||
to_chat(GLOB.directory[ckey], "<font color='red'>Error: You are not an admin.</font>")
|
||||
return FALSE
|
||||
|
||||
if(!rights_required)
|
||||
return TRUE
|
||||
|
||||
if((rights_required & holder.rights) == rights_required)
|
||||
return TRUE
|
||||
else if(!all && (rights_required & holder.rights))
|
||||
return TRUE
|
||||
|
||||
if(show_msg)
|
||||
if(all)
|
||||
to_chat(GLOB.directory[ckey], "<font color='red'>Error: You do not have sufficient rights to do that. You require all of the following flags:[rights2text(rights_required," ")].</font>")
|
||||
else
|
||||
to_chat(GLOB.directory[ckey], "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>")
|
||||
|
||||
return FALSE
|
||||
|
||||
/client/proc/deadmin()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -144,45 +200,39 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
|
||||
message_admins("[key_name(usr)] attempted to de-admin a client via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to de-admin a client via advanced proc-call")
|
||||
return
|
||||
GLOB.admin_datums -= ckey
|
||||
if(holder)
|
||||
holder.disassociate()
|
||||
if(check_rights(R_ADMIN, show_msg = FALSE))
|
||||
GLOB.de_admins += ckey
|
||||
else
|
||||
GLOB.de_mentors += ckey
|
||||
qdel(holder)
|
||||
if(istype(mob, /mob/dead/observer))
|
||||
var/mob/dead/observer/O = mob
|
||||
O.update_admin_actions()
|
||||
return TRUE
|
||||
add_verb(src, /client/proc/readmin)
|
||||
else
|
||||
to_chat(src, "<font color='red'>Error: You were already not an admin.</font>")
|
||||
|
||||
//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
|
||||
/client/proc/readmin()
|
||||
set name = "Re-admin self"
|
||||
set category = "Admin"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
/**
|
||||
* Requires the holder to have all the rights specified
|
||||
*
|
||||
* rights_required = R_ADMIN|R_EVENT means they must have both flags, or it will return false
|
||||
*/
|
||||
/proc/check_rights_all(rights_required, show_msg = TRUE, mob/user = usr)
|
||||
if(!user?.client)
|
||||
return FALSE
|
||||
if(!rights_required)
|
||||
if(user.client.holder)
|
||||
return TRUE
|
||||
if(show_msg)
|
||||
to_chat(user, "<font color='red'>Error: You are not an admin.</font>")
|
||||
return FALSE
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounceooc'>Readmin blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to re-admin a client via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to re-admin a client via advanced proc-call")
|
||||
|
||||
if(!user.client.holder)
|
||||
return FALSE
|
||||
if((user.client.holder.rights & rights_required) == rights_required)
|
||||
return TRUE
|
||||
if(show_msg)
|
||||
to_chat(user, "<font color='red'>Error: You do not have sufficient rights to do that. You require all of the following flags:[rights2text(rights_required, " ")].</font>")
|
||||
return FALSE
|
||||
if(holder)
|
||||
to_chat(usr, "<span class='notice'>You are already an admin.</span>")
|
||||
else if(ckey in (GLOB.de_admins + GLOB.de_mentors))
|
||||
GLOB.de_admins -= ckey
|
||||
GLOB.de_mentors -= ckey
|
||||
reload_one_admin(ckey, silent = TRUE)
|
||||
log_admin("[key_name(usr)] re-adminned themselves.")
|
||||
message_admins("[key_name_admin(usr)] re-adminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Re-admin") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
else
|
||||
to_chat(usr, "<span class='boldannounceooc'>Readmin blocked: You were not an admin or mentor.</span>")
|
||||
message_admins("[key_name(usr)] attempted to re-admin without being an admin or mentor")
|
||||
log_admin("[key_name(usr)] attempted to re-admin without being an admin or mentor")
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
return FALSE // no admin abuse
|
||||
|
||||
@@ -1004,7 +1004,7 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
|
||||
/proc/staff_countup(rank_mask = R_BAN)
|
||||
var/list/result = list(0, 0, 0)
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(rank_mask && !check_rights_for(X, rank_mask))
|
||||
if(rank_mask && !check_rights_client(rank_mask, FALSE, X))
|
||||
result[2]++
|
||||
continue
|
||||
if(X.holder.fakekey)
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
var/datum/asset/permissions_asset = get_asset_datum(/datum/asset/simple/permissions)
|
||||
permissions_asset.send(usr)
|
||||
|
||||
var/db_section = ""
|
||||
if(db_available())
|
||||
db_section = {"
|
||||
<div id='db_notice'><b>Admin database active.<br>All data is pulled from the database, and may require an admin reload to match actual permissions.<br>Automatically-granted localhost admin permissions are not listed.</b><br><br></div>
|
||||
<div id='rank_edit'><b><a href='byond://?src=[UID()];editrank=1'>Edit admin ranks</a></b></div>
|
||||
"}
|
||||
|
||||
var/output = {"<!DOCTYPE html>
|
||||
<html><meta charset='utf-8'>
|
||||
<head>
|
||||
@@ -21,6 +28,8 @@
|
||||
<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='spacer'></div>
|
||||
[db_section]
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:20%;text-align:right;'>CKEY <a class='small' href='byond://?src=[UID()];editrights=add'>\[+\]</a></th>
|
||||
@@ -28,23 +37,75 @@
|
||||
</tr>
|
||||
"}
|
||||
|
||||
for(var/adm_ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.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>
|
||||
<td style='text-align:right;'>[adm_ckey] <a class='small' href='byond://?src=[UID()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>
|
||||
<td><a href='byond://?src=[UID()];editrights=rank;ckey=[adm_ckey]'>[rank]</a></td>
|
||||
<td><a class='small' href='byond://?src=[UID()];editrights=permissions;ckey=[adm_ckey]'>[rights]</a></font></td>
|
||||
</tr>"}
|
||||
var/list/admin_details = list()
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
var/datum/db_query/get_admins = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
admin.ckey,
|
||||
admin_ranks.name,
|
||||
admin.display_rank,
|
||||
IFNULL(admin_ranks.default_permissions, 0),
|
||||
admin.extra_permissions,
|
||||
admin.removed_permissions
|
||||
FROM admin
|
||||
-- We want all admins, and admin_ranks where available.
|
||||
LEFT OUTER JOIN admin_ranks
|
||||
ON admin.permissions_rank = admin_ranks.id
|
||||
ORDER BY admin_ranks.name ASC, admin.ckey ASC"})
|
||||
if(!get_admins.warn_execute())
|
||||
qdel(get_admins)
|
||||
return
|
||||
|
||||
/*output += "<tr>"
|
||||
output += "<td style='text-align:right;'>[adm_ckey] <a class='small' href='byond://?src=[UID()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
|
||||
output += "<td><a href='byond://?src=[UID()];editrights=rank;ckey=[adm_ckey]'>[rank]</a></td>"
|
||||
output += "<td><a class='small' href='byond://?src=[UID()];editrights=permissions;ckey=[adm_ckey]'>[rights]</a></font></td>"
|
||||
output += "</tr>"*/
|
||||
while(get_admins.NextRow())
|
||||
var/ckey = get_admins.item[1]
|
||||
var/rank = get_admins.item[2]
|
||||
var/display_rank = get_admins.item[3]
|
||||
var/rank_permissions = get_admins.item[4]
|
||||
var/extra_permissions = get_admins.item[5]
|
||||
var/removed_permissions = get_admins.item[6]
|
||||
|
||||
if(!rank && !display_rank && !extra_permissions && !removed_permissions)
|
||||
// Former admin, no current rank or permissions. Don't bother showing them.
|
||||
continue
|
||||
|
||||
var/listed_rank
|
||||
if(rank)
|
||||
listed_rank = rank
|
||||
else
|
||||
listed_rank = "*none*"
|
||||
if(display_rank)
|
||||
listed_rank = "[display_rank] ([rank])"
|
||||
var/display_rights = ranked_rights2text(rank_permissions, extra_permissions, removed_permissions," ")
|
||||
if(display_rights == "")
|
||||
display_rights = "*none*"
|
||||
admin_details += list(list(
|
||||
ckey,
|
||||
listed_rank,
|
||||
display_rights
|
||||
))
|
||||
qdel(get_admins)
|
||||
else
|
||||
var/list/sorted_ckeys = list()
|
||||
for(var/adm_ckey in GLOB.admin_datums)
|
||||
sorted_ckeys += adm_ckey
|
||||
sortTim(sorted_ckeys, cmp = GLOBAL_PROC_REF(cmp_text_asc))
|
||||
|
||||
for(var/adm_ckey in sorted_ckeys)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
continue
|
||||
var/rank = D.rank ? D.rank : "*none*"
|
||||
var/rights = rights2text(D.rights," ")
|
||||
if(!rights)
|
||||
rights = "*none*"
|
||||
admin_details += list(list(adm_ckey, rank, rights))
|
||||
|
||||
for(var/list/details in admin_details)
|
||||
output += {"<tr>
|
||||
<td style='text-align:right;'>[details[1]] <a class='small' href='byond://?src=[UID()];editrights=remove;ckey=[details[1]]'>\[-\]</a></td>
|
||||
<td><a href='byond://?src=[UID()];editrights=rank;ckey=[details[1]]'>[details[2]]</a></td>
|
||||
<td><a class='small' href='byond://?src=[UID()];editrights=permissions;ckey=[details[1]]'>[details[3]]</a></font></td>
|
||||
</tr>"}
|
||||
|
||||
output += {"
|
||||
</table></div>
|
||||
@@ -54,202 +115,525 @@
|
||||
|
||||
usr << browse(output,"window=editrights;size=600x500")
|
||||
|
||||
/datum/admins/proc/log_admin_rank_modification(adm_ckey, new_rank)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
/datum/admins/proc/db_available()
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, "<span class='warning'>Failed to establish database connection</span>")
|
||||
return FALSE
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/can_edit_db()
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return FALSE
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounceooc'>Admin edit blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to edit admin DB via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to edit admin DB via advanced proc-call")
|
||||
return FALSE
|
||||
if(!usr.client)
|
||||
return FALSE
|
||||
if(!db_available())
|
||||
to_chat(usr, "<span class='warning'>Admin database unavailable</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/set_db_rank(target_key, new_rank, display_rank = null, clear_custom_permissions = FALSE)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_rank)
|
||||
if(!istext(target_key))
|
||||
to_chat(usr, "<span class='warning'>Provided key '[target_key]' is not text!</span>")
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
target_key = ckey(target_key)
|
||||
if(target_key == "")
|
||||
to_chat(usr, "<span class='warning'>Provided key was blank after converting to ckey!</span>")
|
||||
return
|
||||
|
||||
if(!istext(adm_ckey) || !istext(new_rank))
|
||||
if(!isnum(new_rank))
|
||||
to_chat(usr, "<span class='warning'>Provided rank ID '[new_rank]' is not a number!</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM admin WHERE ckey=:adm_ckey", list(
|
||||
"adm_ckey" = adm_ckey
|
||||
var/datum/db_query/get_rank_name = SSdbcore.NewQuery("SELECT name FROM admin_ranks WHERE id = :new_rank", list(
|
||||
"new_rank" = new_rank
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
qdel(select_query)
|
||||
if(!get_rank_name.warn_execute())
|
||||
qdel(get_rank_name)
|
||||
return
|
||||
var/rank_name
|
||||
if(get_rank_name.NextRow())
|
||||
rank_name = get_rank_name.item[1]
|
||||
qdel(get_rank_name)
|
||||
if(!rank_name)
|
||||
to_chat(usr, "<span class='warning'>Rank with ID [new_rank] not found in database!</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/get_admin_id = SSdbcore.NewQuery("SELECT id FROM admin WHERE ckey = :target_key", list(
|
||||
"target_key" = target_key
|
||||
))
|
||||
if(!get_admin_id.warn_execute())
|
||||
qdel(get_admin_id)
|
||||
return
|
||||
|
||||
var/display_note = ""
|
||||
if(display_rank)
|
||||
display_note = " with the custom rank title [display_rank]"
|
||||
|
||||
var/new_admin = TRUE
|
||||
var/admin_id
|
||||
while(select_query.NextRow())
|
||||
if(get_admin_id.NextRow())
|
||||
new_admin = FALSE
|
||||
admin_id = text2num(select_query.item[1])
|
||||
qdel(select_query)
|
||||
flag_account_for_forum_sync(adm_ckey)
|
||||
admin_id = text2num(get_admin_id.item[1])
|
||||
qdel(get_admin_id)
|
||||
if(new_admin)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO admin (`id`, `ckey`, `admin_rank`, `level`, `flags`) VALUES (null, :adm_ckey, :new_rank, -1, 0)", list(
|
||||
"adm_ckey" = adm_ckey,
|
||||
"new_rank" = new_rank
|
||||
var/datum/db_query/insert_new_admin = SSdbcore.NewQuery("INSERT INTO admin (`ckey`, `permissions_rank`, `display_rank`) VALUES (:target_key, :new_rank, :display_rank)", list(
|
||||
"target_key" = target_key,
|
||||
"new_rank" = new_rank,
|
||||
"display_rank" = display_rank
|
||||
))
|
||||
if(!insert_query.warn_execute())
|
||||
qdel(insert_query)
|
||||
if(!insert_new_admin.warn_execute())
|
||||
qdel(insert_new_admin)
|
||||
return
|
||||
qdel(insert_query)
|
||||
qdel(insert_new_admin)
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: [target_key] (NEW ADMIN) is now a [rank_name][display_note].</span>")
|
||||
|
||||
var/logtxt = "Added new admin [adm_ckey] to rank [new_rank]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
var/logtxt = "Added new admin [target_key] to rank [rank_name][display_note]"
|
||||
var/datum/db_query/add_log = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
if(!log_query.warn_execute())
|
||||
qdel(log_query)
|
||||
if(!add_log.warn_execute())
|
||||
qdel(add_log)
|
||||
return
|
||||
qdel(log_query)
|
||||
|
||||
to_chat(usr, "<span class='notice'>New admin added.</span>")
|
||||
qdel(add_log)
|
||||
else
|
||||
if(!isnull(admin_id) && isnum(admin_id))
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE admin SET admin_rank=:new_rank WHERE id=:admin_id", list(
|
||||
var/datum/db_query/update_admin_rank = SSdbcore.NewQuery("UPDATE admin SET permissions_rank = :new_rank, display_rank = :display_rank WHERE id = :admin_id", list(
|
||||
"new_rank" = new_rank,
|
||||
"display_rank" = display_rank,
|
||||
"admin_id" = admin_id,
|
||||
))
|
||||
if(!insert_query.warn_execute())
|
||||
qdel(insert_query)
|
||||
if(!update_admin_rank.warn_execute())
|
||||
qdel(update_admin_rank)
|
||||
return
|
||||
qdel(insert_query)
|
||||
qdel(update_admin_rank)
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: [target_key] is now a [rank_name][display_note].</span>")
|
||||
var/logtxt = "Edited the rank of [target_key] to [rank_name][display_note]"
|
||||
|
||||
var/logtxt = "Edited the rank of [adm_ckey] to [new_rank]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
if(clear_custom_permissions)
|
||||
var/datum/db_query/clear_permissions = SSdbcore.NewQuery("UPDATE admin SET extra_permissions = 0, removed_permissions = 0 WHERE id = :admin_id", list(
|
||||
"admin_id" = admin_id,
|
||||
))
|
||||
if(!clear_permissions.warn_execute())
|
||||
qdel(clear_permissions)
|
||||
return
|
||||
qdel(clear_permissions)
|
||||
logtxt += " and cleared their custom permissions"
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] no longer has any custom permissions.</span>")
|
||||
|
||||
var/datum/db_query/add_log = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt,
|
||||
))
|
||||
if(!log_query.warn_execute())
|
||||
qdel(log_query)
|
||||
if(!add_log.warn_execute())
|
||||
qdel(add_log)
|
||||
return
|
||||
qdel(log_query)
|
||||
to_chat(usr, "<span class='notice'>Admin rank changed.</span>")
|
||||
qdel(add_log)
|
||||
|
||||
/datum/admins/proc/log_admin_permission_modification(adm_ckey, new_permission)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='boldannounceooc'>Admin edit blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to edit admin ranks via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to edit admin ranks via advanced proc-call")
|
||||
return
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
/datum/admins/proc/toggle_db_permission(target_key, permission_bit)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
if(!usr.client)
|
||||
if(!istext(target_key))
|
||||
to_chat(usr, "<span class='warning'>Provided key '[target_key]' is not text!</span>")
|
||||
return
|
||||
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
target_key = ckey(target_key)
|
||||
if(target_key == "")
|
||||
to_chat(usr, "<span class='warning'>Provided key was blank after converting to ckey!</span>")
|
||||
return
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, "<span class='warning'>Failed to establish database connection</span>")
|
||||
if(!isnum(permission_bit) || permission_bit < 1 || floor(permission_bit) != permission_bit)
|
||||
to_chat(usr, "<span class='warning'>Provided permission '[permission_bit]' is not positive whole number!</span>")
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_permission)
|
||||
var/pow2 = round(log(2, permission_bit), 1)
|
||||
if((2 ** pow2) != permission_bit)
|
||||
to_chat(usr, "<span class='warning'>Provided permission '[permission_bit]' is not a power of two, and would affect multiple permission bits!</span>")
|
||||
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 admin WHERE ckey=:adm_ckey", list(
|
||||
"adm_ckey" = adm_ckey
|
||||
var/datum/db_query/get_admin_permissions = SSdbcore.NewQuery("SELECT admin.id, admin_ranks.default_permissions, admin.extra_permissions, admin.removed_permissions FROM admin LEFT OUTER JOIN admin_ranks ON admin.permissions_rank = admin_ranks.id WHERE ckey = :target_key", list(
|
||||
"target_key" = target_key
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
qdel(select_query)
|
||||
if(!get_admin_permissions.warn_execute())
|
||||
qdel(get_admin_permissions)
|
||||
return
|
||||
|
||||
var/admin_id
|
||||
var/admin_rights
|
||||
while(select_query.NextRow())
|
||||
admin_id = text2num(select_query.item[1])
|
||||
admin_rights = text2num(select_query.item[2])
|
||||
var/rank_permissions = 0
|
||||
var/extra_permissions = 0
|
||||
var/removed_permissions = 0
|
||||
if(get_admin_permissions.NextRow())
|
||||
admin_id = get_admin_permissions.item[1]
|
||||
// || 0 forces this to be numeric if they have no rank in the database.
|
||||
rank_permissions = get_admin_permissions.item[2] || 0
|
||||
extra_permissions = get_admin_permissions.item[3]
|
||||
removed_permissions = get_admin_permissions.item[4]
|
||||
|
||||
qdel(select_query)
|
||||
qdel(get_admin_permissions)
|
||||
if(!admin_id)
|
||||
to_chat(usr, "<span class='warning'>No admin found with ckey [target_key]!</span>")
|
||||
return
|
||||
|
||||
flag_account_for_forum_sync(adm_ckey)
|
||||
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 admin SET flags=:newflags WHERE id=:admin_id", list(
|
||||
"newflags" = (admin_rights & ~new_permission),
|
||||
flag_account_for_forum_sync(target_key)
|
||||
|
||||
if(removed_permissions & permission_bit)
|
||||
// They had an exception removing this permission bit, let them have it.
|
||||
var/datum/db_query/remove_removal = SSdbcore.NewQuery("UPDATE admin SET removed_permissions = removed_permissions & ~:permission_bit WHERE id = :admin_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
if(!insert_query.warn_execute())
|
||||
qdel(insert_query)
|
||||
if(!remove_removal.warn_execute())
|
||||
qdel(remove_removal)
|
||||
return
|
||||
qdel(insert_query)
|
||||
qdel(remove_removal)
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] is no longer excluded from having [rights2text(permission_bit)].</span>")
|
||||
|
||||
var/logtxt = "Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery({"
|
||||
var/logtxt = "Un-excluded permission [rights2text(permission_bit)] (flag = [permission_bit]) from admin [target_key]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
if(!log_query.warn_execute())
|
||||
qdel(log_query)
|
||||
return
|
||||
qdel(log_query)
|
||||
to_chat(usr, "<span class='notice'>Permission removed.</span>")
|
||||
else //This admin doesn't have this permission, so we are adding it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE admin SET flags=:newflags WHERE id=:admin_id", list(
|
||||
"newflags" = (admin_rights | new_permission),
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
return
|
||||
|
||||
if(extra_permissions & permission_bit)
|
||||
// They had an exception adding this permission bit, remove it.
|
||||
var/datum/db_query/remove_extra = SSdbcore.NewQuery("UPDATE admin SET extra_permissions = extra_permissions & ~:permission_bit WHERE id = :admin_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
if(!insert_query.warn_execute())
|
||||
qdel(insert_query)
|
||||
if(!remove_extra.warn_execute())
|
||||
qdel(remove_extra)
|
||||
return
|
||||
qdel(insert_query)
|
||||
qdel(remove_extra)
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] no longer has the extra permission [rights2text(permission_bit)].</span>")
|
||||
|
||||
var/logtxt = "Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery({"
|
||||
var/logtxt = "Removed extra permission [rights2text(permission_bit)] (flag = [permission_bit]) from admin [target_key]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
return
|
||||
|
||||
if(!log_query.warn_execute())
|
||||
qdel(log_query)
|
||||
if(rank_permissions & permission_bit)
|
||||
// They have this permission from their rank, and an exception removing it.
|
||||
var/datum/db_query/create_removal = SSdbcore.NewQuery("UPDATE admin SET removed_permissions = removed_permissions | :permission_bit WHERE id = :admin_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
if(!create_removal.warn_execute())
|
||||
qdel(create_removal)
|
||||
return
|
||||
qdel(log_query)
|
||||
to_chat(usr, "<span class='notice'>Permission added.</span>")
|
||||
qdel(create_removal)
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] is now excluded from having [rights2text(permission_bit)].</span>")
|
||||
|
||||
/datum/admins/proc/updateranktodb(ckey,newrank)
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
var/logtxt = "Excluded permission [rights2text(permission_bit)] (flag = [permission_bit]) from admin [target_key]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
return
|
||||
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastadminrank=:admin_rank WHERE ckey=:ckey", list(
|
||||
"admin_rank" = newrank,
|
||||
"ckey" = ckey
|
||||
// They did not have this permission from their rank, add an exception granting it.
|
||||
var/datum/db_query/add_extra = SSdbcore.NewQuery("UPDATE admin SET extra_permissions = extra_permissions | :permission_bit WHERE id = :admin_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
if(!query_update.warn_execute())
|
||||
qdel(query_update)
|
||||
if(!add_extra.warn_execute())
|
||||
qdel(add_extra)
|
||||
return
|
||||
qdel(add_extra)
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] has been granted the extra permission [rights2text(permission_bit)].</span>")
|
||||
|
||||
var/logtxt = "Added extra permission [rights2text(permission_bit)] (flag = [permission_bit]) to admin [target_key]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
|
||||
/datum/admins/proc/remove_db_admin(target_key, clear_custom_permissions = TRUE)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
qdel(query_update)
|
||||
flag_account_for_forum_sync(ckey)
|
||||
if(!istext(target_key))
|
||||
to_chat(usr, "<span class='warning'>Provided key '[target_key]' is not text!</span>")
|
||||
return
|
||||
|
||||
target_key = ckey(target_key)
|
||||
if(target_key == "")
|
||||
to_chat(usr, "<span class='warning'>Provided key was blank after converting to ckey!</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/get_admin_id = SSdbcore.NewQuery("SELECT admin.id FROM admin WHERE ckey = :target_key", list(
|
||||
"target_key" = target_key
|
||||
))
|
||||
if(!get_admin_id.warn_execute())
|
||||
qdel(get_admin_id)
|
||||
return
|
||||
|
||||
var/admin_id
|
||||
if(get_admin_id.NextRow())
|
||||
admin_id = get_admin_id.item[1]
|
||||
qdel(get_admin_id)
|
||||
|
||||
if(!admin_id)
|
||||
to_chat(usr, "<span class='warning'>No admin found with ckey [target_key]!</span>")
|
||||
return
|
||||
|
||||
flag_account_for_forum_sync(target_key)
|
||||
|
||||
var/datum/db_query/remove_admin = SSdbcore.NewQuery("UPDATE admin SET permissions_rank = NULL, display_rank = NULL WHERE id = :admin_id", list(
|
||||
"admin_id" = admin_id,
|
||||
))
|
||||
if(!remove_admin.warn_execute())
|
||||
qdel(remove_admin)
|
||||
return
|
||||
qdel(remove_admin)
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: [target_key] no longer has any admin rank.</span>")
|
||||
var/logtxt = "Removed the admin rank of [target_key]"
|
||||
|
||||
if(clear_custom_permissions)
|
||||
var/datum/db_query/clear_permissions = SSdbcore.NewQuery("UPDATE admin SET extra_permissions = 0, removed_permissions = 0 WHERE id = :admin_id", list(
|
||||
"admin_id" = admin_id,
|
||||
))
|
||||
if(!clear_permissions.warn_execute())
|
||||
qdel(clear_permissions)
|
||||
return
|
||||
qdel(clear_permissions)
|
||||
message_admins("<span class='notice'>Admin permissions updated by [usr.ckey]: [target_key] no longer has any custom permissions.</span>")
|
||||
logtxt += " and cleared their custom permissions"
|
||||
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
|
||||
/datum/admins/proc/create_db_rank(rank_name)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
if(get_db_rank_id(rank_name))
|
||||
// We already have it.
|
||||
return
|
||||
|
||||
var/datum/db_query/add_rank = SSdbcore.NewQuery("INSERT INTO admin_ranks SET name = :rank_name", list(
|
||||
"rank_name" = rank_name
|
||||
))
|
||||
add_rank.warn_execute()
|
||||
qdel(add_rank)
|
||||
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: new rank [rank_name] created.</span>")
|
||||
var/logtxt = "Created the admin rank [rank_name]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
return get_db_rank_id(rank_name)
|
||||
|
||||
/datum/admins/proc/delete_db_rank(rank_name)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
var/rank_id = get_db_rank_id(rank_name)
|
||||
if(!rank_id)
|
||||
to_chat(usr, "<span class='warning'>No rank named [rank_name] found!</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/get_admins_with_rank = SSdbcore.NewQuery("SELECT ckey FROM admin WHERE permissions_rank = :rank_id", list(
|
||||
"rank_id" = rank_id
|
||||
))
|
||||
if(!get_admins_with_rank.warn_execute())
|
||||
qdel(get_admins_with_rank)
|
||||
return
|
||||
var/list/admins = list()
|
||||
while(get_admins_with_rank.NextRow())
|
||||
admins += get_admins_with_rank.item[1]
|
||||
qdel(get_admins_with_rank)
|
||||
if(length(admins) > 0)
|
||||
to_chat(usr, "<span class='warning'>[rank_name] is still in use, reassign the following admins first: [admins.Join(", ")]</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/delete_rank = SSdbcore.NewQuery("DELETE FROM admin_ranks WHERE id = :rank_id", list(
|
||||
"rank_id" = rank_id
|
||||
))
|
||||
if(!delete_rank.warn_execute())
|
||||
qdel(delete_rank)
|
||||
return
|
||||
qdel(delete_rank)
|
||||
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: unused rank [rank_name] deleted.</span>")
|
||||
var/logtxt = "Deleted the unused admin rank [rank_name]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
|
||||
/datum/admins/proc/toggle_db_rank_permission(rank_name, permission_bit)
|
||||
if(!can_edit_db())
|
||||
return
|
||||
|
||||
var/datum/db_query/get_rank_details = SSdbcore.NewQuery("SELECT id, default_permissions FROM admin_ranks WHERE name = :rank_name", list(
|
||||
"rank_name" = rank_name
|
||||
))
|
||||
if(!get_rank_details.warn_execute())
|
||||
qdel(get_rank_details)
|
||||
return
|
||||
|
||||
var/rank_id
|
||||
var/rank_permissions
|
||||
if(get_rank_details.NextRow())
|
||||
rank_id = get_rank_details.item[1]
|
||||
rank_permissions = get_rank_details.item[2]
|
||||
qdel(get_rank_details)
|
||||
if(!rank_id)
|
||||
to_chat(usr, "<span class='warning'>No rank named [rank_name] found!</span>")
|
||||
return
|
||||
|
||||
if(!isnum(permission_bit) || permission_bit < 1 || floor(permission_bit) != permission_bit)
|
||||
to_chat(usr, "<span class='warning'>Provided permission '[permission_bit]' is not positive whole number!</span>")
|
||||
return
|
||||
|
||||
var/pow2 = round(log(2, permission_bit), 1)
|
||||
if((2 ** pow2) != permission_bit)
|
||||
to_chat(usr, "<span class='warning'>Provided permission '[permission_bit]' is not a power of two, and would affect multiple permission bits!</span>")
|
||||
return
|
||||
|
||||
if(rank_permissions & permission_bit)
|
||||
// Revoke the permission.
|
||||
var/datum/db_query/create_removal = SSdbcore.NewQuery("UPDATE admin_ranks SET default_permissions = default_permissions & ~:permission_bit WHERE id = :rank_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"rank_id" = rank_id
|
||||
))
|
||||
if(!create_removal.warn_execute())
|
||||
qdel(create_removal)
|
||||
return
|
||||
qdel(create_removal)
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: [rank_name] no longer has [rights2text(permission_bit)]. An admin reload is required to apply this change.</span>")
|
||||
|
||||
var/logtxt = "Removed permission [rights2text(permission_bit)] (flag = [permission_bit]) from admin rank [rank_name]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
return
|
||||
|
||||
// Grant the permission
|
||||
var/datum/db_query/grant_permission = SSdbcore.NewQuery("UPDATE admin_ranks SET default_permissions = default_permissions | :permission_bit WHERE id = :rank_id", list(
|
||||
"permission_bit" = permission_bit,
|
||||
"rank_id" = rank_id
|
||||
))
|
||||
if(!grant_permission.warn_execute())
|
||||
qdel(grant_permission)
|
||||
return
|
||||
qdel(grant_permission)
|
||||
message_admins("<span class='notice'>Admin ranks updated by [usr.ckey]: [rank_name] has been given [rights2text(permission_bit)]. An admin reload is required to apply this change.</span>")
|
||||
|
||||
var/logtxt = "Added permission [rights2text(permission_bit)] (flag = [permission_bit]) to admin rank [rank_name]"
|
||||
var/datum/db_query/create_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
))
|
||||
create_log.warn_execute()
|
||||
qdel(create_log)
|
||||
|
||||
/datum/admins/proc/get_db_ranks()
|
||||
if(!db_available())
|
||||
return
|
||||
var/datum/db_query/get_ranks = SSdbcore.NewQuery("SELECT name FROM admin_ranks")
|
||||
if(!get_ranks.warn_execute())
|
||||
qdel(get_ranks)
|
||||
CRASH("Unable to get admin ranks from database.")
|
||||
|
||||
var/list/ranks = list()
|
||||
while(get_ranks.NextRow())
|
||||
ranks += get_ranks.item[1]
|
||||
qdel(get_ranks)
|
||||
|
||||
return ranks
|
||||
|
||||
/datum/admins/proc/get_db_rank_id(rank_name)
|
||||
if(!db_available())
|
||||
return
|
||||
var/datum/db_query/get_rank_id = SSdbcore.NewQuery("SELECT id FROM admin_ranks WHERE name = :rank_name", list(
|
||||
"rank_name" = rank_name
|
||||
))
|
||||
if(!get_rank_id.warn_execute())
|
||||
qdel(get_rank_id)
|
||||
return
|
||||
|
||||
var/rank_id
|
||||
if(get_rank_id.NextRow())
|
||||
rank_id = get_rank_id.item[1]
|
||||
qdel(get_rank_id)
|
||||
return rank_id
|
||||
|
||||
/datum/admins/proc/get_db_rank_permissions(rank_name)
|
||||
if(!db_available())
|
||||
return
|
||||
var/datum/db_query/get_rank_permissions = SSdbcore.NewQuery("SELECT default_permissions FROM admin_ranks WHERE name = :rank_name", list(
|
||||
"rank_name" = rank_name
|
||||
))
|
||||
if(!get_rank_permissions.warn_execute())
|
||||
qdel(get_rank_permissions)
|
||||
return
|
||||
|
||||
var/rank_permissions
|
||||
if(get_rank_permissions.NextRow())
|
||||
rank_permissions = get_rank_permissions.item[1]
|
||||
qdel(get_rank_permissions)
|
||||
return rank_permissions
|
||||
|
||||
+92
-21
@@ -242,6 +242,44 @@
|
||||
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid)
|
||||
|
||||
|
||||
else if(href_list["editrank"])
|
||||
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/rank = input("Please select a rank", "Rank to edit", null, null) as null|anything in (get_db_ranks() | "*New Rank*")
|
||||
if(!rank)
|
||||
return
|
||||
if(rank == "*New Rank*")
|
||||
rank = input("Please input a new rank", "New custom rank", null, null) as null|text
|
||||
if(!rank)
|
||||
return
|
||||
var/rank_id = create_db_rank(rank)
|
||||
if(!rank_id)
|
||||
to_chat(usr, "<span class='warning'>A rank named [rank] already esists.</span>")
|
||||
return
|
||||
|
||||
while(TRUE)
|
||||
var/action = input("What do you want to do to [rank]?", "Editing rank [rank]", null, null) as null|anything in list("List Permissions", "Toggle Permission", "Delete Rank (must be unused)")
|
||||
if(!action)
|
||||
return
|
||||
if(action == "List Permissions")
|
||||
to_chat(usr, "<span class='notice'>Rank [rank] has the permissions: [rights2text(get_db_rank_permissions(rank), " ")]</span>")
|
||||
continue
|
||||
if(action == "Toggle Permission")
|
||||
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/permission = input("Select a permission to turn on/off", "Editing rank [rank]", null, null) as null|anything in permissionlist
|
||||
if(!permission)
|
||||
continue
|
||||
toggle_db_rank_permission(rank, permissionlist[permission])
|
||||
edit_admin_permissions()
|
||||
continue
|
||||
delete_db_rank(rank)
|
||||
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.")
|
||||
@@ -253,8 +291,10 @@
|
||||
var/task = href_list["editrights"]
|
||||
if(task == "add")
|
||||
var/new_ckey = ckey(clean_input("New admin's ckey","Admin ckey", null))
|
||||
if(!new_ckey) return
|
||||
if(new_ckey in GLOB.admin_datums)
|
||||
if(!new_ckey)
|
||||
return
|
||||
var/datum/admins/existing_datum = GLOB.admin_datums[new_ckey]
|
||||
if(existing_datum && existing_datum.rank != "!LOCALHOST!")
|
||||
to_chat(usr, "<font color='red'>Error: Topic 'editrights': [new_ckey] is already an admin</font>")
|
||||
return
|
||||
adm_ckey = new_ckey
|
||||
@@ -268,63 +308,90 @@
|
||||
var/datum/admins/D = GLOB.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
|
||||
if(alert("Are you sure you want to remove [adm_ckey]'s admin rank?","Message","Yes","Cancel") == "Yes")
|
||||
if(!GLOB.configuration.admin.use_database_admins && !D)
|
||||
return
|
||||
GLOB.admin_datums -= adm_ckey
|
||||
D.disassociate()
|
||||
if(D)
|
||||
qdel(D)
|
||||
|
||||
updateranktodb(adm_ckey, "player")
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
var/clear_custom_permissions = alert("Do you also want to clear any custom permissions [adm_ckey] may have?","Message","Yes","No") == "Yes"
|
||||
remove_db_admin(adm_ckey, clear_custom_permissions)
|
||||
reload_one_admin(adm_ckey)
|
||||
edit_admin_permissions()
|
||||
return
|
||||
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(length(GLOB.admin_ranks))
|
||||
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (GLOB.admin_ranks|"*New Rank*")
|
||||
var/display_rank
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (get_db_ranks() | "*New Rank*")
|
||||
else if(length(GLOB.admin_ranks))
|
||||
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (GLOB.admin_ranks | "*New Rank*")
|
||||
else
|
||||
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in list("Mentor", "Trial Admin", "Game Admin", "Developer", "*New Rank*")
|
||||
|
||||
var/rights = 0
|
||||
if(D)
|
||||
rights = D.rights
|
||||
var/rank_id
|
||||
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
|
||||
new_rank = input("Please input a new rank", "Admin rank for [adm_ckey]", null, null) as null|text
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
new_rank = ckeyEx(new_rank)
|
||||
if(!new_rank)
|
||||
to_chat(usr, "<font color='red'>Error: Topic 'editrights': Invalid rank</font>")
|
||||
return
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
rank_id = create_db_rank(new_rank)
|
||||
if(!rank_id)
|
||||
to_chat(usr, "<span class='warning'>A rank named [new_rank] already esists.</span>")
|
||||
return
|
||||
display_rank = input("Give them a custom title?", "Admin rank for [adm_ckey]", null, null) as null|text
|
||||
else
|
||||
if(length(GLOB.admin_ranks))
|
||||
if(new_rank in GLOB.admin_ranks)
|
||||
rights = GLOB.admin_ranks[new_rank] //we typed a rank which already exists, use its rights
|
||||
else
|
||||
GLOB.admin_ranks[new_rank] = 0 //add the new rank to admin_ranks
|
||||
else
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
rank_id = get_db_rank_id(new_rank)
|
||||
if(!rank_id)
|
||||
to_chat(usr, "<span class='warning'>Rank '[new_rank] not found.</span>")
|
||||
return
|
||||
display_rank = input("Give them a custom title?", "Admin rank for [adm_ckey]", null, null) as null|text
|
||||
else
|
||||
new_rank = ckeyEx(new_rank)
|
||||
rights = GLOB.admin_ranks[new_rank] //we input an existing rank, use its rights
|
||||
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
var/clear_custom_permissions = alert("Do you also want to remove any custom permissions [adm_ckey] may have?","Message","Yes","No") == "Yes"
|
||||
if(display_rank == "")
|
||||
display_rank = null
|
||||
set_db_rank(adm_ckey, rank_id, display_rank, clear_custom_permissions)
|
||||
reload_one_admin(adm_ckey)
|
||||
edit_admin_permissions()
|
||||
return
|
||||
|
||||
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)
|
||||
qdel(D)
|
||||
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
|
||||
|
||||
updateranktodb(adm_ckey, new_rank)
|
||||
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
|
||||
if(!D && !GLOB.configuration.admin.use_database_admins)
|
||||
return
|
||||
while(TRUE)
|
||||
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
|
||||
@@ -332,6 +399,11 @@
|
||||
var/new_permission = input("Select a permission to turn on/off", adm_ckey + "'s Permissions", null, null) as null|anything in permissionlist
|
||||
if(!new_permission)
|
||||
return
|
||||
if(GLOB.configuration.admin.use_database_admins)
|
||||
toggle_db_permission(adm_ckey, permissionlist[new_permission])
|
||||
reload_one_admin(adm_ckey)
|
||||
edit_admin_permissions()
|
||||
continue
|
||||
var/oldrights = D.rights
|
||||
var/toggleresult = "ON"
|
||||
D.rights ^= permissionlist[new_permission]
|
||||
@@ -340,7 +412,6 @@
|
||||
|
||||
message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey] to [toggleresult]")
|
||||
log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey] to [toggleresult]")
|
||||
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
|
||||
|
||||
|
||||
edit_admin_permissions()
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
return
|
||||
|
||||
// If we are here, they authed successfully
|
||||
alert(usr, "Congratulations. 2FA is now setup properly for your account. In preferences, you can change whether you want it to ask for a code on every connection or only when your IP changes")
|
||||
B.close()
|
||||
// Default to IP change only
|
||||
prefs._2fa_status = _2FA_ENABLED_IP
|
||||
prefs.save_preferences(src)
|
||||
prefs.ShowChoices(usr)
|
||||
if(holder && holder.restricted_by_2fa)
|
||||
reload_one_admin(ckey)
|
||||
to_chat(usr, "<span class='notice'>2fa configured, admin verbs enabled.")
|
||||
alert(usr, "Congratulations. 2FA is now setup properly for your account. In preferences, you can change whether you want it to ask for a code on every connection or only when your IP changes")
|
||||
return
|
||||
|
||||
|
||||
@@ -79,6 +82,10 @@
|
||||
var/confirm = tgui_alert(usr, "Are you SURE you want to deactivate 2FA?", "WARNING", list("Yes", "No"))
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
if(holder && holder.needs_2fa())
|
||||
confirm = tgui_alert(usr, "This will disable most of your admin permissions. Are you REALLY sure?", "WARNING", list("Yes", "No"))
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
|
||||
// Prompt them for a code to make sure they know what they are doing
|
||||
var/entered_code = input(usr, "Please enter a code from your auth app", "2FA Validation")
|
||||
@@ -106,8 +113,13 @@
|
||||
prefs._2fa_status = _2FA_DISABLED
|
||||
prefs.save_preferences(src)
|
||||
prefs.ShowChoices(usr)
|
||||
if(holder && holder.needs_2fa())
|
||||
reload_one_admin(ckey)
|
||||
alert(usr, "2FA disabled successfully")
|
||||
|
||||
/client/proc/has_2fa()
|
||||
return prefs._2fa_status != _2FA_DISABLED
|
||||
|
||||
/datum/preferences/proc/_2fastatus_to_text()
|
||||
switch(_2fa_status)
|
||||
if(_2FA_DISABLED)
|
||||
|
||||
@@ -310,14 +310,9 @@
|
||||
// Automatically makes localhost connection an admin
|
||||
try_localhost_autoadmin()
|
||||
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
if(holder)
|
||||
GLOB.admins += src
|
||||
holder.owner = src
|
||||
|
||||
log_client_to_db(tdata) // Make sure our client exists in the DB
|
||||
|
||||
// We have a holder. Inform the relevant places
|
||||
// Holder set up. Inform the relevant places
|
||||
INVOKE_ASYNC(src, PROC_REF(announce_join))
|
||||
|
||||
pai_save = new(src)
|
||||
@@ -352,6 +347,12 @@
|
||||
// ToS accepted
|
||||
tos_consent = TRUE
|
||||
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
if(holder)
|
||||
holder.associate(src, delay_2fa_complaint = TRUE)
|
||||
// Must be async because any sleeps (happen in sql queries) will break connecting clients
|
||||
INVOKE_ASYNC(src, PROC_REF(admin_memo_output), "Show", FALSE, TRUE)
|
||||
|
||||
// Setup widescreen
|
||||
view = prefs.viewrange
|
||||
|
||||
@@ -377,22 +378,6 @@
|
||||
GLOB.clients += src
|
||||
connection_time = world.time
|
||||
|
||||
var/_2fa_alert = FALSE // This is so we can display the message where it will be seen
|
||||
if(holder)
|
||||
if(GLOB.configuration.system.is_production && (holder.rights & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
// No, check_rights() does not work in the above proc, because we dont have a mob yet
|
||||
_2fa_alert = TRUE
|
||||
// This also has to be manually done since no mob to use check_rights() on
|
||||
deadmin()
|
||||
add_verb(src, /client/proc/readmin)
|
||||
GLOB.de_admins += ckey
|
||||
|
||||
else
|
||||
add_admin_verbs()
|
||||
// Must be async because any sleeps (happen in sql queries) will break connectings clients
|
||||
INVOKE_ASYNC(src, PROC_REF(admin_memo_output), "Show", FALSE, TRUE)
|
||||
|
||||
|
||||
// Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
|
||||
// (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
|
||||
spawn(5) // And wait a half-second, since it sounds like you can do this too fast.
|
||||
@@ -466,16 +451,13 @@
|
||||
if(check_rights(R_ADMIN, FALSE, mob)) // Mob is required. Dont even try without it.
|
||||
to_chat(src, "The queue server is currently [SSqueue.queue_enabled ? "<font color='green'>enabled</font>" : "<font color='disabled'>disabled</font>"], with a threshold of <b>[SSqueue.queue_threshold]</b>. This <b>[SSqueue.persist_queue ? "will" : "will not"]</b> persist through rounds.")
|
||||
|
||||
if(_2fa_alert)
|
||||
if(holder && holder.restricted_by_2fa)
|
||||
to_chat(src,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
|
||||
// Tell client about their connection
|
||||
to_chat(src, "<span class='notice'>You are currently connected [prefs.server_region ? "via the <b>[prefs.server_region]</b> relay" : "directly"] to Paradise.</span>")
|
||||
to_chat(src, "<span class='notice'>You can change this using the <code>Change Region</code> verb in the OOC tab, as selecting a region closer to you may reduce latency.</span>")
|
||||
display_job_bans(TRUE)
|
||||
if(check_rights(R_DEBUG|R_VIEWRUNTIMES, FALSE, mob))
|
||||
winset(src, "debugmcbutton", "is-disabled=false")
|
||||
winset(src, "profilecode", "is-disabled=false")
|
||||
|
||||
/client/proc/is_connecting_from_localhost()
|
||||
var/static/list/localhost_addresses = list("127.0.0.1", "::1")
|
||||
@@ -605,13 +587,9 @@
|
||||
|
||||
qdel(query)
|
||||
|
||||
var/admin_rank = "Player"
|
||||
// Admins don't get slammed by this, I guess
|
||||
if(holder)
|
||||
admin_rank = holder.rank
|
||||
else
|
||||
if(check_randomizer(connectiontopic))
|
||||
return
|
||||
if(!holder && check_randomizer(connectiontopic))
|
||||
return
|
||||
|
||||
var/client_address = address
|
||||
if(!client_address) // Localhost can sometimes have no address set
|
||||
@@ -625,10 +603,9 @@
|
||||
return // Return here because if we somehow didnt pull a number from an INT column, EVERYTHING is breaking
|
||||
|
||||
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen=NOW(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen=NOW(), ip=:sql_ip, computerid=:sql_cid WHERE id=:sql_id", list(
|
||||
"sql_ip" = client_address,
|
||||
"sql_cid" = computer_id,
|
||||
"sql_ar" = admin_rank,
|
||||
"sql_id" = sql_id
|
||||
))
|
||||
|
||||
@@ -642,11 +619,10 @@
|
||||
|
||||
else
|
||||
//New player!! Need to insert all the stuff
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO player (id, ckey, firstseen, lastseen, ip, computerid) VALUES (null, :ckey, Now(), Now(), :ip, :cid)", list(
|
||||
"ckey" = ckey,
|
||||
"ip" = client_address,
|
||||
"cid" = computer_id,
|
||||
"rank" = admin_rank
|
||||
))
|
||||
if(!query_insert.warn_execute())
|
||||
qdel(query_insert)
|
||||
@@ -1141,8 +1117,22 @@
|
||||
SSambience.ambience_listening_clients -= src
|
||||
|
||||
/client/proc/try_localhost_autoadmin()
|
||||
if(GLOB.configuration.admin.enable_localhost_autoadmin && is_connecting_from_localhost())
|
||||
return new /datum/admins("!LOCALHOST!", R_HOST, ckey)
|
||||
if(!GLOB.configuration.admin.enable_localhost_autoadmin)
|
||||
return FALSE
|
||||
if(!is_connecting_from_localhost())
|
||||
if(holder && holder.is_localhost_autoadmin)
|
||||
qdel(holder)
|
||||
return FALSE
|
||||
|
||||
// Unhook the old admin datum, if any.
|
||||
if(holder)
|
||||
qdel(holder)
|
||||
|
||||
// Hook up a new localhost admin datum.
|
||||
var/datum/admins/admin_datum = new /datum/admins("!LOCALHOST!", R_HOST, ckey)
|
||||
admin_datum.is_localhost_autoadmin = TRUE
|
||||
admin_datum.associate(src)
|
||||
return TRUE
|
||||
|
||||
// Verb scoped to the client level so its ALWAYS available
|
||||
/client/verb/open_tos()
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new)
|
||||
|
||||
/datum/ui_state/admin_state/can_use_topic(src_object, mob/user)
|
||||
if(check_rights_for(user.client, R_ADMIN))
|
||||
if(check_rights_client(R_ADMIN, FALSE, user.client))
|
||||
return UI_INTERACTIVE
|
||||
return UI_CLOSE
|
||||
|
||||
@@ -173,7 +173,7 @@ ipc_screens = [
|
||||
# Enable/disable the database on a whole
|
||||
sql_enabled = false
|
||||
# SQL version. If this is a mismatch, round start will be delayed
|
||||
sql_version = 69
|
||||
sql_version = 70
|
||||
# SQL server address. Can be an IP or DNS name
|
||||
sql_address = "127.0.0.1"
|
||||
# SQL server port
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
body {padding:0px;margin:0px;}
|
||||
#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;}
|
||||
#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;}
|
||||
#main {left:3%;width:96%;text-align:center;z-index:0;}
|
||||
#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";}
|
||||
#spacer {height:50px}
|
||||
#db_notice {width:80%;margin-left:10%;margin-right:10%;text-align:center}
|
||||
#rank_edit {width:100%;text-align:center}
|
||||
tr.norm {background-color:#f4f4f4;}
|
||||
tr.title {background-color:#ccc;}
|
||||
tr.alt {background-color:#e7e7e7;}
|
||||
|
||||
Reference in New Issue
Block a user