Ticket improvements (#4432)

Adds some features and fixes some shit:

Closing of tickets sent to Discord will now alert discord as well.
Adds a reminder period for tickets which starts after they're opened. It's intended to remind staff to close their tickets. Say, something like 10 minutes since opening sounds like a solid idea. If the staff who claimed it is offline, then all staff are reminded of it.
Adds the logging of all tickets to the database at the end of round. Sortable by staff closing, person opening, time opened, time closed, and round ID. This is primarily for Aboshehab.
This commit is contained in:
Erki
2018-03-25 16:32:12 +03:00
committed by GitHub
parent 24433b2e9f
commit 18baa01d0a
9 changed files with 121 additions and 11 deletions
+70 -3
View File
@@ -10,11 +10,22 @@ var/global/list/ticket_panels = list()
var/id
var/opened_time
// Real time references for SQL based logging.
var/opened_rt
var/closed_rt
var/response_time
var/reminder_timer
/datum/ticket/New(var/owner)
src.owner = owner
tickets |= src
id = tickets.len
opened_time = world.time
opened_rt = world.realtime
if (config.ticket_reminder_period)
reminder_timer = addtimer(CALLBACK(src, .proc/remind), config.ticket_reminder_period SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE)
/datum/ticket/proc/close(var/client/closed_by)
if(!closed_by)
@@ -29,14 +40,23 @@ var/global/list/ticket_panels = list()
if(status == TICKET_ASSIGNED && !closed_by.holder) // non-admins can only close a ticket if no admin has taken it
return
var/client/owner_client = client_by_ckey(owner)
if(owner_client && owner_client.adminhelped == ADMINHELPED_DISCORD)
discord_bot.send_to_admins("[key_name(owner_client)]'s request for help has been closed/deemed unnecessary by [key_name(closed_by)].")
owner_client.adminhelped = ADMINHELPED
src.status = TICKET_CLOSED
src.closed_by = closed_by.ckey
src.closed_rt = world.realtime
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()
if (reminder_timer)
deltimer(reminder_timer)
return 1
/datum/ticket/proc/take(var/client/assigned_admin)
@@ -61,13 +81,36 @@ var/global/list/ticket_panels = list()
owner_client.adminhelped = ADMINHELPED
message_admins("<span class='danger'><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>")
to_chat(owner_client, "<span class='notice'><b>[assigned_admin] has added themself to your ticket and should respond shortly. Thanks for your patience!</b></span>")
to_chat(assigned_admin, get_options_bar(owner_client, 2, 1, 1))
update_ticket_panels()
return 1
proc/get_open_ticket_by_ckey(var/owner)
/datum/ticket/proc/remind()
if (status == TICKET_CLOSED)
reminder_timer = null
return
var/admin_found = FALSE
for (var/ckey in assigned_admins)
var/client/C = client_by_ckey(ckey)
if (C)
admin_found = TRUE
to_chat(C, "<span class='danger'><b>You have yet to close [owner]'s ticket!</b></span>")
sound_to(C, 'sound/effects/adminhelp.ogg')
if (!admin_found)
message_admins("<span class='danger'><b>[owner]'s ticket has yet to be closed!</b></span>")
for(var/client/C in admins)
if((C.holder.rights & (R_ADMIN|R_MOD)) && (C.prefs.toggles & SOUND_ADMINHELP))
sound_to(C, 'sound/effects/adminhelp.ogg')
reminder_timer = addtimer(CALLBACK(src, .proc/remind), config.ticket_reminder_period SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE)
/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
@@ -83,6 +126,30 @@ proc/get_open_ticket_by_ckey(var/owner)
return 0
/datum/ticket/proc/log_to_db()
if (status != TICKET_CLOSED)
return
if (!establish_db_connection(dbcon))
return
var/DBQuery/Q = dbcon.NewQuery("INSERT INTO ss13_tickets (game_id, message_count, admin_count, admin_list, opened_by, taken_by, closed_by, response_delay, opened_at, closed_at) VALUES (:g_id:, :m_count:, :a_count:, :a_list:, :opened_by:, :taken_by, :closed_by:, :delay:, :opened_at:, :closed_at:)")
Q.Execute(list("g_id" = game_id, "m_count" = length(msgs), "a_count" = length(assigned_admins), "a_list" = json_encode(assigned_admins), "opened_by" = owner, "taken_by" = assigned_admins[0], "closed_by" = closed_by, "delay" = response_time, "opened_at" = SQLtime(opened_rt), "closed_at" = SQLtime(closed_rt)))
/datum/ticket/proc/append_message(m_from, m_to, msg)
msgs += new /datum/ticket_msg(m_from, m_to, msg)
if (!response_time && m_from != owner)
response_time = round((world.time - opened_time) SECONDS)
update_ticket_panels()
// Referenced in the statistics controller.
/proc/log_all_tickets()
for (var/t in tickets)
var/datum/ticket/T = t
T.log_to_db()
/datum/ticket_msg
var/msg_from
var/msg_to
@@ -177,7 +244,7 @@ proc/get_open_ticket_by_ckey(var/owner)
ticket_panel_window.update()
var/datum/ticket/ticket = locate(href_list["ticket"])
if(!ticket)
if(!istype(ticket))
return
switch(href_list["action"])
+10 -3
View File
@@ -852,7 +852,7 @@
else if(href_list["take_ticket"])
var/datum/ticket/ticket = locate(href_list["take_ticket"])
if(isnull(ticket))
if(!istype(ticket))
return
ticket.take(usr.client)
@@ -870,6 +870,7 @@
var/special_role_description = ""
var/health_description = ""
var/gender_description = ""
var/species_description = "N/A"
var/turf/T = get_turf(M)
//Location
@@ -898,13 +899,19 @@
else
health_description = "This mob type has no health to speak of."
//Gener
//Species
if (ishuman(M))
var/mob/living/carbon/human/H = M
if (H.species)
species_description = "<b>[H.species.name]</b>"
//GenDer
switch(M.gender)
if(MALE,FEMALE) gender_description = "[M.gender]"
else gender_description = "<font color='red'><b>[M.gender]</b></font>"
src.owner << "<b>Info about [M.name]:</b> "
src.owner << "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]"
src.owner << "Mob type = [M.type]; Species = [species_description] Gender = [gender_description] Damage = [health_description]"
src.owner << "Name = <b>[M.name]</b>; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = <b>[M.key]</b>;"
src.owner << "Location = [location_description];"
src.owner << "[special_role_description]"
+1 -2
View File
@@ -111,8 +111,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
to_chat(src, "<span class='warning'>Error: Private-Message: Client not found. They may have lost connection, so please be patient!</span>")
return
ticket.msgs += new /datum/ticket_msg(src.ckey, null, original_msg)
update_ticket_panels()
ticket.append_message(src.ckey, null, original_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)
+1 -2
View File
@@ -151,8 +151,7 @@
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()
ticket.append_message(src.ckey, C.ckey, msg)
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in admins)