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
-
-
-
-
-
-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
+
+
+
+ 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;}