Initial commit, adds admin ticket system framework, styles and hooks into adminhelp system.

This commit is contained in:
Birdtalon
2017-10-01 13:52:53 +01:00
parent 36109c17fa
commit f926bfad2c
11 changed files with 331 additions and 7 deletions
+9 -1
View File
@@ -218,6 +218,12 @@ var/list/admin_verbs_snpc = list(
/client/proc/customiseSNPC,
/client/proc/hide_snpc_verbs
)
var/list/admin_verbs_ticket = list(
/client/proc/startadmintickets,
/client/proc/vvadmintickets,
/client/proc/openTicketUI,
/client/proc/generateTickets,
)
/client/proc/on_holder_add()
if(chatOutput && chatOutput.loaded)
@@ -230,6 +236,7 @@ var/list/admin_verbs_snpc = list(
verbs += /client/proc/togglebuildmodeself
if(holder.rights & R_ADMIN)
verbs += admin_verbs_admin
verbs += admin_verbs_ticket
spawn(1)
control_freak = 0
if(holder.rights & R_BAN)
@@ -280,7 +287,8 @@ var/list/admin_verbs_snpc = list(
admin_verbs_show_debug_verbs,
/client/proc/readmin,
admin_verbs_snpc,
/client/proc/hide_snpc_verbs
/client/proc/hide_snpc_verbs,
admin_verbs_ticket
)
/client/proc/hide_verbs()
+138
View File
@@ -0,0 +1,138 @@
/*
Admin ticket system by Birdtalon
*/
//Global holder
var/global/datum/adminTicketHolder/globAdminTicketHolder = new /datum/adminTicketHolder
//Defines
//Deciseconds until timeout
#define ADMIN_TICKET_TIMEOUT 100
//Decisecions before opening another ticket
#define ADMIN_TICKET_DUPLICATE_COOLDOWN 300
//Status defines
#define ADMIN_TICKET_OPEN 1
#define ADMIN_TICKET_CLOSED 2
#define ADMIN_TICKET_RESOLVED 3
#define ADMIN_TICKET_STALE 4
//Datum holding all tickets
/datum/adminTicketHolder
var/ticketCounter = 1 // Counts the tickets and used to assign the id number
var/list/allTickets = list()
//Return the current ticket number ready to be called off.
/datum/adminTicketHolder/proc/getTicketCounter()
return ticketCounter
//Return the ticket counter and increment
/datum/adminTicketHolder/proc/getTicketCounterAndInc()
var/C = ticketCounter
ticketCounter++
return C
//Set the ticket counter to a value
/datum/adminTicketHolder/proc/setTicketCounter(var/N as num)
ticketCounter = N
/datum/adminTicketHolder/proc/purgeAllTickets() // Delete ALL tickets
QDEL_LIST(allTickets)
message_admins("<span class='adminticket'>[usr] purged all admin tickets!</span>")
/datum/adminTicketHolder/proc/closeAllOpenTickets() // Close all open tickets
for(var/i in allTickets)
var/datum/admin_ticket/T = i
T.ticketState = ADMIN_TICKET_CLOSED
//Open a new ticket and populate details then add to the list of open tickets
/datum/adminTicketHolder/proc/newTicket(var/client/C, var/passedContent)
if(!C || !passedContent)
return
//Check if the user has an open ticket already within the cooldown period, if so we don't create a new one and re-set the cooldown period
var/datum/admin_ticket/existingTicket = checkForOpenTicket(C)
if(existingTicket)
existingTicket.setCooldownPeriod()
to_chat(C, "<span class='adminticket'>Your ticket #[existingTicket.ticketNum] remains open!</span>")
return
var/datum/admin_ticket/T = new /datum/admin_ticket
T.ticketNum = getTicketCounterAndInc()
T.clientName = C
T.timeOpened = worldtime2text()
T.content = passedContent
T.locationSent = C.mob.loc
T.mobControlled = C.mob
T.ticketState = ADMIN_TICKET_OPEN
T.timeUntilStale = world.time + ADMIN_TICKET_TIMEOUT
T.setCooldownPeriod()
allTickets += T
//Inform the user that they have opened a ticket
to_chat(C, "<span class='adminticket'>You have opened admin ticket number #[(globAdminTicketHolder.getTicketCounter() - 1)]! Please be patient and we will help you soon!</span>")
spawn()
T.beginStaleCount()
//Set ticket state with key N to open
/datum/adminTicketHolder/proc/openTicket(var/N as num)
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
T.ticketState = ADMIN_TICKET_OPEN
//Set ticket state with key N to resolved
/datum/adminTicketHolder/proc/resolveTicket(var/N as num)
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
T.ticketState = ADMIN_TICKET_RESOLVED
//Set ticket state with key N to closed
/datum/adminTicketHolder/proc/closeTicket(var/N as num)
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
T.ticketState = ADMIN_TICKET_CLOSED
//List Open Tickets in chat
/datum/adminTicketHolder/proc/listOpenTicketsToChat()
for(var/T in allTickets)
var/datum/admin_ticket/ticket = T
message_admins("<span class='adminticket'>Ticket #[ticket.ticketNum]: Opened by [ticket.clientName] at [ticket.timeOpened]: [ticket.content]</span>")
//Check if the user already has a ticket open and within the cooldown period.
/datum/adminTicketHolder/proc/checkForOpenTicket(var/client/C)
for(var/datum/admin_ticket/T in allTickets)
if(T.clientName == C && T.ticketState == ADMIN_TICKET_OPEN && (T.ticketCooldown > world.time))
return T
return FALSE
//Single admin ticket
/datum/admin_ticket
var/ticketNum // Ticket number
var/clientName // Client which opened the ticket
var/timeOpened // Time the ticket was opened
var/content // content of the admin help
var/lastAdminResponse // Last admin who responded
var/lastResponseTime // When the admin last responded
var/locationSent // Location the player was when they send the ticket
var/mobControlled // Mob they were controlling
var/ticketState // State of the ticket, open, closed, resolved etc
var/timeUntilStale // When the ticket goes stale
var/ticketCooldown // Cooldown before allowing the user to open another ticket.
/datum/admin_ticket/proc/beginStaleCount()
if(!src)
to_chat(world, "DEBUG: NO SRC")
return
while(world.time < timeUntilStale)
sleep(200)
to_chat(world, "DEBUG: CHECKING STATE OF TICKET [ticketNum]")
if(ticketState == ADMIN_TICKET_OPEN && world.time > timeUntilStale)
message_admins("<span class='adminticket'>Ticket #[ticketNum] has been open for [ADMIN_TICKET_TIMEOUT * 0.1] seconds. Changing status to stale.</span>")
ticketState = ADMIN_TICKET_STALE
break
/datum/admin_ticket/proc/setCooldownPeriod()
ticketCooldown = world.time + ADMIN_TICKET_DUPLICATE_COOLDOWN
/datum/admin_ticket/proc/setLastAdminResponse(var/client/C)
lastAdminResponse = C
lastResponseTime = world.time
@@ -0,0 +1,116 @@
/datum/adminTicketHolder/proc/returnUI(var/tab = ADMIN_TICKET_OPEN)
set name = "Open Ticket Interface"
set category = "Tickets"
//dat
var/dat = "<h1>Admin Tickets</h1>"
dat +="<a href='?src=[UID()];refresh=1'>Refresh</a><br /><a href='?src=[UID()];showopen=1'>Open Tickets</a><a href='?src=[UID()];showresolved=1'>Resolved Tickets</a><a href='?src=[UID()];showclosed=1'>Closed Tickets</a>"
if(tab == ADMIN_TICKET_OPEN)
dat += "<h2>Open Tickets</h2>"
dat += "<table class='admintickets'>"
dat +="<tr class='admintickets'><th>Control</th><th>Ticket</th><th>Detail</th></tr>"
for(var/T in allTickets)
var/datum/admin_ticket/ticket = T
if(ticket.ticketState == ADMIN_TICKET_OPEN || ticket.ticketState == ADMIN_TICKET_STALE)
dat += "<tr class='admintickets'><td><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];close=[ticket.ticketNum]'>Close</a></td> <td><b>Ticket #[ticket.ticketNum]: at [ticket.timeOpened]: [ticket.content]</td> <td><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a></td>"
else
continue
dat += "</table>"
return dat
else if(tab == ADMIN_TICKET_RESOLVED)
dat += "<h2>Resolved Tickets</h2>"
dat += "<table class='admintickets'>"
dat +="<tr class='admintickets'><th>Control</th><th>Ticket</th><th>Detail</th></tr>"
for(var/T in allTickets)
var/datum/admin_ticket/ticket = T
if(ticket.ticketState == ADMIN_TICKET_RESOLVED)
dat += "<tr><td><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];close=[ticket.ticketNum]'>Close</a></td> <td><b>Ticket #[ticket.ticketNum]: at [ticket.timeOpened]: [ticket.content]</td> <td><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a></td>"
else
continue
dat += "</table>"
return dat
else if(tab == ADMIN_TICKET_CLOSED)
dat += "<h2>Closed Tickets</h2>"
dat += "<table class='admintickets'>"
dat +="<tr class='admintickets'><th>Control</th><th>Ticket</th><th>Detail</th></tr>"
for(var/T in allTickets)
var/datum/admin_ticket/ticket = T
if(ticket.ticketState == ADMIN_TICKET_CLOSED)
dat += "<tr class='admintickets'><td><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];close=[ticket.ticketNum]'>Close</a></td> <td><b>Ticket #[ticket.ticketNum]: at [ticket.timeOpened]: [ticket.content]</td> <td><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a></td>"
else
continue
dat += "</table>"
return dat
/datum/adminTicketHolder/proc/showUI(var/client/C, var/tab)
var/dat = null
dat = returnUI(tab)
var/datum/browser/popup = new(usr, "admintickets", "Admin Tickets", 1200, 600)
popup.set_content(dat)
popup.open()
/datum/adminTicketHolder/proc/showDetailUI(var/client/C, var/ticketID)
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[ticketID]
var/dat = "<h1>Admin Tickets</h1>"
dat += "<h2>Ticket #[T.ticketNum]</h2>"
dat += "<h4>[T.clientName] / [T.mobControlled] opened this ticket at [T.timeOpened] at location [T.locationSent]</h4>"
dat += "<p>[T.content]</p>"
dat += "<a href='?src=[UID()];reopen=[T.ticketNum]'>Re-Open</a><a href='?src=[UID()];resolve=[T.ticketNum]'>Resolve</a><a href='?src=[UID()];close=[T.ticketNum]'>Close</a>"
var/datum/browser/popup = new(usr, "adminticketsdetail", "Admin Ticket #[T.ticketNum]", 1200, 600)
popup.set_content(dat)
popup.open()
/datum/adminTicketHolder/Topic(href, href_list)
if(href_list["refresh"])
showUI(usr)
return
if(href_list["showopen"])
showUI(usr, ADMIN_TICKET_OPEN)
return
if(href_list["showresolved"])
showUI(usr, ADMIN_TICKET_RESOLVED)
return
if(href_list["showclosed"])
showUI(usr, ADMIN_TICKET_CLOSED)
return
if(href_list["details"])
var/indexNum = text2num(href_list["details"])
showDetailUI(usr.client, indexNum)
return
if(href_list["resolve"])
var/indexNum = text2num(href_list["resolve"])
globAdminTicketHolder.resolveTicket(indexNum)
message_admins("<span class='adminticket'>[usr.client] / ([usr]) resolved admin ticket number [indexNum]</span>")
showUI(usr)
return
if(href_list["close"])
var/indexNum = text2num(href_list["close"])
globAdminTicketHolder.closeTicket(indexNum)
message_admins("<span class='adminticket'>[usr.client] / ([usr]) closed admin ticket number [indexNum]</span>")
showUI(usr)
return
else if(href_list["reopen"])
var/indexNum = text2num(href_list["reopen"])
globAdminTicketHolder.openTicket(indexNum)
message_admins("<span class='adminticket'>[usr.client] / ([usr]) re-opened admin ticket number [indexNum]</span>")
@@ -0,0 +1,35 @@
//Verbs
/client/proc/startadmintickets()
set name = "Restart Admin Ticket System"
set category = "Tickets"
if(!globAdminTicketHolder)
var/global/datum/adminTicketHolder/globAdminTicketHolder = new /datum/adminTicketHolder
else
to_chat(world, "Already one running.")
/client/proc/vvadmintickets()
set name = "Debug Admin Tickets"
set category = "Tickets"
debug_variables(globAdminTicketHolder)
/client/proc/openTicketUI()
set name = "Open Ticket Interface"
set category = "Tickets"
if(!holder)
return
if(!check_rights(R_ADMIN))
return
globAdminTicketHolder.showUI()
/client/proc/generateTickets()
set name = "Generate Ticket"
set category = "Tickets"
var/testmsg = pick("REEEEEEE", "HELP ME I'm NOOB!!", "PLEASE ADMIN REVIVE ME", "IS THIS LEGIT?", "some1 killed me 4noraisen", "birdtalon is powergaming again")
globAdminTicketHolder.newTicket(src, testmsg)
+3
View File
@@ -122,6 +122,9 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
window_flash(X)
to_chat(X, msg)
//Try to open a new adminticket and inform the user if they succed.
globAdminTicketHolder.newTicket(src, msg)
//show it to the person adminhelping too
to_chat(src, "<span class='boldnotice'>[selected_type]</b>: [original_msg]</span>")