Fixes #1147 - type-mismatch

Added helper: /proc/findchar(haystack, needles, start=1, end=0)
works like findtext except it finds the first occurrence of one of the characters from the needles string, within haystack.

Permissions can now be removed as well as added, by replacing the + with a -. e.g. +BAN adds bans permissions, -BAN removes them. This applies to admin_ranks.txt and the permissions panel.

Verb overrides are now possible for admins_ranks. Specific verbs can be forced-on, or forced-off via keywords like +/client/proc/mimespeak or -/client/verb/ooc. This applies both to admin_ranks.txt and the permissions panel. SQL system is not compatible.

admin_ranks are now datums. This means admin_ranks actually behave more like permission groups as intended.
When you temporarily modify an admin's permissions via the permissions panel, their rank_name is appended with "([ckey])". This prevents modifications to their rights affecting everyone.

admin rank names now support - _ and @ characters (since ckeyEx() does not strip these).

SQL permissions system was modified. SQL databases will have to be updated or they will no longer work.

WARNING: admin_ranks.txt and admins.txt format has changed slightly! You will need to redo those txt files!
This commit is contained in:
carnie
2013-08-11 20:43:18 +01:00
parent a6f641a722
commit bbe7354265
12 changed files with 335 additions and 321 deletions
+207 -83
View File
@@ -1,57 +1,106 @@
var/list/admin_ranks = list() //list of all ranks with associated rights
var/list/admin_ranks = list() //list of all admin_rank datums
/datum/admin_rank
var/name = "NoRank"
var/rights = 0
var/list/adds
var/list/subs
/datum/admin_rank/New(init_name, init_rights, list/init_adds, list/init_subs)
name = init_name
switch(name)
if("Removed",null,"")
error("invalid admin-rank name. datum deleted")
del(src)
if(init_rights) rights = init_rights
if(!init_adds) init_adds = list()
if(!init_subs) init_subs = list()
adds = init_adds
subs = init_subs
/datum/admin_rank/proc/process_keyword(word, previous_rights=0)
var/flag = 0
switch(ckey(word))
if("buildmode","build") flag = R_BUILDMODE
if("admin") flag = R_ADMIN
if("ban") flag = R_BAN
if("fun") flag = R_FUN
if("server") flag = R_SERVER
if("debug") flag = R_DEBUG
if("permissions","rights") flag = R_PERMISSIONS
if("possess") flag = R_POSSESS
if("stealth") flag = R_STEALTH
if("rejuv","rejuvinate") flag = R_REJUVINATE
if("varedit") flag = R_VAREDIT
if("everything","host","all") flag = 65535
if("sound","sounds") flag = R_SOUNDS
if("spawn","create") flag = R_SPAWN
if("@","prev") flag = previous_rights
else
//isn't a keyword so maybe it's a verbpath?
var/path = text2path(copytext(word,2,findtext(word," ",2,0)))
if(path)
switch(text2ascii(word,1))
if(43)
if(!subs.Remove(path))
adds += path //+
if(45)
if(!adds.Remove(path))
subs += path //-
return
switch(text2ascii(word,1))
if(43) rights |= flag //+
if(45) rights &= ~flag //-
return
//load our rank - > rights associations
/proc/load_admin_ranks()
admin_ranks.Cut()
var/previous_rights = 0
if(config.admin_legacy_system)
var/previous_rights = 0
//load text from file and process each line seperately
for(var/line in file2list("config/admin_ranks.txt"))
if(!line) continue
if(findtextEx(line,"#",1,2)) continue
//load text from file
var/list/Lines = file2list("config/admin_ranks.txt")
var/next = findtext(line, "=")
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, next)))
if(!R) continue
admin_ranks += R
//process each line seperately
for(var/line in Lines)
if(!length(line)) continue
if(copytext(line,1,2) == "#") continue
var/prev = findchar(line, "+-", next, 0)
while(prev)
next = findchar(line, "+-", prev+1, 0)
R.process_keyword(copytext(line, prev, next), previous_rights)
prev = next
previous_rights = R.rights
else
establish_db_connection()
if(!dbcon.IsConnected())
world.log << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
diary << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
config.admin_legacy_system = 1
load_admin_ranks()
return
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 |= ((2 * R_MAXPERMISSION) - 1)
if("sound","sounds") rights |= R_SOUNDS
if("spawn","create") rights |= R_SPAWN
/* --ONCE FLAGS LARGER OR EQUAL THAN 2^16 = 65536 START BEING USED, USE THIS CODE!
if("nukeeverything") rights += R_NUKEEVERYTHING
*/
admin_ranks[rank] = rights
previous_rights = rights
var/DBQuery/query = dbcon.NewQuery("SELECT rank, flags FROM erro_admin_ranks")
query.Execute()
while(query.NextRow())
var/rank_name = ckeyEx(query.item[1])
var/flags = query.item[2]
if(istext(flags)) flags = text2num(flags)
var/datum/admin_rank/R = new(rank_name, flags)
if(!R) continue
admin_ranks += R
#ifdef TESTING
var/msg = "Permission Sets Built:\n"
for(var/rank in admin_ranks)
msg += "\t[rank] - [admin_ranks[rank]]\n"
for(var/datum/admin_rank/R in admin_ranks)
msg += "\t[R.name]"
var/rights = rights2text(R.rights,"\n\t\t",R.adds,R.subs)
if(rights) msg += "\t\t[rights]\n"
testing(msg)
#endif
@@ -63,43 +112,39 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
C.remove_admin_verbs()
C.holder = null
admins.Cut()
load_admin_ranks()
var/list/rank_names = list()
for(var/datum/admin_rank/R in admin_ranks)
rank_names[R.name] = R
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(findtextEx(line,"#",1,2)) continue
//Split the line at every "-"
var/list/List = text2list(line, "-")
//Split the line at every "="
var/list/List = text2list(line, "=")
if(!List.len) continue
//ckey is before the first "-"
//ckey is before the first "="
var/ckey = ckey(List[1])
if(!ckey) continue
//rank follows the first "-"
//rank follows the first "="
var/rank = ""
if(List.len >= 2)
rank = ckeyEx(List[2])
//load permissions associated with this rank
var/rights = admin_ranks[rank]
//create the admin datum and store it for later use
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
//find the client for a ckey if they are connected and associate them with the new admin datum
D.associate(directory[ckey])
var/datum/admins/D = new(rank_names[rank], ckey) //create the admin datum and store it for later use
if(!D) continue //will occur if an invalid rank is provided
D.associate(directory[ckey]) //find the client for a ckey if they are connected and associate them with the new admin datum
else
//The current admin system uses SQL
establish_db_connection()
if(!dbcon.IsConnected())
world.log << "Failed to connect to database in load_admins(). Reverting to legacy system."
@@ -108,33 +153,20 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
load_admins()
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank FROM erro_admin")
query.Execute()
while(query.NextRow())
var/ckey = query.item[1]
var/rank = query.item[2]
if(rank == "Removed") continue //This person was de-adminned. They are only in the admin list for archive purposes.
var/rights = query.item[4]
if(istext(rights)) rights = text2num(rights)
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
//find the client for a ckey if they are connected and associate them with the new admin datum
D.associate(directory[ckey])
if(!admin_datums)
world.log << "The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system."
diary << "The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system."
config.admin_legacy_system = 1
load_admins()
return
var/ckey = ckey(query.item[1])
var/rank = ckeyEx(query.item[2])
var/datum/admins/D = new(rank, ckey) //create the admin datum and store it for later use
if(!D) continue //will occur if an invalid rank is provided
D.associate(directory[ckey]) //find the client for a ckey if they are connected and associate them with the new admin datum
#ifdef TESTING
var/msg = "Admins Built:\n"
for(var/ckey in admin_datums)
var/rank
var/datum/admins/D = admin_datums[ckey]
if(D) rank = D.rank
msg += "\t[ckey] - [rank]\n"
msg += "\t[ckey] - [D.rank.name]\n"
testing(msg)
#endif
@@ -143,18 +175,110 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
/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)
holder = new /datum/admins(newrank,ckey)
remove_admin_verbs()
holder.associate(src)
/client/verb/changerights(newrights as num)
if(holder)
holder.rights = newrights
holder.rank.rights = newrights
else
holder = new /datum/admins("testing",newrights,ckey)
remove_admin_verbs()
holder.associate(src)
#endif
/datum/admins/proc/edit_rights_topic(list/href_list)
if(!check_rights(R_PERMISSIONS))
message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.")
log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.")
return
var/adm_ckey
var/task = href_list["editrights"]
switch(task)
if("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)
usr << "<font color='red'>Error: Topic 'editrights': [new_ckey] is already an admin</font>"
return
adm_ckey = new_ckey
task = "rank"
else
adm_ckey = ckey(href_list["ckey"])
if(!adm_ckey)
usr << "<font color='red'>Error: Topic 'editrights': No valid ckey</font>"
return
var/datum/admins/D = admin_datums[adm_ckey]
switch(task)
if("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")
log_admin_rank_modification(adm_ckey, "Removed")
if("rank")
var/datum/admin_rank/R
var/list/rank_names = list("*New Rank*")
for(R in admin_ranks)
rank_names[R.name] = R
var/new_rank = input("Please select a rank", "New rank", null, null) as null|anything in rank_names
switch(new_rank)
if(null) return
if("*New Rank*")
new_rank = ckeyEx(input("Please input a new rank", "New custom rank", null, null) as null|text)
if(!new_rank) return
R = rank_names[new_rank]
if(!R) //rank with that name doesn't exist yet - make it
if(D) R = new(new_rank, D.rank.rights, D.rank.adds, D.rank.subs) //duplicate our previous admin_rank but with a new name
else R = new(new_rank) //blank new admin_rank
admin_ranks += R
if(D) //they were previously an admin
D.disassociate() //existing admin needs to be disassociated
D.rank = R //set the admin_rank as our rank
else
D = new(R,adm_ckey) //new admin
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]")
log_admin_rank_modification(adm_ckey, new_rank)
if("permissions")
if(!D) return //they're not an admin!
var/keyword = input("Input permission keyword (one at a time):\ne.g. +BAN or -FUN or +/client/proc/someverb", "Permission toggle", null, null) as null|text
if(!keyword) return
D.disassociate()
if(!findtext(D.rank.name, "([adm_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
D.rank = new("[D.rank.name]([adm_ckey])", D.rank.rights, D.rank.adds, D.rank.subs) //duplicate our previous admin_rank but with a new name
//we don't add this clone to the admin_ranks list, as it is unique to that ckey
D.rank.process_keyword(keyword)
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(usr)] added keyword [keyword] to permission of [adm_ckey]")
log_admin("[key_name(usr)] added keyword [keyword] to permission of [adm_ckey]")
log_admin_permission_modification(adm_ckey, D.rank.rights)
edit_admin_permissions()
+20 -12
View File
@@ -198,19 +198,25 @@ var/list/admin_verbs_hideable = list(
/client/proc/add_admin_verbs()
if(holder)
var/rights = holder.rank.rights
verbs += admin_verbs_default
if(holder.rights & R_BUILDMODE) verbs += /client/proc/togglebuildmodeself
if(holder.rights & R_ADMIN) verbs += admin_verbs_admin
if(holder.rights & R_BAN) verbs += admin_verbs_ban
if(holder.rights & R_FUN) verbs += admin_verbs_fun
if(holder.rights & R_SERVER) verbs += admin_verbs_server
if(holder.rights & R_DEBUG) verbs += admin_verbs_debug
if(holder.rights & R_POSSESS) verbs += admin_verbs_possess
if(holder.rights & R_PERMISSIONS) verbs += admin_verbs_permissions
if(holder.rights & R_STEALTH) verbs += /client/proc/stealth
if(holder.rights & R_REJUVINATE) verbs += admin_verbs_rejuv
if(holder.rights & R_SOUNDS) verbs += admin_verbs_sounds
if(holder.rights & R_SPAWN) verbs += admin_verbs_spawn
if(rights & R_BUILDMODE) verbs += /client/proc/togglebuildmodeself
if(rights & R_ADMIN) verbs += admin_verbs_admin
if(rights & R_BAN) verbs += admin_verbs_ban
if(rights & R_FUN) verbs += admin_verbs_fun
if(rights & R_SERVER) verbs += admin_verbs_server
if(rights & R_DEBUG) verbs += admin_verbs_debug
if(rights & R_POSSESS) verbs += admin_verbs_possess
if(rights & R_PERMISSIONS) verbs += admin_verbs_permissions
if(rights & R_STEALTH) verbs += /client/proc/stealth
if(rights & R_REJUVINATE) verbs += admin_verbs_rejuv
if(rights & R_SOUNDS) verbs += admin_verbs_sounds
if(rights & R_SPAWN) verbs += admin_verbs_spawn
for(var/path in holder.rank.adds)
verbs += path
for(var/path in holder.rank.subs)
verbs -= path
/client/proc/remove_admin_verbs()
verbs.Remove(
@@ -246,6 +252,8 @@ var/list/admin_verbs_hideable = list(
/client/proc/kaboom,
/client/proc/cmd_admin_areatest
)
if(holder)
verbs.Remove(holder.rank.adds)
/client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs
set name = "Adminverbs - Hide Most"
+16 -26
View File
@@ -1,9 +1,9 @@
var/list/admin_datums = list()
/datum/admins
var/rank = "Temporary Admin"
var/datum/admin_rank/rank
var/client/owner = null
var/rights = 0
var/fakekey = null
var/datum/marked_datum
@@ -13,14 +13,17 @@ var/list/admin_datums = list()
var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel
var/admincaster_signature //What you'll sign the newsfeeds as
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
/datum/admins/New(datum/admin_rank/R, ckey)
if(!ckey)
error("Admin datum created without a ckey argument. Datum has been deleted")
del(src)
return
if(!istype(R))
error("Admin datum created without a rank. Datum has been deleted")
del(src)
return
rank = R
admincaster_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
rank = initial_rank
rights = initial_rights
admin_datums[ckey] = src
/datum/admins/proc/associate(client/C)
@@ -65,14 +68,10 @@ you will have to do something like if(client.rights & R_ADMIN) yourself.
if(usr.client.holder)
if(!other || !other.holder)
return 1
var/usr_rights_pt2 = usr.client.holder.rights / 65536
var/other_rights_pt2 = other.holder.rights / 65536
if( (usr_rights_pt2 & other_rights_pt2) == other_rights_pt2 ) //Check values larger than 65535
if(usr.client.holder.rights != other.holder.rights) //Check values smaller than 65536
if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights )
return 1 //we have all the rights they have and more
usr << "<font color='red'>Error: Cannot proceed. They have more or equal rights to us.</font>"
if(usr.client.holder.rank.rights != other.holder.rank.rights) //Check values smaller than 65536
if( (usr.client.holder.rank.rights & other.holder.rank.rights) == other.holder.rank.rights )
return 1 //we have all the rights they have and more
usr << "<font color='red'>Error: Cannot proceed. They have greater or equal rights to us.</font>"
return 0
@@ -85,17 +84,8 @@ you will have to do something like if(client.rights & R_ADMIN) yourself.
//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)
if(rights_required)
if(subject.holder)
if(rights_required >= 65536)
var/rights_required_pt2 = rights_required / 65536
var/rights_pt2 = subject.holder.rights / 65536
if(rights_required_pt2 & rights_pt2)
return 1
if(rights_required & subject.holder.rights)
return 1
else
if(subject.holder)
return 1
if(subject && subject.holder && subject.holder.rank)
if(rights_required && !(rights_required & subject.holder.rank.rights))
return 0
return 1
return 0
@@ -19,21 +19,24 @@
<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>
<th style='width:125px;'>RANK</th>
<th style='width:375px;'>PERMISSIONS</th>
<th style='width:100%;'>VERB-OVERRIDES</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," ")
var/rights = rights2text(D.rank.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></font></td>"
output += "<td><a href='?src=\ref[src];editrights=rank;ckey=[adm_ckey]'>[D.rank.name]</a></td>"
output += "<td><a class='small' href='?src=\ref[src];editrights=permissions;ckey=[adm_ckey]'>[rights]</a></td>"
output += "<td><a class='small' href='?src=\ref[src];editrights=permissions;ckey=[adm_ckey]'>[rights2text(0," ",D.rank.adds,D.rank.subs)]</a></td>"
output += "</tr>"
output += {"
@@ -42,7 +45,7 @@
</body>
</html>"}
usr << browse(output,"window=editrights;size=600x500")
usr << browse(output,"window=editrights;size=900x650")
/datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank)
if(config.admin_legacy_system) return
@@ -93,55 +96,30 @@
log_query.Execute()
usr << "\blue Admin rank changed."
/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission)
if(config.admin_legacy_system) return
if(!usr.client)
return
if (check_rights(R_PERMISSIONS))
return
if(!usr.client) return
if(check_rights(R_PERMISSIONS)) return
establish_db_connection()
if(!dbcon.IsConnected())
usr << "\red Failed to establish database connection"
return
if(!adm_ckey || !new_permission)
return
adm_ckey = ckey(adm_ckey)
if(!adm_ckey)
return
if(istext(new_permission))
new_permission = text2num(new_permission)
if(!istext(adm_ckey) || !isnum(new_permission))
if(!adm_ckey || !istext(adm_ckey) || !isnum(new_permission))
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'")
select_query.Execute()
var/admin_id
var/admin_rights
while(select_query.NextRow())
admin_id = text2num(select_query.item[1])
admin_rights = text2num(select_query.item[2])
if(!admin_id)
return
if(!admin_id) return
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
log_query.Execute()
usr << "\blue Permission removed."
else //This admin doesn't have this permission, so we are adding it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
log_query.Execute()
usr << "\blue Permission added."
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [new_permission] WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edit permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
log_query.Execute()
+1 -92
View File
@@ -146,98 +146,7 @@
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid )
else if(href_list["editrights"])
if(!check_rights(R_PERMISSIONS))
message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.")
log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.")
return
var/adm_ckey
var/task = href_list["editrights"]
if(task == "add")
var/new_ckey = ckey(input(usr,"New admin's ckey","Admin ckey", null) as text|null)
if(!new_ckey) return
if(new_ckey in admin_datums)
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)
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")
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)
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]")
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]")
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
edit_admin_permissions()
edit_rights_topic(href_list)
else if(href_list["call_shuttle"])
if(!check_rights(R_ADMIN)) return