From 31f020f3cc27374785ff937449ffc820026642df Mon Sep 17 00:00:00 2001 From: Jordie <4343468+Jordie0608@users.noreply.github.com> Date: Sun, 12 Aug 2018 06:31:14 +1000 Subject: [PATCH] Add expiration time for admin messages (#39502) * add expiration time for messages * typo * fix * src to usr * allows removing expiry from existing messages * cancel button --- SQL/database_changelog.txt | 13 +++- SQL/tgstation_schema.sql | 1 + SQL/tgstation_schema_prefixed.sql | 1 + code/__DEFINES/subsystems.dm | 2 +- code/modules/admin/NewBan.dm | 4 +- code/modules/admin/sql_message_system.dm | 96 +++++++++++++++++++++--- code/modules/admin/topic.dm | 20 ++++- code/modules/client/client_procs.dm | 6 +- 8 files changed, 121 insertions(+), 22 deletions(-) diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index fc93bb8fec3..dc05bae4431 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,15 +1,22 @@ Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. -The latest database version is 4.5; The query to update the schema revision table is: +The latest database version is 4.6; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (4, 5); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (4, 6); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (4, 5); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (4, 6); In any query remember to add a prefix to the table names if you use one. ---------------------------------------------------- +Version 4.6, 11 August 2018, by Jordie0608 +Modified table `messages`, adding column `expire_timestamp` to allow for auto-"deleting" messages. + +ALTER TABLE `messages` ADD `expire_timestamp` DATETIME NULL DEFAULT NULL AFTER `secret`; + +---------------------------------------------------- + Version 4.5, 9 July 2018, by Jordie0608 Modified table `player`, adding column `byond_key` to store a user's key along with their ckey. To populate this new column run the included script 'populate_key_2018-07', see the file for use instructions. diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 480ad58ff4e..18602cc52a9 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -253,6 +253,7 @@ CREATE TABLE `messages` ( `server_port` smallint(5) unsigned NOT NULL, `round_id` int(11) unsigned NOT NULL, `secret` tinyint(1) unsigned NOT NULL, + `expire_timestamp` datetime DEFAULT NULL, `lasteditor` varchar(32) DEFAULT NULL, `edits` text, `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 2842ee91224..938b293035a 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -253,6 +253,7 @@ CREATE TABLE `SS13_messages` ( `server_port` smallint(5) unsigned NOT NULL, `round_id` int(11) unsigned NOT NULL, `secret` tinyint(1) unsigned NOT NULL, + `expire_timestamp` datetime DEFAULT NULL, `lasteditor` varchar(32) DEFAULT NULL, `edits` text, `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 0317b5ba7f1..6f49344dc6b 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 5 +#define DB_MINOR_VERSION 6 //Timing subsystem //Don't run if there is an identical unique timer active diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index d81d037c50e..fefcf003fe6 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -123,9 +123,9 @@ GLOBAL_PROTECT(Banlist) if (temp) WRITE_FILE(GLOB.Banlist["minutes"], bantimestamp) if(!temp) - create_message("note", key, bannedby, "Permanently banned - [reason]", null, null, 0, 0) + create_message("note", key, bannedby, "Permanently banned - [reason]", null, null, 0, 0, null, 0) else - create_message("note", key, bannedby, "Banned for [minutes] minutes - [reason]", null, null, 0, 0) + create_message("note", key, bannedby, "Banned for [minutes] minutes - [reason]", null, null, 0, 0, null, 0) return 1 /proc/RemoveBan(foldername) diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index 04dda31d48b..e7fa97a407d 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -1,4 +1,4 @@ -/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse) +/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse, expiry) if(!SSdbcore.Connect()) to_chat(usr, "Failed to establish database connection.") return @@ -54,7 +54,24 @@ secret = 0 else return - var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]')") + if(isnull(expiry)) + if(alert(usr, "Set an expiry time? Expired messages are hidden like deleted ones.", "Expiry time?", "Yes", "No", "Cancel") == "Yes") + var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", SQLtime()) as null|text + if(!expire_time) + return + expire_time = sanitizeSQL(expire_time) + var/datum/DBQuery/query_validate_expire_time = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)") + if(!query_validate_expire_time.warn_execute()) + qdel(query_validate_expire_time) + return + if(query_validate_expire_time.NextRow()) + var/checktime = text2num(query_validate_expire_time.item[1]) + if(!checktime) + to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.") + return + expiry = query_validate_expire_time.item[1] + qdel(query_validate_expire_time) + var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret, expire_timestamp) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]', [expiry ? "'[expiry]'" : "NULL"])") var/pm = "[key_name(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]: [text]" var/header = "[key_name_admin(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]" if(!query_create_message.warn_execute()) @@ -146,6 +163,57 @@ browse_messages(target_ckey = ckey(target_key), agegate = TRUE) qdel(query_find_edit_message) +/proc/edit_message_expiry(message_id, browse) + if(!SSdbcore.Connect()) + to_chat(usr, "Failed to establish database connection.") + return + message_id = text2num(message_id) + if(!message_id) + return + var/datum/DBQuery/query_find_edit_expiry_message = SSdbcore.NewQuery("SELECT type, targetckey, adminckey, expire_timestamp FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0") + if(!query_find_edit_expiry_message.warn_execute()) + qdel(query_find_edit_expiry_message) + return + if(query_find_edit_expiry_message.NextRow()) + var/type = query_find_edit_expiry_message.item[1] + var/target_ckey = query_find_edit_expiry_message.item[2] + var/admin_ckey = query_find_edit_expiry_message.item[3] + var/old_expiry = query_find_edit_expiry_message.item[4] + var/editor_ckey = sanitizeSQL(usr.ckey) + var/new_expiry + var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons. Enter -1 to remove expiry time.", "Set expiry time", old_expiry) as null|text + if(!expire_time) + qdel(query_find_edit_expiry_message) + return + if(expire_time == "-1") + new_expiry = "non-expiring" + else + expire_time = sanitizeSQL(expire_time) + var/datum/DBQuery/query_validate_expire_time_edit = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)") + if(!query_validate_expire_time_edit.warn_execute()) + qdel(query_validate_expire_time_edit) + return + if(query_validate_expire_time_edit.NextRow()) + var/checktime = text2num(query_validate_expire_time_edit.item[1]) + if(!checktime) + to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.") + return + new_expiry = query_validate_expire_time_edit.item[1] + qdel(query_validate_expire_time_edit) + var/edit_text = sanitizeSQL("Expiration time edited by [editor_ckey] on [SQLtime()] from [old_expiry] to [new_expiry]
[timestamp] | [server] | [admin_key]") + var/list/data = list("
[timestamp] | [server] | [admin_key]") + if(expire_timestamp) + data += " | Expires [expire_timestamp]" + data += "" if(!linkless) + data += " \[Change Expiry Time\]" data += " \[Delete\]" if(type == "note") data += " [secret ? "\[Secret\]" : "\[Not secret\]"]" @@ -340,7 +418,7 @@ search = "^\[^\[:alpha:\]\]" else search = "^[index]" - var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 ORDER BY targetckey") + var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY targetckey") if(!query_list_messages.warn_execute()) qdel(query_list_messages) return @@ -365,7 +443,7 @@ var/output if(target_ckey) target_ckey = sanitizeSQL(target_ckey) - var/query = "SELECT id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text, timestamp, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0" + var/query = "SELECT id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text, timestamp, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)" if(type == "message" || type == "watchlist entry") query += " AND targetckey = '[target_ckey]'" var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query) @@ -427,7 +505,7 @@ timestamp = query_convert_time.item[1] qdel(query_convert_time) if(ckey && notetext && timestamp && admin_ckey && server) - create_message("note", ckey, admin_ckey, notetext, timestamp, server, 1, 0) + create_message("note", ckey, admin_ckey, notetext, timestamp, server, 1, 0, null, 0) notesfile.cd = "/" notesfile.dir.Remove(ckey) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 378cf7a7019..5b295f384dd 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -268,7 +268,7 @@ if(!DB_ban_record(bantype, playermob, banduration, banreason, banjob, bankey, banip, bancid )) to_chat(usr, "Failed to apply ban.") return - create_message("note", bankey, null, banreason, null, null, 0, 0) + create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0) else if(href_list["editrightsbrowser"]) edit_admin_permissions(0) @@ -604,7 +604,7 @@ jobban_buildcache(M.client) ban_unban_log_save("[key_name(usr)] appearance banned [key_name(M)]. reason: [reason]") log_admin_private("[key_name(usr)] appearance banned [key_name(M)]. \nReason: [reason]") - create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0) + create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0, null, 0) message_admins("[key_name_admin(usr)] appearance banned [key_name_admin(M)].") to_chat(M, "You have been appearance banned by [usr.client.key].") to_chat(M, "The reason is: [reason]") @@ -990,7 +990,7 @@ msg = job else msg += ", [job]" - create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0) + create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0) message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes.") to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") to_chat(M, "The reason is: [reason]") @@ -1013,7 +1013,7 @@ msg = job else msg += ", [job]" - create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0) + create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0) message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg].") to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") to_chat(M, "The reason is: [reason]") @@ -1138,6 +1138,18 @@ var/message_id = href_list["editmessageempty"] edit_message(message_id, browse = 1) + else if(href_list["editmessageexpiry"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageexpiry"] + edit_message_expiry(message_id) + + else if(href_list["editmessageexpiryempty"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageexpiryempty"] + edit_message_expiry(message_id, browse = 1) + else if(href_list["secretmessage"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 50595e7468d..f0520c8ef4e 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -663,7 +663,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) var/sql_system_ckey = sanitizeSQL(system_ckey) var/sql_ckey = sanitizeSQL(ckey) //check to see if we noted them in the last day. - var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0") + var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0 AND expire_timestamp > NOW()") if(!query_get_notes.Execute()) qdel(query_get_notes) return @@ -672,7 +672,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) return qdel(query_get_notes) //regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over. - query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 ORDER BY timestamp DESC LIMIT 1") + query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 AND expire_timestamp > NOW() ORDER BY timestamp DESC LIMIT 1") if(!query_get_notes.Execute()) qdel(query_get_notes) return @@ -681,7 +681,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) qdel(query_get_notes) return qdel(query_get_notes) - create_message("note", key, system_ckey, message, null, null, 0, 0) + create_message("note", key, system_ckey, message, null, null, 0, 0, null, 0) /client/proc/check_ip_intel()