diff --git a/CHANGELOG b/CHANGELOG
index 31b1ea1d..6f63438c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1 +1,6 @@
2009-09-09 r138 Issue #104 Add a CHANGELOG file
+
+2009-09-09 r139 Issue #102 Add Ticket CC's
+Add rudimentary CC: functionality on tickets, controlled by staff users. CC's
+can be e-mail addresses or users, who will receive copies of all emails sent
+to the Submitter. This is a work in progress.
diff --git a/forms.py b/forms.py
index 1e842147..bf533568 100644
--- a/forms.py
+++ b/forms.py
@@ -15,7 +15,7 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from helpdesk.lib import send_templated_mail
-from helpdesk.models import Ticket, Queue, FollowUp, Attachment, IgnoreEmail
+from helpdesk.models import Ticket, Queue, FollowUp, Attachment, IgnoreEmail, TicketCC
class EditTicketForm(forms.ModelForm):
class Meta:
@@ -356,3 +356,8 @@ class UserSettingsForm(forms.Form):
class EmailIgnoreForm(forms.ModelForm):
class Meta:
model = IgnoreEmail
+
+class TicketCCForm(forms.ModelForm):
+ class Meta:
+ model = TicketCC
+ exclude = ('ticket',)
diff --git a/models.py b/models.py
index 72b285f6..2ec8da2d 100644
--- a/models.py
+++ b/models.py
@@ -129,7 +129,7 @@ class Queue(models.Model):
help_text=_('Whether to use SSL for IMAP or POP3 - the default ports '
'when using SSL are 993 for IMAP and 995 for POP3.'),
)
-
+
email_box_user = models.CharField(
_('E-Mail Username'),
max_length=200,
@@ -999,3 +999,58 @@ class IgnoreEmail(models.Model):
return True
else:
return False
+
+class TicketCC(models.Model):
+ """
+ Often, there are people who wish to follow a ticket who aren't the
+ person who originally submitted it. This model provides a way for those
+ people to follow a ticket.
+
+ In this circumstance, a 'person' could be either an e-mail address or
+ an existing system user.
+ """
+
+ ticket = models.ForeignKey(Ticket)
+
+ user = models.ForeignKey(
+ User,
+ blank=True,
+ null=True,
+ help_text=_('User who wishes to receive updates for this ticket.'),
+ )
+
+ email = models.EmailField(
+ _('E-Mail Address'),
+ blank=True,
+ null=True,
+ help_text=_('For non-user followers, enter their e-mail address'),
+ )
+
+ can_view = models.BooleanField(
+ _('Can View Ticket?'),
+ blank=True,
+ help_text=_('Can this CC login to view the ticket details?'),
+ )
+
+ can_update = models.BooleanField(
+ _('Can Update Ticket?'),
+ blank=True,
+ help_text=_('Can this CC login and update the ticket?'),
+ )
+
+ def _email_address(self):
+ if self.user and self.user.email is not None:
+ return self.user.email
+ else:
+ return self.email
+ email_address = property(_email_address)
+
+ def _display(self):
+ if self.user:
+ return self.user
+ else:
+ return self.email
+ display = property(_display)
+
+ def __unicode__(self):
+ return u'%s for %s' % (self.display, self.ticket.title)
diff --git a/templates/helpdesk/email_ignore_del.html b/templates/helpdesk/email_ignore_del.html
index 0ce564c6..93268933 100644
--- a/templates/helpdesk/email_ignore_del.html
+++ b/templates/helpdesk/email_ignore_del.html
@@ -5,7 +5,7 @@
{% block helpdesk_body %}{% blocktrans with ignore.email_address as email_address %}
Un-Ignore E-Mail Address
-Are you sure you wish to stop removing this email address ({{ email_address }}) and allow their e-mails to automatically create tickets in your system? You can re-add this e-mail address at any time.
+
Are you sure you wish to stop removing this email address ({{ email_address }}) and allow their e-mails to automatically create tickets in your system? You can re-add this e-mail address at any time.
{% endblocktrans %}
{% blocktrans %}Keep Ignoring It
diff --git a/templates/helpdesk/ticket.html b/templates/helpdesk/ticket.html
index 5fa6325f..eb2f8366 100644
--- a/templates/helpdesk/ticket.html
+++ b/templates/helpdesk/ticket.html
@@ -67,16 +67,21 @@
+ {% trans "Copies To" %} |
+ {% for ticketcc in ticket.ticketcc_set.all %}{{ ticketcc.display }}{% if not forloop.last %}, {% endif %}{% endfor %} {% trans "Manage" %} |
+
+
+
{% trans "Description" %} |
-
+
{{ ticket.description|force_escape|linebreaksbr }} |
-{% if ticket.resolution %}
+{% if ticket.resolution %}
{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} {% endifequal %} |
-
+
{{ ticket.resolution|force_escape }} |
{% endif %}
diff --git a/templates/helpdesk/ticket_cc_add.html b/templates/helpdesk/ticket_cc_add.html
new file mode 100644
index 00000000..80b9736b
--- /dev/null
+++ b/templates/helpdesk/ticket_cc_add.html
@@ -0,0 +1,25 @@
+{% extends "helpdesk/base.html" %}{% load i18n %}
+
+{% block helpdesk_title %}{% trans "Add Ticket CC" %}{% endblock %}
+
+{% block helpdesk_body %}{% blocktrans %}
+Add Ticket CC
+
+To automatically send an email to a user or e-mail address when this ticket is updated, select the user or enter an e-mail address below.
{% endblocktrans %}
+
+
+
+{% endblock %}
diff --git a/templates/helpdesk/ticket_cc_del.html b/templates/helpdesk/ticket_cc_del.html
new file mode 100644
index 00000000..4aa0bb81
--- /dev/null
+++ b/templates/helpdesk/ticket_cc_del.html
@@ -0,0 +1,14 @@
+{% extends "helpdesk/base.html" %}{% load i18n %}
+
+{% block helpdesk_title %}{% trans "Delete Ticket CC" %}{% endblock %}
+
+{% block helpdesk_body %}{% blocktrans with cc.email_address as email_address %}
+Delete Ticket CC
+
+Are you sure you wish to delete this email address ({{ email_address }}) from the CC list for this ticket? They will stop receiving updates.
+{% endblocktrans %}
+
+{% blocktrans %}Don't Delete
+
+
+{% endblocktrans %}{% endblock %}
diff --git a/templates/helpdesk/ticket_cc_list.html b/templates/helpdesk/ticket_cc_list.html
new file mode 100644
index 00000000..27d7b381
--- /dev/null
+++ b/templates/helpdesk/ticket_cc_list.html
@@ -0,0 +1,31 @@
+{% extends "helpdesk/base.html" %}{% load i18n %}
+
+{% block helpdesk_title %}{% trans "Ticket CC Settings" %}{% endblock %}
+
+{% block helpdesk_body %}{% blocktrans with ticket.title as ticket_title and ticket.id as ticket_id %}
+Ticket CC Settings
+
+The following people will receive an e-mail whenever {{ ticket_title }} is updated. Some people can also view or edit the ticket via the public ticket views.
+
+You can add a new e-mail address to the list or delete any of the items below as required.
{% endblocktrans %}
+
+
+
+{% trans "Ticket CC List" %} |
+{% trans "E-Mail Address" %} | {% trans "View?" %} | {% trans "Update?" %} | {% trans "Delete" %} |
+
+
+{% for person in copies_to %}
+
+ {{ person.display }} |
+ {{ person.can_view }} |
+ {{ person.can_update }} |
+ {% trans "Delete" %} |
+
+{% endfor %}
+
+
+
+{% blocktrans with ticket.title as ticket_title %}Return to {{ ticket_title }}{% endblocktrans %}
+
+{% endblock %}
diff --git a/urls.py b/urls.py
index 162c4086..3a893d0c 100644
--- a/urls.py
+++ b/urls.py
@@ -55,6 +55,18 @@ urlpatterns = patterns('helpdesk.views.staff',
'unhold_ticket',
name='helpdesk_unhold'),
+ url(r'^tickets/(?P[0-9]+)/cc/$',
+ 'ticket_cc',
+ name='helpdesk_ticket_cc'),
+
+ url(r'^tickets/(?P[0-9]+)/cc/add/$',
+ 'ticket_cc_add',
+ name='helpdesk_ticket_cc_add'),
+
+ url(r'^tickets/(?P[0-9]+)/cc/delete/(?P[0-9]+)/$',
+ 'ticket_cc_del',
+ name='helpdesk_ticket_cc_del'),
+
url(r'^raw/(?P\w+)/$',
'raw_details',
name='helpdesk_raw'),
diff --git a/views/api.py b/views/api.py
index 017c51ba..92eeacff 100644
--- a/views/api.py
+++ b/views/api.py
@@ -209,6 +209,18 @@ class API:
)
messages_sent_to.append(ticket.submitter_email)
+ if public:
+ for cc in ticket.ticketcc_set.all():
+ if cc.email_address not in messages_sent_to:
+ send_templated_mail(
+ 'updated_submitter',
+ context,
+ recipients=cc.email_address,
+ sender=ticket.queue.from_address,
+ fail_silently=True,
+ )
+ messages_sent_to.append(cc.email_address)
+
if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
send_templated_mail(
'updated_cc',
@@ -274,6 +286,17 @@ class API:
)
messages_sent_to.append(ticket.submitter_email)
+ for cc in ticket.ticketcc_set.all():
+ if cc.email_address not in messages_sent_to:
+ send_templated_mail(
+ 'resolved_submitter',
+ context,
+ recipients=cc.email_address,
+ sender=ticket.queue.from_address,
+ fail_silently=True,
+ )
+ messages_sent_to.append(cc.email_address)
+
if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
send_templated_mail(
'resolved_cc',
diff --git a/views/staff.py b/views/staff.py
index 5e43b973..8f181713 100644
--- a/views/staff.py
+++ b/views/staff.py
@@ -22,9 +22,9 @@ from django.shortcuts import render_to_response, get_object_or_404
from django.template import loader, Context, RequestContext
from django.utils.translation import ugettext as _
-from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm
+from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict, apply_query, safe_template_context
-from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail
+from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC
staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active and u.is_staff)
@@ -259,6 +259,17 @@ def update_ticket(request, ticket_id, public=False):
)
messages_sent_to.append(ticket.submitter_email)
+ for cc in ticket.ticketcc_set.all():
+ if cc.email_address not in messages_sent_to:
+ send_templated_mail(
+ template,
+ context,
+ recipients=cc.email_address,
+ sender=ticket.queue.from_address,
+ fail_silently=True,
+ )
+ messages_sent_to.append(cc.email_address)
+
if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
# We only send e-mails to staff members if the ticket is updated by
# another user. The actual template varies, depending on what has been
@@ -364,6 +375,17 @@ def mass_update(request):
)
messages_sent_to.append(t.submitter_email)
+ for cc in ticket.ticketcc_set.all():
+ if cc.email_address not in messages_sent_to:
+ send_templated_mail(
+ 'closed_submitter',
+ context,
+ recipients=cc.email_address,
+ sender=ticket.queue.from_address,
+ fail_silently=True,
+ )
+ messages_sent_to.append(cc.email_address)
+
if t.assigned_to and request.user != t.assigned_to and t.assigned_to.email and t.assigned_to.email not in messages_sent_to:
send_templated_mail(
'closed_owner',
@@ -563,6 +585,7 @@ def edit_ticket(request, ticket_id):
RequestContext(request, {
'form': form,
}))
+edit_ticket = staff_member_required(edit_ticket)
def create_ticket(request):
if request.method == 'POST':
@@ -890,3 +913,42 @@ def email_ignore_del(request, id):
'ignore': ignore,
}))
email_ignore_del = superuser_required(email_ignore_del)
+
+def ticket_cc(request, ticket_id):
+ ticket = get_object_or_404(Ticket, id=ticket_id)
+ copies_to = ticket.ticketcc_set.all()
+ return render_to_response('helpdesk/ticket_cc_list.html',
+ RequestContext(request, {
+ 'copies_to': copies_to,
+ 'ticket': ticket,
+ }))
+ticket_cc = staff_member_required(ticket_cc)
+
+def ticket_cc_add(request, ticket_id):
+ ticket = get_object_or_404(Ticket, id=ticket_id)
+ if request.method == 'POST':
+ form = TicketCCForm(request.POST)
+ if form.is_valid():
+ ticketcc = form.save(commit=False)
+ ticketcc.ticket = ticket
+ ticketcc.save()
+ return HttpResponseRedirect(reverse('helpdesk_ticket_cc', kwargs={'ticket_id': ticket.id}))
+ else:
+ form = TicketCCForm()
+ return render_to_response('helpdesk/ticket_cc_add.html',
+ RequestContext(request, {
+ 'ticket': ticket,
+ 'form': form,
+ }))
+ticket_cc_add = staff_member_required(ticket_cc_add)
+
+def ticket_cc_del(request, ticket_id, cc_id):
+ cc = get_object_or_404(TicketCC, ticket__id=ticket_id, id=cc_id)
+ if request.POST:
+ cc.delete()
+ return HttpResponseRedirect(reverse('helpdesk_ticket_cc', kwargs={'ticket_id': cc.ticket.id}))
+ return render_to_response('helpdesk/ticket_cc_del.html',
+ RequestContext(request, {
+ 'cc': cc,
+ }))
+ticket_cc_del = staff_member_required(ticket_cc_del)