Skip to content

Commit

Permalink
Allows players to send more visible adminhelps when no admins are on,…
Browse files Browse the repository at this point in the history
… which'll definitely alert admins (tgstation#62711)

Co-authored-by: Watermelon914 <[email protected]>
  • Loading branch information
Watermelon914 and Watermelon914 authored Nov 20, 2021
1 parent 25a30cc commit fb8d95a
Show file tree
Hide file tree
Showing 15 changed files with 317 additions and 41 deletions.
14 changes: 11 additions & 3 deletions SQL/database_changelog.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
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 5.17; The query to update the schema revision table is:
The latest database version is 5.19; The query to update the schema revision table is:

INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 18);
INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 19);
or
INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 18);
INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 19);

In any query remember to add a prefix to the table names if you use one.

-----------------------------------------------------
Version 5.19, 10 November 2021, by WalterMeldron
Adds an urgent column to tickets for ahelps marked as urgent.

```
ALTER TABLE `ticket` ADD COLUMN `urgent` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `sender`;
```

-----------------------------------------------------
Version 5.18, 1 November 2021, by Mothblocks
Added `known_alts` table for tracking who not to create suspicious logins for.
Expand Down
1 change: 1 addition & 0 deletions SQL/tgstation_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ CREATE TABLE `ticket` (
`round_id` int(11) unsigned NULL,
`ticket` smallint(11) unsigned NOT NULL,
`action` varchar(20) NOT NULL DEFAULT 'Message',
`urgent` TINYINT(1) unsigned NOT NULL DEFAULT '0',
`message` text NOT NULL,
`timestamp` datetime NOT NULL,
`recipient` varchar(32) DEFAULT NULL,
Expand Down
1 change: 1 addition & 0 deletions SQL/tgstation_schema_prefixed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ CREATE TABLE `SS13_ticket` (
`round_id` int(11) unsigned NULL,
`ticket` smallint(11) unsigned NOT NULL,
`action` varchar(20) NOT NULL DEFAULT 'Message',
`urgent` TINYINT(1) unsigned NOT NULL DEFAULT '0',
`message` text NOT NULL,
`timestamp` datetime NOT NULL,
`recipient` varchar(32) DEFAULT NULL,
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*
* make sure you add an update to the schema_version stable in the db changelog
*/
#define DB_MINOR_VERSION 18
#define DB_MINOR_VERSION 19


//! ## Timing subsystem
Expand Down
7 changes: 4 additions & 3 deletions code/__HELPERS/chat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,22 @@ In TGS3 it will always be sent to all connected designated game chats.
*
* message - The message to send.
* channel_tag - Required. If "", the message with be sent to all connected (Game-type for TGS3) channels. Otherwise, it will be sent to TGS4 channels with that tag (Delimited by ','s).
* admin_only - Determines if this communication can only be sent to admin only channels.
*/
/proc/send2chat(message, channel_tag)
/proc/send2chat(message, channel_tag, admin_only = FALSE)
if(channel_tag == null || !world.TgsAvailable())
return

var/datum/tgs_version/version = world.TgsVersion()
if(channel_tag == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
world.TgsTargetedChatBroadcast(message, admin_only)
return

var/list/channels_to_use = list()
for(var/I in world.TgsChatChannelInfo())
var/datum/tgs_chat_channel/channel = I
var/list/applicable_tags = splittext(channel.custom_tag, ",")
if(channel_tag in applicable_tags)
if((!admin_only || channel.is_admin_channel) && (channel_tag in applicable_tags))
channels_to_use += channel

if(channels_to_use.len)
Expand Down
15 changes: 15 additions & 0 deletions code/controllers/configuration/entries/general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,18 @@
min_val = 0

/datum/config_entry/str_list/motd

/datum/config_entry/number/urgent_ahelp_cooldown
default = 300

/datum/config_entry/string/urgent_ahelp_message
default = "This ahelp is urgent!"

/datum/config_entry/string/urgent_ahelp_user_prompt
default = "There are no admins currently on. Do not press the button below if your ahelp is a joke, a request or a question. Use it only for cases of obvious grief."

/datum/config_entry/string/adminhelp_webhook_url

/datum/config_entry/string/adminhelp_webhook_pfp

/datum/config_entry/string/adminhelp_webhook_name
19 changes: 15 additions & 4 deletions code/controllers/subsystem/blackbox.dm
Original file line number Diff line number Diff line change
Expand Up @@ -288,14 +288,25 @@ Versioning
key = new_key
key_type = new_key_type

/datum/controller/subsystem/blackbox/proc/LogAhelp(ticket, action, message, recipient, sender)
/datum/controller/subsystem/blackbox/proc/LogAhelp(ticket, action, message, recipient, sender, urgent = FALSE)
if(!SSdbcore.Connect())
return

var/datum/db_query/query_log_ahelp = SSdbcore.NewQuery({"
INSERT INTO [format_table_name("ticket")] (ticket, action, message, recipient, sender, server_ip, server_port, round_id, timestamp)
VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, :time)
"}, list("ticket" = ticket, "action" = action, "message" = message, "recipient" = recipient, "sender" = sender, "server_ip" = world.internet_address || "0", "server_port" = world.port, "round_id" = GLOB.round_id, "time" = SQLtime()))
INSERT INTO [format_table_name("ticket")] (ticket, action, message, recipient, sender, server_ip, server_port, round_id, timestamp, urgent)
VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, :time, :urgent)
"}, list(
"ticket" = ticket,
"action" = action,
"message" = message,
"recipient" = recipient,
"sender" = sender,
"server_ip" = world.internet_address || "0",
"server_port" = world.port,
"round_id" = GLOB.round_id,
"time" = SQLtime(),
"urgent" = urgent,
))
query_log_ahelp.Execute()
qdel(query_log_ahelp)

Expand Down
2 changes: 1 addition & 1 deletion code/datums/keybinding/client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
. = ..()
if(.)
return
user.get_adminhelp()
user.adminhelp()
return TRUE


Expand Down
2 changes: 1 addition & 1 deletion code/modules/admin/sql_ban_system.dm
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@
break_counter = 0

var/list/other_job_lists = list(
"Abstract" = list("Appearance", "Emote", "Deadchat", "OOC"),
"Abstract" = list("Appearance", "Emote", "Deadchat", "OOC", "Urgent Adminhelp"),
)
for(var/department in other_job_lists)
output += "<div class='column'><label class='rolegroup [ckey(department)]'>[tgui_fancy ? "<input type='checkbox' name='[department]' class='hidden' onClick='header_click_all_checkboxes(this)'>" : ""][department]</label><div class='content'>"
Expand Down
148 changes: 120 additions & 28 deletions code/modules/admin/verbs/adminhelp.dm
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
* * msg_raw - The first message of this admin_help: used for the initial title of the ticket
* * is_bwoink - Boolean operator, TRUE if this ticket was started by an admin PM
*/
/datum/admin_help/New(msg_raw, client/C, is_bwoink)
/datum/admin_help/New(msg_raw, client/C, is_bwoink, urgent = FALSE)
//clean the input msg
var/msg = sanitize(copytext_char(msg_raw, 1, MAX_MESSAGE_LEN))
if(!msg || !C || !C.mob)
Expand Down Expand Up @@ -222,16 +222,46 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
AddInteraction("<font color='blue'>[key_name_admin(usr)] PM'd [LinkedReplyName()]</font>")
message_admins("<font color='blue'>Ticket [TicketHref("#[id]")] created</font>")
else
MessageNoRecipient(msg_raw)

//send it to TGS if nobody is on and tell us how many were on
var/admin_number_present = send2tgs_adminless_only(initiator_ckey, "Ticket #[id]: [msg]")
log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
if(admin_number_present <= 0)
to_chat(C, span_notice("No active admins are online, your adminhelp was sent through TGS to admins who are available. This may use IRC or Discord."), confidential = TRUE)
heard_by_no_admins = TRUE
MessageNoRecipient(msg_raw, urgent)
send_message_to_tgs(msg, urgent)
GLOB.ahelp_tickets.active_tickets += src

/datum/admin_help/proc/send_message_to_tgs(message, urgent = FALSE)
var/message_to_send = message

if(urgent)
var/extra_message_to_send = "[message] - Requested an admin"
var/extra_message = CONFIG_GET(string/urgent_ahelp_message)
if(extra_message)
extra_message_to_send += " ([extra_message])"
to_chat(initiator, span_boldwarning("Notified admins to prioritize your ticket"))
send2adminchat_webhook("RELAY: [initiator_ckey] | Ticket #[id]: [extra_message_to_send]")
//send it to TGS if nobody is on and tell us how many were on
var/admin_number_present = send2tgs_adminless_only(initiator_ckey, "Ticket #[id]: [message_to_send]")
log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
if(admin_number_present <= 0)
to_chat(initiator, span_notice("No active admins are online, your adminhelp was sent to admins who are available through IRC or Discord."), confidential = TRUE)
heard_by_no_admins = TRUE

/proc/send2adminchat_webhook(message)
if(!CONFIG_GET(string/adminhelp_webhook_url))
return
var/message_content = replacetext(replacetext(message, "\proper", ""), "\improper", "")
message_content = GLOB.has_discord_embeddable_links.Replace(replacetext(message, "`", ""), " ```$1``` ")
var/list/webhook_info = list()
webhook_info["content"] = message_content
if(CONFIG_GET(string/adminhelp_webhook_name))
webhook_info["username"] = CONFIG_GET(string/adminhelp_webhook_name)
if(CONFIG_GET(string/adminhelp_webhook_pfp))
webhook_info["avatar_url"] = CONFIG_GET(string/adminhelp_webhook_pfp)
// Uncomment when servers are moved to TGS4
// send2chat("[initiator_ckey] | [message_content]", "ahelp", TRUE)
var/list/headers = list()
headers["Content-Type"] = "application/json"
var/datum/http_request/request = new()
request.prepare(RUSTG_HTTP_METHOD_POST, CONFIG_GET(string/adminhelp_webhook_url), json_encode(webhook_info), headers, "tmp/response.json")
request.begin_async()

/datum/admin_help/Destroy()
RemoveActive()
GLOB.ahelp_tickets.closed_tickets -= src
Expand Down Expand Up @@ -282,7 +312,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)

//message from the initiator without a target, all admins will see this
//won't bug irc/discord
/datum/admin_help/proc/MessageNoRecipient(msg)
/datum/admin_help/proc/MessageNoRecipient(msg, urgent = FALSE)
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
var/ref_src = "[REF(src)]"
//Message to be sent to all admins
Expand All @@ -306,7 +336,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
type = MESSAGE_TYPE_ADMINPM,
html = span_adminnotice("PM to-<b>Admins</b>: <span class='linkify'>[msg]</span>"),
confidential = TRUE)
SSblackbox.LogAhelp(id, "Ticket Opened", msg, null, initiator.ckey)
SSblackbox.LogAhelp(id, "Ticket Opened", msg, null, initiator.ckey, urgent = urgent)

