diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index 6e6bd7f7ca..83bc78050d 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -2,14 +2,22 @@ Any time you make a change to the schema files, remember to increment the databa The latest database version is 4.1; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (4, 1); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (4, 2); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (4, 1); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (4, 2); In any query remember to add a prefix to the table names if you use one. ---------------------------------------------------- +Version 4.2, 17 April 2018, by Jordie0608 +Modified table 'admin', adding the columns 'round_id' and 'target' +ALTER TABLE `admin_log` + ADD COLUMN `round_id` INT UNSIGNED NOT NULL AFTER `datetime`, + ADD COLUMN `target` VARCHAR(32) NOT NULL AFTER `operation`; + +---------------------------------------------------- + Version 4.1, 3 February 2018, by Jordie0608 Modified tables 'admin', 'admin_log' and 'admin_rank', removing unnecessary columns and adding support for excluding rights flags from admin ranks. This change was made to enable use of sql-based admin loading. @@ -41,7 +49,6 @@ ALTER TABLE `admin_ranks` DROP PRIMARY KEY, ADD PRIMARY KEY (`rank`); - ---------------------------------------------------- Version 4.0, 12 November 2017, by Jordie0608 diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index ddd31a7e80..92411ea895 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -33,9 +33,11 @@ DROP TABLE IF EXISTS `admin_log`; CREATE TABLE `admin_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, + `round_id` int(11) unsigned NOT NULL, `adminckey` varchar(32) NOT NULL, `adminip` int(10) unsigned NOT NULL, `operation` enum('add admin','remove admin','change admin rank','add rank','remove rank','change rank flags') NOT NULL, + `target` varchar(32) NOT NULL, `log` varchar(1000) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 01e0ed150b..de9d67e335 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -33,9 +33,11 @@ DROP TABLE IF EXISTS `SS13_admin_log`; CREATE TABLE `SS13_admin_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, + `round_id` int(11) unsigned NOT NULL, `adminckey` varchar(32) NOT NULL, `adminip` int(10) unsigned NOT NULL, `operation` enum('add admin','remove admin','change admin rank','add rank','remove rank','change rank flags') NOT NULL, + `target` varchar(32) NOT NULL, `log` varchar(1000) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 2b5e42e339..3313754324 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -1,7 +1,7 @@ //Update this whenever the db schema changes //make sure you add an update to the schema_version stable in the db changelog #define DB_MAJOR_VERSION 4 -#define DB_MINOR_VERSION 1 +#define DB_MINOR_VERSION 2 //Timing subsystem //Don't run if there is an identical unique timer active diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index dee4787753..7873a97f7c 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -242,7 +242,6 @@ GLOBAL_PROTECT(protected_ranks) var/skip if(rank_names[admin_rank] == null) message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].") - log_sql("[admin_ckey] loaded with invalid admin rank [admin_rank].") skip = 1 if(GLOB.admin_datums[admin_ckey] || GLOB.deadmins[admin_ckey]) skip = 1 diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index f7bb770079..1d0bdddf03 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -6,56 +6,106 @@ return usr.client.holder.edit_admin_permissions() -/datum/admins/proc/edit_admin_permissions() +/datum/admins/proc/edit_admin_permissions(action, target, operation, page) if(!check_rights(R_PERMISSIONS)) return - - var/list/output = list({" - - -Permissions Panel - - - - -
- - - - - - - -"}) - - for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins) - var/datum/admins/D = GLOB.admin_datums[adm_ckey] - if(!D) - D = GLOB.deadmins[adm_ckey] - if (!D) - continue - - var/deadminlink = "" - if (D.deadmined) - deadminlink = " \[RA\]" - else - deadminlink = " \[DA\]" - - output += "" - output += "" - output += "" - output += "" - output += "" - output += "" - output += "" - - output += {" -
CKEY \[+\]RANKPERMISSIONSDENIEDALLOWED TO EDIT
[adm_ckey]
[deadminlink]\[-\]\[SYNC TGDB\]
[D.rank.name][rights2text(D.rank.include_rights," ")][rights2text(D.rank.exclude_rights," ", "-")][rights2text(D.rank.can_edit_rights," ", "*")]
-
Search:
- -"} - - usr << browse(jointext(output, ""),"window=editrights;size=1000x650") + var/list/output = list("\[Permissions\]") + if(action) + output += " | \[Log\] | \[Management\]
" + else + output += "
\[Log\]
\[Management\]" + if(action == 1) + var/list/searchlist = list(" WHERE ") + if(target) + searchlist += "ckey = '[sanitizeSQL(target)]'" + if(operation) + if(target) + searchlist += " AND " + searchlist += "operation = '[sanitizeSQL(operation)]'" + var/search + if(searchlist.len > 1) + search = searchlist.Join("") + var/logcount = 0 + var/logssperpage = 20 + var/pagecount = 0 + page = text2num(page) + var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("admin_log")][search]") + if(!query_count_admin_logs.warn_execute()) + return + if(query_count_admin_logs.NextRow()) + logcount = text2num(query_count_admin_logs.item[1]) + if(logcount > logssperpage) + output += "
Page: " + while(logcount > 0) + output += "|[pagecount == page ? "\[[pagecount]\]" : "\[[pagecount]\]"]" + logcount -= logssperpage + pagecount++ + output += "|" + var/limit = " LIMIT [logssperpage * page], [logssperpage]" + var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, adminckey, operation, target, log FROM [format_table_name("admin_log")][search] ORDER BY datetime DESC[limit]") + if(!query_search_admin_logs.warn_execute()) + return + while(query_search_admin_logs.NextRow()) + var/datetime = query_search_admin_logs.item[1] + var/round_id = query_search_admin_logs.item[2] + var/admin_ckey = query_search_admin_logs.item[3] + operation = query_search_admin_logs.item[4] + target = query_search_admin_logs.item[5] + var/log = query_search_admin_logs.item[6] + output += "

