From 663e007d4d6678ae1183ea8368e5a004d79a250f Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Mon, 1 Apr 2024 00:49:06 -0700 Subject: [PATCH] Added an autoresponse system for mentorhelp, using the existing button. (#24384) * Added an autoresponse system for mentorhelp, using the existing button. * Apply suggestions from code review Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * Review suggestions. * Add How to Objectives * Apply suggestions from code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> * Build the response phrases lists only once. * Add Russian autoresponse. * Corrected Russian Paradise server name. --------- Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> --- code/__DEFINES/tickets_defines.dm | 10 +++ .../subsystem/tickets/mentor_tickets.dm | 40 ++++++++++- code/controllers/subsystem/tickets/tickets.dm | 67 +++++++++---------- code/modules/admin/topic.dm | 11 +-- paradise.dme | 1 + 5 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 code/__DEFINES/tickets_defines.dm diff --git a/code/__DEFINES/tickets_defines.dm b/code/__DEFINES/tickets_defines.dm new file mode 100644 index 00000000000..9fbb25a17d6 --- /dev/null +++ b/code/__DEFINES/tickets_defines.dm @@ -0,0 +1,10 @@ +//Time until ticket becomes stale if unanswered. Alerts admins. +#define TICKET_TIMEOUT (10 MINUTES) +//Time before the user is allowed to open another ticket while their existing one is open. +#define TICKET_DUPLICATE_COOLDOWN (5 MINUTES) + +//Status defines +#define TICKET_OPEN 1 +#define TICKET_CLOSED 2 +#define TICKET_RESOLVED 3 +#define TICKET_STALE 4 diff --git a/code/controllers/subsystem/tickets/mentor_tickets.dm b/code/controllers/subsystem/tickets/mentor_tickets.dm index 6b6af90bd7d..41b5a952289 100644 --- a/code/controllers/subsystem/tickets/mentor_tickets.dm +++ b/code/controllers/subsystem/tickets/mentor_tickets.dm @@ -26,6 +26,23 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets "Please try to be as descriptive as possible in mentor helps. Mentors do not know the full situation you're in and need more information to give you a helpful response.", "Your [ticket_name] has now been closed.") + response_phrases = list("Known Bug" = "Unfortunately, that's a known bug. Hopefully it gets fixed soon.", + "TM Bug" = "Unfortunately, that's a bug with a current test merge. It should go away when the test merge is removed or fixed.", + "Clear Cache" = "To fix a blank screen, go to the 'Special Verbs' tab and press 'Reload UI Resources'. If that fails, clear your BYOND cache (instructions provided with 'Reload UI Resources'). If that still fails, please ask for help again, stating you have already done these steps.", + "Experiment!" = "Experiment! Part of the joy of this game is trying out various things, and dealing with the consequences if/when they go horribly wrong.", + "How to Objectives" = "There are lots of ways to accomplish your objectives as an antagonist. A direct frontal assault may work, provided you can get in and out before backup arrives. Sneaking in can work, too, as long as you're quick and avoid prying eyes. But don't forget roleplaying methods! Tricking your target into a maze of bear traps is much more interesting than just shooting them with a gun. Even if it fails, you and your target (or its guardians) are likely to have more fun this way, and that's the most important part.", + "MHelp was in Russian" = "Привет! Ты попал на английский Paradise сервер. Возможно, ты ошибся. Русский имеет такое название: SS220\[RU]." + ) + + if(GLOB.configuration.url.github_url) + response_phrases["New Bug"] = "That sounds like a bug! To report it, please go to our Github page. Then go to 'Issues', click 'New Issue', and fill out the report form. If the report would reveal current-round information, file it after the round ends." + + var/unsorted_responses = list() + for(var/key in response_phrases) //build a new list based on the short descriptive keys of the master list so we can send this as the input instead of the full paragraphs to the admin choosing which autoresponse + unsorted_responses += key + sorted_responses = sortTim(unsorted_responses, GLOBAL_PROC_REF(cmp_text_asc)) //use sortTim and cmp_text_asc to sort alphabetically + + /datum/controller/subsystem/tickets/mentor_tickets/message_staff(msg, prefix_type = NONE, important = FALSE) message_mentorTicket(msg, important) @@ -33,4 +50,25 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets SStickets.newTicket(get_client_by_ckey(T.client_ckey), T.first_raw_response, T.title) /datum/controller/subsystem/tickets/mentor_tickets/autoRespond(N) - return + if(!check_rights(rights_needed)) + return + + var/datum/ticket/T = allTickets[N] + var/client/C = usr.client + if((T.staffAssigned && T.staffAssigned != C) || (T.lastStaffResponse && T.lastStaffResponse != C) || ((T.ticketState != TICKET_OPEN) && (T.ticketState != TICKET_STALE))) //if someone took this ticket, is it the same mentor who is autoresponding? if so, then skip the warning + if(alert(usr, "[T.ticketState == TICKET_OPEN ? "Another mentor appears to already be handling this." : "This ticket is already marked as closed or resolved"] Are you sure you want to continue?", "Confirmation", "Yes", "No") != "Yes") + return + T.assignStaff(C) + + var/message_key = input("Select an autoresponse. This will mark the ticket as resolved.", "Autoresponse") as null|anything in sortTim(sorted_responses, GLOBAL_PROC_REF(cmp_text_asc)) //use sortTim and cmp_text_asc to sort alphabetically + var/client/ticket_owner = get_client_by_ckey(T.client_ckey) + if(message_key == null) + T.staffAssigned = null //if they cancel we dont need to hold this ticket anymore + return + + SEND_SOUND(returnClient(N), sound('sound/effects/adminhelp.ogg')) + to_chat_safe(returnClient(N), "[key_name_hidden(C)] is autoresponding with: [response_phrases[message_key]]") //for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key] + message_staff("[C] has auto responded to [ticket_owner]\'s mentorhelp with: [message_key]") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key + T.lastStaffResponse = "Autoresponse: [message_key]" + resolveTicket(N) + log_game("[C] has auto responded to [ticket_owner]\'s mentorhelp with: [response_phrases[message_key]]") diff --git a/code/controllers/subsystem/tickets/tickets.dm b/code/controllers/subsystem/tickets/tickets.dm index 655f6eda086..a349ba9acf3 100644 --- a/code/controllers/subsystem/tickets/tickets.dm +++ b/code/controllers/subsystem/tickets/tickets.dm @@ -1,15 +1,3 @@ -//Defines -//Deciseconds until ticket becomes stale if unanswered. Alerts admins. -#define TICKET_TIMEOUT 6000 // 10 minutes -//Decisecions before the user is allowed to open another ticket while their existing one is open. -#define TICKET_DUPLICATE_COOLDOWN 3000 // 5 minutes - -//Status defines -#define TICKET_OPEN 1 -#define TICKET_CLOSED 2 -#define TICKET_RESOLVED 3 -#define TICKET_STALE 4 - #define TICKET_STAFF_MESSAGE_ADMIN_CHANNEL 1 #define TICKET_STAFF_MESSAGE_PREFIX 2 @@ -44,6 +32,11 @@ SUBSYSTEM_DEF(tickets) /// DB ID for these tickets to be logged with var/db_save_id = "ADMIN" + // Autoresponse phrases. + var/response_phrases + // Autoresponse keys, in sorted order. + var/sorted_responses + /datum/controller/subsystem/tickets/get_metrics() . = ..() var/list/cust = list() @@ -55,6 +48,31 @@ SUBSYSTEM_DEF(tickets) "Please try to be calm, clear, and descriptive in admin helps, do not assume the staff member has seen any related events, and clearly state the names of anybody you are reporting. If you asked a question, please ensure it was clear what you were asking.", "Your [ticket_name] has now been closed.") + response_phrases = list("Thanks" = "Thanks for the ahelp!", + "Handling It" = "The issue is being looked into, thanks.", + "Already Resolved" = "The problem has been resolved already.", + "Mentorhelp" = "Please redirect your question to Mentorhelp, as they are better experienced with these types of questions.", + "Happens Again" = "Thanks, let us know if it continues to happen.", + "Clear Cache" = "To fix a blank screen, go to the 'Special Verbs' tab and press 'Reload UI Resources'. If that fails, clear your BYOND cache (instructions provided with 'Reload UI Resources'). If that still fails, please adminhelp again, stating you have already done the following." , + "IC Issue" = "This is an In Character (IC) issue and will not be handled by admins. You could speak to Security, Internal Affairs, a Departmental Head, Nanotrasen Representative, or any other relevant authority currently on station.", + "Reject" = "Reject", + "Man Up" = "Man Up", + ) + + if(GLOB.configuration.url.banappeals_url) + response_phrases["Appeal on the Forums"] = "Appealing a ban must occur on the forums. Privately messaging, or adminhelping about your ban will not resolve it. To appeal your ban, please head to [GLOB.configuration.url.banappeals_url]" + + if(GLOB.configuration.url.github_url) + response_phrases["Github Issue Report"] = "To report a bug, please go to our Github page. Then go to 'Issues'. Then 'New Issue'. Then fill out the report form. If the report would reveal current-round information, file it after the round ends." + + if(GLOB.configuration.url.exploit_url) + response_phrases["Exploit Report"] = "To report an exploit, please go to our Exploit Report page. Then 'Start New Topic'. Then fill out the topic with as much information about the exploit that you can. If possible, add steps taken to reproduce the exploit. The Development Team will be informed automatically of the post." + + var/unsorted_responses = list() + for(var/key in response_phrases) //build a new list based on the short descriptive keys of the master list so we can send this as the input instead of the full paragraphs to the admin choosing which autoresponse + unsorted_responses += key + sorted_responses = sortTim(unsorted_responses, GLOBAL_PROC_REF(cmp_text_asc)) //use sortTim and cmp_text_asc to sort alphabetically + /datum/controller/subsystem/tickets/fire() var/stales = checkStaleness() if(LAZYLEN(stales)) @@ -242,31 +260,8 @@ SUBSYSTEM_DEF(tickets) return T.assignStaff(C) - var/response_phrases = list("Thanks" = "Thanks for the ahelp!", - "Handling It" = "The issue is being looked into, thanks.", - "Already Resolved" = "The problem has been resolved already.", - "Mentorhelp" = "Please redirect your question to Mentorhelp, as they are better experienced with these types of questions.", - "Happens Again" = "Thanks, let us know if it continues to happen.", - "Clear Cache" = "To fix a blank screen, go to the 'Special Verbs' tab and press 'Reload UI Resources'. If that fails, clear your BYOND cache (instructions provided with 'Reload UI Resources'). If that still fails, please adminhelp again, stating you have already done the following." , - "IC Issue" = "This is an In Character (IC) issue and will not be handled by admins. You could speak to Security, Internal Affairs, a Departmental Head, Nanotrasen Representative, or any other relevant authority currently on station.", - "Reject" = "Reject", - "Man Up" = "Man Up", - ) - if(GLOB.configuration.url.banappeals_url) - response_phrases["Appeal on the Forums"] = "Appealing a ban must occur on the forums. Privately messaging, or adminhelping about your ban will not resolve it. To appeal your ban, please head to [GLOB.configuration.url.banappeals_url]" - - if(GLOB.configuration.url.github_url) - response_phrases["Github Issue Report"] = "To report a bug, please go to our Github page. Then go to 'Issues'. Then 'New Issue'. Then fill out the report form. If the report would reveal current-round information, file it after the round ends." - - if(GLOB.configuration.url.exploit_url) - response_phrases["Exploit Report"] = "To report an exploit, please go to our Exploit Report page. Then 'Start New Topic'. Then fill out the topic with as much information about the exploit that you can. If possible, add steps taken to reproduce the exploit. The Development Team will be informed automatically of the post." - - var/sorted_responses = list() - for(var/key in response_phrases) //build a new list based on the short descriptive keys of the master list so we can send this as the input instead of the full paragraphs to the admin choosing which autoresponse - sorted_responses += key - - var/message_key = input("Select an autoresponse. This will mark the ticket as resolved.", "Autoresponse") as null|anything in sortTim(sorted_responses, GLOBAL_PROC_REF(cmp_text_asc)) //use sortTim and cmp_text_asc to sort alphabetically + var/message_key = input("Select an autoresponse. This will mark the ticket as resolved.", "Autoresponse") as null|anything in sorted_responses var/client/ticket_owner = get_client_by_ckey(T.client_ckey) if(!ticket_owner) to_chat(C, "Can't respond to the ticket of a disconnected user.") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 021efa163c2..1f9256283d6 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1728,13 +1728,16 @@ SStickets.resolveTicket(index) else if(href_list["autorespond"]) + var/datum/controller/subsystem/tickets/ticketSystem if(href_list["is_mhelp"]) - to_chat(usr, "Auto responses are not available for mentor helps.") + ticketSystem = SSmentor_tickets + else //Ahelp + ticketSystem = SStickets + + if(!check_rights(ticketSystem.rights_needed)) return var/index = text2num(href_list["autorespond"]) - if(!check_rights(R_ADMIN|R_MOD)) - return - SStickets.autoRespond(index) + ticketSystem.autoRespond(index) if(href_list["convert_ticket"]) var/indexNum = text2num(href_list["convert_ticket"]) diff --git a/paradise.dme b/paradise.dme index 1ae3ef8e6eb..99ff381c75c 100644 --- a/paradise.dme +++ b/paradise.dme @@ -120,6 +120,7 @@ #include "code\__DEFINES\tg_cooldowns.dm" #include "code\__DEFINES\tgs.dm" #include "code\__DEFINES\tgui_defines.dm" +#include "code\__DEFINES\tickets_defines.dm" #include "code\__DEFINES\tools_defines.dm" #include "code\__DEFINES\turfs.dm" #include "code\__DEFINES\typeids.dm"