diff --git a/docs/webhooks.rst b/docs/webhooks.rst index 257dbe3f..967fd8fa 100644 --- a/docs/webhooks.rst +++ b/docs/webhooks.rst @@ -10,3 +10,29 @@ You can register webhooks to allow third party apps to be notified of helpdesk e 3. You can optionally set ``HELPDESK_WEBHOOK_TIMEOUT`` which defaults to 3 seconds. Warning, however, webhook requests are sent out sychronously on ticket update. If your webhook handling server is too slow, you should fix this rather than causing helpdesk freezes by messing with this variable. Once these URLs are configured, a serialized copy of the ticket object will be posted to each of these URLs each time a ticket is created or followed up on respectively. + + +Signals +-------------- + +Webhooks are triggered through `Django Signals _`. + +The two available signals are: + - new_ticket_done + - update_ticket_done + +You have the opportunity to listen to those in your project if you have post processing workflows outside of webhooks:: + + + from django.dispatch import receiver + from helpdesk.signals import new_ticket_done, update_ticket_done + + @receiver(new_ticket_done) + def process_new_ticket(sender, ticket, **kwargs): + "Triggers this code when a ticket is created." + pass + + @receiver(update_ticket_done) + def process_followup_update(sender, followup, **kwargs): + "Triggers this code when a follow-up is created." + pass diff --git a/helpdesk/email.py b/helpdesk/email.py index c454d5a2..f0d3a70f 100644 --- a/helpdesk/email.py +++ b/helpdesk/email.py @@ -21,10 +21,10 @@ from email.message import EmailMessage, MIMEPart from email.utils import getaddresses from email_reply_parser import EmailReplyParser from helpdesk import settings -from helpdesk import webhooks from helpdesk.exceptions import DeleteIgnoredTicketException, IgnoreTicketException from helpdesk.lib import process_attachments, safe_template_context from helpdesk.models import FollowUp, IgnoreEmail, Queue, Ticket +from helpdesk.signals import new_ticket_done, update_ticket_done import imaplib import logging import mimetypes @@ -617,8 +617,12 @@ def create_object_from_email_message(message, ticket_id, payload, files, logger) "Message seems to be auto-reply, not sending any emails back to the sender") else: send_info_email(message_id, f, ticket, context, queue, new) - if not new: - webhooks.notify_followup_webhooks(f) + if new: + # emit signal when a new ticket is created + new_ticket_done.send(sender="create_object_from_email_message", ticket=ticket) + else: + # emit signal with followup when the ticket is updated + update_ticket_done.send(sender="create_object_from_email_message", followup=f) return ticket diff --git a/helpdesk/forms.py b/helpdesk/forms.py index e63072cd..eb77c2e6 100644 --- a/helpdesk/forms.py +++ b/helpdesk/forms.py @@ -36,6 +36,7 @@ from helpdesk.settings import ( CUSTOMFIELD_TO_FIELD_DICT ) from helpdesk.validators import validate_file_extension +from helpdesk.signals import new_ticket_done import logging @@ -418,6 +419,10 @@ class TicketForm(AbstractTicketForm): followup.save() files = self._attach_files_to_follow_up(followup) + + # emit signal when the TicketForm.save is done + new_ticket_done.send(sender="TicketForm", ticket=ticket) + self._send_messages(ticket=ticket, queue=queue, followup=followup, @@ -507,6 +512,10 @@ class PublicTicketForm(AbstractTicketForm): followup.save() files = self._attach_files_to_follow_up(followup) + + # emit signal when the PublicTicketForm.save is done + new_ticket_done.send(sender="PublicTicketForm", ticket=ticket) + self._send_messages(ticket=ticket, queue=queue, followup=followup, diff --git a/helpdesk/models.py b/helpdesk/models.py index a9ce9a1b..eacdfe6e 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -11,7 +11,6 @@ models.py - Model (and hence database) definitions. This is the core of the from .lib import format_time_spent, convert_value, daily_time_spent_calculation from .templated_email import send_templated_mail from .validators import validate_file_extension -from .webhooks import send_new_ticket_webhook import datetime from django.conf import settings from django.contrib.auth import get_user_model @@ -644,8 +643,6 @@ class Ticket(models.Model): if self.queue.enable_notifications_on_email_events: for cc in self.ticketcc_set.all(): send('ticket_cc', cc.email_address) - if "new_ticket_cc" in roles: - send_new_ticket_webhook(self) return recipients def _get_assigned_to(self): diff --git a/helpdesk/signals.py b/helpdesk/signals.py new file mode 100644 index 00000000..0f72ef20 --- /dev/null +++ b/helpdesk/signals.py @@ -0,0 +1,7 @@ +import django.dispatch + +# create a signal for *TicketForm +new_ticket_done = django.dispatch.Signal() + +# create a signal for ticket_update view +update_ticket_done = django.dispatch.Signal() \ No newline at end of file diff --git a/helpdesk/templates/helpdesk/my_tickets.html b/helpdesk/templates/helpdesk/my_tickets.html index cde160a1..ab25a840 100644 --- a/helpdesk/templates/helpdesk/my_tickets.html +++ b/helpdesk/templates/helpdesk/my_tickets.html @@ -37,7 +37,9 @@ window.addEventListener('load', function() data.results.forEach(function(ticket) { $('#ticketsTable tbody').append(` - ${ticket.title} + + ${ticket.title} + ${ticket.queue.title} ${ticket.status} ${ticket.created} diff --git a/helpdesk/templates/helpdesk/public_view_ticket.html b/helpdesk/templates/helpdesk/public_view_ticket.html index 62f37a43..77de5af1 100644 --- a/helpdesk/templates/helpdesk/public_view_ticket.html +++ b/helpdesk/templates/helpdesk/public_view_ticket.html @@ -103,7 +103,10 @@
-
{% trans "You can insert ticket and queue details in your message. For more information, see the context help page." %}
+ {% url "helpdesk:help_context" as context_help_url %} + {% blocktrans %} +
You can insert ticket and queue details in your message. For more information, see the context help page.
+ {% endblocktrans %} {% if not ticket.can_be_resolved %}
{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}
{% endif %} {% if ticket.status == 1 %} diff --git a/helpdesk/templates/helpdesk/ticket.html b/helpdesk/templates/helpdesk/ticket.html index 8f0ede76..b61743f7 100644 --- a/helpdesk/templates/helpdesk/ticket.html +++ b/helpdesk/templates/helpdesk/ticket.html @@ -105,7 +105,10 @@
-
{% trans "You can insert ticket and queue details in your message. For more information, see the context help page." %}
+ {% url "helpdesk:help_context" as context_help_url %} + {% blocktrans %} +
You can insert ticket and queue details in your message. For more information, see the context help page.
+ {% endblocktrans %}
{% if not ticket.can_be_resolved %}
{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}
{% endif %} diff --git a/helpdesk/update_ticket.py b/helpdesk/update_ticket.py index deca0b40..989e04e4 100644 --- a/helpdesk/update_ticket.py +++ b/helpdesk/update_ticket.py @@ -15,8 +15,8 @@ from helpdesk.models import ( FollowUp, Ticket, TicketCC, - TicketChange, ) +from helpdesk.signals import update_ticket_done User = get_user_model() @@ -268,41 +268,33 @@ def update_ticket( files = process_attachments(f, files) if files else [] if ticket_title and ticket_title != ticket.title: - c = TicketChange( - followup=f, + c = f.ticketchange_set.create( field=_('Title'), old_value=ticket.title, new_value=ticket_title, ) - c.save() ticket.title = ticket_title if new_status != old_status: - c = TicketChange( - followup=f, + c = f.ticketchange_set.create( field=_('Status'), old_value=old_status_str, new_value=ticket.get_status_display(), ) - c.save() if ticket.assigned_to != old_owner: - c = TicketChange( - followup=f, + c = f.ticketchange_set.create( field=_('Owner'), old_value=old_owner, new_value=ticket.assigned_to, ) - c.save() if priority != ticket.priority: - c = TicketChange( - followup=f, + c = f.ticketchange_set.create( field=_('Priority'), old_value=ticket.priority, new_value=priority, ) - c.save() ticket.priority = priority if queue != ticket.queue.id: @@ -314,13 +306,11 @@ def update_ticket( ticket.queue_id = queue if due_date != ticket.due_date: - c = TicketChange( - followup=f, + c = f.ticketchange_set.create( field=_('Due on'), old_value=ticket.due_date, new_value=due_date, ) - c.save() ticket.due_date = due_date for checklist in ticket.checklists.all(): @@ -397,8 +387,9 @@ def update_ticket( )) ticket.save() - from helpdesk.webhooks import notify_followup_webhooks - notify_followup_webhooks(f) + # emit signal with followup when the ticket update is done + # internally used for webhooks + update_ticket_done.send(sender="update_ticket", followup=f) # auto subscribe user if enabled add_staff_subscription(user, ticket) diff --git a/helpdesk/webhooks.py b/helpdesk/webhooks.py index 3133a3fa..1770e753 100644 --- a/helpdesk/webhooks.py +++ b/helpdesk/webhooks.py @@ -1,8 +1,10 @@ -from . import settings - import requests import requests.exceptions import logging +from django.dispatch import receiver + +from . import settings +from .signals import new_ticket_done, update_ticket_done logger = logging.getLogger(__name__) @@ -10,6 +12,7 @@ def notify_followup_webhooks(followup): urls = settings.HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS() if not urls: return + # Serialize the ticket associated with the followup from .serializers import TicketSerializer ticket = followup.ticket @@ -29,6 +32,11 @@ def notify_followup_webhooks(followup): except requests.exceptions.Timeout: logger.error('Timeout while sending followup webhook to %s', url) +# listener is loaded via app.py HelpdeskConfig.ready() +@receiver(update_ticket_done) +def notify_followup_webhooks_receiver(sender, followup, **kwargs): + notify_followup_webhooks(followup) + def send_new_ticket_webhook(ticket): urls = settings.HELPDESK_GET_NEW_TICKET_WEBHOOK_URLS() @@ -50,3 +58,8 @@ def send_new_ticket_webhook(ticket): requests.post(url, json=data, timeout=settings.HELPDESK_WEBHOOK_TIMEOUT) except requests.exceptions.Timeout: logger.error('Timeout while sending new ticket webhook to %s', url) + +# listener is loaded via app.py HelpdeskConfig.ready() +@receiver(new_ticket_done) +def send_new_ticket_webhook_receiver(sender, ticket, **kwargs): + send_new_ticket_webhook(ticket) \ No newline at end of file