mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-22 07:53:19 +01:00
Merge branch 'main' into view_protectors
This commit is contained in:
commit
a6bb99f1e8
@ -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.
|
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.
|
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
|
||||||
|
@ -21,10 +21,10 @@ from email.message import EmailMessage, MIMEPart
|
|||||||
from email.utils import getaddresses
|
from email.utils import getaddresses
|
||||||
from email_reply_parser import EmailReplyParser
|
from email_reply_parser import EmailReplyParser
|
||||||
from helpdesk import settings
|
from helpdesk import settings
|
||||||
from helpdesk import webhooks
|
|
||||||
from helpdesk.exceptions import DeleteIgnoredTicketException, IgnoreTicketException
|
from helpdesk.exceptions import DeleteIgnoredTicketException, IgnoreTicketException
|
||||||
from helpdesk.lib import process_attachments, safe_template_context
|
from helpdesk.lib import process_attachments, safe_template_context
|
||||||
from helpdesk.models import FollowUp, IgnoreEmail, Queue, Ticket
|
from helpdesk.models import FollowUp, IgnoreEmail, Queue, Ticket
|
||||||
|
from helpdesk.signals import new_ticket_done, update_ticket_done
|
||||||
import imaplib
|
import imaplib
|
||||||
import logging
|
import logging
|
||||||
import mimetypes
|
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")
|
"Message seems to be auto-reply, not sending any emails back to the sender")
|
||||||
else:
|
else:
|
||||||
send_info_email(message_id, f, ticket, context, queue, new)
|
send_info_email(message_id, f, ticket, context, queue, new)
|
||||||
if not new:
|
if new:
|
||||||
webhooks.notify_followup_webhooks(f)
|
# 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
|
return ticket
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ from helpdesk.settings import (
|
|||||||
CUSTOMFIELD_TO_FIELD_DICT
|
CUSTOMFIELD_TO_FIELD_DICT
|
||||||
)
|
)
|
||||||
from helpdesk.validators import validate_file_extension
|
from helpdesk.validators import validate_file_extension
|
||||||
|
from helpdesk.signals import new_ticket_done
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
@ -418,6 +419,10 @@ class TicketForm(AbstractTicketForm):
|
|||||||
followup.save()
|
followup.save()
|
||||||
|
|
||||||
files = self._attach_files_to_follow_up(followup)
|
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,
|
self._send_messages(ticket=ticket,
|
||||||
queue=queue,
|
queue=queue,
|
||||||
followup=followup,
|
followup=followup,
|
||||||
@ -507,6 +512,10 @@ class PublicTicketForm(AbstractTicketForm):
|
|||||||
followup.save()
|
followup.save()
|
||||||
|
|
||||||
files = self._attach_files_to_follow_up(followup)
|
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,
|
self._send_messages(ticket=ticket,
|
||||||
queue=queue,
|
queue=queue,
|
||||||
followup=followup,
|
followup=followup,
|
||||||
|
@ -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 .lib import format_time_spent, convert_value, daily_time_spent_calculation
|
||||||
from .templated_email import send_templated_mail
|
from .templated_email import send_templated_mail
|
||||||
from .validators import validate_file_extension
|
from .validators import validate_file_extension
|
||||||
from .webhooks import send_new_ticket_webhook
|
|
||||||
import datetime
|
import datetime
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
@ -644,8 +643,6 @@ class Ticket(models.Model):
|
|||||||
if self.queue.enable_notifications_on_email_events:
|
if self.queue.enable_notifications_on_email_events:
|
||||||
for cc in self.ticketcc_set.all():
|
for cc in self.ticketcc_set.all():
|
||||||
send('ticket_cc', cc.email_address)
|
send('ticket_cc', cc.email_address)
|
||||||
if "new_ticket_cc" in roles:
|
|
||||||
send_new_ticket_webhook(self)
|
|
||||||
return recipients
|
return recipients
|
||||||
|
|
||||||
def _get_assigned_to(self):
|
def _get_assigned_to(self):
|
||||||
|
7
helpdesk/signals.py
Normal file
7
helpdesk/signals.py
Normal file
@ -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()
|
@ -37,7 +37,9 @@ window.addEventListener('load', function()
|
|||||||
data.results.forEach(function(ticket) {
|
data.results.forEach(function(ticket) {
|
||||||
$('#ticketsTable tbody').append(`
|
$('#ticketsTable tbody').append(`
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/view/?ticket=${ticket.id}&email=${ticket.submitter}&key=${ticket.secret_key}">${ticket.title}</a></td>
|
<td>
|
||||||
|
<a href='{% url "helpdesk:public_view" %}?ticket=${ticket.id}&email=${ticket.submitter}&key=${ticket.secret_key}'>${ticket.title}</a>
|
||||||
|
</td>
|
||||||
<td>${ticket.queue.title}</td>
|
<td>${ticket.queue.title}</td>
|
||||||
<td>${ticket.status}</td>
|
<td>${ticket.status}</td>
|
||||||
<td>${ticket.created}</td>
|
<td>${ticket.created}</td>
|
||||||
|
@ -103,7 +103,10 @@
|
|||||||
|
|
||||||
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
|
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
|
||||||
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
|
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
|
||||||
<dd class='form_help_text'>{% trans "You can insert ticket and queue details in your message. For more information, see the <a href='../../help/context/'>context help page</a>." %}</dd>
|
{% url "helpdesk:help_context" as context_help_url %}
|
||||||
|
{% blocktrans %}
|
||||||
|
<dd class='form_help_text'>You can insert ticket and queue details in your message. For more information, see the <a href='{{ context_help_url }}'>context help page</a>.</dd>
|
||||||
|
{% endblocktrans %}
|
||||||
|
|
||||||
{% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %}
|
{% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %}
|
||||||
{% if ticket.status == 1 %}
|
{% if ticket.status == 1 %}
|
||||||
|
@ -105,7 +105,10 @@
|
|||||||
|
|
||||||
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
|
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
|
||||||
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
|
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
|
||||||
<dd class='form_help_text'>{% trans "You can insert ticket and queue details in your message. For more information, see the <a href='../../help/context/'>context help page</a>." %}</dd>
|
{% url "helpdesk:help_context" as context_help_url %}
|
||||||
|
{% blocktrans %}
|
||||||
|
<dd class='form_help_text'>You can insert ticket and queue details in your message. For more information, see the <a href='{{ context_help_url }}'>context help page</a>.</dd>
|
||||||
|
{% endblocktrans %}
|
||||||
|
|
||||||
<dt><label>{% trans "New Status" %}</label></dt>
|
<dt><label>{% trans "New Status" %}</label></dt>
|
||||||
{% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %}
|
{% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %}
|
||||||
|
@ -15,8 +15,8 @@ from helpdesk.models import (
|
|||||||
FollowUp,
|
FollowUp,
|
||||||
Ticket,
|
Ticket,
|
||||||
TicketCC,
|
TicketCC,
|
||||||
TicketChange,
|
|
||||||
)
|
)
|
||||||
|
from helpdesk.signals import update_ticket_done
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
@ -268,41 +268,33 @@ def update_ticket(
|
|||||||
files = process_attachments(f, files) if files else []
|
files = process_attachments(f, files) if files else []
|
||||||
|
|
||||||
if ticket_title and ticket_title != ticket.title:
|
if ticket_title and ticket_title != ticket.title:
|
||||||
c = TicketChange(
|
c = f.ticketchange_set.create(
|
||||||
followup=f,
|
|
||||||
field=_('Title'),
|
field=_('Title'),
|
||||||
old_value=ticket.title,
|
old_value=ticket.title,
|
||||||
new_value=ticket_title,
|
new_value=ticket_title,
|
||||||
)
|
)
|
||||||
c.save()
|
|
||||||
ticket.title = ticket_title
|
ticket.title = ticket_title
|
||||||
|
|
||||||
if new_status != old_status:
|
if new_status != old_status:
|
||||||
c = TicketChange(
|
c = f.ticketchange_set.create(
|
||||||
followup=f,
|
|
||||||
field=_('Status'),
|
field=_('Status'),
|
||||||
old_value=old_status_str,
|
old_value=old_status_str,
|
||||||
new_value=ticket.get_status_display(),
|
new_value=ticket.get_status_display(),
|
||||||
)
|
)
|
||||||
c.save()
|
|
||||||
|
|
||||||
if ticket.assigned_to != old_owner:
|
if ticket.assigned_to != old_owner:
|
||||||
c = TicketChange(
|
c = f.ticketchange_set.create(
|
||||||
followup=f,
|
|
||||||
field=_('Owner'),
|
field=_('Owner'),
|
||||||
old_value=old_owner,
|
old_value=old_owner,
|
||||||
new_value=ticket.assigned_to,
|
new_value=ticket.assigned_to,
|
||||||
)
|
)
|
||||||
c.save()
|
|
||||||
|
|
||||||
if priority != ticket.priority:
|
if priority != ticket.priority:
|
||||||
c = TicketChange(
|
c = f.ticketchange_set.create(
|
||||||
followup=f,
|
|
||||||
field=_('Priority'),
|
field=_('Priority'),
|
||||||
old_value=ticket.priority,
|
old_value=ticket.priority,
|
||||||
new_value=priority,
|
new_value=priority,
|
||||||
)
|
)
|
||||||
c.save()
|
|
||||||
ticket.priority = priority
|
ticket.priority = priority
|
||||||
|
|
||||||
if queue != ticket.queue.id:
|
if queue != ticket.queue.id:
|
||||||
@ -314,13 +306,11 @@ def update_ticket(
|
|||||||
ticket.queue_id = queue
|
ticket.queue_id = queue
|
||||||
|
|
||||||
if due_date != ticket.due_date:
|
if due_date != ticket.due_date:
|
||||||
c = TicketChange(
|
c = f.ticketchange_set.create(
|
||||||
followup=f,
|
|
||||||
field=_('Due on'),
|
field=_('Due on'),
|
||||||
old_value=ticket.due_date,
|
old_value=ticket.due_date,
|
||||||
new_value=due_date,
|
new_value=due_date,
|
||||||
)
|
)
|
||||||
c.save()
|
|
||||||
ticket.due_date = due_date
|
ticket.due_date = due_date
|
||||||
|
|
||||||
for checklist in ticket.checklists.all():
|
for checklist in ticket.checklists.all():
|
||||||
@ -397,8 +387,9 @@ def update_ticket(
|
|||||||
))
|
))
|
||||||
ticket.save()
|
ticket.save()
|
||||||
|
|
||||||
from helpdesk.webhooks import notify_followup_webhooks
|
# emit signal with followup when the ticket update is done
|
||||||
notify_followup_webhooks(f)
|
# internally used for webhooks
|
||||||
|
update_ticket_done.send(sender="update_ticket", followup=f)
|
||||||
|
|
||||||
# auto subscribe user if enabled
|
# auto subscribe user if enabled
|
||||||
add_staff_subscription(user, ticket)
|
add_staff_subscription(user, ticket)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from . import settings
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
import logging
|
import logging
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from . import settings
|
||||||
|
from .signals import new_ticket_done, update_ticket_done
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ def notify_followup_webhooks(followup):
|
|||||||
urls = settings.HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS()
|
urls = settings.HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS()
|
||||||
if not urls:
|
if not urls:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Serialize the ticket associated with the followup
|
# Serialize the ticket associated with the followup
|
||||||
from .serializers import TicketSerializer
|
from .serializers import TicketSerializer
|
||||||
ticket = followup.ticket
|
ticket = followup.ticket
|
||||||
@ -29,6 +32,11 @@ def notify_followup_webhooks(followup):
|
|||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
logger.error('Timeout while sending followup webhook to %s', url)
|
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):
|
def send_new_ticket_webhook(ticket):
|
||||||
urls = settings.HELPDESK_GET_NEW_TICKET_WEBHOOK_URLS()
|
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)
|
requests.post(url, json=data, timeout=settings.HELPDESK_WEBHOOK_TIMEOUT)
|
||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
logger.error('Timeout while sending new ticket webhook to %s', url)
|
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)
|
Loading…
Reference in New Issue
Block a user