//Reopen a closed ticket
/datum/admin_help/proc/Reopen()
Expand Down Expand Up @@ -535,38 +565,100 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
deltimer(adminhelptimerid)
adminhelptimerid = 0

// Used for methods where input via arg doesn't work
/client/proc/get_adminhelp()
var/msg = input(src, "Please describe your problem concisely and an admin will help as soon as they're able.", "Adminhelp contents") as message|null
adminhelp(msg)
GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new)

/client/verb/adminhelp(msg as message)
set category = "Admin"
set name = "Adminhelp"
/datum/admin_help_ui_handler
var/list/ahelp_cooldowns = list()

/datum/admin_help_ui_handler/ui_state(mob/user)
return GLOB.always_state

/datum/admin_help_ui_handler/ui_data(mob/user)
. = list()
var/list/admins = get_admin_counts(R_BAN)
.["adminCount"] = length(admins["present"])

/datum/admin_help_ui_handler/ui_static_data(mob/user)
. = list()
.["bannedFromUrgentAhelp"] = is_banned_from(user.ckey, "Urgent Adminhelp")
.["urgentAhelpPromptMessage"] = CONFIG_GET(string/urgent_ahelp_user_prompt)
var/webhook_url = CONFIG_GET(string/adminhelp_webhook_url)
if(webhook_url)
.["urgentAhelpEnabled"] = TRUE

