-
Notifications
You must be signed in to change notification settings - Fork 18
Autoresolve for "expired" tickets #139
base: master
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ def short_name(self): | |
return first_name.rsplit('@')[0] | ||
return first_name | ||
|
||
TicketStatus = enum.Enum('TicketStatus', 'pending assigned resolved deleted') | ||
TicketStatus = enum.Enum('TicketStatus', 'pending assigned resolved deleted autoresolved autodeleted') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think a separate "autoresolved" category is necessary. I don't see any situation where we'd need to be able to distinguish resolved vs autoresolved tickets (and if we really need to, we could always inspect the events) I'd lean toward the same for autodeleted tickets, but I'm more open to a separate category there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense, I'll not add any categories here. |
||
|
||
class Ticket(db.Model): | ||
"""Represents an ticket in the queue. A student submits a ticket and receives | ||
|
@@ -87,7 +87,7 @@ def by_status(cls, status=None): | |
|
||
TicketEventType = enum.Enum( | ||
'TicketEventType', | ||
'create assign unassign resolve delete describe', | ||
'create assign unassign resolve delete describe autoresolve autodelete', | ||
) | ||
|
||
class TicketEvent(db.Model): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,11 +41,24 @@ def ticket_json(ticket): | |
} | ||
|
||
def emit_event(ticket, event_type): | ||
ticket_event = TicketEvent( | ||
if event_type == TicketEventType.autodelete: | ||
ticket_event = TicketEvent( | ||
event_type=event_type, | ||
ticket=ticket, | ||
user=current_user, | ||
user_id=0 # assuming ids start @ 1, 0 signifies admin/autodelete | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems hacky. I'd prefer to change TicketEvent to allow the user to be nullable (though that would require a migration) |
||
) | ||
elif event_type == TicketEventType.autoresolve: | ||
ticket_event = TicketEvent( | ||
event_type=event_type, | ||
ticket=ticket, | ||
user_id=ticket.helper_id | ||
) | ||
else: | ||
ticket_event = TicketEvent( | ||
event_type=event_type, | ||
ticket=ticket, | ||
user=current_user, | ||
) | ||
db.session.add(ticket_event) | ||
db.session.commit() | ||
socketio.emit('event', { | ||
|
@@ -131,6 +144,21 @@ def disconnect(): | |
|
||
@socketio.on('refresh') | ||
def refresh(ticket_ids): | ||
""" Cuts out tickets that have elapsed time beyond cuttoff in minutes""" | ||
pending_cutoff = 180 | ||
assigned_cutoff = 30 | ||
|
||
pending_cutoff_time = datetime.datetime.utcnow() - datetime.timedelta(minutes = pending_cutoff) | ||
assigned_cutoff_time = datetime.datetime.utcnow() - datetime.timedelta(minutes = assigned_cutoff) | ||
|
||
exp_pending_tickets = Ticket.query.filter(Ticket.created < pending_cutoff_time, Ticket.status == TicketStatus.pending).all() | ||
exp_pending_ticket_ids = [tick.id for tick in exp_pending_tickets] | ||
autodelete(exp_pending_ticket_ids) | ||
|
||
exp_assigned_tickets = Ticket.query.filter(Ticket.updated < assigned_cutoff_time, Ticket.status == TicketStatus.assigned).all() | ||
exp_assigned_ticket_ids = [tick.id for tick in exp_assigned_tickets] | ||
autoresolve(exp_assigned_ticket_ids) | ||
|
||
tickets = Ticket.query.filter(Ticket.id.in_(ticket_ids)).all() | ||
return { | ||
'tickets': [ticket_json(ticket) for ticket in tickets], | ||
|
@@ -204,6 +232,14 @@ def delete(ticket_ids): | |
emit_event(ticket, TicketEventType.delete) | ||
db.session.commit() | ||
|
||
@socketio.on('autodelete') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should only be triggered on the server-side, so I don't think the socket event listener is necessary. |
||
def autodelete(ticket_ids): | ||
tickets = get_tickets(ticket_ids) | ||
for ticket in tickets: | ||
ticket.status = TicketStatus.autodeleted | ||
emit_event(ticket, TicketEventType.autodelete) | ||
db.session.commit() | ||
|
||
@socketio.on('resolve') | ||
@logged_in | ||
def resolve(ticket_ids): | ||
|
@@ -216,6 +252,15 @@ def resolve(ticket_ids): | |
db.session.commit() | ||
return get_next_ticket() | ||
|
||
@socketio.on('resolve') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment about autodelete above (also, this shouldn't have the same socket event as the existing resolve function. |
||
def autoresolve(ticket_ids): | ||
tickets = get_tickets(ticket_ids) | ||
for ticket in tickets: | ||
ticket.status = TicketStatus.autoresolved | ||
emit_event(ticket, TicketEventType.autoresolve) | ||
db.session.commit() | ||
#return get_next_ticket() | ||
|
||
@socketio.on('assign') | ||
@is_staff | ||
def assign(ticket_ids): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is really necessary. If we do want to keep this, you should create the ticket outside the if and then update the fields for certain values.