From 266f163879d8d1b439c4436d92e48d8454ff31ca Mon Sep 17 00:00:00 2001 From: "baloh.matevz" Date: Sun, 14 Oct 2012 19:45:21 +0000 Subject: [PATCH] - To support the SQL based admin rank system, I added a permission assignment panel, which is accessible to the people who have the PERMISSIONS permission. This panel can be used to add new admins, remove or edit the rank of existing admins. Screenshot: http://www.kamletos.si/permissions%20panel.PNG git-svn-id: http://tgstation13.googlecode.com/svn/trunk@4878 316c924e-a436-60f5-8080-3fe189b3f50e --- code/defines/procs/helper_list.dm | 20 ++- code/global.dm | 28 ++++ code/modules/admin/admin_verbs.dm | 1 + code/modules/admin/holder2.dm | 44 ++++++ .../admin/permissionverbs/assignment.dm | 12 ++ .../admin/permissionverbs/permissionedit.dm | 127 ++++++++++++++++++ code/modules/admin/verbs/modifyvariables.dm | 2 + code/world.dm | 36 ++++- tgstation.dme | 4 + 9 files changed, 268 insertions(+), 6 deletions(-) create mode 100644 code/modules/admin/permissionverbs/assignment.dm create mode 100644 code/modules/admin/permissionverbs/permissionedit.dm diff --git a/code/defines/procs/helper_list.dm b/code/defines/procs/helper_list.dm index cfc9a6edefe..827a6348c26 100644 --- a/code/defines/procs/helper_list.dm +++ b/code/defines/procs/helper_list.dm @@ -286,4 +286,22 @@ proc/listclearnulls(list/list) if(Li <= L.len) return (result + L.Copy(Li, 0)) - return (result + R.Copy(Ri, 0)) \ No newline at end of file + return (result + R.Copy(Ri, 0)) + + +//Converts a bitfield to a list of numbers (or words if a wordlist is provided) +/proc/bitfield2list(bitfield = 0, list/wordlist) + var/list/r = list() + if(istype(wordlist,/list)) + var/max = min(wordlist.len,16) + var/bit = 1 + for(var/i=1, i<=max, i++) + if(bitfield & bit) + r += wordlist[i] + bit = bit << 1 + else + for(var/bit=1, bit<=65535, bit = bit << 1) + if(bitfield & bit) + r += bit + + return r \ No newline at end of file diff --git a/code/global.dm b/code/global.dm index 5b77d1acc8c..698fa2397f2 100644 --- a/code/global.dm +++ b/code/global.dm @@ -205,3 +205,31 @@ var/forum_authenticated_group = "10" // For FTP requests. (i.e. downloading runtime logs.) // However it'd be ok to use for accessing attack logs and such too, which are even laggier. var/fileaccess_timer = 1800 //Cannot access files by ftp until the game is finished setting up and stuff. + + +#define BUILDMODE 1 +#define ADMIN 2 +#define BAN 4 +#define FUN 8 +#define SERVER 16 +#define ADMDEBUG 32 +#define POSSESS 64 +#define PERMISSIONS 128 +//Keep this list synced with the #defines above +var/global/list/permissionwords = list("BUILDMODE", "ADMIN", "BAN", "FUN", "SERVER", "DEBUG", "POSSESS", "EDITPERMISSIONS") + + + +//Please do not edit these values. The database assigning proper rights relies on this. You can add new values, just don't change existing ones. +//This list is separate from the list used ingame, so that one can be edited with little consequence. This one is tied to the database +//The database admins should be consulted before any edits to this list. +#define SQL_BUILDMODE 1 +#define SQL_ADMIN 2 +#define SQL_BAN 4 +#define SQL_FUN 8 +#define SQL_SERVER 16 +#define SQL_DEBUG 32 +#define SQL_POSSESS 64 +#define SQL_PERMISSIONS 128 +//Same rules apply to this list as to the values above. You can only add stuff to it. +var/global/list/permissionwords_sql = list("BUILDMODE", "ADMIN", "BAN", "FUN", "SERVER", "DEBUG", "POSSESS", "EDITPERMISSIONS") \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 7171236bb9f..bd66109623e 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -40,6 +40,7 @@ if(!need_update) return clear_admin_verbs() + handle_permission_verbs() switch(rank) if("Game Master") diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index c10d4b494fc..7949e046dca 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -19,6 +19,7 @@ var/list/admin_datums = list() var/fakekey = null var/ooccolor = "#b82e00" var/sound_adminhelp = 0 //If set to 1 this will play a sound when adminhelps are received. + var/sql_permissions = 0 //Permissions for different admin command groups. Must not be editable ingame. var/datum/marked_datum @@ -84,6 +85,49 @@ var/list/admin_datums = list() usr << "\red Unfortunatly there were no candidates available" return + if(href_list["editadminpermissions"]) + if(!usr.client) + return + + var/adm_ckey = href_list["editadminckey"] + if(!adm_ckey) + usr << "\red no valid ckey" + return + + if(!usr.client.holder || !(usr.client.holder.sql_permissions & PERMISSIONS)) + usr << "\red You do not have permission to do this!" + message_admins("[key_name_admin(usr)] attempted to edit the admin permissions of [adm_ckey] without authentication!") + log_admin("[key_name(usr)] attempted to edit the admin permissions of [adm_ckey] without authentication!") + return + + switch(href_list["editadminpermissions"]) + if("permissions") + usr << "Currently unavailable since nothing runs off of permissions" + if("rank") + var/new_rank = input("Please, select a rank", "New rank for player", null, null) as null|anything in list("Game Master","Game Admin", "Trial Admin", "Admin Observer") + if(!new_rank) + return + 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("remove") + if(alert("Are you sure you want to remove [adm_ckey]?","Message","Yes","Cancel") == "Yes") + 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("add") + var/new_ckey = input(usr,"New admin's ckey","Admin ckey", null) as text|null + if(!new_ckey) + return + var/new_rank = input("Please, select a rank", "New rank for player", null, null) as null|anything in list("Game Master","Game Admin", "Trial Admin", "Admin Observer") + if(!new_rank) + return + message_admins("[key_name_admin(usr)] added [new_ckey] as a new admin to the rank [new_rank]") + log_admin("[key_name(usr)] added [new_ckey] as a new admin to the rank [new_rank]") + log_admin_rank_modification(new_ckey, new_rank) + + + if(href_list["call_shuttle"]) if (src.rank in list("Trial Admin", "Badmin", "Game Admin", "Game Master")) if( ticker.mode.name == "blob" ) diff --git a/code/modules/admin/permissionverbs/assignment.dm b/code/modules/admin/permissionverbs/assignment.dm new file mode 100644 index 00000000000..66affaa6969 --- /dev/null +++ b/code/modules/admin/permissionverbs/assignment.dm @@ -0,0 +1,12 @@ + + + +//Before this proc is called, the holder variable must already be set, with the proper rank, level and permissions set. +//This proc also DOES NOT CLEAR EXISTING ADMIN VERBS + +/client/proc/handle_permission_verbs() + if(!holder || !holder.rank || !holder.sql_permissions) + return + + if(holder.sql_permissions & PERMISSIONS) + verbs += /client/proc/edit_admin_permissions \ No newline at end of file diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm new file mode 100644 index 00000000000..f69138f23bb --- /dev/null +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -0,0 +1,127 @@ +/client/proc/edit_admin_permissions() + set category = "Admin" + set name = "Permissions Panel" + set desc = "Edit admin permissions" + + if(!holder) + return + holder.edit_admin_permissions() + +/datum/admins/proc/edit_admin_permissions() + if(!usr.client) + return + + if(!usr.client.holder || !(usr.client.holder.sql_permissions & PERMISSIONS)) + usr << "\red You do not have permission to do this!" + return + + var/user = sqlfdbklogin + var/pass = sqlfdbkpass + var/db = sqlfdbkdb + var/address = sqladdress + var/port = sqlport + + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + if(!dbcon.IsConnected()) + usr << "\red Failed to establish database connection" + return + + var/DBQuery/select_query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin ORDER BY rank, ckey") + select_query.Execute() + + var/output = "