/datum/admin_help_ui_handler/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Adminhelp")
ui.open()
ui.set_autoupdate(FALSE)

/datum/admin_help_ui_handler/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
var/client/user_client = usr.client
var/message = sanitize_text(trim(params["message"]))
var/urgent = !!params["urgent"]
var/list/admins = get_admin_counts(R_BAN)
if(length(admins["present"]) != 0 || is_banned_from(user_client.ckey, "Urgent Adminhelp"))
urgent = FALSE

if(user_client.adminhelptimerid)
return

perform_adminhelp(user_client, message, urgent)
ui.close()

/datum/admin_help_ui_handler/proc/perform_adminhelp(client/user_client, message, urgent)
if(GLOB.say_disabled) //This is here to try to identify lag problems
to_chat(usr, span_danger("Speech is currently admin-disabled."), confidential = TRUE)
return

if(!message)
return

//handle muting and automuting
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, span_danger("Error: Admin-PM: You cannot send adminhelps (Muted)."), confidential = TRUE)
if(user_client.prefs.muted & MUTE_ADMINHELP)
to_chat(user_client, span_danger("Error: Admin-PM: You cannot send adminhelps (Muted)."), confidential = TRUE)
return
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
if(user_client.handle_spam_prevention(message, MUTE_ADMINHELP))
return