[datetime] | Round ID [round_id] | Admin [admin_ckey] | Operation [operation] on [target]
[log]


" + if(action == 2) + output += "

Admin ckeys with invalid ranks

" + var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT ckey, [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL") + if(!query_check_admin_errors.warn_execute()) + return + while(query_check_admin_errors.NextRow()) + var/admin_ckey = query_check_admin_errors.item[1] + var/admin_rank = query_check_admin_errors.item[2] + output += "[admin_ckey] has non-existant rank [admin_rank] | \[Change Rank\] | \[Remove\]" + output += "
" + output += "

Unused ranks

" + var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].rank FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].rank = [format_table_name("admin_ranks")].rank WHERE [format_table_name("admin")].rank IS NULL") + if(!query_check_unused_rank.warn_execute()) + return + while(query_check_unused_rank.NextRow()) + var/admin_rank = query_check_unused_rank.item[1] + output += "Rank [admin_rank] is not held by any admin | \[Remove\]" + output += "
" + else if(!action) + output += {" + Permissions Panel + + + +
+ + + + + + + + "} + for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins) + var/datum/admins/D = GLOB.admin_datums[adm_ckey] + if(!D) + D = GLOB.deadmins[adm_ckey] + if (!D) + continue + var/deadminlink = "" + if (D.deadmined) + deadminlink = " \[RA\]" + else + deadminlink = " \[DA\]" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "
CKEY \[+\]RANKPERMISSIONSDENIEDALLOWED TO EDIT
[adm_ckey]
[deadminlink]\[-\]\[SYNC TGDB\]
[D.rank.name][rights2text(D.rank.include_rights," ")][rights2text(D.rank.exclude_rights," ", "-")][rights2text(D.rank.can_edit_rights," ", "*")]
Search:
" + usr << browse("[jointext(output, "")]","window=editrights;size=1000x650") /datum/admins/proc/edit_rights_topic(list/href_list) if(!check_rights(R_PERMISSIONS)) @@ -142,10 +192,17 @@ return FALSE if(use_db) . = sanitizeSQL(.) + //if an admin exists without a datum they won't be caught by the above + var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE ckey = '[.]'") + if(!query_admin_in_db.warn_execute()) + return FALSE + if(query_admin_in_db.NextRow()) + to_chat(usr, "[.] already listed in admin database. Check the Management tab if they don't appear in the list of admins.") + return FALSE var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')") if(!query_add_admin.warn_execute()) return FALSE - var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', 'New admin added: [.]')") + var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', '[.]', 'New admin added: [.]')") if(!query_add_admin_log.warn_execute()) return FALSE @@ -153,12 +210,13 @@ if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it") GLOB.admin_datums -= admin_ckey GLOB.deadmins -= admin_ckey - D.disassociate() + if(D) + D.disassociate() if(use_db) var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'") if(!query_add_rank.warn_execute()) return - var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', 'Admin removed: [admin_ckey]')") + var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', '[admin_ckey]', 'Admin removed: [admin_ckey]')") if(!query_add_rank_log.warn_execute()) return message_admins("[key_name_admin(usr)] removed [admin_ckey] from the admins list [use_db ? "permanently" : "temporarily"]") @@ -216,13 +274,13 @@ var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')") if(!query_add_rank.warn_execute()) return - var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', 'New rank added: [admin_ckey]')") + var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', '[new_rank]', 'New rank added: [new_rank]')") if(!query_add_rank_log.warn_execute()) return var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'") if(!query_change_rank.warn_execute()) return - var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')") + var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', '[admin_ckey]', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')") if(!query_change_rank_log.warn_execute()) return if(D) //they were previously an admin @@ -259,7 +317,7 @@ var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[D.rank.name]'") if(!query_change_rank_flags.warn_execute()) return - var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', 'Permissions of [admin_ckey] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')") + var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', '[D.rank.name]', 'Permissions of [D.rank.name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')") if(!query_change_rank_flags_log.warn_execute()) return for(var/datum/admin_rank/R in GLOB.admin_ranks) @@ -294,6 +352,36 @@ message_admins("[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]") log_admin("[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]") +/datum/admins/proc/remove_rank(admin_rank) + if(!admin_rank) + return + for(var/datum/admin_rank/R in GLOB.admin_ranks) + if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights)) + to_chat(usr, "You don't have edit rights to all the rights this rank has, rank deletion not permitted.") + return + if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks)) + to_chat(usr, "Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.") + return + if(CONFIG_GET(flag/load_legacy_ranks_only)) + to_chat(usr, "Rank deletion not permitted while database rank loading is disabled.") + return + admin_rank = sanitizeSQL(admin_rank) + var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE rank = '[admin_rank]'") + if(!query_admins_with_rank.warn_execute()) + return + if(query_admins_with_rank.NextRow()) + to_chat(usr, "Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.") + return + if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it") + var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE rank = '[admin_rank]'") + if(!query_add_rank.warn_execute()) + return + var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove rank', '[admin_rank]', 'Rank removed: [admin_rank]')") + if(!query_add_rank_log.warn_execute()) + return + message_admins("[key_name_admin(usr)] removed rank [admin_rank] permanently") + log_admin("[key_name(usr)] removed rank [admin_rank] permanently") + /datum/admins/proc/sync_lastadminrank(admin_ckey, datum/admins/D) var/sqlrank = sanitizeSQL(D.rank.name) admin_ckey = sanitizeSQL(admin_ckey) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 56ff2e816e..f5f5852848 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -273,6 +273,21 @@ return create_message("note", banckey, null, banreason, null, null, 0, 0) + else if(href_list["editrightsbrowser"]) + edit_admin_permissions(0) + + else if(href_list["editrightsbrowserlog"]) + edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"]) + + if(href_list["editrightsbrowsermanage"]) + if(href_list["editrightschange"]) + change_admin_rank(href_list["editrightschange"], TRUE) + else if(href_list["editrightsremove"]) + remove_admin(href_list["editrightsremove"], TRUE) + else if(href_list["editrightsremoverank"]) + remove_rank(href_list["editrightsremoverank"]) + edit_admin_permissions(2) + else if(href_list["editrights"]) edit_rights_topic(href_list) diff --git a/html/panels.css b/html/panels.css index ac44cf5487..1f969c690e 100644 --- a/html/panels.css +++ b/html/panels.css @@ -1,10 +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;} -#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} -tr.norm {background-color:#f4f4f4;} -tr.title {background-color:#ccc;} -tr.alt {background-color:#e7e7e7;} -.small {font-size:80%;} -a {text-decoration:none;color:#a0a;} -a:hover {color:#d3d;} +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:10px;left:3%;width:96%;text-align:center;z-index:0;} +#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} +tr.norm {background-color:#f4f4f4;} +tr.title {background-color:#ccc;} +tr.alt {background-color:#e7e7e7;} +.small {font-size:80%;} +a {text-decoration:none;} +a:hover {color:#d3d;}