\d+)\]", subject)
if matchobj:
# This is a reply or forward.
ticket = matchobj.group('id')
@@ -210,9 +241,10 @@ def ticket_from_message(message, queue, quiet):
if name:
name = collapse_rfc2231_value(name)
- if part.get_content_maintype() == 'text' and name == None:
+ if part.get_content_maintype() == 'text' and name is None:
if part.get_content_subtype() == 'plain':
- body_plain = EmailReplyParser.parse_reply(decodeUnknown(part.get_content_charset(), part.get_payload(decode=True)))
+ body_plain = EmailReplyParser.parse_reply(
+ decodeUnknown(part.get_content_charset(), part.get_payload(decode=True)))
else:
body_html = part.get_payload(decode=True)
else:
@@ -224,7 +256,7 @@ def ticket_from_message(message, queue, quiet):
'filename': name,
'content': part.get_payload(decode=True),
'type': part.get_content_type()},
- )
+ )
counter += 1
@@ -259,7 +291,7 @@ def ticket_from_message(message, queue, quiet):
if smtp_priority in high_priority_types or smtp_importance in high_priority_types:
priority = 2
- if ticket == None:
+ if ticket is None:
t = Ticket(
title=subject,
queue=queue,
@@ -270,24 +302,24 @@ def ticket_from_message(message, queue, quiet):
)
t.save()
new = True
- update = ''
+ # update = ''
elif t.status == Ticket.CLOSED_STATUS:
t.status = Ticket.REOPENED_STATUS
t.save()
f = FollowUp(
- ticket = t,
- title = _('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}),
- date = timezone.now(),
- public = True,
- comment = body,
+ ticket=t,
+ title=_('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}),
+ date=timezone.now(),
+ public=True,
+ comment=body,
)
if t.status == Ticket.REOPENED_STATUS:
f.new_status = Ticket.REOPENED_STATUS
f.title = _('Ticket Re-Opened by E-Mail Received from %(sender_email)s' % {'sender_email': sender_email})
-
+
f.save()
if not quiet:
@@ -302,13 +334,12 @@ def ticket_from_message(message, queue, quiet):
filename=filename,
mime_type=file['type'],
size=len(file['content']),
- )
+ )
a.file.save(filename, ContentFile(file['content']), save=False)
a.save()
if not quiet:
print(" - %s" % filename)
-
context = safe_template_context(t)
if new:
@@ -320,7 +351,7 @@ def ticket_from_message(message, queue, quiet):
recipients=sender_email,
sender=queue.from_address,
fail_silently=True,
- )
+ )
if queue.new_ticket_cc:
send_templated_mail(
@@ -329,7 +360,7 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.new_ticket_cc,
sender=queue.from_address,
fail_silently=True,
- )
+ )
if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc:
send_templated_mail(
@@ -338,15 +369,15 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.updated_ticket_cc,
sender=queue.from_address,
fail_silently=True,
- )
+ )
else:
context.update(comment=f.comment)
- if t.status == Ticket.REOPENED_STATUS:
- update = _(' (Reopened)')
- else:
- update = _(' (Updated)')
+ # if t.status == Ticket.REOPENED_STATUS:
+ # update = _(' (Reopened)')
+ # else:
+ # update = _(' (Updated)')
if t.assigned_to:
send_templated_mail(
@@ -355,7 +386,7 @@ def ticket_from_message(message, queue, quiet):
recipients=t.assigned_to.email,
sender=queue.from_address,
fail_silently=True,
- )
+ )
if queue.updated_ticket_cc:
send_templated_mail(
@@ -364,11 +395,10 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.updated_ticket_cc,
sender=queue.from_address,
fail_silently=True,
- )
+ )
return t
if __name__ == '__main__':
process_email()
-
diff --git a/helpdesk/migrations/0003_initial_data_import.py b/helpdesk/migrations/0003_initial_data_import.py
index 566993e0..cc478377 100644
--- a/helpdesk/migrations/0003_initial_data_import.py
+++ b/helpdesk/migrations/0003_initial_data_import.py
@@ -25,7 +25,7 @@ def load_fixture(apps, schema_editor):
def unload_fixture(apps, schema_editor):
- "Delete all EmailTemplate objects"
+ """Delete all EmailTemplate objects"""
objects = deserialize_fixture()
diff --git a/helpdesk/models.py b/helpdesk/models.py
index 57823fcc..9405730c 100644
--- a/helpdesk/models.py
+++ b/helpdesk/models.py
@@ -12,14 +12,10 @@ from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
-from django.contrib.auth import get_user_model
from django.conf import settings
from django.utils.translation import ugettext_lazy as _, ugettext
-from django import VERSION
from django.utils.encoding import python_2_unicode_compatible
-from helpdesk import settings as helpdesk_settings
-
try:
from django.utils import timezone
except ImportError:
@@ -40,56 +36,56 @@ class Queue(models.Model):
title = models.CharField(
_('Title'),
max_length=100,
- )
+ )
slug = models.SlugField(
_('Slug'),
max_length=50,
unique=True,
help_text=_('This slug is used when building ticket ID\'s. Once set, '
- 'try not to change it or e-mailing may get messy.'),
- )
+ 'try not to change it or e-mailing may get messy.'),
+ )
email_address = models.EmailField(
_('E-Mail Address'),
blank=True,
null=True,
help_text=_('All outgoing e-mails for this queue will use this e-mail '
- 'address. If you use IMAP or POP3, this should be the e-mail '
- 'address for that mailbox.'),
- )
+ 'address. If you use IMAP or POP3, this should be the e-mail '
+ 'address for that mailbox.'),
+ )
locale = models.CharField(
_('Locale'),
max_length=10,
blank=True,
null=True,
- help_text=_('Locale of this queue. All correspondence in this queue will be in this language.'),
- )
+ help_text=_('Locale of this queue. All correspondence in this '
+ 'queue will be in this language.'),
+ )
allow_public_submission = models.BooleanField(
_('Allow Public Submission?'),
blank=True,
default=False,
- help_text=_('Should this queue be listed on the public submission '
- 'form?'),
- )
+ help_text=_('Should this queue be listed on the public submission form?'),
+ )
allow_email_submission = models.BooleanField(
_('Allow E-Mail Submission?'),
blank=True,
default=False,
help_text=_('Do you want to poll the e-mail box below for new '
- 'tickets?'),
- )
+ 'tickets?'),
+ )
escalate_days = models.IntegerField(
_('Escalation Days'),
blank=True,
null=True,
help_text=_('For tickets which are not held, how often do you wish to '
- 'increase their priority? Set to 0 for no escalation.'),
- )
+ 'increase their priority? Set to 0 for no escalation.'),
+ )
new_ticket_cc = models.CharField(
_('New Ticket CC Address'),
@@ -97,9 +93,9 @@ class Queue(models.Model):
null=True,
max_length=200,
help_text=_('If an e-mail address is entered here, then it will '
- 'receive notification of all new tickets created for this queue. '
- 'Enter a comma between multiple e-mail addresses.'),
- )
+ 'receive notification of all new tickets created for this queue. '
+ 'Enter a comma between multiple e-mail addresses.'),
+ )
updated_ticket_cc = models.CharField(
_('Updated Ticket CC Address'),
@@ -107,10 +103,10 @@ class Queue(models.Model):
null=True,
max_length=200,
help_text=_('If an e-mail address is entered here, then it will '
- 'receive notification of all activity (new tickets, closed '
- 'tickets, updates, reassignments, etc) for this queue. Separate '
- 'multiple addresses with a comma.'),
- )
+ 'receive notification of all activity (new tickets, closed '
+ 'tickets, updates, reassignments, etc) for this queue. Separate '
+ 'multiple addresses with a comma.'),
+ )
email_box_type = models.CharField(
_('E-Mail Box Type'),
@@ -119,8 +115,8 @@ class Queue(models.Model):
blank=True,
null=True,
help_text=_('E-Mail server type for creating tickets automatically '
- 'from a mailbox - both POP3 and IMAP are supported.'),
- )
+ 'from a mailbox - both POP3 and IMAP are supported.'),
+ )
email_box_host = models.CharField(
_('E-Mail Hostname'),
@@ -128,25 +124,25 @@ class Queue(models.Model):
blank=True,
null=True,
help_text=_('Your e-mail server address - either the domain name or '
- 'IP address. May be "localhost".'),
- )
+ 'IP address. May be "localhost".'),
+ )
email_box_port = models.IntegerField(
_('E-Mail Port'),
blank=True,
null=True,
help_text=_('Port number to use for accessing e-mail. Default for '
- 'POP3 is "110", and for IMAP is "143". This may differ on some '
- 'servers. Leave it blank to use the defaults.'),
- )
+ 'POP3 is "110", and for IMAP is "143". This may differ on some '
+ 'servers. Leave it blank to use the defaults.'),
+ )
email_box_ssl = models.BooleanField(
_('Use SSL for E-Mail?'),
blank=True,
default=False,
help_text=_('Whether to use SSL for IMAP or POP3 - the default ports '
- 'when using SSL are 993 for IMAP and 995 for POP3.'),
- )
+ 'when using SSL are 993 for IMAP and 995 for POP3.'),
+ )
email_box_user = models.CharField(
_('E-Mail Username'),
@@ -154,7 +150,7 @@ class Queue(models.Model):
blank=True,
null=True,
help_text=_('Username for accessing this mailbox.'),
- )
+ )
email_box_pass = models.CharField(
_('E-Mail Password'),
@@ -162,7 +158,7 @@ class Queue(models.Model):
blank=True,
null=True,
help_text=_('Password for the above username'),
- )
+ )
email_box_imap_folder = models.CharField(
_('IMAP Folder'),
@@ -170,10 +166,10 @@ class Queue(models.Model):
blank=True,
null=True,
help_text=_('If using IMAP, what folder do you wish to fetch messages '
- 'from? This allows you to use one IMAP account for multiple '
- 'queues, by filtering messages on your IMAP server into separate '
- 'folders. Default: INBOX.'),
- )
+ 'from? This allows you to use one IMAP account for multiple '
+ 'queues, by filtering messages on your IMAP server into separate '
+ 'folders. Default: INBOX.'),
+ )
permission_name = models.CharField(
_('Django auth permission name'),
@@ -182,8 +178,7 @@ class Queue(models.Model):
null=True,
editable=False,
help_text=_('Name used in the django.contrib.auth permission system'),
- )
-
+ )
email_box_interval = models.IntegerField(
_('E-Mail Check Interval'),
@@ -191,14 +186,14 @@ class Queue(models.Model):
blank=True,
null=True,
default='5',
- )
+ )
email_box_last_check = models.DateTimeField(
blank=True,
null=True,
editable=False,
# This is updated by management/commands/get_mail.py.
- )
+ )
socks_proxy_type = models.CharField(
_('Socks Proxy Type'),
@@ -351,32 +346,32 @@ class Ticket(models.Model):
title = models.CharField(
_('Title'),
max_length=200,
- )
+ )
queue = models.ForeignKey(
Queue,
verbose_name=_('Queue'),
- )
+ )
created = models.DateTimeField(
_('Created'),
blank=True,
help_text=_('Date this ticket was first created'),
- )
+ )
modified = models.DateTimeField(
_('Modified'),
blank=True,
help_text=_('Date this ticket was most recently changed.'),
- )
+ )
submitter_email = models.EmailField(
_('Submitter E-Mail'),
blank=True,
null=True,
help_text=_('The submitter will receive an email for all public '
- 'follow-ups left for this task.'),
- )
+ 'follow-ups left for this task.'),
+ )
assigned_to = models.ForeignKey(
settings.AUTH_USER_MODEL,
@@ -384,35 +379,34 @@ class Ticket(models.Model):
blank=True,
null=True,
verbose_name=_('Assigned to'),
- )
+ )
status = models.IntegerField(
_('Status'),
choices=STATUS_CHOICES,
default=OPEN_STATUS,
- )
+ )
on_hold = models.BooleanField(
_('On Hold'),
blank=True,
default=False,
- help_text=_('If a ticket is on hold, it will not automatically be '
- 'escalated.'),
- )
+ help_text=_('If a ticket is on hold, it will not automatically be escalated.'),
+ )
description = models.TextField(
_('Description'),
blank=True,
null=True,
help_text=_('The content of the customers query.'),
- )
+ )
resolution = models.TextField(
_('Resolution'),
blank=True,
null=True,
help_text=_('The resolution provided to the customer by our staff.'),
- )
+ )
priority = models.IntegerField(
_('Priority'),
@@ -420,21 +414,21 @@ class Ticket(models.Model):
default=3,
blank=3,
help_text=_('1 = Highest Priority, 5 = Low Priority'),
- )
+ )
due_date = models.DateTimeField(
_('Due on'),
blank=True,
null=True,
- )
+ )
last_escalation = models.DateTimeField(
blank=True,
null=True,
editable=False,
help_text=_('The date this ticket was last escalated - updated '
- 'automatically by management/commands/escalate_tickets.py.'),
- )
+ 'automatically by management/commands/escalate_tickets.py.'),
+ )
def _get_assigned_to(self):
""" Custom property to allow us to easily print 'Unassigned' if a
@@ -453,7 +447,7 @@ class Ticket(models.Model):
""" A user-friendly ticket ID, which is a combination of ticket ID
and queue slug. This is generally used in e-mail subjects. """
- return u"[%s]" % (self.ticket_for_url)
+ return u"[%s]" % self.ticket_for_url
ticket = property(_get_ticket)
def _get_ticket_for_url(self):
@@ -484,9 +478,11 @@ class Ticket(models.Model):
Displays the ticket status, with an "On Hold" message if needed.
"""
held_msg = ''
- if self.on_hold: held_msg = _(' - On Hold')
+ if self.on_hold:
+ held_msg = _(' - On Hold')
dep_msg = ''
- if self.can_be_resolved == False: dep_msg = _(' - Open dependencies')
+ if not self.can_be_resolved:
+ dep_msg = _(' - Open dependencies')
return u'%s%s%s' % (self.get_status_display(), held_msg, dep_msg)
get_status = property(_get_status)
@@ -506,7 +502,7 @@ class Ticket(models.Model):
reverse('helpdesk:public_view'),
self.ticket_for_url,
self.submitter_email
- )
+ )
ticket_url = property(_get_ticket_url)
def _get_staff_url(self):
@@ -523,8 +519,8 @@ class Ticket(models.Model):
return u"http://%s%s" % (
site.domain,
reverse('helpdesk:view',
- args=[self.id])
- )
+ args=[self.id])
+ )
staff_url = property(_get_staff_url)
def _can_be_resolved(self):
@@ -534,7 +530,8 @@ class Ticket(models.Model):
False = There are non-resolved dependencies
"""
OPEN_STATUSES = (Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS)
- return TicketDependency.objects.filter(ticket=self).filter(depends_on__status__in=OPEN_STATUSES).count() == 0
+ return TicketDependency.objects.filter(ticket=self).filter(
+ depends_on__status__in=OPEN_STATUSES).count() == 0
can_be_resolved = property(_can_be_resolved)
class Meta:
@@ -547,7 +544,7 @@ class Ticket(models.Model):
return '%s %s' % (self.id, self.title)
def get_absolute_url(self):
- return ('helpdesk:view', (self.id,))
+ return 'helpdesk:view', (self.id,)
get_absolute_url = models.permalink(get_absolute_url)
def save(self, *args, **kwargs):
@@ -562,8 +559,8 @@ class Ticket(models.Model):
super(Ticket, self).save(*args, **kwargs)
- @classmethod
- def queue_and_id_from_query(klass, query):
+ @staticmethod
+ def queue_and_id_from_query(query):
# Apply the opposite logic here compared to self._get_ticket_for_url
# Ensure that queues with '-' in them will work
parts = query.split('-')
@@ -572,6 +569,7 @@ class Ticket(models.Model):
class FollowUpManager(models.Manager):
+
def private_followups(self):
return self.filter(public=False)
@@ -596,40 +594,40 @@ class FollowUp(models.Model):
ticket = models.ForeignKey(
Ticket,
verbose_name=_('Ticket'),
- )
+ )
date = models.DateTimeField(
_('Date'),
- default = timezone.now
- )
+ default=timezone.now
+ )
title = models.CharField(
_('Title'),
max_length=200,
blank=True,
null=True,
- )
+ )
comment = models.TextField(
_('Comment'),
blank=True,
null=True,
- )
+ )
public = models.BooleanField(
_('Public'),
blank=True,
default=False,
help_text=_('Public tickets are viewable by the submitter and all '
- 'staff, but non-public tickets can only be seen by staff.'),
- )
+ 'staff, but non-public tickets can only be seen by staff.'),
+ )
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
blank=True,
null=True,
verbose_name=_('User'),
- )
+ )
new_status = models.IntegerField(
_('New Status'),
@@ -637,12 +635,12 @@ class FollowUp(models.Model):
blank=True,
null=True,
help_text=_('If the status was changed, what was it changed to?'),
- )
+ )
objects = FollowUpManager()
class Meta:
- ordering = ['date']
+ ordering = ('date',)
verbose_name = _('Follow-up')
verbose_name_plural = _('Follow-ups')
@@ -669,24 +667,24 @@ class TicketChange(models.Model):
followup = models.ForeignKey(
FollowUp,
verbose_name=_('Follow-up'),
- )
+ )
field = models.CharField(
_('Field'),
max_length=100,
- )
+ )
old_value = models.TextField(
_('Old Value'),
blank=True,
null=True,
- )
+ )
new_value = models.TextField(
_('New Value'),
blank=True,
null=True,
- )
+ )
def __str__(self):
out = '%s ' % self.field
@@ -698,7 +696,7 @@ class TicketChange(models.Model):
out += ugettext('changed from "%(old_value)s" to "%(new_value)s"') % {
'old_value': self.old_value,
'new_value': self.new_value
- }
+ }
return out
class Meta:
@@ -714,7 +712,7 @@ def attachment_path(instance, filename):
import os
from django.conf import settings
os.umask(0)
- path = 'helpdesk/attachments/%s/%s' % (instance.followup.ticket.ticket_for_url, instance.followup.id )
+ path = 'helpdesk/attachments/%s/%s' % (instance.followup.ticket.ticket_for_url, instance.followup.id)
att_path = os.path.join(settings.MEDIA_ROOT, path)
if settings.DEFAULT_FILE_STORAGE == "django.core.files.storage.FileSystemStorage":
if not os.path.exists(att_path):
@@ -732,28 +730,28 @@ class Attachment(models.Model):
followup = models.ForeignKey(
FollowUp,
verbose_name=_('Follow-up'),
- )
+ )
file = models.FileField(
_('File'),
upload_to=attachment_path,
max_length=1000,
- )
+ )
filename = models.CharField(
_('Filename'),
max_length=1000,
- )
+ )
mime_type = models.CharField(
_('MIME Type'),
max_length=255,
- )
+ )
size = models.IntegerField(
_('Size'),
help_text=_('Size of this file in bytes'),
- )
+ )
def get_upload_to(self, field_attname):
""" Get upload_to path specific to this item """
@@ -762,13 +760,13 @@ class Attachment(models.Model):
return u'helpdesk/attachments/%s/%s' % (
self.followup.ticket.ticket_for_url,
self.followup.id
- )
+ )
def __str__(self):
return '%s' % self.filename
class Meta:
- ordering = ['filename',]
+ ordering = ('filename',)
verbose_name = _('Attachment')
verbose_name_plural = _('Attachments')
@@ -785,32 +783,31 @@ class PreSetReply(models.Model):
When replying to a ticket, the user can select any reply set for the current
queue, and the body text is fetched via AJAX.
"""
+ class Meta:
+ ordering = ('name',)
+ verbose_name = _('Pre-set reply')
+ verbose_name_plural = _('Pre-set replies')
queues = models.ManyToManyField(
Queue,
blank=True,
help_text=_('Leave blank to allow this reply to be used for all '
- 'queues, or select those queues you wish to limit this reply to.'),
- )
+ 'queues, or select those queues you wish to limit this reply to.'),
+ )
name = models.CharField(
_('Name'),
max_length=100,
help_text=_('Only used to assist users with selecting a reply - not '
- 'shown to the user.'),
- )
+ 'shown to the user.'),
+ )
body = models.TextField(
_('Body'),
help_text=_('Context available: {{ ticket }} - ticket object (eg '
- '{{ ticket.title }}); {{ queue }} - The queue; and {{ user }} '
- '- the current user.'),
- )
-
- class Meta:
- ordering = ['name',]
- verbose_name = _('Pre-set reply')
- verbose_name_plural = _('Pre-set replies')
+ '{{ ticket.title }}); {{ queue }} - The queue; and {{ user }} '
+ '- the current user.'),
+ )
def __str__(self):
return '%s' % self.name
@@ -831,20 +828,19 @@ class EscalationExclusion(models.Model):
queues = models.ManyToManyField(
Queue,
blank=True,
- help_text=_('Leave blank for this exclusion to be applied to all '
- 'queues, or select those queues you wish to exclude with this '
- 'entry.'),
- )
+ help_text=_('Leave blank for this exclusion to be applied to all queues, '
+ 'or select those queues you wish to exclude with this entry.'),
+ )
name = models.CharField(
_('Name'),
max_length=100,
- )
+ )
date = models.DateField(
_('Date'),
help_text=_('Date on which escalation should not happen'),
- )
+ )
def __str__(self):
return '%s' % self.name
@@ -867,36 +863,35 @@ class EmailTemplate(models.Model):
template_name = models.CharField(
_('Template Name'),
max_length=100,
- )
+ )
subject = models.CharField(
_('Subject'),
max_length=100,
help_text=_('This will be prefixed with "[ticket.ticket] ticket.title"'
- '. We recommend something simple such as "(Updated") or "(Closed)"'
- ' - the same context is available as in plain_text, below.'),
- )
+ '. We recommend something simple such as "(Updated") or "(Closed)"'
+ ' - the same context is available as in plain_text, below.'),
+ )
heading = models.CharField(
_('Heading'),
max_length=100,
help_text=_('In HTML e-mails, this will be the heading at the top of '
- 'the email - the same context is available as in plain_text, '
- 'below.'),
- )
+ 'the email - the same context is available as in plain_text, '
+ 'below.'),
+ )
plain_text = models.TextField(
_('Plain Text'),
help_text=_('The context available to you includes {{ ticket }}, '
- '{{ queue }}, and depending on the time of the call: '
- '{{ resolution }} or {{ comment }}.'),
- )
+ '{{ queue }}, and depending on the time of the call: '
+ '{{ resolution }} or {{ comment }}.'),
+ )
html = models.TextField(
_('HTML'),
- help_text=_('The same context is available here as in plain_text, '
- 'above.'),
- )
+ help_text=_('The same context is available here as in plain_text, above.'),
+ )
locale = models.CharField(
_('Locale'),
@@ -904,13 +899,13 @@ class EmailTemplate(models.Model):
blank=True,
null=True,
help_text=_('Locale of this template.'),
- )
+ )
def __str__(self):
return '%s' % self.template_name
class Meta:
- ordering = ['template_name', 'locale']
+ ordering = ('template_name', 'locale')
verbose_name = _('e-mail template')
verbose_name_plural = _('e-mail templates')
@@ -925,26 +920,26 @@ class KBCategory(models.Model):
title = models.CharField(
_('Title'),
max_length=100,
- )
+ )
slug = models.SlugField(
_('Slug'),
- )
+ )
description = models.TextField(
_('Description'),
- )
+ )
def __str__(self):
return '%s' % self.title
class Meta:
- ordering = ['title',]
+ ordering = ('title',)
verbose_name = _('Knowledge base category')
verbose_name_plural = _('Knowledge base categories')
def get_absolute_url(self):
- return ('kb_category', (), {'slug': self.slug})
+ return 'kb_category', (), {'slug': self.slug}
get_absolute_url = models.permalink(get_absolute_url)
@@ -957,39 +952,38 @@ class KBItem(models.Model):
category = models.ForeignKey(
KBCategory,
verbose_name=_('Category'),
- )
+ )
title = models.CharField(
_('Title'),
max_length=100,
- )
+ )
question = models.TextField(
_('Question'),
- )
+ )
answer = models.TextField(
_('Answer'),
- )
+ )
votes = models.IntegerField(
_('Votes'),
help_text=_('Total number of votes cast for this item'),
default=0,
- )
+ )
recommendations = models.IntegerField(
_('Positive Votes'),
help_text=_('Number of votes for this item which were POSITIVE.'),
default=0,
- )
+ )
last_updated = models.DateTimeField(
_('Last Updated'),
- help_text=_('The date on which this question was most recently '
- 'changed.'),
+ help_text=_('The date on which this question was most recently changed.'),
blank=True,
- )
+ )
def save(self, *args, **kwargs):
if not self.last_updated:
@@ -1007,12 +1001,12 @@ class KBItem(models.Model):
return '%s' % self.title
class Meta:
- ordering = ['title',]
+ ordering = ('title',)
verbose_name = _('Knowledge base item')
verbose_name_plural = _('Knowledge base items')
def get_absolute_url(self):
- return ('helpdesk:kb_item', (self.id,))
+ return 'helpdesk:kb_item', (self.id,)
get_absolute_url = models.permalink(get_absolute_url)
@@ -1031,25 +1025,25 @@ class SavedSearch(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_('User'),
- )
+ )
title = models.CharField(
_('Query Name'),
max_length=100,
help_text=_('User-provided name for this query'),
- )
+ )
shared = models.BooleanField(
_('Shared With Other Users?'),
blank=True,
default=False,
help_text=_('Should other users see this query?'),
- )
+ )
query = models.TextField(
_('Search Query'),
help_text=_('Pickled query object. Be wary changing this.'),
- )
+ )
def __str__(self):
if self.shared:
@@ -1076,10 +1070,11 @@ class UserSettings(models.Model):
settings_pickled = models.TextField(
_('Settings Dictionary'),
- help_text=_('This is a base64-encoded representation of a pickled Python dictionary. Do not change this field via the admin.'),
+ help_text=_('This is a base64-encoded representation of a pickled Python dictionary. '
+ 'Do not change this field via the admin.'),
blank=True,
null=True,
- )
+ )
def _set_settings(self, data):
# data should always be a Python dictionary.
@@ -1125,15 +1120,7 @@ def create_usersettings(sender, instance, created, **kwargs):
if created:
UserSettings.objects.create(user=instance, settings=DEFAULT_USER_SETTINGS)
-try:
- # Connecting via settings.AUTH_USER_MODEL (string) fails in Django < 1.7. We need the actual model there.
- # https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#referencing-the-user-model
- if VERSION < (1, 7):
- raise ValueError
- models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
-except:
- signal_user = get_user_model()
- models.signals.post_save.connect(create_usersettings, sender=signal_user)
+models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
@python_2_unicode_compatible
@@ -1143,41 +1130,43 @@ class IgnoreEmail(models.Model):
processing IMAP and POP3 mailboxes, eg mails from postmaster or from
known trouble-makers.
"""
+ class Meta:
+ verbose_name = _('Ignored e-mail address')
+ verbose_name_plural = _('Ignored e-mail addresses')
+
queues = models.ManyToManyField(
Queue,
blank=True,
- help_text=_('Leave blank for this e-mail to be ignored on all '
- 'queues, or select those queues you wish to ignore this e-mail '
- 'for.'),
- )
+ help_text=_('Leave blank for this e-mail to be ignored on all queues, '
+ 'or select those queues you wish to ignore this e-mail for.'),
+ )
name = models.CharField(
_('Name'),
max_length=100,
- )
+ )
date = models.DateField(
_('Date'),
help_text=_('Date on which this e-mail address was added'),
blank=True,
editable=False
- )
+ )
email_address = models.CharField(
_('E-Mail Address'),
max_length=150,
help_text=_('Enter a full e-mail address, or portions with '
- 'wildcards, eg *@domain.com or postmaster@*.'),
- )
+ 'wildcards, eg *@domain.com or postmaster@*.'),
+ )
keep_in_mailbox = models.BooleanField(
_('Save Emails in Mailbox?'),
blank=True,
default=False,
- help_text=_('Do you want to save emails from this address in the '
- 'mailbox? If this is unticked, emails from this address will '
- 'be deleted.'),
- )
+ help_text=_('Do you want to save emails from this address in the mailbox? '
+ 'If this is unticked, emails from this address will be deleted.'),
+ )
def __str__(self):
return '%s' % self.name
@@ -1202,18 +1191,14 @@ class IgnoreEmail(models.Model):
own_parts = self.email_address.split("@")
email_parts = email.split("@")
- if self.email_address == email \
- or own_parts[0] == "*" and own_parts[1] == email_parts[1] \
- or own_parts[1] == "*" and own_parts[0] == email_parts[0] \
- or own_parts[0] == "*" and own_parts[1] == "*":
+ if self.email_address == email or \
+ own_parts[0] == "*" and own_parts[1] == email_parts[1] or \
+ own_parts[1] == "*" and own_parts[0] == email_parts[0] or \
+ own_parts[0] == "*" and own_parts[1] == "*":
return True
else:
return False
- class Meta:
- verbose_name = _('Ignored e-mail address')
- verbose_name_plural = _('Ignored e-mail addresses')
-
@python_2_unicode_compatible
class TicketCC(models.Model):
@@ -1229,7 +1214,7 @@ class TicketCC(models.Model):
ticket = models.ForeignKey(
Ticket,
verbose_name=_('Ticket'),
- )
+ )
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
@@ -1237,28 +1222,28 @@ class TicketCC(models.Model):
null=True,
help_text=_('User who wishes to receive updates for this ticket.'),
verbose_name=_('User'),
- )
+ )
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,
default=False,
help_text=_('Can this CC login to view the ticket details?'),
- )
+ )
can_update = models.BooleanField(
_('Can Update Ticket?'),
blank=True,
default=False,
help_text=_('Can this CC login and update the ticket?'),
- )
+ )
def _email_address(self):
if self.user and self.user.email is not None:
@@ -1277,7 +1262,9 @@ class TicketCC(models.Model):
def __str__(self):
return '%s for %s' % (self.display, self.ticket.title)
+
class CustomFieldManager(models.Manager):
+
def get_queryset(self):
return super(CustomFieldManager, self).get_queryset().order_by('ordering')
@@ -1290,78 +1277,80 @@ class CustomField(models.Model):
name = models.SlugField(
_('Field Name'),
- help_text=_('As used in the database and behind the scenes. Must be unique and consist of only lowercase letters with no punctuation.'),
+ help_text=_('As used in the database and behind the scenes. '
+ 'Must be unique and consist of only lowercase letters with no punctuation.'),
unique=True,
- )
+ )
label = models.CharField(
_('Label'),
max_length=30,
help_text=_('The display label for this field'),
- )
+ )
help_text = models.TextField(
_('Help Text'),
help_text=_('Shown to the user when editing the ticket'),
blank=True,
null=True
- )
+ )
DATA_TYPE_CHOICES = (
- ('varchar', _('Character (single line)')),
- ('text', _('Text (multi-line)')),
- ('integer', _('Integer')),
- ('decimal', _('Decimal')),
- ('list', _('List')),
- ('boolean', _('Boolean (checkbox yes/no)')),
- ('date', _('Date')),
- ('time', _('Time')),
- ('datetime', _('Date & Time')),
- ('email', _('E-Mail Address')),
- ('url', _('URL')),
- ('ipaddress', _('IP Address')),
- ('slug', _('Slug')),
- )
+ ('varchar', _('Character (single line)')),
+ ('text', _('Text (multi-line)')),
+ ('integer', _('Integer')),
+ ('decimal', _('Decimal')),
+ ('list', _('List')),
+ ('boolean', _('Boolean (checkbox yes/no)')),
+ ('date', _('Date')),
+ ('time', _('Time')),
+ ('datetime', _('Date & Time')),
+ ('email', _('E-Mail Address')),
+ ('url', _('URL')),
+ ('ipaddress', _('IP Address')),
+ ('slug', _('Slug')),
+ )
data_type = models.CharField(
_('Data Type'),
max_length=100,
help_text=_('Allows you to restrict the data entered into this field'),
choices=DATA_TYPE_CHOICES,
- )
+ )
max_length = models.IntegerField(
_('Maximum Length (characters)'),
blank=True,
null=True,
- )
+ )
decimal_places = models.IntegerField(
_('Decimal Places'),
help_text=_('Only used for decimal fields'),
blank=True,
null=True,
- )
+ )
empty_selection_list = models.BooleanField(
_('Add empty first choice to List?'),
default=False,
- help_text=_('Only for List: adds an empty first entry to the choices list, which enforces that the user makes an active choice.'),
- )
+ help_text=_('Only for List: adds an empty first entry to the choices list, '
+ 'which enforces that the user makes an active choice.'),
+ )
list_values = models.TextField(
_('List Values'),
help_text=_('For list fields only. Enter one option per line.'),
blank=True,
null=True,
- )
+ )
ordering = models.IntegerField(
_('Ordering'),
help_text=_('Lower numbers are displayed first; higher numbers are listed later'),
blank=True,
null=True,
- )
+ )
def _choices_as_array(self):
from StringIO import StringIO
@@ -1375,18 +1364,19 @@ class CustomField(models.Model):
_('Required?'),
help_text=_('Does the user have to enter a value for this field?'),
default=False,
- )
+ )
staff_only = models.BooleanField(
_('Staff Only?'),
- help_text=_('If this is ticked, then the public submission form will NOT show this field'),
+ help_text=_('If this is ticked, then the public submission form '
+ 'will NOT show this field'),
default=False,
- )
+ )
objects = CustomFieldManager()
def __str__(self):
- return '%s' % (self.name)
+ return '%s' % self.name
class Meta:
verbose_name = _('Custom field')
@@ -1398,12 +1388,12 @@ class TicketCustomFieldValue(models.Model):
ticket = models.ForeignKey(
Ticket,
verbose_name=_('Ticket'),
- )
+ )
field = models.ForeignKey(
CustomField,
verbose_name=_('Field'),
- )
+ )
value = models.TextField(blank=True, null=True)
@@ -1423,22 +1413,22 @@ class TicketDependency(models.Model):
To help enforce this, a helper function `can_be_resolved` on each Ticket instance checks that
these have all been resolved.
"""
+ class Meta:
+ unique_together = (('ticket', 'depends_on'),)
+ verbose_name = _('Ticket dependency')
+ verbose_name_plural = _('Ticket dependencies')
+
ticket = models.ForeignKey(
Ticket,
verbose_name=_('Ticket'),
related_name='ticketdependency',
- )
+ )
depends_on = models.ForeignKey(
Ticket,
verbose_name=_('Depends On Ticket'),
related_name='depends_on',
- )
+ )
def __str__(self):
return '%s / %s' % (self.ticket, self.depends_on)
-
- class Meta:
- unique_together = (('ticket', 'depends_on'),)
- verbose_name = _('Ticket dependency')
- verbose_name_plural = _('Ticket dependencies')
diff --git a/helpdesk/settings.py b/helpdesk/settings.py
index 0ead588d..606af04f 100644
--- a/helpdesk/settings.py
+++ b/helpdesk/settings.py
@@ -11,22 +11,27 @@ try:
except:
DEFAULT_USER_SETTINGS = None
-if type(DEFAULT_USER_SETTINGS) != type(dict()):
+if not isinstance(DEFAULT_USER_SETTINGS, dict):
DEFAULT_USER_SETTINGS = {
- 'use_email_as_submitter': True,
- 'email_on_ticket_assign': True,
- 'email_on_ticket_change': True,
- 'login_view_ticketlist': True,
- 'email_on_ticket_apichange': True,
- 'tickets_per_page': 25
- }
+ 'use_email_as_submitter': True,
+ 'email_on_ticket_assign': True,
+ 'email_on_ticket_change': True,
+ 'login_view_ticketlist': True,
+ 'email_on_ticket_apichange': True,
+ 'tickets_per_page': 25
+ }
HAS_TAG_SUPPORT = False
-''' generic options - visible on all pages '''
+##########################################
+# generic options - visible on all pages #
+##########################################
+
# redirect to login page instead of the default homepage when users visits "/"?
-HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = getattr(settings, 'HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT', False)
+HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = getattr(settings,
+ 'HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT',
+ False)
# show knowledgebase links?
HELPDESK_KB_ENABLED = getattr(settings, 'HELPDESK_KB_ENABLED', True)
@@ -34,14 +39,20 @@ HELPDESK_KB_ENABLED = getattr(settings, 'HELPDESK_KB_ENABLED', True)
# show extended navigation by default, to all users, irrespective of staff status?
HELPDESK_NAVIGATION_ENABLED = getattr(settings, 'HELPDESK_NAVIGATION_ENABLED', False)
-# use public CDNs to serve jquery and other javascript by default? otherwise, use built-in static copy
+# use public CDNs to serve jquery and other javascript by default?
+# otherwise, use built-in static copy
HELPDESK_USE_CDN = getattr(settings, 'HELPDESK_USE_CDN', False)
# show dropdown list of languages that ticket comments can be translated into?
-HELPDESK_TRANSLATE_TICKET_COMMENTS = getattr(settings, 'HELPDESK_TRANSLATE_TICKET_COMMENTS', False)
+HELPDESK_TRANSLATE_TICKET_COMMENTS = getattr(settings,
+ 'HELPDESK_TRANSLATE_TICKET_COMMENTS',
+ False)
-# list of languages to offer. if set to false, all default google translate languages will be shown.
-HELPDESK_TRANSLATE_TICKET_COMMENTS_LANG = getattr(settings, 'HELPDESK_TRANSLATE_TICKET_COMMENTS_LANG', ["en", "de", "fr", "it", "ru"])
+# list of languages to offer. if set to false,
+# all default google translate languages will be shown.
+HELPDESK_TRANSLATE_TICKET_COMMENTS_LANG = getattr(settings,
+ 'HELPDESK_TRANSLATE_TICKET_COMMENTS_LANG',
+ ["en", "de", "fr", "it", "ru"])
# show link to 'change password' on 'User Settings' page?
HELPDESK_SHOW_CHANGE_PASSWORD = getattr(settings, 'HELPDESK_SHOW_CHANGE_PASSWORD', False)
@@ -50,10 +61,15 @@ HELPDESK_SHOW_CHANGE_PASSWORD = getattr(settings, 'HELPDESK_SHOW_CHANGE_PASSWORD
HELPDESK_FOLLOWUP_MOD = getattr(settings, 'HELPDESK_FOLLOWUP_MOD', False)
# auto-subscribe user to ticket if (s)he responds to a ticket?
-HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE = getattr(settings, 'HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE', False)
+HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE = getattr(settings,
+ 'HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE',
+ False)
-''' options for public pages '''
+############################
+# options for public pages #
+############################
+
# show 'view a ticket' section on public page?
HELPDESK_VIEW_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC', True)
@@ -61,17 +77,25 @@ HELPDESK_VIEW_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC
HELPDESK_SUBMIT_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_SUBMIT_A_TICKET_PUBLIC', True)
+###################################
+# options for update_ticket views #
+###################################
-''' options for update_ticket views '''
-# allow non-staff users to interact with tickets? this will also change how 'staff_member_required'
+# allow non-staff users to interact with tickets?
+# this will also change how 'staff_member_required'
# in staff.py will be defined.
-HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = getattr(settings, 'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE', False)
+HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = getattr(settings,
+ 'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE',
+ False)
# show edit buttons in ticket follow ups.
-HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings, 'HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP', True)
+HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings,
+ 'HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP',
+ True)
# show delete buttons in ticket follow ups if user is 'superuser'
-HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP = getattr(settings, 'HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP', False)
+HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP = getattr(
+ settings, 'HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP', False)
# make all updates public by default? this will hide the 'is this update public' checkbox
HELPDESK_UPDATE_PUBLIC_DEFAULT = getattr(settings, 'HELPDESK_UPDATE_PUBLIC_DEFAULT', False)
@@ -82,21 +106,28 @@ HELPDESK_STAFF_ONLY_TICKET_OWNERS = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKE
# only show staff users in ticket cc drop-down
HELPDESK_STAFF_ONLY_TICKET_CC = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKET_CC', False)
-
# allow the subject to have a configurable template.
-HELPDESK_EMAIL_SUBJECT_TEMPLATE = getattr(settings, 'HELPDESK_EMAIL_SUBJECT_TEMPLATE', "{{ ticket.ticket }} {{ ticket.title|safe }} %(subject)s")
+HELPDESK_EMAIL_SUBJECT_TEMPLATE = getattr(
+ settings, 'HELPDESK_EMAIL_SUBJECT_TEMPLATE',
+ "{{ ticket.ticket }} {{ ticket.title|safe }} %(subject)s")
# default fallback locale when queue locale not found
HELPDESK_EMAIL_FALLBACK_LOCALE = getattr(settings, 'HELPDESK_EMAIL_FALLBACK_LOCALE', 'en')
-''' options for staff.create_ticket view '''
+########################################
+# options for staff.create_ticket view #
+########################################
+
# hide the 'assigned to' / 'Case owner' field from the 'create_ticket' view?
-HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO = getattr(settings, 'HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO', False)
+HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO = getattr(
+ settings, 'HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO', False)
+#################
+# email options #
+#################
-''' email options '''
# default Queue email submission settings
QUEUE_EMAIL_BOX_TYPE = getattr(settings, 'QUEUE_EMAIL_BOX_TYPE', None)
QUEUE_EMAIL_BOX_SSL = getattr(settings, 'QUEUE_EMAIL_BOX_SSL', None)
@@ -104,6 +135,6 @@ QUEUE_EMAIL_BOX_HOST = getattr(settings, 'QUEUE_EMAIL_BOX_HOST', None)
QUEUE_EMAIL_BOX_USER = getattr(settings, 'QUEUE_EMAIL_BOX_USER', None)
QUEUE_EMAIL_BOX_PASSWORD = getattr(settings, 'QUEUE_EMAIL_BOX_PASSWORD', None)
-
# only allow users to access queues that they are members of?
-HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION = getattr(settings, 'HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION', False)
+HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION = getattr(
+ settings, 'HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION', False)
diff --git a/helpdesk/templatetags/in_list.py b/helpdesk/templatetags/in_list.py
index 16c3d678..fcc58898 100644
--- a/helpdesk/templatetags/in_list.py
+++ b/helpdesk/templatetags/in_list.py
@@ -17,8 +17,9 @@ Assuming 'food' = 'pizza' and 'best_foods' = ['pizza', 'pie', 'cake]:
from django import template
+
def in_list(value, arg):
- return value in ( arg or [] )
+ return value in (arg or [])
register = template.Library()
register.filter(in_list)
diff --git a/helpdesk/templatetags/load_helpdesk_settings.py b/helpdesk/templatetags/load_helpdesk_settings.py
index f14e4b30..4b1afcf4 100644
--- a/helpdesk/templatetags/load_helpdesk_settings.py
+++ b/helpdesk/templatetags/load_helpdesk_settings.py
@@ -1,20 +1,22 @@
"""
django-helpdesk - A Django powered ticket tracker for small enterprise.
-templatetags/load_helpdesk_settings.py - returns the settings as defined in
+templatetags/load_helpdesk_settings.py - returns the settings as defined in
django-helpdesk/helpdesk/settings.py
"""
-
+from __future__ import print_function
from django.template import Library
from helpdesk import settings as helpdesk_settings_config
+
def load_helpdesk_settings(request):
try:
return helpdesk_settings_config
except Exception as e:
import sys
- print >> sys.stderr, "'load_helpdesk_settings' template tag (django-helpdesk) crashed with following error:"
- print >> sys.stderr, e
+ print("'load_helpdesk_settings' template tag (django-helpdesk) crashed with following error:",
+ file=sys.stderr)
+ print(e, file=sys.stderr)
return ''
register = Library()
diff --git a/helpdesk/templatetags/saved_queries.py b/helpdesk/templatetags/saved_queries.py
index ebedf9bb..e3f9a954 100644
--- a/helpdesk/templatetags/saved_queries.py
+++ b/helpdesk/templatetags/saved_queries.py
@@ -1,7 +1,7 @@
"""
django-helpdesk - A Django powered ticket tracker for small enterprise.
-templatetags/saved_queries.py - This template tag returns previously saved
+templatetags/saved_queries.py - This template tag returns previously saved
queries. Therefore you don't need to modify
any views.
"""
@@ -17,8 +17,8 @@ def saved_queries(user):
return user_saved_queries
except Exception as e:
import sys
- print >> sys.stderr, "'saved_queries' template tag (django-helpdesk) crashed with following error:"
- print >> sys.stderr, e
+ print >> sys.stderr, "'saved_queries' template tag (django-helpdesk) crashed with following error:"
+ print >> sys.stderr, e
return ''
register = Library()
diff --git a/helpdesk/templatetags/ticket_to_link.py b/helpdesk/templatetags/ticket_to_link.py
index 91faafba..1280f846 100644
--- a/helpdesk/templatetags/ticket_to_link.py
+++ b/helpdesk/templatetags/ticket_to_link.py
@@ -20,18 +20,6 @@ from django.utils.safestring import mark_safe
from helpdesk.models import Ticket
-class ReverseProxy:
- def __init__(self, sequence):
- self.sequence = sequence
-
- def __iter__(self):
- length = len(self.sequence)
- i = length
- while i > 0:
- i = i - 1
- yield self.sequence[i]
-
-
def num_to_link(text):
if text == '':
return text
@@ -40,9 +28,7 @@ def num_to_link(text):
for match in re.finditer(r"(?:[^&]|\b|^)#(\d+)\b", text):
matches.append(match)
- for match in ReverseProxy(matches):
- start = match.start()
- end = match.end()
+ for match in reversed(matches):
number = match.groups()[0]
url = reverse('helpdesk:view', args=[number])
try:
@@ -52,7 +38,8 @@ def num_to_link(text):
if ticket:
style = ticket.get_status_display()
- text = "%s #%s%s" % (text[:match.start()], url, style, match.groups()[0], text[match.end():])
+ text = "%s #%s%s" % (
+ text[:match.start()], url, style, match.groups()[0], text[match.end():])
return mark_safe(text)
register = template.Library()
diff --git a/helpdesk/templatetags/user_admin_url.py b/helpdesk/templatetags/user_admin_url.py
index 13517609..e779ee9f 100644
--- a/helpdesk/templatetags/user_admin_url.py
+++ b/helpdesk/templatetags/user_admin_url.py
@@ -12,6 +12,7 @@ templatetags/admin_url.py - Very simple template tag allow linking to the
from django import template
from django.contrib.auth import get_user_model
+
def user_admin_url(action):
user = get_user_model()
try:
diff --git a/helpdesk/tests/helpers.py b/helpdesk/tests/helpers.py
index b64970be..09055adc 100644
--- a/helpdesk/tests/helpers.py
+++ b/helpdesk/tests/helpers.py
@@ -1,11 +1,8 @@
# -*- coding: utf-8 -*-
import sys
-try:
- from django.contrib.auth import get_user_model
-except ImportError:
- from django.contrib.auth.models import User
-else:
- User = get_user_model()
+from django.contrib.auth import get_user_model
+
+User = get_user_model()
def get_staff_user(username='helpdesk.staff', password='password'):
diff --git a/helpdesk/tests/test_public_actions.py b/helpdesk/tests/test_public_actions.py
index 85deefdc..38adc422 100644
--- a/helpdesk/tests/test_public_actions.py
+++ b/helpdesk/tests/test_public_actions.py
@@ -1,9 +1,9 @@
-from helpdesk.models import Queue, CustomField, Ticket
+from helpdesk.models import Queue, Ticket
from django.test import TestCase
-from django.core import mail
from django.test.client import Client
from django.core.urlresolvers import reverse
+
class PublicActionsTestCase(TestCase):
"""
Tests for public actions:
@@ -11,17 +11,28 @@ class PublicActionsTestCase(TestCase):
- Add a followup
- Close resolved case
"""
+
def setUp(self):
"""
Create a queue & ticket we can use for later tests.
"""
- self.queue = Queue.objects.create(title='Queue 1', slug='q', allow_public_submission=True, new_ticket_cc='new.public@example.com', updated_ticket_cc='update.public@example.com')
- self.ticket = Ticket.objects.create(title='Test Ticket', queue=self.queue, submitter_email='test.submitter@example.com', description='This is a test ticket.')
+ self.queue = Queue.objects.create(title='Queue 1',
+ slug='q',
+ allow_public_submission=True,
+ new_ticket_cc='new.public@example.com',
+ updated_ticket_cc='update.public@example.com')
+ self.ticket = Ticket.objects.create(title='Test Ticket',
+ queue=self.queue,
+ submitter_email='test.submitter@example.com',
+ description='This is a test ticket.')
self.client = Client()
def test_public_view_ticket(self):
- response = self.client.get('%s?ticket=%s&email=%s' % (reverse('helpdesk:public_view'), self.ticket.ticket_for_url, 'test.submitter@example.com'))
+ response = self.client.get('%s?ticket=%s&email=%s' % (
+ reverse('helpdesk:public_view'),
+ self.ticket.ticket_for_url,
+ 'test.submitter@example.com'))
self.assertEqual(response.status_code, 200)
self.assertTemplateNotUsed(response, 'helpdesk/public_view_form.html')
@@ -31,23 +42,26 @@ class PublicActionsTestCase(TestCase):
resolution_text = 'Resolved by test script'
ticket = Ticket.objects.get(id=self.ticket.id)
-
+
ticket.status = Ticket.RESOLVED_STATUS
ticket.resolution = resolution_text
ticket.save()
current_followups = ticket.followup_set.all().count()
-
- response = self.client.get('%s?ticket=%s&email=%s&close' % (reverse('helpdesk:public_view'), ticket.ticket_for_url, 'test.submitter@example.com'))
-
+
+ response = self.client.get('%s?ticket=%s&email=%s&close' % (
+ reverse('helpdesk:public_view'),
+ ticket.ticket_for_url,
+ 'test.submitter@example.com'))
+
ticket = Ticket.objects.get(id=self.ticket.id)
self.assertEqual(response.status_code, 302)
self.assertTemplateNotUsed(response, 'helpdesk/public_view_form.html')
self.assertEqual(ticket.status, Ticket.CLOSED_STATUS)
self.assertEqual(ticket.resolution, resolution_text)
- self.assertEqual(current_followups+1, ticket.followup_set.all().count())
-
+ self.assertEqual(current_followups + 1, ticket.followup_set.all().count())
+
ticket.resolution = old_resolution
ticket.status = old_status
ticket.save()
diff --git a/helpdesk/tests/test_savequery.py b/helpdesk/tests/test_savequery.py
index 1c0244f0..5aaa7086 100644
--- a/helpdesk/tests/test_savequery.py
+++ b/helpdesk/tests/test_savequery.py
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from django.core.urlresolvers import reverse
from django.test import TestCase
-from helpdesk.models import Ticket, Queue
-from helpdesk.tests.helpers import get_staff_user, reload_urlconf
+from helpdesk.models import Queue
+from helpdesk.tests.helpers import get_staff_user
+
class TestSavingSharedQuery(TestCase):
def setUp(self):
@@ -15,12 +16,15 @@ class TestSavingSharedQuery(TestCase):
url = reverse('helpdesk:savequery')
self.client.login(username=get_staff_user().get_username(),
password='password')
- response = self.client.post(url,
- data={'title': 'ticket on my queue',
- 'queue':self.q,
- 'shared':'on',
- 'query_encoded':'KGRwMApWZmlsdGVyaW5nCnAxCihkcDIKVnN0YXR1c19faW4KcDMKKGxwNApJMQphSTIKYUkzCmFzc1Zzb3J0aW5nCnA1ClZjcmVhdGVkCnA2CnMu'})
+ response = self.client.post(
+ url,
+ data={
+ 'title': 'ticket on my queue',
+ 'queue': self.q,
+ 'shared': 'on',
+ 'query_encoded':
+ 'KGRwMApWZmlsdGVyaW5nCnAxCihkcDIKVnN0YXR1c19faW4KcDMKKG'
+ 'xwNApJMQphSTIKYUkzCmFzc1Zzb3J0aW5nCnA1ClZjcmVhdGVkCnA2CnMu'
+ })
self.assertEqual(response.status_code, 302)
self.assertTrue('tickets/?saved_query=1' in response.url)
-
-
diff --git a/helpdesk/tests/test_ticket_lookup.py b/helpdesk/tests/test_ticket_lookup.py
index 4fa30e38..d98406a1 100644
--- a/helpdesk/tests/test_ticket_lookup.py
+++ b/helpdesk/tests/test_ticket_lookup.py
@@ -3,6 +3,7 @@ from django.core.urlresolvers import reverse
from django.test import TestCase
from helpdesk.models import Ticket, Queue
+
class TestKBDisabled(TestCase):
def setUp(self):
q = Queue(title='Q1', slug='q1')
@@ -14,22 +15,19 @@ class TestKBDisabled(TestCase):
def test_ticket_by_id(self):
"""Can a ticket be looked up by its ID"""
- from django.core.urlresolvers import NoReverseMatch
-
# get the ticket from models
t = Ticket.objects.get(id=self.ticket.id)
self.assertEqual(t.title, self.ticket.title)
def test_ticket_by_link(self):
"""Can a ticket be looked up by its link from (eg) an email"""
- # Work out the link which would have been inserted into the email
- link = self.ticket.ticket_url
- # however instead of using that link, we will exercise 'reverse'
- # to lookup/build the URL from the ticket info we have
- # http://example.com/helpdesk/view/?ticket=q1-1&email=None
+ # Instead of using the ticket_for_url link,
+ # we will exercise 'reverse' to lookup/build the URL
+ # from the ticket info we have
+ # http://example.com/helpdesk/view/?ticket=q1-1&email=None
response = self.client.get(reverse('helpdesk:public_view'),
{'ticket': self.ticket.ticket_for_url,
- 'email':self.ticket.submitter_email})
+ 'email': self.ticket.submitter_email})
self.assertEqual(response.status_code, 200)
def test_ticket_with_changed_queue(self):
@@ -40,7 +38,7 @@ class TestKBDisabled(TestCase):
# grab the URL / params which would have been emailed out to submitter.
url = reverse('helpdesk:public_view')
params = {'ticket': self.ticket.ticket_for_url,
- 'email':self.ticket.submitter_email}
+ 'email': self.ticket.submitter_email}
# Pickup the ticket created in setup() and change its queue
self.ticket.queue = q2
self.ticket.save()
diff --git a/helpdesk/tests/test_ticket_submission.py b/helpdesk/tests/test_ticket_submission.py
index 7334a129..a88c7121 100644
--- a/helpdesk/tests/test_ticket_submission.py
+++ b/helpdesk/tests/test_ticket_submission.py
@@ -14,13 +14,23 @@ class TicketBasicsTestCase(TestCase):
fixtures = ['emailtemplate.json']
def setUp(self):
- self.queue_public = Queue.objects.create(title='Queue 1', slug='q1', allow_public_submission=True, new_ticket_cc='new.public@example.com', updated_ticket_cc='update.public@example.com')
- self.queue_private = Queue.objects.create(title='Queue 2', slug='q2', allow_public_submission=False, new_ticket_cc='new.private@example.com', updated_ticket_cc='update.private@example.com')
+ self.queue_public = Queue.objects.create(
+ title='Queue 1',
+ slug='q1',
+ allow_public_submission=True,
+ new_ticket_cc='new.public@example.com',
+ updated_ticket_cc='update.public@example.com')
+ self.queue_private = Queue.objects.create(
+ title='Queue 2',
+ slug='q2',
+ allow_public_submission=False,
+ new_ticket_cc='new.private@example.com',
+ updated_ticket_cc='update.private@example.com')
self.ticket_data = {
- 'title': 'Test Ticket',
- 'description': 'Some Test Ticket',
- }
+ 'title': 'Test Ticket',
+ 'description': 'Some Test Ticket',
+ }
self.client = Client()
@@ -30,7 +40,6 @@ class TicketBasicsTestCase(TestCase):
ticket = Ticket.objects.create(**ticket_data)
self.assertEqual(ticket.ticket_for_url, "q1-%s" % ticket.id)
self.assertEqual(email_count, len(mail.outbox))
-
def test_create_ticket_public(self):
email_count = len(mail.outbox)
@@ -39,17 +48,17 @@ class TicketBasicsTestCase(TestCase):
self.assertEqual(response.status_code, 200)
post_data = {
- 'title': 'Test ticket title',
- 'queue': self.queue_public.id,
- 'submitter_email': 'ticket1.submitter@example.com',
- 'body': 'Test ticket body',
- 'priority': 3,
- }
+ 'title': 'Test ticket title',
+ 'queue': self.queue_public.id,
+ 'submitter_email': 'ticket1.submitter@example.com',
+ 'body': 'Test ticket body',
+ 'priority': 3,
+ }
response = self.client.post(reverse('helpdesk:home'), post_data, follow=True)
last_redirect = response.redirect_chain[-1]
last_redirect_url = last_redirect[0]
- last_redirect_status = last_redirect[1]
+ # last_redirect_status = last_redirect[1]
# Ensure we landed on the "View" page.
# Django 1.9 compatible way of testing this
@@ -58,17 +67,17 @@ class TicketBasicsTestCase(TestCase):
self.assertEqual(urlparts.path, reverse('helpdesk:public_view'))
# Ensure submitter, new-queue + update-queue were all emailed.
- self.assertEqual(email_count+3, len(mail.outbox))
+ self.assertEqual(email_count + 3, len(mail.outbox))
def test_create_ticket_private(self):
email_count = len(mail.outbox)
post_data = {
- 'title': 'Private ticket test',
- 'queue': self.queue_private.id,
- 'submitter_email': 'ticket2.submitter@example.com',
- 'body': 'Test ticket body',
- 'priority': 3,
- }
+ 'title': 'Private ticket test',
+ 'queue': self.queue_private.id,
+ 'submitter_email': 'ticket2.submitter@example.com',
+ 'body': 'Test ticket body',
+ 'priority': 3,
+ }
response = self.client.post(reverse('helpdesk:home'), post_data)
self.assertEqual(response.status_code, 200)
@@ -77,24 +86,35 @@ class TicketBasicsTestCase(TestCase):
def test_create_ticket_customfields(self):
email_count = len(mail.outbox)
- queue_custom = Queue.objects.create(title='Queue 3', slug='q3', allow_public_submission=True, updated_ticket_cc='update.custom@example.com')
- custom_field_1 = CustomField.objects.create(name='textfield', label='Text Field', data_type='varchar', max_length=100, ordering=10, required=False, staff_only=False)
+ queue_custom = Queue.objects.create(
+ title='Queue 3',
+ slug='q3',
+ allow_public_submission=True,
+ updated_ticket_cc='update.custom@example.com')
+ custom_field_1 = CustomField.objects.create(
+ name='textfield',
+ label='Text Field',
+ data_type='varchar',
+ max_length=100,
+ ordering=10,
+ required=False,
+ staff_only=False)
post_data = {
- 'queue': queue_custom.id,
- 'title': 'Ticket with custom text field',
- 'submitter_email': 'ticket3.submitter@example.com',
- 'body': 'Test ticket body',
- 'priority': 3,
- 'custom_textfield': 'This is my custom text.',
- }
+ 'queue': queue_custom.id,
+ 'title': 'Ticket with custom text field',
+ 'submitter_email': 'ticket3.submitter@example.com',
+ 'body': 'Test ticket body',
+ 'priority': 3,
+ 'custom_textfield': 'This is my custom text.',
+ }
response = self.client.post(reverse('helpdesk:home'), post_data, follow=True)
custom_field_1.delete()
last_redirect = response.redirect_chain[-1]
last_redirect_url = last_redirect[0]
- last_redirect_status = last_redirect[1]
-
+ # last_redirect_status = last_redirect[1]
+
# Ensure we landed on the "View" page.
# Django 1.9 compatible way of testing this
# https://docs.djangoproject.com/en/1.9/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris
@@ -102,4 +122,4 @@ class TicketBasicsTestCase(TestCase):
self.assertEqual(urlparts.path, reverse('helpdesk:public_view'))
# Ensure only two e-mails were sent - submitter & updated.
- self.assertEqual(email_count+2, len(mail.outbox))
+ self.assertEqual(email_count + 2, len(mail.outbox))
diff --git a/helpdesk/urls.py b/helpdesk/urls.py
index 7fd7e009..833a89df 100644
--- a/helpdesk/urls.py
+++ b/helpdesk/urls.py
@@ -7,21 +7,18 @@ urls.py - Mapping of URL's to our various views. Note we always used NAMED
views for simplicity in linking later on.
"""
-from django.conf import settings
-import django
-if django.get_version().startswith("1.3"):
- from django.conf.urls.defaults import *
-else:
- from django.conf.urls import *
+from django.conf.urls import url
from django.contrib.auth.decorators import login_required
+from django.contrib.auth import views as auth_views
+from django.views.generic import TemplateView
from helpdesk import settings as helpdesk_settings
from helpdesk.views import feeds, staff, public, api, kb
-from django.contrib.auth import views as auth_views
-from django.views.generic import TemplateView
+
class DirectTemplateView(TemplateView):
extra_context = None
+
def get_context_data(self, **kwargs):
context = super(self.__class__, self).get_context_data(**kwargs)
if self.extra_context is not None:
diff --git a/helpdesk/views/api.py b/helpdesk/views/api.py
index 072caee2..dc286202 100644
--- a/helpdesk/views/api.py
+++ b/helpdesk/views/api.py
@@ -11,16 +11,10 @@ The API documentation can be accessed by visiting http://helpdesk/api/help/
through templates/helpdesk/help_api.html.
"""
-from django import forms
from django.contrib.auth import authenticate
-try:
- from django.contrib.auth import get_user_model
- User = get_user_model()
-except ImportError:
- from django.contrib.auth.models import User
+from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.shortcuts import render
-from django.template import loader, Context
import simplejson
from django.views.decorators.csrf import csrf_exempt
@@ -35,6 +29,8 @@ from helpdesk.models import Ticket, Queue, FollowUp
import warnings
+User = get_user_model()
+
STATUS_OK = 200
STATUS_ERROR = 400
@@ -61,7 +57,9 @@ def api(request, method):
"""
- warnings.warn("django-helpdesk API will be removed in January 2016. See https://github.com/django-helpdesk/django-helpdesk/issues/198 for details.", category=DeprecationWarning)
+ warnings.warn("django-helpdesk API will be removed in January 2016. "
+ "See https://github.com/django-helpdesk/django-helpdesk/issues/198 for details.",
+ category=DeprecationWarning)
if method == 'help':
return render(request, template_name='helpdesk/help_api.html')
@@ -114,7 +112,6 @@ class API:
def __init__(self, request):
self.request = request
-
def api_public_create_ticket(self):
form = TicketForm(self.request.POST)
form.fields['queue'].choices = [[q.id, q.title] for q in Queue.objects.all()]
@@ -126,10 +123,11 @@ class API:
else:
return api_return(STATUS_ERROR, text=form.errors.as_text())
-
def api_public_list_queues(self):
- return api_return(STATUS_OK, simplejson.dumps([{"id": "%s" % q.id, "title": "%s" % q.title} for q in Queue.objects.all()]), json=True)
-
+ return api_return(STATUS_OK, simplejson.dumps([
+ {"id": "%s" % q.id, "title": "%s" % q.title}
+ for q in Queue.objects.all()
+ ]), json=True)
def api_public_find_user(self):
username = self.request.POST.get('username', False)
@@ -141,7 +139,6 @@ class API:
except User.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid username provided")
-
def api_public_delete_ticket(self):
if not self.request.POST.get('confirm', False):
return api_return(STATUS_ERROR, "No confirmation provided")
@@ -155,7 +152,6 @@ class API:
return api_return(STATUS_OK)
-
def api_public_hold_ticket(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
@@ -167,7 +163,6 @@ class API:
return api_return(STATUS_OK)
-
def api_public_unhold_ticket(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
@@ -179,7 +174,6 @@ class API:
return api_return(STATUS_OK)
-
def api_public_add_followup(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
@@ -264,7 +258,6 @@ class API:
return api_return(STATUS_OK)
-
def api_public_resolve(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
@@ -289,7 +282,7 @@ class API:
context = safe_template_context(ticket)
context['resolution'] = f.comment
- subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
+ # subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
messages_sent_to = []
@@ -324,7 +317,12 @@ class API:
)
messages_sent_to.append(ticket.queue.updated_ticket_cc)
- if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
+ if ticket.assigned_to and \
+ self.request.user != ticket.assigned_to and \
+ getattr(ticket.assigned_to.usersettings.settings,
+ 'email_on_ticket_apichange', False) and \
+ ticket.assigned_to.email and \
+ ticket.assigned_to.email not in messages_sent_to:
send_templated_mail(
'resolved_resolved',
context,
diff --git a/helpdesk/views/feeds.py b/helpdesk/views/feeds.py
index cd3bc06c..08fc74ef 100644
--- a/helpdesk/views/feeds.py
+++ b/helpdesk/views/feeds.py
@@ -7,11 +7,7 @@ views/feeds.py - A handful of staff-only RSS feeds to provide ticket details
to feed readers or similar software.
"""
-try:
- from django.contrib.auth import get_user_model
- User = get_user_model()
-except ImportError:
- from django.contrib.auth.models import User
+from django.contrib.auth import get_user_model
from django.contrib.syndication.views import Feed
from django.core.urlresolvers import reverse
from django.db.models import Q
@@ -20,6 +16,8 @@ from django.shortcuts import get_object_or_404
from helpdesk.models import Ticket, FollowUp, Queue
+User = get_user_model()
+
class OpenTicketsByUser(Feed):
title_template = 'helpdesk/rss/ticket_title.html'
@@ -39,22 +37,22 @@ class OpenTicketsByUser(Feed):
return _("Helpdesk: Open Tickets in queue %(queue)s for %(username)s") % {
'queue': obj['queue'].title,
'username': obj['user'].get_username(),
- }
+ }
else:
return _("Helpdesk: Open Tickets for %(username)s") % {
'username': obj['user'].get_username(),
- }
+ }
def description(self, obj):
if obj['queue']:
return _("Open and Reopened Tickets in queue %(queue)s for %(username)s") % {
'queue': obj['queue'].title,
'username': obj['user'].get_username(),
- }
+ }
else:
return _("Open and Reopened Tickets for %(username)s") % {
'username': obj['user'].get_username(),
- }
+ }
def link(self, obj):
if obj['queue']:
@@ -62,28 +60,28 @@ class OpenTicketsByUser(Feed):
reverse('helpdesk:list'),
obj['user'].id,
obj['queue'].id,
- )
+ )
else:
return u'%s?assigned_to=%s' % (
reverse('helpdesk:list'),
obj['user'].id,
- )
+ )
def items(self, obj):
if obj['queue']:
return Ticket.objects.filter(
- assigned_to=obj['user']
- ).filter(
- queue=obj['queue']
- ).filter(
- Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
- )
+ assigned_to=obj['user']
+ ).filter(
+ queue=obj['queue']
+ ).filter(
+ Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
+ )
else:
return Ticket.objects.filter(
- assigned_to=obj['user']
- ).filter(
- Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
- )
+ assigned_to=obj['user']
+ ).filter(
+ Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
+ )
def item_pubdate(self, item):
return item.created
@@ -101,19 +99,18 @@ class UnassignedTickets(Feed):
title = _('Helpdesk: Unassigned Tickets')
description = _('Unassigned Open and Reopened tickets')
- link = ''#%s?assigned_to=' % reverse('helpdesk:list')
+ link = '' # '%s?assigned_to=' % reverse('helpdesk:list')
def items(self, obj):
return Ticket.objects.filter(
- assigned_to__isnull=True
- ).filter(
- Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
- )
+ assigned_to__isnull=True
+ ).filter(
+ Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
+ )
def item_pubdate(self, item):
return item.created
-
def item_author_name(self, item):
if item.assigned_to:
return item.assigned_to.get_username()
@@ -127,7 +124,7 @@ class RecentFollowUps(Feed):
title = _('Helpdesk: Recent Followups')
description = _('Recent FollowUps, such as e-mail replies, comments, attachments and resolutions')
- link = '/tickets/' # reverse('helpdesk:list')
+ link = '/tickets/' # reverse('helpdesk:list')
def items(self):
return FollowUp.objects.order_by('-date')[:20]
@@ -143,25 +140,25 @@ class OpenTicketsByQueue(Feed):
def title(self, obj):
return _('Helpdesk: Open Tickets in queue %(queue)s') % {
'queue': obj.title,
- }
+ }
def description(self, obj):
return _('Open and Reopened Tickets in queue %(queue)s') % {
'queue': obj.title,
- }
+ }
def link(self, obj):
return '%s?queue=%s' % (
reverse('helpdesk:list'),
obj.id,
- )
+ )
def items(self, obj):
return Ticket.objects.filter(
- queue=obj
- ).filter(
- Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
- )
+ queue=obj
+ ).filter(
+ Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)
+ )
def item_pubdate(self, item):
return item.created
@@ -171,4 +168,3 @@ class OpenTicketsByQueue(Feed):
return item.assigned_to.get_username()
else:
return _('Unassigned')
-
diff --git a/helpdesk/views/kb.py b/helpdesk/views/kb.py
index 384efd84..a7e7a1e8 100644
--- a/helpdesk/views/kb.py
+++ b/helpdesk/views/kb.py
@@ -8,12 +8,8 @@ views/kb.py - Public-facing knowledgebase views. The knowledgebase is a
resolutions to common problems.
"""
-from datetime import datetime
-
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
-from django.template import RequestContext
-from django.utils.translation import ugettext as _
from helpdesk import settings as helpdesk_settings
from helpdesk.models import KBCategory, KBItem
@@ -22,31 +18,28 @@ from helpdesk.models import KBCategory, KBItem
def index(request):
category_list = KBCategory.objects.all()
# TODO: It'd be great to have a list of most popular items here.
- return render(request, template_name='helpdesk/kb_index.html',
- context = {
- 'kb_categories': category_list,
- 'helpdesk_settings': helpdesk_settings,
- })
+ return render(request, 'helpdesk/kb_index.html', {
+ 'kb_categories': category_list,
+ 'helpdesk_settings': helpdesk_settings,
+ })
def category(request, slug):
category = get_object_or_404(KBCategory, slug__iexact=slug)
items = category.kbitem_set.all()
- return render(request, template_name='helpdesk/kb_category.html',
- context = {
- 'category': category,
- 'items': items,
- 'helpdesk_settings': helpdesk_settings,
- })
+ return render(request, 'helpdesk/kb_category.html', {
+ 'category': category,
+ 'items': items,
+ 'helpdesk_settings': helpdesk_settings,
+ })
def item(request, item):
item = get_object_or_404(KBItem, pk=item)
- return render(request, template_name='helpdesk/kb_item.html',
- context = {
- 'item': item,
- 'helpdesk_settings': helpdesk_settings,
- })
+ return render(request, 'helpdesk/kb_item.html', {
+ 'item': item,
+ 'helpdesk_settings': helpdesk_settings,
+ })
def vote(request, item):
@@ -59,4 +52,3 @@ def vote(request, item):
item.save()
return HttpResponseRedirect(item.get_absolute_url())
-
diff --git a/helpdesk/views/public.py b/helpdesk/views/public.py
index d9041e9d..383f36f1 100644
--- a/helpdesk/views/public.py
+++ b/helpdesk/views/public.py
@@ -6,16 +6,15 @@ django-helpdesk - A Django powered ticket tracker for small enterprise.
views/public.py - All public facing views, eg non-staff (no authentication
required) views.
"""
-
+from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect, Http404, HttpResponse
-from django.shortcuts import render, get_object_or_404
-from django.template import loader, Context, RequestContext
+from django.http import HttpResponseRedirect
+from django.shortcuts import render
from django.utils.translation import ugettext as _
from helpdesk import settings as helpdesk_settings
from helpdesk.forms import PublicTicketForm
-from helpdesk.lib import send_templated_mail, text_is_spam
+from helpdesk.lib import text_is_spam
from helpdesk.models import Ticket, Queue, UserSettings, KBCategory
@@ -23,7 +22,9 @@ def homepage(request):
if not request.user.is_authenticated() and helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT:
return HttpResponseRedirect(reverse('helpdesk:login'))
- if (request.user.is_staff or (request.user.is_authenticated() and helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE)):
+ if request.user.is_staff or \
+ (request.user.is_authenticated() and
+ helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
try:
if request.user.usersettings.settings.get('login_view_ticketlist', False):
return HttpResponseRedirect(reverse('helpdesk:list'))
@@ -34,18 +35,19 @@ def homepage(request):
if request.method == 'POST':
form = PublicTicketForm(request.POST, request.FILES)
- form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.filter(allow_public_submission=True)]
+ form.fields['queue'].choices = [('', '--------')] + [
+ (q.id, q.title) for q in Queue.objects.filter(allow_public_submission=True)]
if form.is_valid():
if text_is_spam(form.cleaned_data['body'], request):
# This submission is spam. Let's not save it.
return render(request, template_name='helpdesk/public_spam.html')
else:
ticket = form.save()
- return HttpResponseRedirect('%s?ticket=%s&email=%s'% (
+ return HttpResponseRedirect('%s?ticket=%s&email=%s' % (
reverse('helpdesk:public_view'),
ticket.ticket_for_url,
ticket.submitter_email)
- )
+ )
else:
try:
queue = Queue.objects.get(slug=request.GET.get('queue', None))
@@ -59,34 +61,36 @@ def homepage(request):
initial_data['submitter_email'] = request.user.email
form = PublicTicketForm(initial=initial_data)
- form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.filter(allow_public_submission=True)]
+ form.fields['queue'].choices = [('', '--------')] + [
+ (q.id, q.title) for q in Queue.objects.filter(allow_public_submission=True)]
knowledgebase_categories = KBCategory.objects.all()
- return render(request, 'helpdesk/public_homepage.html',
- {
- 'form': form,
- 'helpdesk_settings': helpdesk_settings,
- 'kb_categories': knowledgebase_categories
- })
+ return render(request, 'helpdesk/public_homepage.html', {
+ 'form': form,
+ 'helpdesk_settings': helpdesk_settings,
+ 'kb_categories': knowledgebase_categories
+ })
def view_ticket(request):
ticket_req = request.GET.get('ticket', '')
- ticket = False
email = request.GET.get('email', '')
- error_message = ''
if ticket_req and email:
queue, ticket_id = Ticket.queue_and_id_from_query(ticket_req)
try:
ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
- except:
- ticket = False
+ except ObjectDoesNotExist:
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
- if ticket:
-
+ return render(request, 'helpdesk/public_view_form.html', {
+ 'ticket': False,
+ 'email': email,
+ 'error_message': error_message,
+ 'helpdesk_settings': helpdesk_settings,
+ })
+ else:
if request.user.is_staff:
redirect_url = reverse('helpdesk:view', args=[ticket_id])
if 'close' in request.GET:
@@ -102,7 +106,7 @@ def view_ticket(request):
'public': 1,
'title': ticket.title,
'comment': _('Submitter accepted resolution and closed ticket'),
- }
+ }
if ticket.assigned_to:
request.POST['owner'] = ticket.assigned_to.id
request.GET = {}
@@ -114,25 +118,16 @@ def view_ticket(request):
if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED:
redirect_url = reverse('helpdesk:view', args=[ticket_id])
- return render(request, 'helpdesk/public_view_ticket.html',
- {
- 'ticket': ticket,
- 'helpdesk_settings': helpdesk_settings,
- 'next': redirect_url,
- })
+ return render(request, 'helpdesk/public_view_ticket.html', {
+ 'ticket': ticket,
+ 'helpdesk_settings': helpdesk_settings,
+ 'next': redirect_url,
+ })
- return render(request, template_name='helpdesk/public_view_form.html',
- context = {
- 'ticket': ticket,
- 'email': email,
- 'error_message': error_message,
- 'helpdesk_settings': helpdesk_settings,
- })
def change_language(request):
return_to = ''
if 'return_to' in request.GET:
return_to = request.GET['return_to']
- return render(request, template_name='helpdesk/public_change_language.html',
- context = {'next': return_to})
+ return render(request, 'helpdesk/public_change_language.html', {'next': return_to})
diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py
index c96be858..357fa64e 100644
--- a/helpdesk/views/staff.py
+++ b/helpdesk/views/staff.py
@@ -7,19 +7,12 @@ views/staff.py - The bulk of the application - provides most business logic and
renders all staff-facing views.
"""
from __future__ import unicode_literals
-from django.utils.encoding import python_2_unicode_compatible
from datetime import datetime, timedelta
-import sys
from django import VERSION
from django.conf import settings
-try:
- from django.contrib.auth import get_user_model
- User = get_user_model()
-except ImportError:
- from django.contrib.auth.models import User
-from django.contrib.auth.decorators import login_required, user_passes_test
-from django.core.files.base import ContentFile
+from django.contrib.auth import get_user_model
+from django.contrib.auth.decorators import user_passes_test
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError, PermissionDenied
from django.core import paginator
@@ -27,7 +20,6 @@ from django.db import connection
from django.db.models import Q
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.shortcuts import render, get_object_or_404
-from django.template import loader, Context, RequestContext
from django.utils.dates import MONTHS_3
from django.utils.translation import ugettext as _
from django.utils.html import escape
@@ -38,19 +30,33 @@ try:
except ImportError:
from datetime import datetime as timezone
-from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, EditFollowUpForm, TicketDependencyForm
-from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context
-from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
+from helpdesk.forms import (
+ TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm,
+ EditFollowUpForm, TicketDependencyForm
+)
+from helpdesk.lib import (
+ send_templated_mail, query_to_dict, apply_query, safe_template_context,
+)
+from helpdesk.models import (
+ Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch,
+ IgnoreEmail, TicketCC, TicketDependency,
+)
from helpdesk import settings as helpdesk_settings
+User = get_user_model()
+
+
if helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
# treat 'normal' users like 'staff'
- staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active)
+ staff_member_required = user_passes_test(
+ lambda u: u.is_authenticated() and u.is_active)
else:
- staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active and u.is_staff)
+ staff_member_required = user_passes_test(
+ lambda u: u.is_authenticated() and u.is_active and u.is_staff)
-superuser_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active and u.is_superuser)
+superuser_required = user_passes_test(
+ lambda u: u.is_authenticated() and u.is_active and u.is_superuser)
def _get_user_queues(user):
@@ -60,7 +66,9 @@ def _get_user_queues(user):
:return: A Python list of Queues
"""
all_queues = Queue.objects.all()
- limit_queues_by_user = helpdesk_settings.HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION and not user.is_superuser
+ limit_queues_by_user = \
+ helpdesk_settings.HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION \
+ and not user.is_superuser
if limit_queues_by_user:
id_list = [q.pk for q in all_queues if user.has_perm(q.permission_name)]
return all_queues.filter(pk__in=id_list)
@@ -90,24 +98,24 @@ def dashboard(request):
# open & reopened tickets, assigned to current user
tickets = Ticket.objects.select_related('queue').filter(
- assigned_to=request.user,
- ).exclude(
- status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS],
- )
+ assigned_to=request.user,
+ ).exclude(
+ status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS],
+ )
# closed & resolved tickets, assigned to current user
- tickets_closed_resolved = Ticket.objects.select_related('queue').filter(
- assigned_to=request.user,
- status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS])
+ tickets_closed_resolved = Ticket.objects.select_related('queue').filter(
+ assigned_to=request.user,
+ status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS])
user_queues = _get_user_queues(request.user)
unassigned_tickets = Ticket.objects.select_related('queue').filter(
- assigned_to__isnull=True,
- queue__in=user_queues
- ).exclude(
- status=Ticket.CLOSED_STATUS,
- )
+ assigned_to__isnull=True,
+ queue__in=user_queues
+ ).exclude(
+ status=Ticket.CLOSED_STATUS,
+ )
# all tickets, reported by current user
all_tickets_reported_by_current_user = ''
@@ -117,10 +125,10 @@ def dashboard(request):
submitter_email=email_current_user,
).order_by('status')
- Tickets = Ticket.objects.filter(
- queue__in=user_queues,
- )
- basic_ticket_stats = calc_basic_ticket_stats(Tickets)
+ tickets_in_queues = Ticket.objects.filter(
+ queue__in=user_queues,
+ )
+ basic_ticket_stats = calc_basic_ticket_stats(tickets_in_queues)
# The following query builds a grid of queues & ticket statuses,
# to be displayed to the user. EG:
@@ -153,15 +161,14 @@ def dashboard(request):
dash_tickets = query_to_dict(cursor.fetchall(), cursor.description)
- return render(request, 'helpdesk/dashboard.html',
- {
- 'user_tickets': tickets,
- 'user_tickets_closed_resolved': tickets_closed_resolved,
- 'unassigned_tickets': unassigned_tickets,
- 'all_tickets_reported_by_current_user': all_tickets_reported_by_current_user,
- 'dash_tickets': dash_tickets,
- 'basic_ticket_stats': basic_ticket_stats,
- })
+ return render(request, 'helpdesk/dashboard.html', {
+ 'user_tickets': tickets,
+ 'user_tickets_closed_resolved': tickets_closed_resolved,
+ 'unassigned_tickets': unassigned_tickets,
+ 'all_tickets_reported_by_current_user': all_tickets_reported_by_current_user,
+ 'dash_tickets': dash_tickets,
+ 'basic_ticket_stats': basic_ticket_stats,
+ })
dashboard = staff_member_required(dashboard)
@@ -171,38 +178,38 @@ def delete_ticket(request, ticket_id):
raise PermissionDenied()
if request.method == 'GET':
- return render(request, template_name='helpdesk/delete_ticket.html',
- context = {
- 'ticket': ticket,
- })
+ return render(request, 'helpdesk/delete_ticket.html', {
+ 'ticket': ticket,
+ })
else:
ticket.delete()
return HttpResponseRedirect(reverse('helpdesk:home'))
delete_ticket = staff_member_required(delete_ticket)
+
def followup_edit(request, ticket_id, followup_id):
- "Edit followup options with an ability to change the ticket."
+ """Edit followup options with an ability to change the ticket."""
followup = get_object_or_404(FollowUp, id=followup_id)
ticket = get_object_or_404(Ticket, id=ticket_id)
if not _has_access_to_queue(request.user, ticket.queue):
raise PermissionDenied()
if request.method == 'GET':
- form = EditFollowUpForm(initial=
- {'title': escape(followup.title),
- 'ticket': followup.ticket,
- 'comment': escape(followup.comment),
- 'public': followup.public,
- 'new_status': followup.new_status,
- })
+ form = EditFollowUpForm(initial={
+ 'title': escape(followup.title),
+ 'ticket': followup.ticket,
+ 'comment': escape(followup.comment),
+ 'public': followup.public,
+ 'new_status': followup.new_status,
+ })
- ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(request.user, ticket)
+ ticketcc_string, show_subscribe = \
+ return_ticketccstring_and_show_subscribe(request.user, ticket)
- return render(request, template_name='helpdesk/followup_edit.html',
- context = {
- 'followup': followup,
- 'ticket': ticket,
- 'form': form,
- 'ticketcc_string': ticketcc_string,
+ return render(request, 'helpdesk/followup_edit.html', {
+ 'followup': followup,
+ 'ticket': ticket,
+ 'form': form,
+ 'ticketcc_string': ticketcc_string,
})
elif request.method == 'POST':
form = EditFollowUpForm(request.POST)
@@ -212,7 +219,7 @@ def followup_edit(request, ticket_id, followup_id):
comment = form.cleaned_data['comment']
public = form.cleaned_data['public']
new_status = form.cleaned_data['new_status']
- #will save previous date
+ # will save previous date
old_date = followup.date
new_followup = FollowUp(title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status, )
# keep old user if one did exist before.
@@ -220,7 +227,7 @@ def followup_edit(request, ticket_id, followup_id):
new_followup.user = followup.user
new_followup.save()
# get list of old attachments & link them to new_followup
- attachments = Attachment.objects.filter(followup = followup)
+ attachments = Attachment.objects.filter(followup=followup)
for attachment in attachments:
attachment.followup = new_followup
attachment.save()
@@ -229,8 +236,9 @@ def followup_edit(request, ticket_id, followup_id):
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
followup_edit = staff_member_required(followup_edit)
+
def followup_delete(request, ticket_id, followup_id):
- ''' followup delete for superuser'''
+ """followup delete for superuser"""
ticket = get_object_or_404(Ticket, id=ticket_id)
if not request.user.is_superuser:
@@ -262,8 +270,9 @@ def view_ticket(request, ticket_id):
if 'subscribe' in request.GET:
# Allow the user to subscribe him/herself to the ticket whilst viewing it.
- ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(request.user, ticket)
- if SHOW_SUBSCRIBE:
+ ticket_cc, show_subscribe = \
+ return_ticketccstring_and_show_subscribe(request.user, ticket)
+ if show_subscribe:
subscribe_staff_member_to_ticket(ticket, request.user)
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
@@ -281,7 +290,7 @@ def view_ticket(request, ticket_id):
'owner': owner,
'title': ticket.title,
'comment': _('Accepted resolution and closed ticket'),
- }
+ }
return update_ticket(request, ticket_id)
@@ -290,26 +299,27 @@ def view_ticket(request, ticket_id):
else:
users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
-
# TODO: shouldn't this template get a form to begin with?
- form = TicketForm(initial={'due_date':ticket.due_date})
+ form = TicketForm(initial={'due_date': ticket.due_date})
- ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(request.user, ticket)
+ ticketcc_string, show_subscribe = \
+ return_ticketccstring_and_show_subscribe(request.user, ticket)
- return render(request, template_name='helpdesk/ticket.html',
- context = {
- 'ticket': ticket,
- 'form': form,
- 'active_users': users,
- 'priorities': Ticket.PRIORITY_CHOICES,
- 'preset_replies': PreSetReply.objects.filter(Q(queues=ticket.queue) | Q(queues__isnull=True)),
- 'ticketcc_string': ticketcc_string,
- 'SHOW_SUBSCRIBE': SHOW_SUBSCRIBE,
- })
+ return render(request, 'helpdesk/ticket.html', {
+ 'ticket': ticket,
+ 'form': form,
+ 'active_users': users,
+ 'priorities': Ticket.PRIORITY_CHOICES,
+ 'preset_replies': PreSetReply.objects.filter(
+ Q(queues=ticket.queue) | Q(queues__isnull=True)),
+ 'ticketcc_string': ticketcc_string,
+ 'SHOW_SUBSCRIBE': show_subscribe,
+ })
view_ticket = staff_member_required(view_ticket)
+
def return_ticketccstring_and_show_subscribe(user, ticket):
- ''' used in view_ticket() and followup_edit()'''
+ """used in view_ticket() and followup_edit()"""
# create the ticketcc_string and check whether current user is already
# subscribed
username = user.get_username().upper()
@@ -321,14 +331,14 @@ def return_ticketccstring_and_show_subscribe(user, ticket):
ticketcc_string = ''
all_ticketcc = ticket.ticketcc_set.all()
counter_all_ticketcc = len(all_ticketcc) - 1
- SHOW_SUBSCRIBE = True
+ show_subscribe = True
for i, ticketcc in enumerate(all_ticketcc):
ticketcc_this_entry = str(ticketcc.display)
- ticketcc_string = ticketcc_string + ticketcc_this_entry
+ ticketcc_string += ticketcc_this_entry
if i < counter_all_ticketcc:
- ticketcc_string = ticketcc_string + ', '
+ ticketcc_string += ', '
if strings_to_check.__contains__(ticketcc_this_entry.upper()):
- SHOW_SUBSCRIBE = False
+ show_subscribe = False
# check whether current user is a submitter or assigned to ticket
assignedto_username = str(ticket.assigned_to).upper()
@@ -337,24 +347,30 @@ def return_ticketccstring_and_show_subscribe(user, ticket):
strings_to_check.append(assignedto_username)
strings_to_check.append(submitter_email)
if strings_to_check.__contains__(username) or strings_to_check.__contains__(useremail):
- SHOW_SUBSCRIBE = False
+ show_subscribe = False
- return ticketcc_string, SHOW_SUBSCRIBE
+ return ticketcc_string, show_subscribe
def subscribe_staff_member_to_ticket(ticket, user):
- ''' used in view_ticket() and update_ticket() '''
- ticketcc = TicketCC()
- ticketcc.ticket = ticket
- ticketcc.user = user
- ticketcc.can_view = True
- ticketcc.can_update = True
+ """used in view_ticket() and update_ticket()"""
+ ticketcc = TicketCC(
+ ticket=ticket,
+ user=user,
+ can_view=True,
+ can_update=True,
+ )
ticketcc.save()
def update_ticket(request, ticket_id, public=False):
- if not (public or (request.user.is_authenticated() and request.user.is_active and (request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))):
- return HttpResponseRedirect('%s?next=%s' % (reverse('helpdesk:login'), request.path))
+ if not (public or (
+ request.user.is_authenticated() and
+ request.user.is_active and (
+ request.user.is_staff or
+ helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))):
+ return HttpResponseRedirect('%s?next=%s' %
+ (reverse('helpdesk:login'), request.path))
ticket = get_object_or_404(Ticket, id=ticket_id)
@@ -384,7 +400,8 @@ def update_ticket(request, ticket_id, public=False):
title == ticket.title,
priority == int(ticket.priority),
due_date == ticket.due_date,
- (owner == -1) or (not owner and not ticket.assigned_to) or (owner and User.objects.get(id=owner) == ticket.assigned_to),
+ (owner == -1) or (not owner and not ticket.assigned_to) or
+ (owner and User.objects.get(id=owner) == ticket.assigned_to),
])
if no_changes:
return return_to_ticket(request.user, helpdesk_settings, ticket)
@@ -398,7 +415,8 @@ def update_ticket(request, ticket_id, public=False):
# then the following line will give us a crash, since django expects {% if %}
# to be closed with an {% endif %} tag.
- # get_template_from_string was removed in Django 1.8 http://django.readthedocs.org/en/1.8.x/ref/templates/upgrading.html
+ # get_template_from_string was removed in Django 1.8
+ # http://django.readthedocs.org/en/1.8.x/ref/templates/upgrading.html
try:
from django.template import engines
template_func = engines['django'].from_string
@@ -428,7 +446,7 @@ def update_ticket(request, ticket_id, public=False):
new_user = User.objects.get(id=owner)
f.title = _('Assigned to %(username)s') % {
'username': new_user.get_username(),
- }
+ }
ticket.assigned_to = new_user
reassigned = True
# user changed owner to 'unassign'
@@ -455,7 +473,7 @@ def update_ticket(request, ticket_id, public=False):
files = []
if request.FILES:
- import mimetypes, os
+ import mimetypes
for file in request.FILES.getlist('attachment'):
filename = file.name.encode('ascii', 'ignore')
a = Attachment(
@@ -463,7 +481,7 @@ def update_ticket(request, ticket_id, public=False):
filename=filename,
mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream',
size=file.size,
- )
+ )
a.file.save(filename, file, save=False)
a.save()
@@ -472,14 +490,13 @@ def update_ticket(request, ticket_id, public=False):
# settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email.
files.append([a.filename, a.file])
-
if title != ticket.title:
c = TicketChange(
followup=f,
field=_('Title'),
old_value=ticket.title,
new_value=title,
- )
+ )
c.save()
ticket.title = title
@@ -489,7 +506,7 @@ def update_ticket(request, ticket_id, public=False):
field=_('Priority'),
old_value=ticket.priority,
new_value=priority,
- )
+ )
c.save()
ticket.priority = priority
@@ -499,11 +516,11 @@ def update_ticket(request, ticket_id, public=False):
field=_('Due on'),
old_value=ticket.due_date,
new_value=due_date,
- )
+ )
c.save()
ticket.due_date = due_date
- if new_status in [ Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS ]:
+ if new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS):
if new_status == Ticket.RESOLVED_STATUS or ticket.resolution is None:
ticket.resolution = comment
@@ -515,11 +532,11 @@ def update_ticket(request, ticket_id, public=False):
context.update(
resolution=ticket.resolution,
comment=f.comment,
- )
-
- if public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))):
-
+ )
+ if public and (f.comment or (
+ f.new_status in (Ticket.RESOLVED_STATUS,
+ Ticket.CLOSED_STATUS))):
if f.new_status == Ticket.RESOLVED_STATUS:
template = 'resolved_'
elif f.new_status == Ticket.CLOSED_STATUS:
@@ -537,7 +554,7 @@ def update_ticket(request, ticket_id, public=False):
sender=ticket.queue.from_address,
fail_silently=True,
files=files,
- )
+ )
messages_sent_to.append(ticket.submitter_email)
template_suffix = 'cc'
@@ -551,10 +568,13 @@ def update_ticket(request, ticket_id, public=False):
sender=ticket.queue.from_address,
fail_silently=True,
files=files,
- )
+ )
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:
+ 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
# changed.
@@ -567,7 +587,13 @@ def update_ticket(request, ticket_id, public=False):
else:
template_staff = 'updated_owner'
- if (not reassigned or ( reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_assign', False))) or (not reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_change', False)):
+ if (not reassigned or
+ (reassigned and
+ ticket.assigned_to.usersettings.settings.get(
+ 'email_on_ticket_assign', False))) or \
+ (not reassigned and
+ ticket.assigned_to.usersettings.settings.get(
+ 'email_on_ticket_change', False)):
send_templated_mail(
template_staff,
context,
@@ -575,7 +601,7 @@ def update_ticket(request, ticket_id, public=False):
sender=ticket.queue.from_address,
fail_silently=True,
files=files,
- )
+ )
messages_sent_to.append(ticket.assigned_to.email)
if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
@@ -595,7 +621,7 @@ def update_ticket(request, ticket_id, public=False):
sender=ticket.queue.from_address,
fail_silently=True,
files=files,
- )
+ )
ticket.save()
@@ -609,7 +635,7 @@ def update_ticket(request, ticket_id, public=False):
def return_to_ticket(user, helpdesk_settings, ticket):
- ''' Helpder function for update_ticket '''
+ """Helper function for update_ticket"""
if user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
return HttpResponseRedirect(ticket.get_absolute_url())
@@ -638,29 +664,47 @@ def mass_update(request):
if action == 'assign' and t.assigned_to != user:
t.assigned_to = user
t.save()
- f = FollowUp(ticket=t, date=timezone.now(), title=_('Assigned to %(username)s in bulk update' % {'username': user.get_username()}), public=True, user=request.user)
+ f = FollowUp(ticket=t,
+ date=timezone.now(),
+ title=_('Assigned to %(username)s in bulk update' % {
+ 'username': user.get_username()
+ }),
+ public=True,
+ user=request.user)
f.save()
elif action == 'unassign' and t.assigned_to is not None:
t.assigned_to = None
t.save()
- f = FollowUp(ticket=t, date=timezone.now(), title=_('Unassigned in bulk update'), public=True, user=request.user)
+ f = FollowUp(ticket=t,
+ date=timezone.now(),
+ title=_('Unassigned in bulk update'),
+ public=True,
+ user=request.user)
f.save()
elif action == 'close' and t.status != Ticket.CLOSED_STATUS:
t.status = Ticket.CLOSED_STATUS
t.save()
- f = FollowUp(ticket=t, date=timezone.now(), title=_('Closed in bulk update'), public=False, user=request.user, new_status=Ticket.CLOSED_STATUS)
+ f = FollowUp(ticket=t,
+ date=timezone.now(),
+ title=_('Closed in bulk update'),
+ public=False,
+ user=request.user,
+ new_status=Ticket.CLOSED_STATUS)
f.save()
elif action == 'close_public' and t.status != Ticket.CLOSED_STATUS:
t.status = Ticket.CLOSED_STATUS
t.save()
- f = FollowUp(ticket=t, date=timezone.now(), title=_('Closed in bulk update'), public=True, user=request.user, new_status=Ticket.CLOSED_STATUS)
+ f = FollowUp(ticket=t,
+ date=timezone.now(),
+ title=_('Closed in bulk update'),
+ public=True,
+ user=request.user,
+ new_status=Ticket.CLOSED_STATUS)
f.save()
# Send email to Submitter, Owner, Queue CC
context = safe_template_context(t)
- context.update(
- resolution = t.resolution,
- queue = t.queue,
- )
+ context.update(resolution=t.resolution,
+ queue=t.queue)
messages_sent_to = []
@@ -671,7 +715,7 @@ def mass_update(request):
recipients=t.submitter_email,
sender=t.queue.from_address,
fail_silently=True,
- )
+ )
messages_sent_to.append(t.submitter_email)
for cc in t.ticketcc_set.all():
@@ -682,27 +726,31 @@ def mass_update(request):
recipients=cc.email_address,
sender=t.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:
+ 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',
context,
recipients=t.assigned_to.email,
sender=t.queue.from_address,
fail_silently=True,
- )
+ )
messages_sent_to.append(t.assigned_to.email)
- if t.queue.updated_ticket_cc and t.queue.updated_ticket_cc not in messages_sent_to:
+ if t.queue.updated_ticket_cc and \
+ t.queue.updated_ticket_cc not in messages_sent_to:
send_templated_mail(
'closed_cc',
context,
recipients=t.queue.updated_ticket_cc,
sender=t.queue.from_address,
fail_silently=True,
- )
+ )
elif action == 'delete':
t.delete()
@@ -710,6 +758,7 @@ def mass_update(request):
return HttpResponseRedirect(reverse('helpdesk:list'))
mass_update = staff_member_required(mass_update)
+
def ticket_list(request):
context = {}
@@ -725,7 +774,7 @@ def ticket_list(request):
'sortreverse': False,
'keyword': None,
'search_string': None,
- }
+ }
from_saved_query = False
@@ -745,7 +794,7 @@ def ticket_list(request):
id = None
if id:
- filter = {'queue__slug': queue, 'id': id }
+ filter = {'queue__slug': queue, 'id': id}
else:
try:
query = int(query)
@@ -753,7 +802,7 @@ def ticket_list(request):
query = None
if query:
- filter = {'id': int(query) }
+ filter = {'id': int(query)}
if filter:
try:
@@ -781,13 +830,12 @@ def ticket_list(request):
# Query deserialization failed. (E.g. was a pickled query)
return HttpResponseRedirect(reverse('helpdesk:list'))
- elif not ( 'queue' in request.GET
- or 'assigned_to' in request.GET
- or 'status' in request.GET
- or 'q' in request.GET
- or 'sort' in request.GET
- or 'sortreverse' in request.GET
- ):
+ elif not ('queue' in request.GET or
+ 'assigned_to' in request.GET or
+ 'status' in request.GET or
+ 'q' in request.GET or
+ 'sort' in request.GET or
+ 'sortreverse' in request.GET):
# Fall-back if no querying is being done, force the list to only
# show open/reopened/resolved (not closed) cases sorted by creation
@@ -830,14 +878,14 @@ def ticket_list(request):
if date_to:
query_params['filtering']['created__lte'] = date_to
- ### KEYWORD SEARCHING
+ # KEYWORD SEARCHING
q = request.GET.get('q', None)
if q:
context = dict(context, query=q)
query_params['search_string'] = q
- ### SORTING
+ # SORTING
sort = request.GET.get('sort', None)
if sort not in ('status', 'assigned_to', 'created', 'title', 'queue', 'priority'):
sort = 'created'
@@ -858,11 +906,13 @@ def ticket_list(request):
}
ticket_qs = apply_query(tickets, query_params)
- ticket_paginator = paginator.Paginator(ticket_qs, request.user.usersettings.settings.get('tickets_per_page') or 20)
+ ticket_paginator = paginator.Paginator(
+ ticket_qs,
+ request.user.usersettings.settings.get('tickets_per_page') or 20)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
- page = 1
+ page = 1
try:
tickets = ticket_paginator.page(page)
@@ -871,8 +921,13 @@ def ticket_list(request):
search_message = ''
if 'query' in context and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
- search_message = _('Note: Your keyword search is case sensitive because of your database. This means the search will not be accurate. By switching to a different database system you will gain better searching! For more information, read the Django Documentation on string matching in SQLite.')
-
+ search_message = _(
+ '
Note: Your keyword search is case sensitive '
+ 'because of your database. This means the search will not '
+ 'be accurate. By switching to a different database system you will gain '
+ 'better searching! For more information, read the '
+ ''
+ 'Django Documentation on string matching in SQLite.')
import json
from helpdesk.lib import b64encode
@@ -883,22 +938,20 @@ def ticket_list(request):
querydict = request.GET.copy()
querydict.pop('page', 1)
-
- return render(request, 'helpdesk/ticket_list.html',
- dict(
- context,
- query_string=querydict.urlencode(),
- tickets=tickets,
- user_choices=User.objects.filter(is_active=True,is_staff=True),
- queue_choices=user_queues,
- status_choices=Ticket.STATUS_CHOICES,
- urlsafe_query=urlsafe_query,
- user_saved_queries=user_saved_queries,
- query_params=query_params,
- from_saved_query=from_saved_query,
- saved_query=saved_query,
- search_message=search_message,
- ))
+ return render(request, 'helpdesk/ticket_list.html', dict(
+ context,
+ query_string=querydict.urlencode(),
+ tickets=tickets,
+ user_choices=User.objects.filter(is_active=True, is_staff=True),
+ queue_choices=user_queues,
+ status_choices=Ticket.STATUS_CHOICES,
+ urlsafe_query=urlsafe_query,
+ user_saved_queries=user_saved_queries,
+ query_params=query_params,
+ from_saved_query=from_saved_query,
+ saved_query=saved_query,
+ search_message=search_message,
+ ))
ticket_list = staff_member_required(ticket_list)
@@ -915,12 +968,10 @@ def edit_ticket(request, ticket_id):
else:
form = EditTicketForm(instance=ticket)
- return render(request, template_name='helpdesk/edit_ticket.html',
- context = {
- 'form': form,
- })
+ return render(request, 'helpdesk/edit_ticket.html', {'form': form})
edit_ticket = staff_member_required(edit_ticket)
+
def create_ticket(request):
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_OWNERS:
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
@@ -929,8 +980,10 @@ def create_ticket(request):
if request.method == 'POST':
form = TicketForm(request.POST, request.FILES)
- form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
- form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.get_username()] for u in assignable_users]
+ form.fields['queue'].choices = [('', '--------')] + [
+ (q.id, q.title) for q in Queue.objects.all()]
+ form.fields['assigned_to'].choices = [('', '--------')] + [
+ (u.id, u.get_username()) for u in assignable_users]
if form.is_valid():
ticket = form.save(user=request.user)
if _has_access_to_queue(request.user, ticket.queue):
@@ -945,13 +998,14 @@ def create_ticket(request):
initial_data['queue'] = request.GET['queue']
form = TicketForm(initial=initial_data)
- form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
- form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.get_username()] for u in assignable_users]
+ form.fields['queue'].choices = [('', '--------')] + [
+ (q.id, q.title) for q in Queue.objects.all()]
+ form.fields['assigned_to'].choices = [('', '--------')] + [
+ (u.id, u.get_username()) for u in assignable_users]
if helpdesk_settings.HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO:
form.fields['assigned_to'].widget = forms.HiddenInput()
- return render(request, template_name='helpdesk/create_ticket.html',
- context = {'form': form})
+ return render(request, 'helpdesk/create_ticket.html', {'form': form})
create_ticket = staff_member_required(create_ticket)
@@ -960,7 +1014,7 @@ def raw_details(request, type):
# in the future it needs to be expanded to include other items. All it
# does is return a plain-text representation of an object.
- if not type in ('preset',):
+ if type not in ('preset',):
raise Http404
if type == 'preset' and request.GET.get('id', False):
@@ -987,11 +1041,11 @@ def hold_ticket(request, ticket_id, unhold=False):
title = _('Ticket placed on hold')
f = FollowUp(
- ticket = ticket,
- user = request.user,
- title = title,
- date = timezone.now(),
- public = True,
+ ticket=ticket,
+ user=request.user,
+ title=title,
+ date=timezone.now(),
+ public=True,
)
f.save()
@@ -1007,26 +1061,24 @@ unhold_ticket = staff_member_required(unhold_ticket)
def rss_list(request):
- return render(request, template_name='helpdesk/rss_list.html',
- context = {
- 'queues': Queue.objects.all(),
- })
+ return render(request, 'helpdesk/rss_list.html', {'queues': Queue.objects.all()})
rss_list = staff_member_required(rss_list)
def report_index(request):
number_tickets = Ticket.objects.all().count()
saved_query = request.GET.get('saved_query', None)
- return render(request, template_name='helpdesk/report_index.html',
- context = {
- 'number_tickets': number_tickets,
- 'saved_query': saved_query,
- })
+ return render(request, 'helpdesk/report_index.html', {
+ 'number_tickets': number_tickets,
+ 'saved_query': saved_query,
+ })
report_index = staff_member_required(report_index)
def run_report(request, report):
- if Ticket.objects.all().count() == 0 or report not in ('queuemonth', 'usermonth', 'queuestatus', 'queuepriority', 'userstatus', 'userpriority', 'userqueue', 'daysuntilticketclosedbymonth'):
+ if Ticket.objects.all().count() == 0 or report not in (
+ 'queuemonth', 'usermonth', 'queuestatus', 'queuepriority', 'userstatus',
+ 'userpriority', 'userqueue', 'daysuntilticketclosedbymonth'):
return HttpResponseRedirect(reverse("helpdesk_report_index"))
report_queryset = Ticket.objects.all().select_related().filter(
@@ -1059,7 +1111,8 @@ def run_report(request, report):
# a second table for more complex queries
summarytable2 = defaultdict(int)
- month_name = lambda m: MONTHS_3[m].title()
+ def month_name(m):
+ MONTHS_3[m].title()
first_ticket = Ticket.objects.all().order_by('created')[0]
first_month = first_ticket.created.month
@@ -1191,22 +1244,21 @@ def run_report(request, report):
data.append(summarytable[item, hdr])
table.append([item] + data)
- return render(request, 'helpdesk/report_output.html',
- {
- 'title': title,
- 'charttype': charttype,
- 'data': table,
- 'headings': column_headings,
- 'from_saved_query': from_saved_query,
- 'saved_query': saved_query,
- })
+ return render(request, 'helpdesk/report_output.html', {
+ 'title': title,
+ 'charttype': charttype,
+ 'data': table,
+ 'headings': column_headings,
+ 'from_saved_query': from_saved_query,
+ 'saved_query': saved_query,
+ })
run_report = staff_member_required(run_report)
def save_query(request):
title = request.POST.get('title', None)
shared = request.POST.get('shared', False)
- if shared == 'on': # django only translates '1', 'true', 't' into True
+ if shared == 'on': # django only translates '1', 'true', 't' into True
shared = True
query_encoded = request.POST.get('query_encoded', None)
@@ -1227,10 +1279,7 @@ def delete_saved_query(request, id):
query.delete()
return HttpResponseRedirect(reverse('helpdesk:list'))
else:
- return render(request, template_name='helpdesk/confirm_delete_saved_query.html',
- context = {
- 'query': query,
- })
+ return render(request, 'helpdesk/confirm_delete_saved_query.html', {'query': query})
delete_saved_query = staff_member_required(delete_saved_query)
@@ -1244,18 +1293,14 @@ def user_settings(request):
else:
form = UserSettingsForm(s.settings)
- return render(request, template_name='helpdesk/user_settings.html',
- context = {
- 'form': form,
- })
+ return render(request, 'helpdesk/user_settings.html', {'form': form})
user_settings = staff_member_required(user_settings)
def email_ignore(request):
- return render(request, template_name='helpdesk/email_ignore_list.html',
- context = {
- 'ignore_list': IgnoreEmail.objects.all(),
- })
+ return render(request, 'helpdesk/email_ignore_list.html', {
+ 'ignore_list': IgnoreEmail.objects.all(),
+ })
email_ignore = superuser_required(email_ignore)
@@ -1263,15 +1308,12 @@ def email_ignore_add(request):
if request.method == 'POST':
form = EmailIgnoreForm(request.POST)
if form.is_valid():
- ignore = form.save()
+ form.save()
return HttpResponseRedirect(reverse('helpdesk:email_ignore'))
else:
form = EmailIgnoreForm(request.GET)
- return render(request, template_name='helpdesk/email_ignore_add.html',
- context = {
- 'form': form,
- })
+ return render(request, 'helpdesk/email_ignore_add.html', {'form': form})
email_ignore_add = superuser_required(email_ignore_add)
@@ -1281,25 +1323,23 @@ def email_ignore_del(request, id):
ignore.delete()
return HttpResponseRedirect(reverse('helpdesk:email_ignore'))
else:
- return render(request, template_name='helpdesk/email_ignore_del.html',
- context = {
- 'ignore': ignore,
- })
+ return render(request, 'helpdesk/email_ignore_del.html', {'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)
if not _has_access_to_queue(request.user, ticket.queue):
raise PermissionDenied()
copies_to = ticket.ticketcc_set.all()
- return render(request, template_name='helpdesk/ticket_cc_list.html',
- context = {
- 'copies_to': copies_to,
- 'ticket': ticket,
- })
+ return render(request, 'helpdesk/ticket_cc_list.html', {
+ '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 not _has_access_to_queue(request.user, ticket.queue):
@@ -1311,28 +1351,28 @@ def ticket_cc_add(request, ticket_id):
ticketcc = form.save(commit=False)
ticketcc.ticket = ticket
ticketcc.save()
- return HttpResponseRedirect(reverse('helpdesk:ticket_cc', kwargs={'ticket_id': ticket.id}))
+ return HttpResponseRedirect(reverse('helpdesk:ticket_cc',
+ kwargs={'ticket_id': ticket.id}))
else:
form = TicketCCForm()
- return render(request, template_name='helpdesk/ticket_cc_add.html',
- context = {
- 'ticket': ticket,
- 'form': form,
- })
+ return render(request, 'helpdesk/ticket_cc_add.html', {
+ '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.method == 'POST':
cc.delete()
- return HttpResponseRedirect(reverse('helpdesk:ticket_cc', kwargs={'ticket_id': cc.ticket.id}))
- return render(request, template_name='helpdesk/ticket_cc_del.html',
- context = {
- 'cc': cc,
- })
+ return HttpResponseRedirect(reverse('helpdesk:ticket_cc',
+ kwargs={'ticket_id': cc.ticket.id}))
+ return render(request, 'helpdesk/ticket_cc_del.html', {'cc': cc})
ticket_cc_del = staff_member_required(ticket_cc_del)
+
def ticket_dependency_add(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
if not _has_access_to_queue(request.user, ticket.queue):
@@ -1347,24 +1387,22 @@ def ticket_dependency_add(request, ticket_id):
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
else:
form = TicketDependencyForm()
- return render(request, template_name='helpdesk/ticket_dependency_add.html',
- context = {
- 'ticket': ticket,
- 'form': form,
- })
+ return render(request, 'helpdesk/ticket_dependency_add.html', {
+ 'ticket': ticket,
+ 'form': form,
+ })
ticket_dependency_add = staff_member_required(ticket_dependency_add)
+
def ticket_dependency_del(request, ticket_id, dependency_id):
dependency = get_object_or_404(TicketDependency, ticket__id=ticket_id, id=dependency_id)
if request.method == 'POST':
dependency.delete()
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket_id]))
- return render(request, template_name='helpdesk/ticket_dependency_del.html',
- context = {
- 'dependency': dependency,
- })
+ return render(request, 'helpdesk/ticket_dependency_del.html', {'dependency': dependency})
ticket_dependency_del = staff_member_required(ticket_dependency_del)
+
def attachment_del(request, ticket_id, attachment_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
if not _has_access_to_queue(request.user, ticket.queue):
@@ -1374,6 +1412,7 @@ def attachment_del(request, ticket_id, attachment_id):
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket_id]))
attachment_del = staff_member_required(attachment_del)
+
def calc_average_nbr_days_until_ticket_resolved(Tickets):
nbr_closed_tickets = len(Tickets)
days_per_ticket = 0
@@ -1392,9 +1431,10 @@ def calc_average_nbr_days_until_ticket_resolved(Tickets):
return mean_per_ticket
+
def calc_basic_ticket_stats(Tickets):
# all not closed tickets (open, reopened, resolved,) - independent of user
- all_open_tickets = Tickets.exclude(status = Ticket.CLOSED_STATUS)
+ all_open_tickets = Tickets.exclude(status=Ticket.CLOSED_STATUS)
today = datetime.today()
date_30 = date_rel_to_today(today, 30)
@@ -1403,57 +1443,66 @@ def calc_basic_ticket_stats(Tickets):
date_60_str = date_60.strftime('%Y-%m-%d')
# > 0 & <= 30
- ota_le_30 = all_open_tickets.filter(created__gte = date_30_str)
+ ota_le_30 = all_open_tickets.filter(created__gte=date_30_str)
N_ota_le_30 = len(ota_le_30)
# >= 30 & <= 60
- ota_le_60_ge_30 = all_open_tickets.filter(created__gte = date_60_str, created__lte = date_30_str)
+ ota_le_60_ge_30 = all_open_tickets.filter(created__gte=date_60_str, created__lte=date_30_str)
N_ota_le_60_ge_30 = len(ota_le_60_ge_30)
# >= 60
- ota_ge_60 = all_open_tickets.filter(created__lte = date_60_str)
+ ota_ge_60 = all_open_tickets.filter(created__lte=date_60_str)
N_ota_ge_60 = len(ota_ge_60)
# (O)pen (T)icket (S)tats
ots = list()
# label, number entries, color, sort_string
- ots.append(['< 30 days', N_ota_le_30, get_color_for_nbr_days(N_ota_le_30), sort_string(date_30_str, ''), ])
- ots.append(['30 - 60 days', N_ota_le_60_ge_30, get_color_for_nbr_days(N_ota_le_60_ge_30), sort_string(date_60_str, date_30_str), ])
- ots.append(['> 60 days', N_ota_ge_60, get_color_for_nbr_days(N_ota_ge_60), sort_string('', date_60_str), ])
+ ots.append(['< 30 days', N_ota_le_30, get_color_for_nbr_days(N_ota_le_30),
+ sort_string(date_30_str, ''), ])
+ ots.append(['30 - 60 days', N_ota_le_60_ge_30, get_color_for_nbr_days(N_ota_le_60_ge_30),
+ sort_string(date_60_str, date_30_str), ])
+ ots.append(['> 60 days', N_ota_ge_60, get_color_for_nbr_days(N_ota_ge_60),
+ sort_string('', date_60_str), ])
# all closed tickets - independent of user.
- all_closed_tickets = Tickets.filter(status = Ticket.CLOSED_STATUS)
- average_nbr_days_until_ticket_closed = calc_average_nbr_days_until_ticket_resolved(all_closed_tickets)
+ all_closed_tickets = Tickets.filter(status=Ticket.CLOSED_STATUS)
+ average_nbr_days_until_ticket_closed = \
+ calc_average_nbr_days_until_ticket_resolved(all_closed_tickets)
# all closed tickets that were opened in the last 60 days.
- all_closed_last_60_days = all_closed_tickets.filter(created__gte = date_60_str)
- average_nbr_days_until_ticket_closed_last_60_days = calc_average_nbr_days_until_ticket_resolved(all_closed_last_60_days)
+ all_closed_last_60_days = all_closed_tickets.filter(created__gte=date_60_str)
+ average_nbr_days_until_ticket_closed_last_60_days = \
+ calc_average_nbr_days_until_ticket_resolved(all_closed_last_60_days)
# put together basic stats
- basic_ticket_stats = { 'average_nbr_days_until_ticket_closed': average_nbr_days_until_ticket_closed,
- 'average_nbr_days_until_ticket_closed_last_60_days': average_nbr_days_until_ticket_closed_last_60_days,
- 'open_ticket_stats': ots, }
+ basic_ticket_stats = {
+ 'average_nbr_days_until_ticket_closed': average_nbr_days_until_ticket_closed,
+ 'average_nbr_days_until_ticket_closed_last_60_days':
+ average_nbr_days_until_ticket_closed_last_60_days,
+ 'open_ticket_stats': ots,
+ }
return basic_ticket_stats
+
def get_color_for_nbr_days(nbr_days):
- ''' '''
if nbr_days < 5:
color_string = 'green'
- elif nbr_days >= 5 and nbr_days < 10:
+ elif nbr_days < 10:
color_string = 'orange'
- else: # more than 10 days
+ else: # more than 10 days
color_string = 'red'
return color_string
+
def days_since_created(today, ticket):
return (today - ticket.created).days
+
def date_rel_to_today(today, offset):
- return today - timedelta(days = offset)
+ return today - timedelta(days=offset)
+
def sort_string(begin, end):
- return 'sort=created&date_from=%s&date_to=%s&status=%s&status=%s&status=%s' %(begin, end, Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS, Ticket.RESOLVED_STATUS)
-
-
-
+ return 'sort=created&date_from=%s&date_to=%s&status=%s&status=%s&status=%s' % (
+ begin, end, Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS, Ticket.RESOLVED_STATUS)
diff --git a/quicktest.py b/quicktest.py
index c3170bc5..479dbadb 100644
--- a/quicktest.py
+++ b/quicktest.py
@@ -38,6 +38,27 @@ class QuickDjangoTest(object):
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
+ TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': (
+ # Defaults:
+ "django.contrib.auth.context_processors.auth",
+ "django.template.context_processors.debug",
+ "django.template.context_processors.i18n",
+ "django.template.context_processors.media",
+ "django.template.context_processors.static",
+ "django.template.context_processors.tz",
+ "django.contrib.messages.context_processors.messages",
+ # Our extra:
+ "django.template.context_processors.request",
+ ),
+ },
+ },
+ ]
+
def __init__(self, *args, **kwargs):
self.apps = args
# Get the version of the test suite
@@ -61,11 +82,11 @@ class QuickDjangoTest(object):
"""
Fire up the Django test suite from before version 1.2
"""
- settings.configure(DEBUG = True,
- DATABASE_ENGINE = 'sqlite3',
- DATABASE_NAME = os.path.join(self.DIRNAME, 'database.db'),
- INSTALLED_APPS = self.INSTALLED_APPS + self.apps
- )
+ settings.configure(DEBUG=True,
+ DATABASE_ENGINE='sqlite3',
+ DATABASE_NAME=os.path.join(self.DIRNAME, 'database.db'),
+ INSTALLED_APPS=self.INSTALLED_APPS + self.apps
+ )
from django.test.simple import run_tests
failures = run_tests(self.apps, verbosity=1)
if failures:
@@ -77,8 +98,8 @@ class QuickDjangoTest(object):
"""
settings.configure(
- DEBUG = True,
- DATABASES = {
+ DEBUG=True,
+ DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(self.DIRNAME, 'database.db'),
@@ -88,15 +109,16 @@ class QuickDjangoTest(object):
'PORT': '',
}
},
- INSTALLED_APPS = self.INSTALLED_APPS + self.apps,
- MIDDLEWARE_CLASSES = self.MIDDLEWARE_CLASSES,
- ROOT_URLCONF = 'helpdesk.tests.urls',
- STATIC_URL = '/static/'
+ INSTALLED_APPS=self.INSTALLED_APPS + self.apps,
+ MIDDLEWARE_CLASSES=self.MIDDLEWARE_CLASSES,
+ ROOT_URLCONF='helpdesk.tests.urls',
+ STATIC_URL='/static/',
+ TEMPLATES=self.TEMPLATES
)
# compatibility with django 1.8 downwards
# see: http://stackoverflow.com/questions/3841725/how-to-launch-tests-for-django-reusable-app
-
+
try:
# Django >= 1.6
from django.test.runner import DiscoverRunner
@@ -129,4 +151,3 @@ if __name__ == '__main__':
parser.add_argument('apps', nargs='+', type=str)
args = parser.parse_args()
QuickDjangoTest(*args.apps)
-