msg = trim(msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

if(!msg)
if(urgent)
if(!COOLDOWN_FINISHED(src, ahelp_cooldowns?[user_client.ckey]))
urgent = FALSE // Prevent abuse
else
COOLDOWN_START(src, ahelp_cooldowns[user_client.ckey], CONFIG_GET(number/urgent_ahelp_cooldown) * (1 SECONDS))

if(user_client.current_ticket)
user_client.current_ticket.TimeoutVerb()
if(urgent)
var/sanitized_message = sanitize(copytext_char(message, 1, MAX_MESSAGE_LEN))
user_client.current_ticket.send_message_to_tgs(sanitized_message, urgent = TRUE)
user_client.current_ticket.MessageNoRecipient(message, urgent)
return

SSblackbox.record_feedback("tally", "admin_verb", 1, "Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(current_ticket)
current_ticket.MessageNoRecipient(msg)
current_ticket.TimeoutVerb()
new /datum/admin_help(message, user_client, FALSE, urgent)

/client/verb/no_tgui_adminhelp(message as message)
set name = "NoTguiAdminhelp"
set hidden = TRUE

if(adminhelptimerid)
return

new /datum/admin_help(msg, src, FALSE)
message = trim(message)

GLOB.admin_help_ui_handler.perform_adminhelp(src, message, FALSE)

/client/verb/adminhelp()
set category = "Admin"
set name = "Adminhelp"
GLOB.admin_help_ui_handler.ui_interact(mob)
to_chat(src, span_boldnotice("Adminhelp failing to open or work? <a href='?src=[REF(src)];tguiless_adminhelp=1'>Click here</a>"))


//
Expand Down
3 changes: 3 additions & 0 deletions code/modules/client/client_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
var/externalreplyamount = 0
///Tracks say() usage for ic/dchat while slowmode is enabled
COOLDOWN_DECLARE(say_slowmode)
/// The last urgent ahelp that this player sent
COOLDOWN_DECLARE(urgent_ahelp_cooldown)

/////////
//OTHER//
/////////
Expand Down
4 changes: 4 additions & 0 deletions code/modules/client/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(href_list["priv_msg"])
cmd_admin_pm(href_list["priv_msg"],null)
return
// TGUIless adminhelp
if(href_list["tguiless_adminhelp"])
no_tgui_adminhelp(input(src, "Enter your ahelp", "Ahelp") as null|message)
return

switch(href_list["_src_"])
if("holder")
Expand Down
19 changes: 19 additions & 0 deletions config/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,25 @@ DEFAULT_VIEW_SQUARE 15x15
## Once a typepath causes overrun from hard deletes this many times, stop hard deleting it on garbage collection failures. (set to 0 to disable)
#HARD_DELETES_OVERRUN_LIMIT 0

## The URL to the webhook for adminhelps to relay the urgent ahelp message to
## If not set, will disable urgent ahelps.
#ADMINHELP_WEBHOOK_URL

## The urgent ahelp cooldown for a given player if they're alone on a server and need to send an urgent ahelp.
URGENT_AHELP_COOLDOWN 300

## The message that is sent to the discord if an urgent ahelp is sent. Useful for sending a role ping.
#URGENT_AHELP_MESSAGE Ban ban ban ban

## The message that the player receives whenever prompted whether they want to send an urgent ahelp or not.
#URGENT_AHELP_USER_PROMPT This'll ping the admins!

## The URL for the pfp of the webhook
#ADMINHELP_WEBHOOK_PFP

## The name of the webhook
#ADMINHELP_WEBHOOK_NAME

## Sets an MOTD of the server.
## You can use this multiple times, and the MOTDs will be appended in order.
## Based on config directory, so "motd.txt" points to "config/motd.txt"
Expand Down
Loading

0 comments on commit fb8d95a

Please sign in to comment.