Current admins

" + + output += "Add new admin" + + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + + var/color1 = "#f4f4f4" + var/color2 = "#e7e7e7" + var/i = 1 //Used to determine the color of each row + + while(select_query.NextRow()) + i = !i + var/adm_ckey = select_query.item[1] + var/adm_rank = select_query.item[2] + var/adm_level = select_query.item[3] + var/adm_flags = text2num(select_query.item[4]) + output += "" + output += "" + output += "" + output += "" + var/list/permissionlist = bitfield2list(adm_flags, permissionwords_sql) + output += "" + output += "" + output += "" + + output += "
CKEYRANKLEVELPERMISSIONSOPTIONS
[adm_ckey][adm_rank][adm_level]" + for(var/word in permissionlist) + output += "[word]
" + output += "
" + + //Options + output += "PERMISSIONS
" + output += "RANK
" + output += "REMOVE" + + output += "
" + + usr << browse(output,"window=editadminpermissions;size=600x500") + + +/datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank) + if(!usr.client) + return + + if(!usr.client.holder || !(usr.client.holder.sql_permissions & PERMISSIONS)) + usr << "\red You do not have permission to do this!" + return + + var/user = sqlfdbklogin + var/pass = sqlfdbkpass + var/db = sqlfdbkdb + var/address = sqladdress + var/port = sqlport + + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + if(!dbcon.IsConnected()) + usr << "\red Failed to establish database connection" + return + + if(!adm_ckey || !new_rank) + return + + if(!istext(adm_ckey) || !istext(new_rank)) + return + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'") + select_query.Execute() + + var/new_admin = 1 + var/admin_id + while(select_query.NextRow()) + new_admin = 0 + admin_id = text2num(select_query.item[1]) + + if(new_admin) + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") + 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 new admin [adm_ckey] to rank [new_rank]');") + log_query.Execute() + usr << "\blue New admin added." + else + if(!isnull(admin_id) && isnum(admin_id)) + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' 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]', 'Edited the rank of [adm_ckey] to [new_rank]');") + log_query.Execute() + usr << "\blue Admin rank changed." diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 43fb36977de..877fd47182e 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -4,12 +4,14 @@ var/list/forbidden_varedit_object_types = list( /datum/feedback_variable //Prevents people messing with feedback gathering ) +/* /client/proc/cmd_modify_object_variables(obj/O as obj|mob|turf|area in world) set category = "Debug" set name = "Edit Variables" set desc="(target) Edit a target item's variables" src.modify_variables(O) feedback_add_details("admin_verb","EDITV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +*/ /client/proc/cmd_modify_ticker_variables() set category = "Debug" diff --git a/code/world.dm b/code/world.dm index c79e20cf8f4..7ef8e8e55c9 100644 --- a/code/world.dm +++ b/code/world.dm @@ -189,7 +189,6 @@ Starting up. [time2text(world.timeofday, "hh:mm.ss")] /world/proc/load_motd() join_motd = file2text("config/motd.txt") - /world/proc/load_admins() if(config.admin_legacy_system) //Legacy admin system uses admins.txt @@ -228,14 +227,43 @@ Starting up. [time2text(world.timeofday, "hh:mm.ss")] load_admins() return - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level FROM erro_admin") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin") query.Execute() while(query.NextRow()) var/adminckey = query.item[1] var/adminrank = query.item[2] var/adminlevel = query.item[3] + if(istext(adminlevel)) + adminlevel = text2num(adminlevel) + var/permissions = query.item[4] + if(istext(permissions)) + permissions = text2num(permissions) + + //This list of stuff translates the permission defines the database uses to the permission structure that the game uses. + var/permissions_actual = 0 + if(permissions & SQL_BUILDMODE) + permissions_actual |= BUILDMODE + if(permissions & SQL_ADMIN) + permissions_actual |= ADMIN + if(permissions & SQL_BAN) + permissions_actual |= BAN + if(permissions & SQL_FUN) + permissions_actual |= FUN + if(permissions & SQL_SERVER) + permissions_actual |= SERVER + if(permissions & SQL_DEBUG) + permissions_actual |= ADMDEBUG + if(permissions & SQL_POSSESS) + permissions_actual |= POSSESS + if(permissions & SQL_PERMISSIONS) + permissions_actual |= PERMISSIONS + + if(adminrank == "Removed") + return //This person was de-adminned. They are only in the admin list for archive purposes. + var/datum/admins/AD = new /datum/admins(adminrank) - AD.level = adminlevel + AD.level = adminlevel //Legacy support for old verbs + AD.sql_permissions = permissions_actual admins[adminckey] = AD if(!admins) @@ -244,8 +272,6 @@ Starting up. [time2text(world.timeofday, "hh:mm.ss")] load_admins() return - - /world/proc/load_configuration() config = new /datum/configuration() config.load("config/config.txt") diff --git a/tgstation.dme b/tgstation.dme index 22a4387fbc4..79a55391560 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -93,6 +93,7 @@ #define FILE_DIR "code/modules" #define FILE_DIR "code/modules/admin" #define FILE_DIR "code/modules/admin/DB ban" +#define FILE_DIR "code/modules/admin/permissionverbs" #define FILE_DIR "code/modules/admin/verbs" #define FILE_DIR "code/modules/assembly" #define FILE_DIR "code/modules/awaymissions" @@ -205,6 +206,7 @@ #define FILE_DIR "icons/vending_icons" #define FILE_DIR "interface" #define FILE_DIR "maps" +#define FILE_DIR "maps/backup" #define FILE_DIR "maps/RandomZLevels" #define FILE_DIR "sound" #define FILE_DIR "sound/AI" @@ -820,6 +822,8 @@ #include "code\modules\admin\player_panel.dm" #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\DB ban\functions.dm" +#include "code\modules\admin\permissionverbs\assignment.dm" +#include "code\modules\admin\permissionverbs\permissionedit.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminpm.dm"