mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-23 13:05:44 +01:00
Replaces dibs with Bay's ticket system. (#3984)
A user ahelping creates a ticket. Any further ahelps while that ticket is open will go to that ticket (and either adminhelp or pm an admin assigned to the ticket, if one has taken it). A user can close their own ticket up until an admin takes it. Admins can take tickets either manually or just by replying to the PM. An admin taking a ticket notifies other admins. If another admin attempts to take or respond to an assigned ticket, they receive a notification asking if they would like to join the ticket or cancel (any number of admins can join a ticket). When an admin finishes with a ticket, they must close it -- both for logistics and closure for the user. If there is an open ticket assigned to an active admin, round end is automatically delayed (unassigned tickets or tickets assigned to disconnected or afk admins do not delay). Round end will automatically continue once all active tickets are closed. Both staff and non-staff have access to a ticket panel listing tickets, their statuses, and their messages. Non-staff can only see their own tickets. This panel is optional and all features are available inline with chat.
This commit is contained in:
@@ -1204,7 +1204,7 @@ proc/admin_notice(var/message, var/rights)
|
||||
H.regenerate_icons()
|
||||
|
||||
|
||||
/proc/get_options_bar(whom, detail = 2, name = 0, link = 1, highlight_special = 1)
|
||||
/proc/get_options_bar(whom, detail = 2, name = 0, link = 1, highlight_special = 1, var/datum/ticket/ticket = null)
|
||||
if(!whom)
|
||||
return "<b>(*null*)</b>"
|
||||
var/mob/M
|
||||
@@ -1216,25 +1216,25 @@ proc/admin_notice(var/message, var/rights)
|
||||
M = whom
|
||||
C = M.client
|
||||
else
|
||||
return "<b>(*not an mob*)</b>"
|
||||
return "<b>(*not a mob*)</b>"
|
||||
switch(detail)
|
||||
if(0)
|
||||
return "<b>[key_name(C, link, name, highlight_special)]</b>"
|
||||
return "<b>[key_name(C, link, name, highlight_special, ticket)]</b>"
|
||||
|
||||
if(1) //Private Messages
|
||||
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>)</b>"
|
||||
return "<b>[key_name(C, link, name, highlight_special, ticket)](<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>)</b>"
|
||||
|
||||
if(2) //Admins
|
||||
var/ref_mob = "\ref[M]"
|
||||
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M, src)]) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>)</b>"
|
||||
return "<b>[key_name(C, link, name, highlight_special, ticket)](<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M, src)]) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>)</b>"
|
||||
|
||||
if(3) //Undibbsed
|
||||
if(3) //Devs
|
||||
var/ref_mob = "\ref[M]"
|
||||
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;admindibs=\ref[C]'>DIBS</A>) (<A HREF='?_src_=holder;adminplayeropts=\ref[M]'>PP</A>) ([admin_jump_link(M, src)])</b>"
|
||||
return "<b>[key_name(C, link, name, highlight_special, ticket)](<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>)([admin_jump_link(M, src)])</b>"
|
||||
|
||||
if(4) //Mentors
|
||||
var/ref_mob = "\ref[M]"
|
||||
return "<b>[key_name(C, link, name, highlight_special)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M, src)])</b>"
|
||||
return "<b>[key_name(C, link, name, highlight_special, ticket)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M, src)])</b>"
|
||||
|
||||
//
|
||||
//ALL DONE
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
var/global/list/tickets = list()
|
||||
var/global/list/ticket_panels = list()
|
||||
|
||||
/datum/ticket
|
||||
var/owner
|
||||
var/list/assigned_admins = list()
|
||||
var/status = TICKET_OPEN
|
||||
var/list/msgs = list()
|
||||
var/closed_by
|
||||
var/id
|
||||
var/opened_time
|
||||
|
||||
/datum/ticket/New(var/owner)
|
||||
src.owner = owner
|
||||
tickets |= src
|
||||
id = tickets.len
|
||||
opened_time = world.time
|
||||
|
||||
/datum/ticket/proc/close(var/client/closed_by)
|
||||
if(!closed_by)
|
||||
return
|
||||
|
||||
if(status == TICKET_CLOSED)
|
||||
return
|
||||
|
||||
if(status == TICKET_ASSIGNED && !((closed_by.ckey in assigned_admins) || owner == closed_by.ckey) && alert(closed_by, "You are not assigned to this ticket. Are you sure you want to close it?", "Close ticket?" , "Yes" , "No") != "Yes")
|
||||
return
|
||||
|
||||
if(status == TICKET_ASSIGNED && !closed_by.holder) // non-admins can only close a ticket if no admin has taken it
|
||||
return
|
||||
|
||||
src.status = TICKET_CLOSED
|
||||
src.closed_by = closed_by.ckey
|
||||
|
||||
to_chat(client_by_ckey(src.owner), "<span class='notice'><b>Your ticket has been closed by [closed_by].</b></span>")
|
||||
message_admins("<span class='notice'><b>[src.owner]</b>'s ticket has been closed by <b>[key_name(closed_by)]</b>.</span>")
|
||||
|
||||
update_ticket_panels()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/ticket/proc/take(var/client/assigned_admin)
|
||||
if(!assigned_admin)
|
||||
return
|
||||
|
||||
if(status == TICKET_CLOSED)
|
||||
return
|
||||
|
||||
if(assigned_admin.ckey == owner)
|
||||
return
|
||||
|
||||
if(status == TICKET_ASSIGNED && ((assigned_admin.ckey in assigned_admins) || alert(assigned_admin, "This ticket is already assigned. Do you want to add yourself to the ticket?", "Join ticket?" , "Yes" , "No") != "Yes"))
|
||||
return
|
||||
|
||||
assigned_admins |= assigned_admin.ckey
|
||||
src.status = TICKET_ASSIGNED
|
||||
|
||||
var/client/owner_client = client_by_ckey(src.owner)
|
||||
if(owner_client && owner_client.adminhelped == ADMINHELPED_DISCORD)
|
||||
discord_bot.send_to_admins("[key_name(owner_client)]'s request for help has been taken by [key_name(assigned_admin)].")
|
||||
owner_client.adminhelped = ADMINHELPED
|
||||
|
||||
message_admins("<span class='notice'><b>[key_name(assigned_admin)]</b> has assigned themself to <b>[src.owner]'s</b> ticket.</span>")
|
||||
to_chat(client_by_ckey(src.owner), "<span class='notice'><b>[assigned_admin] has added themself to your ticket and should respond shortly. Thanks for your patience!</b></span>")
|
||||
|
||||
update_ticket_panels()
|
||||
|
||||
return 1
|
||||
|
||||
proc/get_open_ticket_by_ckey(var/owner)
|
||||
for(var/datum/ticket/ticket in tickets)
|
||||
if(ticket.owner == owner && (ticket.status == TICKET_OPEN || ticket.status == TICKET_ASSIGNED))
|
||||
return ticket // there should only be one open ticket by a client at a time, so no need to keep looking
|
||||
|
||||
/datum/ticket/proc/is_active()
|
||||
if(status != TICKET_ASSIGNED)
|
||||
return 0
|
||||
|
||||
for(var/admin in assigned_admins)
|
||||
var/client/admin_client = client_by_ckey(admin)
|
||||
if(admin_client && !admin_client.is_afk())
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/datum/ticket_msg
|
||||
var/msg_from
|
||||
var/msg_to
|
||||
var/msg
|
||||
var/time_stamp
|
||||
|
||||
/datum/ticket_msg/New(var/msg_from, var/msg_to, var/msg)
|
||||
src.msg_from = msg_from
|
||||
src.msg_to = msg_to
|
||||
src.msg = msg
|
||||
src.time_stamp = time_stamp()
|
||||
|
||||
/datum/ticket_panel
|
||||
var/datum/ticket/open_ticket = null
|
||||
var/datum/browser/ticket_panel_window
|
||||
|
||||
/datum/ticket_panel/proc/get_dat()
|
||||
var/client/C = ticket_panel_window.user.client
|
||||
if(!C)
|
||||
return
|
||||
|
||||
var/list/dat = list()
|
||||
|
||||
var/list/ticket_dat = list()
|
||||
for(var/id = tickets.len, id >= 1, id--)
|
||||
var/datum/ticket/ticket = tickets[id]
|
||||
if(C.holder || ticket.owner == C.ckey)
|
||||
var/client/owner_client = client_by_ckey(ticket.owner)
|
||||
var/status = "Unknown status"
|
||||
var/color = "#6aa84f"
|
||||
switch(ticket.status)
|
||||
if(TICKET_OPEN)
|
||||
status = "Opened [round((world.time - ticket.opened_time) / (1 MINUTE))] minute\s ago, unassigned"
|
||||
if(TICKET_ASSIGNED)
|
||||
status = "Assigned to [english_list(ticket.assigned_admins, "no one")]"
|
||||
color = "#ffffff"
|
||||
if(TICKET_CLOSED)
|
||||
status = "Closed by [ticket.closed_by]"
|
||||
color = "#cc2222"
|
||||
ticket_dat += "<li style='padding-bottom:10px;color:[color]'>"
|
||||
if(open_ticket && open_ticket == ticket)
|
||||
ticket_dat += "<i>"
|
||||
ticket_dat += "Ticket #[id] - [ticket.owner] [owner_client ? "" : "(DC)"] - [status]<br /><a href='byond://?src=\ref[src];action=view;ticket=\ref[ticket]'>VIEW</a>"
|
||||
if(ticket.status)
|
||||
ticket_dat += " - <a href='byond://?src=\ref[src];action=pm;ticket=\ref[ticket]'>PM</a>"
|
||||
if(C.holder)
|
||||
ticket_dat += " - <a href='byond://?src=\ref[src];action=take;ticket=\ref[ticket]'>[(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]</a>"
|
||||
if(ticket.status != TICKET_CLOSED && (C.holder || ticket.status == TICKET_OPEN))
|
||||
ticket_dat += " - <a href='byond://?src=\ref[src];action=close;ticket=\ref[ticket]'>CLOSE</a>"
|
||||
if(C.holder)
|
||||
var/ref_mob = ""
|
||||
if(owner_client)
|
||||
ref_mob = "\ref[owner_client.mob]"
|
||||
ticket_dat += " - <A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A> - <A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A> - <A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A> - <A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>[owner_client ? "- [admin_jump_link(owner_client, src)]" : ""]"
|
||||
if(open_ticket && open_ticket == ticket)
|
||||
ticket_dat += "</i>"
|
||||
ticket_dat += "</li>"
|
||||
|
||||
if(ticket_dat.len)
|
||||
dat += "<br /><div style='width:50%;float:left;'><p><b>Available tickets:</b></p><ul>[jointext(ticket_dat, null)]</ul></div>"
|
||||
|
||||
if(open_ticket)
|
||||
dat += "<div style='width:50%;float:left;'><p><b>\[<a href='byond://?src=\ref[src];action=unview;'>X</a>\] Messages for ticket #[open_ticket.id]:</b></p>"
|
||||
|
||||
var/list/msg_dat = list()
|
||||
for(var/datum/ticket_msg/msg in open_ticket.msgs)
|
||||
var/msg_to = msg.msg_to ? msg.msg_to : "Adminhelp"
|
||||
msg_dat += "<li>\[[msg.time_stamp]\] [msg.msg_from] -> [msg_to]: [C.holder ? generate_ahelp_key_words(C.mob, msg.msg) : msg.msg]</li>"
|
||||
|
||||
if(msg_dat.len)
|
||||
dat += "<ul>[jointext(msg_dat, null)]</ul></div>"
|
||||
else
|
||||
dat += "<p>No messages to display.</p></div>"
|
||||
else
|
||||
dat += "<p>No tickets to display.</p>"
|
||||
dat += "</body></html>"
|
||||
|
||||
return jointext(dat, null)
|
||||
|
||||
/datum/ticket_panel/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if(href_list["close"])
|
||||
ticket_panels -= usr.client
|
||||
|
||||
switch(href_list["action"])
|
||||
if("unview")
|
||||
open_ticket = null
|
||||
ticket_panel_window.set_content(get_dat())
|
||||
ticket_panel_window.update()
|
||||
|
||||
var/datum/ticket/ticket = locate(href_list["ticket"])
|
||||
if(!ticket)
|
||||
return
|
||||
|
||||
switch(href_list["action"])
|
||||
if("view")
|
||||
open_ticket = ticket
|
||||
ticket_panel_window.set_content(get_dat())
|
||||
ticket_panel_window.update()
|
||||
if("take")
|
||||
ticket.take(usr.client)
|
||||
if("close")
|
||||
ticket.close(usr.client)
|
||||
if("pm")
|
||||
if(usr.client.holder && ticket.owner != usr.ckey)
|
||||
usr.client.cmd_admin_pm(client_by_ckey(ticket.owner), ticket = ticket)
|
||||
else if(ticket.status == TICKET_ASSIGNED)
|
||||
// manually check that the target client exists here as to not spam the usr for each logged out admin on the ticket
|
||||
var/admin_found = 0
|
||||
for(var/admin in ticket.assigned_admins)
|
||||
var/client/admin_client = client_by_ckey(admin)
|
||||
if(admin_client)
|
||||
admin_found = 1
|
||||
usr.client.cmd_admin_pm(admin_client, ticket = ticket)
|
||||
break
|
||||
if(!admin_found)
|
||||
to_chat(usr, "<span class='warning'>Error: Private-Message: Client not found. They may have lost connection, so please be patient!</span>")
|
||||
else
|
||||
usr.client.adminhelp(input(usr,"", "adminhelp \"text\"") as text)
|
||||
|
||||
/client/verb/view_tickets()
|
||||
set name = "View Tickets"
|
||||
set category = "Admin"
|
||||
|
||||
var/datum/ticket_panel/ticket_panel = new()
|
||||
ticket_panels[src] = ticket_panel
|
||||
ticket_panel.ticket_panel_window = new(src.mob, "ticketpanel", "Ticket Manager", 1024, 768, ticket_panel)
|
||||
|
||||
ticket_panel.ticket_panel_window.set_content(ticket_panel.get_dat())
|
||||
ticket_panel.ticket_panel_window.open()
|
||||
|
||||
/proc/update_ticket_panels()
|
||||
for(var/client/C in ticket_panels)
|
||||
var/datum/ticket_panel/ticket_panel = ticket_panels[C]
|
||||
if(C.mob != ticket_panel.ticket_panel_window.user)
|
||||
C.view_tickets()
|
||||
else
|
||||
ticket_panel.ticket_panel_window.set_content(ticket_panel.get_dat())
|
||||
ticket_panel.ticket_panel_window.update()
|
||||
+11
-27
@@ -849,6 +849,14 @@
|
||||
sleep(2)
|
||||
C.jumptocoord(x,y,z)
|
||||
|
||||
else if(href_list["take_ticket"])
|
||||
var/datum/ticket/ticket = locate(href_list["take_ticket"])
|
||||
|
||||
if(isnull(ticket))
|
||||
return
|
||||
|
||||
ticket.take(usr.client)
|
||||
|
||||
else if(href_list["adminchecklaws"])
|
||||
output_ai_laws()
|
||||
|
||||
@@ -1580,33 +1588,6 @@
|
||||
|
||||
paralyze_mob(M)
|
||||
|
||||
else if(href_list["admindibs"])
|
||||
if (!check_rights(R_ADMIN|R_MOD))
|
||||
return
|
||||
|
||||
var/client/C = locate(href_list["admindibs"])
|
||||
|
||||
if (!istype(C) || !C)
|
||||
usr << "<span class='danger'>Player not found!</span>"
|
||||
return
|
||||
|
||||
if (C.adminhelped >= 2)
|
||||
log_and_message_admins("has called <font color='red'>dibs</font> on [key_name_admin(C)]'s adminhelp!")
|
||||
usr << "<font color='blue'><b>You have taken over [key_name_admin(C)]'s adminhelp.</b></font>'"
|
||||
usr << "[get_options_bar(C, 2, 1, 1)]"
|
||||
|
||||
C << "<font color='red'><b>Your adminhelp will be tended [usr.client.holder.fakekey ? "shortly" : "by [key_name(usr, 0, 0)]"]. Please allow the staff member a minute or two to write up a response.</b></font>"
|
||||
|
||||
if (C.adminhelped == 3)
|
||||
post_webhook_event(WEBHOOK_ADMIN_PM, list("title"="Help is nolonger needed", "message"="Request for Help from **[key_name(C)]** is being tended to by **[key_name(usr)]**."))
|
||||
discord_bot.send_to_admins("Request for Help from [key_name(C)] is being tended to by [key_name(usr)].")
|
||||
|
||||
C.adminhelped = 1
|
||||
else
|
||||
usr << "<font color='red'><b>The adminhelp has already been claimed!</b></font>"
|
||||
|
||||
return
|
||||
|
||||
else if(href_list["access_control"])
|
||||
access_control_topic(href_list["access_control"])
|
||||
return
|
||||
@@ -1620,6 +1601,9 @@ mob/living/carbon/human/can_centcom_reply()
|
||||
mob/living/silicon/ai/can_centcom_reply()
|
||||
return common_radio != null && !check_unable(2)
|
||||
|
||||
/client/proc/extra_admin_link()
|
||||
return
|
||||
|
||||
/atom/proc/extra_admin_link()
|
||||
return
|
||||
|
||||
|
||||
@@ -2,52 +2,20 @@
|
||||
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
|
||||
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as")
|
||||
|
||||
/client/verb/adminhelp(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Adminhelp"
|
||||
|
||||
if(say_disabled) //This is here to try to identify lag problems
|
||||
usr << "<span class='warning'>Speech is currently admin-disabled.</span>"
|
||||
return
|
||||
|
||||
//handle muting and automuting
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
src << "<font color='red'>Error: Admin-PM: You cannot send adminhelps (Muted).</font>"
|
||||
return
|
||||
|
||||
adminhelped = 2 //Determines if they get the message to reply by clicking the name.
|
||||
|
||||
/*A wee bit of an update here: we're using the following table for adminhelped values:
|
||||
3 - Adminhelp has not been claimed and was sent to discord as well.
|
||||
2 - Adminhelp has not been claimed by anyone.
|
||||
1 - Adminhelp has been claimed, initial message has not been sent.
|
||||
0 - Adminhelp has been claimed, initial message has been sent.
|
||||
*/
|
||||
|
||||
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
//clean the input msg
|
||||
if(!msg)
|
||||
return
|
||||
msg = sanitize(msg)
|
||||
if(!msg)
|
||||
return
|
||||
var/original_msg = msg
|
||||
|
||||
//explode the input msg into a list
|
||||
var/list/msglist = text2list(msg, " ")
|
||||
|
||||
//generate keywords lookup
|
||||
/proc/generate_ahelp_key_words(var/mob/mob, var/msg)
|
||||
var/list/surnames = list()
|
||||
var/list/forenames = list()
|
||||
var/list/ckeys = list()
|
||||
|
||||
//explode the input msg into a list
|
||||
var/list/msglist = splittext(msg, " ")
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
var/list/indexing = list(M.real_name, M.name)
|
||||
if(M.mind) indexing += M.mind.name
|
||||
|
||||
for(var/string in indexing)
|
||||
var/list/L = text2list(string, " ")
|
||||
var/list/L = splittext(string, " ")
|
||||
var/surname_found = 0
|
||||
//surnames
|
||||
for(var/i=L.len, i>=1, i--)
|
||||
@@ -71,8 +39,10 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
var/word = ckey(original_word)
|
||||
if(word)
|
||||
if(!(word in adminhelp_ignored_words))
|
||||
if(word == "ai")
|
||||
if(word == "ai" && !ai_found)
|
||||
ai_found = 1
|
||||
msg += "<b>[original_word] <A HREF='?_src_=holder;adminchecklaws=\ref[mob]'>(CL)</A></b> "
|
||||
continue
|
||||
else
|
||||
var/mob/found = ckeys[word]
|
||||
if(!found)
|
||||
@@ -82,23 +52,72 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
if(found)
|
||||
if(!(found in mobs_found))
|
||||
mobs_found += found
|
||||
msg += "<b>[original_word] <A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>(?)</A>"
|
||||
if(!ai_found && isAI(found))
|
||||
ai_found = 1
|
||||
msg += "<b><font color='black'>[original_word] (<A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>?</A>)</font></b> "
|
||||
msg += " <A HREF='?_src_=holder;adminchecklaws=\ref[mob]'>(CL)</A>"
|
||||
msg += "</b> "
|
||||
continue
|
||||
msg += "[original_word] "
|
||||
|
||||
return msg
|
||||
|
||||
/client/verb/adminhelp(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Adminhelp"
|
||||
|
||||
if(say_disabled) //This is here to try to identify lag problems
|
||||
usr << "<span class='warning'>Speech is currently admin-disabled.</span>"
|
||||
return
|
||||
|
||||
//handle muting and automuting
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
src << "<font color='red'>Error: Admin-PM: You cannot send adminhelps (Muted).</font>"
|
||||
return
|
||||
|
||||
adminhelped = ADMINHELPED
|
||||
|
||||
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
//clean the input msg
|
||||
if(!msg)
|
||||
return
|
||||
msg = sanitize(msg)
|
||||
if(!msg)
|
||||
return
|
||||
var/original_msg = msg
|
||||
|
||||
if(!mob) //this doesn't happen
|
||||
return
|
||||
|
||||
var/ai_cl
|
||||
if(ai_found)
|
||||
ai_cl = " (<A HREF='?_src_=holder;adminchecklaws=\ref[mob]'>CL</A>)"
|
||||
//generate keywords lookup
|
||||
msg = generate_ahelp_key_words(mob, msg)
|
||||
|
||||
//Options bar: mob, details ( admin = 2, undibbsed admin = 3, mentor = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so),
|
||||
// highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name)
|
||||
// handle ticket
|
||||
var/datum/ticket/ticket = get_open_ticket_by_ckey(ckey)
|
||||
if(!ticket)
|
||||
ticket = new /datum/ticket(ckey)
|
||||
else if(ticket.status == TICKET_ASSIGNED)
|
||||
// manually check that the target client exists here as to not spam the usr for each logged out admin on the ticket
|
||||
var/admin_found = 0
|
||||
for(var/admin in ticket.assigned_admins)
|
||||
var/client/admin_client = client_by_ckey(admin)
|
||||
if(admin_client)
|
||||
admin_found = 1
|
||||
src.cmd_admin_pm(admin_client, original_msg, ticket)
|
||||
break
|
||||
if(!admin_found)
|
||||
to_chat(src, "<span class='warning'>Error: Private-Message: Client not found. They may have lost connection, so please be patient!</span>")
|
||||
return
|
||||
|
||||
msg = "<span class='notice'><b><font color=red>Request for Help: </font>[get_options_bar(mob, 3, 1, 1)][ai_cl]:</b> [msg]</span>"
|
||||
ticket.msgs += new /datum/ticket_msg(src.ckey, null, original_msg)
|
||||
update_ticket_panels()
|
||||
|
||||
//Options bar: mob, details ( admin = 2, undibbsed admin = 3, mentor = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so),
|
||||
// highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name)
|
||||
|
||||
msg = "<span class='notice'><b><font color=red>HELP: </font>[get_options_bar(mob, 2, 1, 1, 1, ticket)] (<a href='?_src_=holder;take_ticket=\ref[ticket]'>[(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]</a>) (<a href='?src=\ref[usr];close_ticket=\ref[ticket]'>CLOSE</a>):</b> [msg]</span>"
|
||||
|
||||
var/admin_number_present = 0
|
||||
var/admin_number_afk = 0
|
||||
@@ -121,6 +140,6 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
if(admin_number_active <= 0)
|
||||
post_webhook_event(WEBHOOK_ADMIN_PM_IMPORTANT, list("title"="Help is requested", "message"="Request for Help from **[key_name(src)]**: ```[html_decode(original_msg)]```\n[admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!"))
|
||||
discord_bot.send_to_admins("@here Request for Help from [key_name(src)]: [html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!")
|
||||
adminhelped = 3
|
||||
adminhelped = ADMINHELPED_DISCORD
|
||||
feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM.
|
||||
//Fetching a message if needed. src is the sender and C is the target client
|
||||
|
||||
/client/proc/cmd_admin_pm(var/client/C, var/msg = null)
|
||||
/client/proc/cmd_admin_pm(var/client/C, var/msg = null, var/datum/ticket/ticket = null)
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
src << "<font color='red'>Error: Private-Message: You are unable to use PM-s (muted).</font>"
|
||||
return
|
||||
@@ -46,6 +46,25 @@
|
||||
else src << "<font color='red'>Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!</font>"
|
||||
return
|
||||
|
||||
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
var/recieve_pm_type = "Player"
|
||||
//mod PMs are maroon
|
||||
//PMs sent from admins and mods display their rank
|
||||
if(holder)
|
||||
if(!C.holder && holder.fakekey)
|
||||
recieve_pm_type = "Admin"
|
||||
else
|
||||
recieve_pm_type = holder.rank
|
||||
|
||||
else if(!C.holder)
|
||||
src << "<span class='warning'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</span>"
|
||||
return
|
||||
|
||||
if(!check_rights(R_SERVER|R_DEBUG|R_DEV, 0))
|
||||
msg = sanitize(msg)
|
||||
|
||||
//get message text, limit it's length.and clean/escape html
|
||||
if(!msg)
|
||||
msg = input(src,"Message:", "Private message to [key_name(C, 0, holder ? 1 : 0)]") as text|null
|
||||
@@ -56,36 +75,42 @@
|
||||
else src << "<font color='red'>Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!</font>"
|
||||
return
|
||||
|
||||
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
//clean the message if it's not sent by a high-rank admin
|
||||
//todo: sanitize for all???
|
||||
if(!check_rights(R_SERVER|R_DEBUG|R_DEV,0))
|
||||
msg = sanitize(msg)
|
||||
if(!msg) return
|
||||
|
||||
var/recieve_pm_type = "Player"
|
||||
if(holder)
|
||||
//mod PMs are maroon
|
||||
//PMs sent from admins and mods display their rank
|
||||
// searches for an open ticket, in case an outdated link was clicked
|
||||
// I'm paranoid about the problems that could be caused by accidentally finding the wrong ticket, which is why this is strict
|
||||
if(isnull(ticket))
|
||||
if(holder)
|
||||
if(!C.holder && holder && holder.fakekey)
|
||||
recieve_pm_type = "Admin"
|
||||
else
|
||||
recieve_pm_type = holder.rank
|
||||
ticket = get_open_ticket_by_ckey(C.ckey) // it's more likely an admin clicked a different PM link, so check admin -> player with ticket first
|
||||
if(isnull(ticket) && C.holder)
|
||||
ticket = get_open_ticket_by_ckey(src.ckey) // if still no dice, try an admin with ticket -> admin
|
||||
else
|
||||
ticket = get_open_ticket_by_ckey(src.ckey) // lastly, check player with ticket -> admin
|
||||
|
||||
else if(!C.holder)
|
||||
src << "<font color='red'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</font>"
|
||||
|
||||
if(isnull(ticket)) // finally, accept that no ticket exists
|
||||
if(holder && src != C)
|
||||
ticket = new /datum/ticket(C.ckey)
|
||||
ticket.take(src)
|
||||
else
|
||||
src << "<span class='notice'>You do not have an open ticket. Please use the adminhelp verb to open a ticket.</span>"
|
||||
return
|
||||
else if(ticket.status != TICKET_ASSIGNED && src.ckey == ticket.owner)
|
||||
src << "<span class='notice'>Your ticket is not open for conversation. Please wait for an administrator to receive your adminhelp.</span>"
|
||||
return
|
||||
|
||||
// if the sender is an admin and they're not assigned to the ticket, ask them if they want to take/join it, unless the admin is responding to their own ticket
|
||||
if(holder && !(src.ckey in ticket.assigned_admins))
|
||||
if(src.ckey != ticket.owner && !ticket.take(src))
|
||||
return
|
||||
|
||||
var/recieve_message
|
||||
|
||||
if(holder && !C.holder)
|
||||
recieve_message = "<span class='pm'><span class='howto'><b>-- Click the [recieve_pm_type]'s name to reply --</b></span></span>\n"
|
||||
if(C.adminhelped)
|
||||
C << recieve_message
|
||||
C.adminhelped = 0
|
||||
C.adminhelped = NOT_ADMINHELPED
|
||||
|
||||
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
|
||||
if(config.popup_admin_pm)
|
||||
@@ -99,8 +124,24 @@
|
||||
else
|
||||
adminhelp(reply) //sender has left, adminhelp instead
|
||||
return
|
||||
src << "<span class='pm'><span class='out'>" + create_text_tag("pm_out_alt", "PM", src) + " to <span class='name'>[get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]</span>: <span class='message'>[msg]</span></span></span>"
|
||||
C << "<span class='pm'><span class='in'>" + create_text_tag("pm_in", "", C) + " <b>\[[recieve_pm_type] PM\]</b> <span class='name'>[get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]</span>: <span class='message'>[msg]</span></span></span>"
|
||||
|
||||
var/sender_message = "<span class='pm'><span class='out'>" + create_text_tag("pm_out_alt", "PM", src) + " to <span class='name'>[get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]</span>"
|
||||
if(holder)
|
||||
sender_message += " (<a href='?_src_=holder;take_ticket=\ref[ticket]'>[(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]</a>) (<a href='?src=\ref[usr];close_ticket=\ref[ticket]'>CLOSE</a>)"
|
||||
sender_message += ": <span class='message'>[generate_ahelp_key_words(mob, msg)]</span>"
|
||||
else
|
||||
sender_message += ": <span class='message'>[msg]</span>"
|
||||
sender_message += "</span></span>"
|
||||
src << sender_message
|
||||
|
||||
var/receiver_message = "<span class='pm'><span class='in'>" + create_text_tag("pm_in", "", C) + " <b>\[[recieve_pm_type] PM\]</b> <span class='name'>[get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]</span>"
|
||||
if(C.holder)
|
||||
receiver_message += " (<a href='?_src_=holder;take_ticket=\ref[ticket]'>[(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]</a>) (<a href='?src=\ref[usr];close_ticket=\ref[ticket]'>CLOSE</a>)"
|
||||
receiver_message += ": <span class='message'>[generate_ahelp_key_words(C.mob, msg)]</span>"
|
||||
else
|
||||
receiver_message += ": <span class='message'>[msg]</span>"
|
||||
receiver_message += "</span></span>"
|
||||
C << receiver_message
|
||||
|
||||
//play the recieving admin the adminhelp sound (if they have them enabled)
|
||||
//non-admins shouldn't be able to disable this
|
||||
@@ -109,13 +150,16 @@
|
||||
|
||||
log_admin("PM: [key_name(src)]->[key_name(C)]: [msg]", admin_key = key_name(src), ckey_target = key_name(C))
|
||||
|
||||
ticket.msgs += new /datum/ticket_msg(src.ckey, C.ckey, msg)
|
||||
update_ticket_panels()
|
||||
|
||||
//we don't use message_admins here because the sender/receiver might get it too
|
||||
for(var/client/X in admins)
|
||||
//check client/X is an admin and isn't the sender or recipient
|
||||
if(X == C || X == src)
|
||||
continue
|
||||
if(X.key != key && X.key != C.key && (X.holder.rights & (R_ADMIN|R_MOD)))
|
||||
X << "<span class='pm'><span class='other'>" + create_text_tag("pm_other", "PM:", X) + " <span class='name'>[key_name(src, X, 0)]</span> to <span class='name'>[key_name(C, X, 0)]</span>: <span class='message'>[msg]</span></span></span>"
|
||||
X << "<span class='pm'><span class='other'>" + create_text_tag("pm_other", "PM:", X) + " <span class='name'>[key_name(src, X, 0, ticket)]</span> to <span class='name'>[key_name(C, X, 0, ticket)]</span> (<a href='?_src_=holder;take_ticket=\ref[ticket]'>[(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]</a>) (<a href='?src=\ref[usr];close_ticket=\ref[ticket]'>CLOSE</a>): <span class='message'>[msg]</span></span></span>"
|
||||
|
||||
/client/proc/cmd_admin_discord_pm(sender)
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
|
||||
Reference in New Issue
Block a user