Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit a signal when a ticket is updated #1169

Merged
merged 16 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/webhooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://docs.djangoproject.com/en/stable/topics/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
10 changes: 7 additions & 3 deletions helpdesk/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
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
Expand Down Expand Up @@ -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


Expand Down
9 changes: 9 additions & 0 deletions helpdesk/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
CUSTOMFIELD_TO_FIELD_DICT
)
from helpdesk.validators import validate_file_extension
from helpdesk.signals import new_ticket_done
import logging


Expand Down Expand Up @@ -418,6 +419,10 @@ def save(self, user):
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,
Expand Down Expand Up @@ -507,6 +512,10 @@ def save(self, user):
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,
Expand Down
3 changes: 0 additions & 3 deletions helpdesk/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
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
Expand Down Expand Up @@ -644,8 +643,6 @@ def send(role, recipient):
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):
Expand Down
7 changes: 7 additions & 0 deletions helpdesk/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import django.dispatch

# create a signal for *TicketForm
samsplunks marked this conversation as resolved.
Show resolved Hide resolved
new_ticket_done = django.dispatch.Signal()

# create a signal for ticket_update view
update_ticket_done = django.dispatch.Signal()
27 changes: 9 additions & 18 deletions helpdesk/update_ticket.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
FollowUp,
Ticket,
TicketCC,
TicketChange,
)
from helpdesk.signals import update_ticket_done

User = get_user_model()

Expand Down Expand Up @@ -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:
Expand All @@ -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():
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 15 additions & 2 deletions helpdesk/webhooks.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
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__)

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
Expand All @@ -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()
Expand All @@ -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)