* Added i18n hooks, eg _() and {% trans %} tags around all helpdesk-generated

text to assist with future translation efforts. I've no doubt missed a few.
  Also we don't have a "Change Language" view in here, unsure if this should
  be a helpdesk function or a function of the parent project.
* Updated svn:ignore to ignore .pyc files
* Added new function to replace cursor.dictfetchall() which is available in
  psycopg1 but not psycopg2. New function should work across other database
  systems, but is untested.
This commit is contained in:
Ross Poulton 2008-05-07 09:04:18 +00:00
parent ad05df8dda
commit dfb821336e
25 changed files with 364 additions and 335 deletions

2
api.py
View File

@ -11,7 +11,7 @@ The API documentation can be accessed by visiting http://helpdesk/api/help/
through templates/helpdesk/api_help.html.
"""
from datetime import datetime
import simplejson
from django.utils import simplejson
from django.contrib.auth.models import User
from django.contrib.auth import authenticate

View File

@ -2,6 +2,7 @@ from django.contrib.auth.models import User
from django.contrib.syndication.feeds import Feed
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.utils.translation import ugettext as _
from models import Ticket, FollowUp, Queue
@ -22,21 +23,21 @@ class OpenTicketsByUser(Feed):
def title(self, obj):
if obj['queue']:
return "Helpdesk: Open Tickets in queue %s for %s" % (obj['queue'].title, obj['user'].username)
return _("Helpdesk: Open Tickets in queue %(queue)s for %(username)s") % {'queue': obj['queue'].title, 'username': obj['user'].username}
else:
return "Helpdesk: Open Tickets for %s" % obj['user'].username
return _("Helpdesk: Open Tickets for %(username)s") % {'username': obj['user'].username}
def description(self, obj):
if obj['queue']:
return "Open and Reopened Tickets in queue %s for %s" % (obj['queue'].title, obj['user'].username)
return _("Open and Reopened Tickets in queue %(queue)s for %(username)s") % {'queue': obj['queue'].title, 'username': obj['user'].username}
else:
return "Open and Reopened Tickets for %s" % obj['user'].username
return _("Open and Reopened Tickets for %(username)s") % {'username': obj['user'].username}
def link(self, obj):
if obj['queue']:
return '%s?assigned_to=%s&queue=%s' % (reverse('helpdesk_list'), obj['user'].id, obj['queue'].id)
return u'%s?assigned_to=%s&queue=%s' % (reverse('helpdesk_list'), obj['user'].id, obj['queue'].id)
else:
return '%s?assigned_to=%s' % (reverse('helpdesk_list'), obj['user'].id)
return u'%s?assigned_to=%s' % (reverse('helpdesk_list'), obj['user'].id)
def items(self, obj):
if obj['queue']:
@ -51,15 +52,15 @@ class OpenTicketsByUser(Feed):
if item.assigned_to:
return item.assigned_to.username
else:
return "Unassigned"
return _('Unassigned')
class UnassignedTickets(Feed):
title_template = 'helpdesk/rss/ticket_title.html'
description_template = 'helpdesk/rss/ticket_description.html'
title = "Helpdesk: Unassigned Tickets"
description = "Unassigned Open and Reopened tickets"
title = _('Helpdesk: Unassigned Tickets')
description = _('Unassigned Open and Reopened tickets')
link = ''#%s?assigned_to=' % reverse('helpdesk_list')
def items(self, obj):
@ -73,15 +74,15 @@ class UnassignedTickets(Feed):
if item.assigned_to:
return item.assigned_to.username
else:
return "Unassigned"
return _('Unassigned')
class RecentFollowUps(Feed):
title_template = 'helpdesk/rss/recent_activity_title.html'
description_template = 'helpdesk/rss/recent_activity_description.html'
title = "Helpdesk: Recent Followups"
description = "Recent FollowUps, such as e-mail replies, comments, attachments and resolutions"
title = _('Helpdesk: Recent Followups')
description = _('Recent FollowUps, such as e-mail replies, comments, attachments and resolutions')
link = '/tickets/' # reverse('helpdesk_list')
def items(self):
@ -98,10 +99,10 @@ class OpenTicketsByQueue(Feed):
return Queue.objects.get(slug__exact=bits[0])
def title(self, obj):
return "Helpdesk: Open Tickets in queue %s" % obj.title
return _('Helpdesk: Open Tickets in queue %(queue)s') % {'queue': obj.title}
def description(self, obj):
return "Open and Reopened Tickets in queue %s" % obj.title
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)
@ -116,7 +117,7 @@ class OpenTicketsByQueue(Feed):
if item.assigned_to:
return item.assigned_to.username
else:
return "Unassigned"
return _('Unassigned')
feed_setup = {

View File

@ -11,30 +11,31 @@ from django import newforms as forms
from helpdesk.models import Ticket, Queue, FollowUp
from django.contrib.auth.models import User
from datetime import datetime
from django.utils.translation import ugettext as _
class TicketForm(forms.Form):
queue = forms.ChoiceField(label=u'Queue', required=True, choices=())
queue = forms.ChoiceField(label=_('Queue'), required=True, choices=())
title = forms.CharField(max_length=100, required=True,
widget=forms.TextInput(),
label=u'Summary of the problem')
label=_('Summary of the problem'))
submitter_email = forms.EmailField(required=False,
label=u'Submitter E-Mail Address',
help_text=u'This e-mail address will receive copies of all public updates to this ticket.')
label=_('Submitter E-Mail Address'),
help_text=_('This e-mail address will receive copies of all public updates to this ticket.'))
body = forms.CharField(widget=forms.Textarea(),
label=u'Description of Issue', required=True)
label=_('Description of Issue'), required=True)
assigned_to = forms.ChoiceField(choices=(), required=False,
label=u'Case owner',
help_text=u'If you select an owner other than yourself, they\'ll be e-mailed details of this ticket immediately.')
label=_('Case owner'),
help_text=_('If you select an owner other than yourself, they\'ll be e-mailed details of this ticket immediately.'))
priority = forms.ChoiceField(choices=Ticket.PRIORITY_CHOICES,
required=False,
initial='3',
label=u'Priority',
help_text=u'Please select a priority carefully. If unsure, leave it as \'3\'.')
label=_('Priority'),
help_text=_('Please select a priority carefully. If unsure, leave it as \'3\'.'))
def save(self, user):
"""
@ -61,14 +62,14 @@ class TicketForm(forms.Form):
t.save()
f = FollowUp( ticket = t,
title = 'Ticket Opened',
title = _('Ticket Opened'),
date = datetime.now(),
public = True,
comment = self.cleaned_data['body'],
user = user,
)
if self.cleaned_data['assigned_to']:
f.title = 'Ticket Opened & Assigned to %s' % t.get_assigned_to
f.title = _('Ticket Opened & Assigned to %(name)s') % {'name': t.get_assigned_to}
f.save()
@ -94,25 +95,25 @@ class TicketForm(forms.Form):
return t
class PublicTicketForm(forms.Form):
queue = forms.ChoiceField(label=u'Queue', required=True, choices=())
queue = forms.ChoiceField(label=_('Queue'), required=True, choices=())
title = forms.CharField(max_length=100, required=True,
widget=forms.TextInput(),
label=u'Summary of your query')
label=_('Summary of your query'))
submitter_email = forms.EmailField(required=True,
label=u'Your E-Mail Address',
help_text=u'We will e-mail you when your ticket is updated.')
label=_('Your E-Mail Address'),
help_text=_('We will e-mail you when your ticket is updated.'))
body = forms.CharField(widget=forms.Textarea(),
label=u'Description of your issue', required=True,
help_text=u'Please be as descriptive as possible, including any details we may need to address your query.')
label=_('Description of your issue'), required=True,
help_text=_('Please be as descriptive as possible, including any details we may need to address your query.'))
priority = forms.ChoiceField(choices=Ticket.PRIORITY_CHOICES,
required=True,
initial='3',
label=u'Urgency',
help_text=u'Please select a priority carefully.')
label=_('Urgency'),
help_text=_('Please select a priority carefully.'))
def save(self):
"""
@ -133,7 +134,7 @@ class PublicTicketForm(forms.Form):
t.save()
f = FollowUp( ticket = t,
title = 'Ticket Opened Via Web',
title = _('Ticket Opened Via Web'),
date = datetime.now(),
public = True,
comment = self.cleaned_data['body'],

17
lib.py
View File

@ -184,3 +184,20 @@ def bar_chart(data):
chart_url += '&chxl=0:|%s|1:|0|%s' % ('|'.join(column_headings), max) # Axis Label Text
return chart_url
def query_to_dict(results, descriptions):
""" Replacement method for cursor.dictfetchall() as that method no longer
exists in psycopg2, and I'm guessing in other backends too.
Converts the results of a raw SQL query into a list of dictionaries, suitable
for use in templates etc. """
output = []
for data in results:
row = {}
i = 0
for column in descriptions:
row[column[0]] = data[i]
i += 1
output.append(row)
return output

139
models.py
View File

@ -13,6 +13,7 @@ from django.contrib.auth.models import User
from django.db import models
from django.conf import settings
from django.dispatch import dispatcher
from django.utils.translation import ugettext_lazy as _
class Queue(models.Model):
"""
@ -25,28 +26,28 @@ class Queue(models.Model):
TODO: Add e-mail inboxes (either using piped e-mail or IMAP/POP3) so we
can automatically get tickets via e-mail.
"""
title = models.CharField(max_length=100)
slug = models.SlugField(help_text='This slug is used when building ticket ID\'s. Once set, try not to change it or e-mailing may get messy.')
email_address = models.EmailField(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 shoul be the e-mail address for that mailbox.')
escalate_days = models.IntegerField(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.')
title = models.CharField(_('Title'), max_length=100)
slug = models.SlugField(_('Slug'), help_text=_('This slug is used when building ticket ID\'s. Once set, 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.'))
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.'))
def _from_address(self):
if not self.email_address:
return 'NO QUEUE EMAIL ADDRESS DEFINED <%s>' % settings.DEFAULT_FROM_EMAIL
return u'NO QUEUE EMAIL ADDRESS DEFINED <%s>' % settings.DEFAULT_FROM_EMAIL
else:
return '%s <%s>' % (self.title, self.email_address)
return u'%s <%s>' % (self.title, self.email_address)
from_address = property(_from_address)
new_ticket_cc = models.EmailField(blank=True, null=True, help_text='If an e-mail address is entered here, then it will receive notification of all new tickets created for this queue')
updated_ticket_cc = models.EmailField(blank=True, null=True, 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')
new_ticket_cc = models.EmailField(_('New Ticket CC Address'), blank=True, null=True, help_text=_('If an e-mail address is entered here, then it will receive notification of all new tickets created for this queue'))
updated_ticket_cc = models.EmailField(_('Updated Ticket CC Address'), blank=True, null=True, 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'))
email_box_type = models.CharField(max_length=5, choices=(('pop3', 'POP 3'),('imap', 'IMAP')), blank=True, null=True, help_text='E-Mail Server Type - Both POP3 and IMAP are supported. Select your email server type here.')
email_box_host = models.CharField(max_length=200, blank=True, null=True, help_text='Your e-mail server address - either the domain name or IP address. May be "localhost".')
email_box_port = models.IntegerField(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.')
email_box_user = models.CharField(max_length=200, blank=True, null=True, help_text='Username for accessing this mailbox.')
email_box_pass = models.CharField(max_length=200, blank=True, null=True, help_text='Password for the above username')
email_box_imap_folder = models.CharField(max_length=100, 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.')
email_box_interval = models.IntegerField(help_text='How often do you wish to check this mailbox? (in Minutes)', blank=True, null=True, default='5')
email_box_type = models.CharField(_('E-Mail Box Type'), max_length=5, choices=(('pop3', _('POP 3')),('imap', _('IMAP'))), blank=True, null=True, help_text=_('E-Mail server type for creating tickets automatically from a mailbox - both POP3 and IMAP are supported.'))
email_box_host = models.CharField(_('E-Mail Hostname'), max_length=200, blank=True, null=True, help_text=_('Your e-mail server address - either the domain name or 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.'))
email_box_user = models.CharField(_('E-Mail Username'), max_length=200, blank=True, null=True, help_text=_('Username for accessing this mailbox.'))
email_box_pass = models.CharField(_('E-Mail Password'), max_length=200, blank=True, null=True, help_text=_('Password for the above username'))
email_box_imap_folder = models.CharField(_('IMAP Folder'), max_length=100, 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.'))
email_box_interval = models.IntegerField(_('E-Mail Check Interval'), help_text=_('How often do you wish to check this mailbox? (in Minutes)'), blank=True, null=True, default='5')
email_box_last_check = models.DateTimeField(blank=True, null=True, editable=False) # Updated by the auto-pop3-and-imap-checker
def __unicode__(self):
@ -87,34 +88,34 @@ class Ticket(models.Model):
CLOSED_STATUS = 4
STATUS_CHOICES = (
(OPEN_STATUS, 'Open'),
(REOPENED_STATUS, 'Reopened'),
(RESOLVED_STATUS, 'Resolved'),
(CLOSED_STATUS, 'Closed'),
(OPEN_STATUS, _('Open')),
(REOPENED_STATUS, _('Reopened')),
(RESOLVED_STATUS, _('Resolved')),
(CLOSED_STATUS, _('Closed')),
)
PRIORITY_CHOICES = (
(1, '1. Critical'),
(2, '2. High'),
(3, '3. Normal'),
(4, '4. Low'),
(5, '5. Very Low'),
(1, _('1. Critical')),
(2, _('2. High')),
(3, _('3. Normal')),
(4, _('4. Low')),
(5, _('5. Very Low')),
)
title = models.CharField(max_length=200)
title = models.CharField(_('Title'), max_length=200)
queue = models.ForeignKey(Queue)
created = models.DateTimeField(blank=True)
modified = models.DateTimeField(blank=True)
submitter_email = models.EmailField(blank=True, null=True, help_text='The submitter will receive an email for all public follow-ups left for this task.')
created = models.DateTimeField(_('Created'), blank=True)
modified = models.DateTimeField(_('Modified'), blank=True)
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.'))
assigned_to = models.ForeignKey(User, related_name='assigned_to', blank=True, null=True)
status = models.IntegerField(choices=STATUS_CHOICES, default=OPEN_STATUS)
status = models.IntegerField(_('Status'), choices=STATUS_CHOICES, default=OPEN_STATUS)
on_hold = models.BooleanField(blank=True, null=True)
on_hold = models.BooleanField(_('On Hold'), blank=True, null=True)
description = models.TextField(blank=True, null=True)
resolution = models.TextField(blank=True, null=True)
description = models.TextField(_('Description'), blank=True, null=True)
resolution = models.TextField(_('Resolution'), blank=True, null=True)
priority = models.IntegerField(choices=PRIORITY_CHOICES, default=3, blank=3)
priority = models.IntegerField(_('Priority'), choices=PRIORITY_CHOICES, default=3, blank=3)
last_escalation = models.DateTimeField(blank=True, null=True, editable=False)
@ -123,7 +124,7 @@ class Ticket(models.Model):
ticket has no owner, or the users name if it's assigned. If the user
has a full name configured, we use that, otherwise their username. """
if not self.assigned_to:
return 'Unassigned'
return _('Unassigned')
else:
if self.assigned_to.get_full_name():
return self.assigned_to.get_full_name()
@ -135,36 +136,36 @@ 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-mails. """
return "[%s]" % (self.ticket_for_url)
return u"[%s]" % (self.ticket_for_url)
ticket = property(_get_ticket)
def _get_ticket_for_url(self):
return "%s-%s" % (self.queue.slug, self.id)
return u"%s-%s" % (self.queue.slug, self.id)
ticket_for_url = property(_get_ticket_for_url)
def _get_priority_img(self):
from django.conf import settings
return "%s/helpdesk/priorities/priority%s.png" % (settings.MEDIA_URL, self.priority)
return u"%s/helpdesk/priorities/priority%s.png" % (settings.MEDIA_URL, self.priority)
get_priority_img = property(_get_priority_img)
def _get_status(self):
held_msg = ''
if self.on_hold: held_msg = ' - On Hold'
return '%s%s' % (self.get_status_display(), held_msg)
if self.on_hold: held_msg = _(' - On Hold')
return u'%s%s' % (self.get_status_display(), held_msg)
get_status = property(_get_status)
def _get_ticket_url(self):
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
site = Site.objects.get_current()
return "http://%s%s?ticket=%s&email=%s" % (site.domain, reverse('helpdesk_public_view'), self.ticket_for_url, self.submitter_email)
return u"http://%s%s?ticket=%s&email=%s" % (site.domain, reverse('helpdesk_public_view'), self.ticket_for_url, self.submitter_email)
ticket_url = property(_get_ticket_url)
def _get_staff_url(self):
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
site = Site.objects.get_current()
return "http://%s%s" % (site.domain, reverse('helpdesk_view', args=[self.id]))
return u"http://%s%s" % (site.domain, reverse('helpdesk_view', args=[self.id]))
staff_url = property(_get_staff_url)
class Admin:
@ -213,13 +214,13 @@ class FollowUp(models.Model):
although all staff can see them.
"""
ticket = models.ForeignKey(Ticket)
date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=200, blank=True, null=True)
comment = models.TextField(blank=True, null=True)
public = models.BooleanField(blank=True, null=True)
date = models.DateTimeField(_('Date'), auto_now_add=True)
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, null=True)
user = models.ForeignKey(User, blank=True, null=True)
new_status = models.IntegerField(choices=Ticket.STATUS_CHOICES, blank=True, null=True)
new_status = models.IntegerField(_('New Status'), choices=Ticket.STATUS_CHOICES, blank=True, null=True)
objects = FollowUpManager()
@ -233,7 +234,7 @@ class FollowUp(models.Model):
return u'%s' % self.title
def get_absolute_url(self):
return "%s#followup%s" % (self.ticket.get_absolute_url(), self.id)
return u"%s#followup%s" % (self.ticket.get_absolute_url(), self.id)
def save(self):
@ -247,18 +248,18 @@ class TicketChange(models.Model):
etc) are tracked here for display purposes.
"""
followup = models.ForeignKey(FollowUp, edit_inline=models.TABULAR)
field = models.CharField(max_length=100, core=True)
old_value = models.TextField(blank=True, null=True, core=True)
new_value = models.TextField(blank=True, null=True, core=True)
field = models.CharField(_('Field'), max_length=100, core=True)
old_value = models.TextField(_('Old Value'), blank=True, null=True, core=True)
new_value = models.TextField(_('New Value'), blank=True, null=True, core=True)
def __unicode__(self):
str = u'%s ' % field
if not new_value:
str += 'removed'
str += _('removed')
elif not old_value:
str += 'set to %s' % new_value
str += _('set to %s' % new_value)
else:
str += 'changed from "%s" to "%s"' % (old_value, new_value)
str += _('changed from "%s" to "%s"' % (old_value, new_value))
return str
@ -290,14 +291,14 @@ class DynamicFileField(models.FileField):
class Attachment(models.Model):
followup = models.ForeignKey(FollowUp, edit_inline=models.TABULAR)
file = DynamicFileField(upload_to='helpdesk/attachments', core=True)
filename = models.CharField(max_length=100)
mime_type = models.CharField(max_length=30)
size = models.IntegerField(help_text='Size of this file in bytes')
file = DynamicFileField(_('File'), upload_to='helpdesk/attachments', core=True)
filename = models.CharField(_('Filename'), max_length=100)
mime_type = models.CharField(_('MIME Type'), max_length=30)
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 """
return 'helpdesk/attachments/%s/%s' % (self.followup.ticket.ticket_for_url, self.followup.id)
return u'helpdesk/attachments/%s/%s' % (self.followup.ticket.ticket_for_url, self.followup.id)
def __unicode__(self):
return u'%s' % self.filename
@ -316,9 +317,9 @@ 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."""
queues = models.ManyToManyField(Queue, blank=True, null=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.')
name = models.CharField(max_length=100, help_text='Only used to assist users with selecting a reply - not shown to the user.')
body = models.TextField(help_text='Context available: {{ ticket }} - ticket object (eg {{ ticket.title }}); {{ queue }} - The queue; and {{ user }} - the current user.')
queues = models.ManyToManyField(Queue, blank=True, null=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.'))
name = models.CharField(_('Name'), max_length=100, help_text=_('Only used to assist users with selecting a reply - not 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 Admin:
list_display = ('name',)
@ -330,11 +331,11 @@ class PreSetReply(models.Model):
return u'%s' % self.name
class EscalationExclusion(models.Model):
queues = models.ManyToManyField(Queue, blank=True, null=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.')
queues = models.ManyToManyField(Queue, blank=True, null=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.'))
name = models.CharField(max_length=100)
name = models.CharField(_('Name'), max_length=100)
date = models.DateField(help_text='Date on which escalation should not happen')
date = models.DateField(_('Date'), help_text=_('Date on which escalation should not happen'))
class Admin:
pass
@ -348,12 +349,12 @@ class EmailTemplate(models.Model):
them in the database.
"""
template_name = models.CharField(max_length=100, unique=True)
template_name = models.CharField(_('Template Name'), max_length=100, unique=True)
subject = models.CharField(max_length=100, help_text=u'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.')
heading = models.CharField(max_length=100, help_text=u'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.')
plain_text = models.TextField(help_text=u'The context available to you includes {{ ticket }}, {{ queue }}, and depending on the time of the call: {{ resolution }} or {{ comment }}.')
html = models.TextField(help_text=u'The same context is available here as in plain_text, above.')
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.'))
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.'))
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 }}.'))
html = models.TextField(_('HTML'), help_text=_('The same context is available here as in plain_text, above.'))
class Admin:
pass

0
scripts/__init__.py Normal file
View File

View File

@ -8,10 +8,13 @@ scripts/escalate_tickets.py - Easy way to escalate tickets based on their age,
designed to be run from Cron or similar.
"""
from datetime import datetime, timedelta, date
import sys, getopt
from django.db.models import Q
from django.utils.translation import ugettext as _
from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange
from helpdesk.lib import send_templated_mail
import sys, getopt
def escalate_tickets(queues, verbose):
""" Only include queues with escalation configured """
@ -64,13 +67,13 @@ def escalate_tickets(queues, verbose):
title = 'Ticket Escalated',
date=datetime.now(),
public=True,
comment='Ticket escalated after %s days' % q.escalate_days,
comment=_('Ticket escalated after %s days' % q.escalate_days),
)
f.save()
tc = TicketChange(
followup = f,
field = 'Priority',
field = _('Priority'),
old_value = t.priority + 1,
new_value = t.priority,
)

View File

@ -24,53 +24,57 @@ def process_email():
if (q.email_box_last_check + timedelta(minutes=q.email_box_interval)) > datetime.now():
continue
print "Processing: %s" % q
if q.email_box_type == 'pop3':
server = poplib.POP3(q.email_box_host)
server.getwelcome()
server.user(q.email_box_user)
server.pass_(q.email_box_pass)
messagesInfo = server.list()[1]
for msg in messagesInfo:
msgNum = msg.split(" ")[0]
msgSize = msg.split(" ")[1]
full_message = "\n".join(server.retr(msgNum)[1])
ticket_from_message(message=full_message, queue=q)
server.dele(msgNum)
server.quit()
elif q.email_box_type == 'imap':
if not q.email_box_port: q.email_box_port = 143
server = imaplib.IMAP4(q.email_box_host, q.email_box_port)
server.login(q.email_box_user, q.email_box_pass)
server.select(q.email_box_imap_folder)
status, data = server.search(None, 'ALL')
for num in data[0].split():
status, data = server.fetch(num, '(RFC822)')
ticket_from_message(message=data[0][1], queue=q)
server.store(num, '+FLAGS', '\\Deleted')
server.expunge()
server.close()
server.logout()
process_queue(q)
q.email_box_last_check = datetime.now()
q.save()
def process_queue(q):
print "Processing: %s" % q
if q.email_box_type == 'pop3':
server = poplib.POP3(q.email_box_host)
server.getwelcome()
server.user(q.email_box_user)
server.pass_(q.email_box_pass)
messagesInfo = server.list()[1]
for msg in messagesInfo:
msgNum = msg.split(" ")[0]
msgSize = msg.split(" ")[1]
full_message = "\n".join(server.retr(msgNum)[1])
ticket_from_message(message=full_message, queue=q)
server.dele(msgNum)
server.quit()
elif q.email_box_type == 'imap':
if not q.email_box_port: q.email_box_port = 143
server = imaplib.IMAP4(q.email_box_host, q.email_box_port)
server.login(q.email_box_user, q.email_box_pass)
server.select(q.email_box_imap_folder)
status, data = server.search(None, 'ALL')
for num in data[0].split():
status, data = server.fetch(num, '(RFC822)')
ticket_from_message(message=data[0][1], queue=q)
server.store(num, '+FLAGS', '\\Deleted')
server.expunge()
server.close()
server.logout()
def ticket_from_message(message, queue):
# 'message' must be an RFC822 formatted message.
msg = message
message = email.message_from_string(msg)
subject = message.get('subject', 'Created from e-mail')
subject = message.get('subject', _('Created from e-mail'))
subject = subject.replace("Re: ", "").replace("Fw: ", "").strip()
sender = message.get('from', 'Unknown Sender')
sender = message.get('from', _('Unknown Sender'))
sender_email = parseaddr(message.get('from', 'Unknown Sender'))[1]
sender_email = parseaddr(sender)[1]
if sender_email.startswith('postmaster'):
sender_email = ''
@ -147,7 +151,7 @@ def ticket_from_message(message, queue):
send_templated_mail('newticket_cc', context, recipients=queue.updated_ticket_cc, sender=queue.from_address, fail_silently=True)
else:
update = " (Updated)"
update = _(' (Updated)')
if t.assigned_to:
send_templated_mail('updated_owner', context, recipients=t.assigned_to.email, sender=queue.from_address, fail_silently=True)
@ -157,7 +161,7 @@ def ticket_from_message(message, queue):
f = FollowUp(
ticket = t,
title = 'E-Mail Received from %s' % sender_email,
title = _('E-Mail Received from %s' % sender_email),
date = datetime.now(),
public = True,
comment = body,

View File

@ -1,32 +1,32 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
{% load i18n %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{% block helpdesk_title %}Helpdesk{% endblock %} Powered by Jutda Helpdesk</title>
<title>{% block helpdesk_title %}Helpdesk{% endblock %} :: {% trans "Powered by Jutda Helpdesk" %}</title>
<script src='{{ MEDIA_URL }}/helpdesk/jquery.js' type='text/javascript' language='javascript'></script>
<link rel='stylesheet' href='{{ MEDIA_URL }}/helpdesk/helpdesk.css' type='text/css' />
<link rel='alternate' href='{% url helpdesk_rss "user" %}{{ user.username }}/' type='application/rss+xml' title='My Open Tickets' />
<link rel='alternate' href='{% url helpdesk_rss "recent" %}' type='application/rss+xml' title='All Recent Activity' />
<link rel='alternate' href='{% url helpdesk_rss "unassigned" %}' type='application/rss+xml' title='Unassigned Tickets' />
<link rel='alternate' href='{% url helpdesk_rss "user" %}{{ user.username }}/' type='application/rss+xml' title='{% trans "My Open Tickets" %}' />
<link rel='alternate' href='{% url helpdesk_rss "recent" %}' type='application/rss+xml' title='{% trans "All Recent Activity" %}' />
<link rel='alternate' href='{% url helpdesk_rss "unassigned" %}' type='application/rss+xml' title='{% trans "Unassigned Tickets" %}' />
{% block helpdesk_head %}{% endblock %}
</head>
<body>
<div id='container'>
<div id='header'>
<h1>Helpdesk</h1>
<h1>{% trans "Helpdesk" %}</h1>
<ul>
<li><a href='{% url helpdesk_home %}'>Dashboard</a></li>
<li><a href='{% url helpdesk_list %}'>Tickets</a></li>
<li><a href='{% url helpdesk_submit %}'>New Ticket</a></li>
<li><a href='{% url helpdesk_report_index %}'>Stats</a></li>
<li><a href='{% url logout %}'>Logout</a></li>
{% if not query %}<li><form id='searchform' method='get' action='{% url helpdesk_list %}'><input type='text' name='q' size='10' class='input' value='Search...' id='search_query' onFocus='s = document.getElementById("search_query");if (s.value == "Search...") { s.value = ""; }' /><input type='hidden' name='status' value='1' /><input type='hidden' name='status' value='2' /><input type='hidden' name='status' value='3' /></form></li>{% endif %}
<li><a href='{% url helpdesk_home %}'>{% trans "Dashboard" %}</a></li>
<li><a href='{% url helpdesk_list %}'>{% trans "Tickets" %}</a></li>
<li><a href='{% url helpdesk_submit %}'>{% trans "New Ticket" %}</a></li>
<li><a href='{% url helpdesk_report_index %}'>{% trans "Stats" %}</a></li>
<li><a href='{% url logout %}'>{% trans "Logout" %}</a></li>
{% if not query %}<li><form id='searchform' method='get' action='{% url helpdesk_list %}'><input type='text' name='q' size='10' class='input' value='{% trans "Search..." %}' id='search_query' onFocus='s=document.getElementById("search_query");if (s.value == "{% trans "Search..." %}") { s.value = ""; }' /><input type='hidden' name='status' value='1' /><input type='hidden' name='status' value='2' /><input type='hidden' name='status' value='3' /></form></li>{% endif %}
</ul>
</div>
<div id='body'>
{% block helpdesk_body %}{% endblock %}
</div>
<div id='footer'>
<p>Powered by <a href='http://www.jutda.com.au/'>Jutda HelpDesk</a>. <a href='{% url helpdesk_rss_index %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='RSS Feeds' border='0' />RSS Feeds</a> <a href='{% url helpdesk_api_help %}'>API</a></p>
<p>{% trans "Powered by <a href='http://www.jutda.com.au/'>Jutda Helpdesk</a>." %} <a href='{% url helpdesk_rss_index %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "RSS Feeds" %}' border='0' />{% trans "RSS Feeds" %}</a> <a href='{% url helpdesk_api_help %}'>{% trans "API" %}</a></p>
</div>
</div>
{% include "helpdesk/debug.html" %}

View File

@ -1,6 +1,6 @@
{% extends "helpdesk/base.html" %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% block helpdesk_title %}{% trans "Create Ticket" %}{% endblock %}
{% block helpdesk_head %}
<script src="http://media.jutda.com.au/helpdesk/nicEdit.js" type="text/javascript"></script>
@ -12,9 +12,9 @@
{% endblock %}
{% block helpdesk_body %}
<h2>Submit a Ticket</h2>
{% blocktrans %}<h2>Submit a Ticket</h2>
<p>Unless otherwise stated, all fields are required. Please provide as descriptive a title and description as possible.</p>
<p>Unless otherwise stated, all fields are required. Please provide as descriptive a title and description as possible.</p>{% endblocktrans %}
<form method='post' action='./'>
<fieldset>
@ -27,7 +27,7 @@
<dd>{{ form.title }}</dd>
{% if form.title.errors %}<dd class='error'>{{ form.title.errors }}</dd>{% endif %}
<dt><label for='id_submitter_email'>{{ form.submitter_email.label }}</label> <span class='form_optional'>(Optional)</span></dt>
<dt><label for='id_submitter_email'>{{ form.submitter_email.label }}</label> <span class='form_optional'>{% trans "(Optional)" %}</span></dt>
<dd>{{ form.submitter_email }}</dd>
{% if form.submitter_email.errors %}<dd class='error'>{{ form.submitter_email.errors }}</dd>{% endif %}
<dd class='form_help_text'>{{ form.submitter_email.help_text }}</dd>
@ -36,7 +36,7 @@
<dd>{{ form.body }}</dd>
{% if form.body.errors %}<dd class='error'>{{ form.body.errors }}</dd>{% endif %}
<dt><label for='id_assigned_to'>{{ form.assigned_to.label }}</label> <span class='form_optional'>(Optional)</span></dt>
<dt><label for='id_assigned_to'>{{ form.assigned_to.label }}</label> <span class='form_optional'>{% trans "(Optional)" %}</span></dt>
<dd>{{ form.assigned_to }}</dd>
{% if form.assigned_to.errors %}<dd class='error'>{{ form.assigned_to.errors }}</dd>{% endif %}
<dd class='form_help_text'>{{ form.assigned_to.help_text }}</dd>
@ -48,7 +48,7 @@
</dl>
<div class='buttons'>
<input type='submit' value='Submit Ticket' />
<input type='submit' value='{% trans "Submit Ticket" %}' />
</div>
</fieldset>

View File

@ -1,12 +1,12 @@
{% extends "helpdesk/base.html" %}
{% block helpdesk_title %}Helpdesk Dashboard{% endblock %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "Helpdesk Dashboard" %}{% endblock %}
{% block helpdesk_head %}
<script type='text/javascript' language='javascript' src='{{ MEDIA_URL }}/helpdesk/hover.js'></script>
{% endblock %}
{% block helpdesk_body %}
<table width='30%'>
<tr class='row_tablehead'><td colspan='4'>Helpdesk Summary</td></tr>
<tr class='row_columnheads'><th>Queue</th><th>Open</th><th>Resolved</th></tr>
<tr class='row_tablehead'><td colspan='4'>{% trans "Helpdesk Summary" %}</td></tr>
<tr class='row_columnheads'><th>{% trans "Queue" %}</th><th>{% trans "Open" %}</th><th>{% trans "Resolved" %}</th></tr>
{% for queue in dash_tickets %}
<tr class='row_{% cycle odd,even %} row_hover '>
<th><a href='{% url helpdesk_list %}?queue={{ queue.queue }}'>{{ queue.name }}</a></th>
@ -16,13 +16,14 @@
{% endfor %}
</table>
<table width='100%'>
<tr class='row_tablehead'><td colspan='6'>Your Tickets</td></tr>
<tr class='row_columnheads'><th>#</th><th>Pr</th><th>Title</th><th>Queue</th><th>Status</th><th>Last Update</th></tr>
<tr class='row_tablehead'><td colspan='6'>{% trans "Your Tickets" %}</td></tr>
<tr class='row_columnheads'><th>#</th><th>{% trans "Pr" %}</th><th>{% trans "Title" %}</th><th>{% trans "Queue" %}</th><th>{% trans "Status" %}</th><th>{% trans "Last Update" %}</th></tr>
{% for ticket in user_tickets %}
<tr class='row_{% cycle odd,even %} row_hover'>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
<td><img src='{{ ticket.get_priority_img }}' alt='Priority {{ ticket.priority }}' title='Priority {{ ticket.priority }}' height='16' width='16' /></td>
<td><img src='{{ ticket.get_priority_img }}' alt='{% blocktrans with ticket.priority as priority %}Priority {{ priority }}{% endblocktrans %}' title='{% blocktrans with ticket.priority as priority %}Priority {{ priority }}{% endblocktrans %}' height='16' width='16' /></td>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></th>
<td>{{ ticket.queue }}</td>
<td>{{ ticket.get_status }}</td>
@ -32,16 +33,16 @@
</table>
<table width='100%'>
<tr class='row_tablehead'><td colspan='6'>Unassigned Tickets</td></tr>
<tr class='row_columnheads'><th>#</th><th>Pr</th><th>Title</th><th>Queue</th><th>Created</th><th>&nbsp;</th></tr>
<tr class='row_tablehead'><td colspan='6'>{% trans "Unassigned Tickets" %}</td></tr>
<tr class='row_columnheads'><th>#</th><th>{% trans "Pr" %}</th><th>{% trans "Title" %}</th><th>{% trans "Queue" %}</th><th>{% trans "Created" %}</th><th>&nbsp;</th></tr>
{% for ticket in unassigned_tickets %}
<tr class='row_{% cycle odd,even %} row_hover'>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
<td><img src='{{ ticket.get_priority_img }}' alt='Priority {{ ticket.priority }}' title='Priority {{ ticket.priority }}' height='16' width='16' /></td>
<td><img src='{{ ticket.get_priority_img }}' alt='{% blocktrans with ticket.priority as priority %}Priority {{ priority }}{% endblocktrans %}' title='{% blocktrans with ticket.priority as priority %}Priority {{ priority }}{% endblocktrans %}' height='16' width='16' /></td>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></th>
<td>{{ ticket.queue }}</td>
<td><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|timesince }} ago</span></td>
<th><a href='{{ ticket.get_absolute_url }}?take'><img src='{{ MEDIA_URL }}/helpdesk/buttons/take.png' width='60' height='15' alt='Take' title='Assign this ticket to yourself' /></a></th>
<th><a href='{{ ticket.get_absolute_url }}?take'><img src='{{ MEDIA_URL }}/helpdesk/buttons/take.png' width='60' height='15' alt='{% trans "Take" %}' title='{% trans "Assign this ticket to yourself" %}' /></a></th>
</tr>
{% endfor %}
</table>

View File

@ -1,8 +1,8 @@
{% extends "helpdesk/base.html" %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}Delete Ticket{% endblock %}
{% block helpdesk_title %}{% trans "Delete Ticket" %}{% endblock %}
{% block helpdesk_body %}
{% block helpdesk_body %}{% blocktrans %}
<h2>Delete Ticket</h2>
<p>Are you sure you want to delete this ticket (<em>{{ ticket.title }}</em>)? All traces of the ticket, including followups, attachments, and updates will be irreversably removed.</p>
@ -10,4 +10,4 @@
<p><a href='../'>No, Don't Delete It</a></p>
<form method='post' action='./'><input type='submit' value='Yes - Delete It' /></form>
{% endblock %}
{% endblocktrans %}{% endblock %}

View File

@ -1,6 +1,6 @@
<html>
{% load i18n %}<html>
<head>
<title>{% block helpdesk_title %}Helpdesk{% endblock %}</title>
<title>{% block helpdesk_title %}{% trans "Helpdesk" %}{% endblock %}</title>
<script src='{{ MEDIA_URL }}/helpdesk/jquery.js' type='text/javascript' language='javascript'></script>
<link rel='stylesheet' href='{{ MEDIA_URL }}/helpdesk/helpdesk.css' type='text/css' />
{% block helpdesk_head %}{% endblock %}
@ -8,17 +8,17 @@
<body>
<div id='container'>
<div id='header'>
<h1>Helpdesk</h1>
<h1>{% trans "Helpdesk" %}</h1>
<ul>
<li><a href='{% url helpdesk_home %}'>Submit A Ticket</a></li>
<li><a href='{% url login %}'>Log In</a></li>
<li><a href='{% url helpdesk_home %}'>{% trans "Submit A Ticket" %}</a></li>
<li><a href='{% url login %}'>{% trans "Log In" %}</a></li>
</ul>
</div>
<div id='body'>
{% block helpdesk_body %}{% endblock %}
</div>
<div id='footer'>
<p>Powered by <a href='http://www.jutda.com.au/'>Jutda HelpDesk</a></p>
<p>{% trans "Powered by <a href='http://www.jutda.com.au/'>Jutda HelpDesk</a>." %}</p>
</div>
</div>{% include "helpdesk/debug.html" %}
</body>

View File

@ -1,5 +1,4 @@
{% extends "helpdesk/public_base.html" %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_head %}
<script src="http://media.jutda.com.au/helpdesk/nicEdit.js" type="text/javascript"></script>
@ -11,25 +10,25 @@
{% endblock %}
{% block helpdesk_body %}
<h2>View a Ticket</h2>
<h2>{% trans "View a Ticket" %}</h2>
<form method='get' action='{% url helpdesk_public_view %}'>
<fieldset>
<dl>
<dt><label for='id_ticket'>Ticket</label></dt>
<dt><label for='id_ticket'>{% trans "Ticket" %}</label></dt>
<dd><input type='text' name='ticket' /></dd>
<dt><label for='id_email'>Your E-mail Address</label></dt>
<dt><label for='id_email'>{% trans "Your E-mail Address" %}</label></dt>
<dd><input type='text' name='email' /></dd>
</dl>
<input type='submit' value='View Ticket' />
<input type='submit' value='{% trans "View Ticket" %}' />
</fieldset>
</form>
<h2 name='submit'>Submit a Ticket</h2>
<h2 name='submit'>{% trans "Submit a Ticket" %}</h2>
<p>All fields are required. Please provide as descriptive a title and description as possible.</p>
<p>{% trans "All fields are required. Please provide as descriptive a title and description as possible." %}</p>
<form method='post' action='./#submit'>
<fieldset>
@ -63,7 +62,7 @@
</dl>
<div class='buttons'>
<input type='submit' value='Submit Ticket' />
<input type='submit' value='{% trans "Submit Ticket" %}' />
</div>
</fieldset>

View File

@ -1,23 +1,24 @@
{% extends "helpdesk/public_base.html" %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_body %}
<h2>View a Ticket</h2>
<h2>{% trans "View a Ticket" %}</h2>
<form method='get' action='{% url helpdesk_public_view %}'>
{% if error_message %}<p><strong>Error:</strong> {{ error_message }}</p>{% endif %}
{% if error_message %}<p><strong>{% trans "Error:" %}</strong> {{ error_message }}</p>{% endif %}
<fieldset>
<dl>
<dt><label for='id_ticket'>Ticket</label></dt>
<dd><input type='text' name='ticket' value='{{ ticket }}' /></dd>
<dt><label for='id_ticket'>{% trans "Ticket" %}</label></dt>
<dd><input type='text' name='ticket' /></dd>
<dt><label for='id_email'>Your E-mail Address</label></dt>
<dd><input type='text' name='email' value='{{ email }}' /></dd>
<dt><label for='id_email'>{% trans "Your E-mail Address" %}</label></dt>
<dd><input type='text' name='email' /></dd>
</dl>
<input type='submit' value='View Ticket' />
<input type='submit' value='{% "View Ticket" %}' />
</fieldset>
</form>
{% endblock %}

View File

@ -1,5 +1,5 @@
{% extends "helpdesk/public_base.html" %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "View a Ticket" %}{% endblock %}
{% block helpdesk_head %}
<script src="http://media.jutda.com.au/helpdesk/nicEdit.js" type="text/javascript"></script>
<script type="text/javascript">
@ -13,32 +13,32 @@
<table width='100%'>
<tr class='row_tablehead'><td colspan='2'>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</td></tr>
<tr class='row_columnheads'><th colspan='2'>Queue: {{ ticket.queue }}</th></tr>
<tr class='row_columnheads'><th colspan='2'>{% blocktrans %}Queue: {{ ticket.queue }}{% endblocktrans %}</th></tr>
<tr class='row_odd'>
<th>Submitted On</th>
<th>{% trans "Submitted On" %}</th>
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|timesince }} ago)</td>
</tr>
<tr class='row_even'>
<th>Submitter E-Mail</th>
<th>{% trans "Submitter E-Mail" %}</th>
<td>{{ ticket.submitter_email }}</td>
</tr>
<tr class='row_odd'>
<th>Priority</th>
<th>{% trans "Priority" %}</th>
<td>{{ ticket.get_priority_display }}</td>
</tr>
<tr class='row_even'>
<th colspan='2'>Description</th>
<th colspan='2'>{% trans "Description" %}</th>
</tr>
<tr class='row_odd'>
<td colspan='2'>{{ ticket.description }}</td>
</tr>
{% if ticket.resolution %}<tr class='row_even'>
<th colspan='2'>Resolution{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}/helpdesk/buttons/accept.png' alt='Accept' title='Accept and Close' width='60' height='15' /></a>{% endifequal %}</th>
<th colspan='2'>{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}/helpdesk/buttons/accept.png' alt='{% trans "Accept" %}' title='{% trans "Accept and Close" %}' width='60' height='15' /></a>{% endifequal %}</th>
</tr>
<tr class='row_odd'>
<td colspan='2'>{{ ticket.resolution }}</td>
@ -47,7 +47,7 @@
</table>
{% if ticket.followup_set.public_followups %}
<h3>Follow-Ups</h3>
<h3>{% trans "Follow-Ups" %}</h3>
{% load ticket_to_link %}
{% for followup in ticket.followup_set.public_followups %}
<div class='followup'>
@ -55,7 +55,7 @@
{{ followup.comment|num_to_link }}
{% if followup.ticketchange_set.all %}<div class='changes'><ul>
{% for change in followup.ticketchange_set.all %}
<li>Changed {{ change.field }} from {{ change.old_value }} to {{ change.new_value }}.</li>
<li>{% blocktrans %}Changed {{ change.field }} from {{ change.old_value }} to {{ change.new_value }}.{% endblocktrans %}</li>
{% endfor %}
</div></ul>{% endif %}
</div>

View File

@ -1,8 +1,8 @@
{% extends "helpdesk/base.html" %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}Reports &amp; Statistics{% endblock %}
{% block helpdesk_title %}{% trans "Reports &amp; Statistics" %}{% endblock %}
{% block helpdesk_body %}
{% block helpdesk_body %}{% blocktrans %}
<h2>Reports &amp; Statistics</h2>
<ul>
@ -24,4 +24,4 @@
</ul></li>
</ul>
{% endblock %}
{% endblocktrans %}{% endblock %}

View File

@ -1,9 +1,9 @@
{% extends "helpdesk/base.html" %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}Reports &amp; Statistics{% endblock %}
{% block helpdesk_title %}{% trans "Reports &amp; Statistics" %}{% endblock %}
{% block helpdesk_body %}
<h2>Reports &amp; Statistics</h2>
<h2>{% trans "Reports &amp; Statistics" %}</h2>
<table>
<tr>{% for h in headings %}<th>{{ h }}</th>{% endfor %}</tr>

View File

@ -1,31 +1,31 @@
{% extends "helpdesk/base.html" %}
{% block helpdesk_title %}RSS Feeds{% endblock %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "RSS Feeds" %}{% endblock %}
{% block helpdesk_body %}
<h2>RSS Feeds</h2>
<h2>{% trans "RSS Feeds" %}</h2>
<p>The following RSS feeds are available for you to monitor using your preferred RSS software. With the exception of the 'Latest Activity' feed, all feeds provide information only on Open and Reopened cases. This ensures your RSS reader isn't full of information about closed or historical tasks.</p>
<p>{% trans "The following RSS feeds are available for you to monitor using your preferred RSS software. With the exception of the 'Latest Activity' feed, all feeds provide information only on Open and Reopened cases. This ensures your RSS reader isn't full of information about closed or historical tasks." %}</p>
<dl>
<dt><a href='{% url helpdesk_rss "user" %}{{ user.username }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='My Open Tickets' border='0' />My Open Tickets</a></dt>
<dd>A summary of your open tickets - useful for getting alerted to new tickets opened for you</dd>
<dt><a href='{% url helpdesk_rss "user" %}{{ user.username }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' />{% trans "My Open Tickets" %}</a></dt>
<dd>{% trans "A summary of your open tickets - useful for getting alerted to new tickets opened for you" %}</dd>
<dt><a href='{% url helpdesk_rss "recent_activity" %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='Latest Activity' border='0' />Latest Activity</a></dt>
<dd>A summary of all helpdesk activity - including comments, emails, attachments, and more</dd>
<dt><a href='{% url helpdesk_rss "recent_activity" %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Latest Activity" %}' border='0' />{% trans "Latest Activity" %}</a></dt>
<dd>{% trans "A summary of all helpdesk activity - including comments, emails, attachments, and more" %}</dd>
<dt><a href='{% url helpdesk_rss "unassigned" %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='Unassigned Tickets' border='0' />Unassigned Tickets</a></dt>
<dd>All unassigned tickets - useful for being alerted to new tickets opened by the public via the web or via e-mail</dd>
<dt><a href='{% url helpdesk_rss "unassigned" %}'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Unassigned Tickets" %}' border='0' />{% trans "Unassigned Tickets" %}</a></dt>
<dd>{% trans "All unassigned tickets - useful for being alerted to new tickets opened by the public via the web or via e-mail" %}</dd>
</dl>
<p>These RSS feeds allow you to view a summary of either your own tickets, or all tickets, for each of the queues in your helpdesk. For example, if you manage the staff who utilise a particular queue, this may be used to view new tickets coming into that queue.</p>
<p>{% trans "These RSS feeds allow you to view a summary of either your own tickets, or all tickets, for each of the queues in your helpdesk. For example, if you manage the staff who utilise a particular queue, this may be used to view new tickets coming into that queue." %}</p>
<table width='50%'>
<tr class='row_tablehead'><td colspan='4'>Per-Queue Feeds</td></tr>
<tr class='row_columnheads'><th>Queue</th><th align='center'>All Open Tickets</th><th align='center'>My Open Tickets</th></tr>
<tr class='row_tablehead'><td colspan='4'>{% trans "Per-Queue Feeds" %}</td></tr>
<tr class='row_columnheads'><th>{% trans "Queue" %}</th><th align='center'>{% trans "All Open Tickets" %}</th><th align='center'>{% trans "My Open Tickets" %}</th></tr>
{% for queue in queues %}
<tr>
<td>{{ queue.title }}</td>
<td align='center'><a href='{% url helpdesk_rss "queue" %}{{ queue.slug }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='Open Tickets' border='0' /></a></td>
<td align='center'><a href='{% url helpdesk_rss "user" %}{{ user.username }}/{{ queue.slug }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='RSS Icon' title='My Open Tickets' border='0' /></a></td>
<td align='center'><a href='{% url helpdesk_rss "queue" %}{{ queue.slug }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Open Tickets" %}' border='0' /></a></td>
<td align='center'><a href='{% url helpdesk_rss "user" %}{{ user.username }}/{{ queue.slug }}/'><img src='{{ MEDIA_URL }}/helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' /></a></td>
{% endfor %}
</table>
{% endblock %}

View File

@ -1,5 +1,5 @@
{% extends "helpdesk/base.html" %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "View Ticket Details" %}{% endblock %}
{% block helpdesk_head %}
<script src="http://media.jutda.com.au/helpdesk/nicEdit.js" type="text/javascript"></script>
<script type="text/javascript">
@ -33,7 +33,7 @@
distribution, this will have to do. */
$(".AddAnotherFile>a").click(function() {
$(this).parent().hide();
$("#FileUpload>dl").append("<dt><label>Attach another File</label></dt><dd><input type='file' name='attachment' id='file' /> <span class='AddAnotherFile'>(<a href='#'>Add Another File</a>)</span></dd>");
$("#FileUpload>dl").append("<dt><label>{% trans "Attach another File" %}</label></dt><dd><input type='file' name='attachment' id='file' /> <span class='AddAnotherFile'>(<a href='#'>{% trans "Add Another File" %}</a>)</span></dd>");
processAddFileClick();
return false;
});
@ -45,38 +45,38 @@
{% block helpdesk_body %}
<table width='100%'>
<tr class='row_tablehead'><td>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</td><td align='right'><a href='#edit'><img src='{{ MEDIA_URL }}/helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a><a href='{% url helpdesk_delete ticket.id %}'><img src='{{ MEDIA_URL }}/helpdesk/buttons/delete.png' alt='Delete' title='Delete' width='60' height='15' /></a>{% if ticket.on_hold %}<a href='unhold/'>Unhold</a>{% else %}<a href='hold/'>Hold</a>{% endif %}</td></tr>
<tr class='row_columnheads'><th colspan='2'>Queue: {{ ticket.queue }}</th></tr>
<tr class='row_tablehead'><td>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</td><td align='right'><a href='#edit'><img src='{{ MEDIA_URL }}/helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a><a href='{% url helpdesk_delete ticket.id %}'><img src='{{ MEDIA_URL }}/helpdesk/buttons/delete.png' alt='Delete' title='Delete' width='60' height='15' /></a>{% if ticket.on_hold %}<a href='unhold/'>{% trans "Unhold" %}</a>{% else %}<a href='hold/'>{% trans "Hold" %}</a>{% endif %}</td></tr>
<tr class='row_columnheads'><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
<tr class='row_odd'>
<th>Submitted On</th>
<th>{% trans "Submitted On" %}</th>
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|timesince }} ago)</td>
</tr>
<tr class='row_even'>
<th>Assigned To</th>
<td>{{ ticket.get_assigned_to }}{% ifequal ticket.get_assigned_to 'Unassigned' %} <strong><a href='?take'><img src='{{ MEDIA_URL }}/helpdesk/buttons/take.png' width='60' height='15' alt='Take' title='Assign this ticket to yourself' /></a></strong>{% endifequal %}</td>
<th>{% trans "Assigned To" %}</th>
<td>{{ ticket.get_assigned_to }}{% ifequal ticket.get_assigned_to _('Unassigned') %} <strong><a href='?take'><img src='{{ MEDIA_URL }}/helpdesk/buttons/take.png' width='60' height='15' alt='{% trans "Take" %}' title='{% trans "Assign this ticket to yourself" %}' /></a></strong>{% endifequal %}</td>
</tr>
<tr class='row_odd'>
<th>Submitter E-Mail</th>
<th>{% trans "Submitter E-Mail" %}</th>
<td>{{ ticket.submitter_email }}</td>
</tr>
<tr class='row_even'>
<th>Priority</th>
<th>{% trans "Priority" %}</th>
<td>{{ ticket.get_priority_display }}</td>
</tr>
<tr class='row_odd'>
<th colspan='2'>Description</th>
<th colspan='2'>{% trans "Description" %}</th>
</tr>
<tr class='row_even'>
<td colspan='2'>{{ ticket.description|safe }}</td>
</tr>
{% if ticket.resolution %}<tr class='row_odd'>
<th colspan='2'>Resolution{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}/helpdesk/buttons/accept.png' alt='Accept' title='Accept and Close' width='60' height='15' /></a>{% endifequal %}</th>
<th colspan='2'>{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}/helpdesk/buttons/accept.png' alt='{% trans "Accept" %}' title='{% trans "Accept and Close" %}' width='60' height='15' /></a>{% endifequal %}</th>
</tr>
<tr class='row_even'>
<td colspan='2'>{{ ticket.resolution|safe }}</td>
@ -85,15 +85,15 @@
</table>
{% if ticket.followup_set.all %}
<h3>Follow-Ups</h3>
<h3>{% trans "Follow-Ups" %}</h3>
{% load ticket_to_link %}
{% for followup in ticket.followup_set.all %}
<div class='followup'>
<div class='title'>{{ followup.title }} <span class='byline'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"r" }}'>{{ followup.date|timesince }} ago</span>{% if not followup.public %} <span class='private'>(Private)</span>{% endif %}</span></div>
<div class='title'>{{ followup.title }} <span class='byline'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"r" }}'>{{ followup.date|timesince }} ago</span>{% if not followup.public %} <span class='private'>({% trans "Private" %})</span>{% endif %}</span></div>
{% if followup.comment %}{{ followup.comment|num_to_link|safe }}{% endif %}
{% for change in followup.ticketchange_set.all %}
{% if forloop.first %}<div class='changes'><ul>{% endif %}
<li>Changed {{ change.field }} from {{ change.old_value }} to {{ change.new_value }}.</li>
<li>{% blocktrans %}Changed {{ change.field }} from {{ change.old_value }} to {{ change.new_value }}.{% endblocktrans %}</li>
{% if forloop.last %}</div></ul>{% endif %}
{% endfor %}
{% for attachment in followup.attachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
@ -104,80 +104,80 @@
{% endfor %}
{% endif %}
<h3>Respond to this ticket</h3>
<h3>{% trans "Respond to this ticket" %}</h3>
<form method='post' action='update/' enctype='multipart/form-data'>
<fieldset>
<dl>
<dt><label for='id_preset'>Use a Pre-set Reply</label> <span class='form_optional'>(Optional)</span></dt>
<dt><label for='id_preset'>{% trans "Use a Pre-set Reply" %}</label> <span class='form_optional'>(Optional)</span></dt>
<dd><select name='preset' id='id_preset'><option value=''>------</option>{% for preset in preset_replies %}<option value='{{ preset.id }}'>{{ preset.name }}</option>{% endfor %}</select></dd>
<dd class='form_help_text'>Selecting a pre-set reply will over-write your comment below. You can then modify the pre-set reply to your liking before saving this update.</dd>
<dd class='form_help_text'>{% trans "Selecting a pre-set reply will over-write your comment below. You can then modify the pre-set reply to your liking before saving this update." %}</dd>
<dt><label for='commentBox'>Comment / Resolution</label></dt>
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
<dd class='form_help_text'>You can use the ticket and queue template variables in your message.</dd>
<dd class='form_help_text'>{% trans "You can use the ticket and queue template variables in your message." %}</dd>
<dt><label>New Status</label></dt>
<dt><label>{% trans "New Status" %}</label></dt>
{% ifequal ticket.status 1 %}
<dd><input type='radio' name='new_status' value='1' id='st_open' checked='checked'><label for='st_open' class='active'>Open</label> &raquo;
<input type='radio' name='new_status' value='3' id='st_resolved'><label for='st_resolved'>Resolved</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>Closed</label></dd>
<dd><input type='radio' name='new_status' value='1' id='st_open' checked='checked'><label for='st_open' class='active'>{% trans "Open" %}</label> &raquo;
<input type='radio' name='new_status' value='3' id='st_resolved'><label for='st_resolved'>{% trans "Resolved" %}</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>{% trans "Closed" %}</label></dd>
{% endifequal %}
{% ifequal ticket.status 2 %}
<dd><input type='radio' name='new_status' value='2' id='st_reopened' checked='checked'><label for='st_reopened' class='active'>Reopened</label> &raquo;
<input type='radio' name='new_status' value='3' id='st_resolved'><label for='st_resolved'>Resolved</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>Closed</label> </dd>
<dd><input type='radio' name='new_status' value='2' id='st_reopened' checked='checked'><label for='st_reopened' class='active'>{% trans "Reopened" %}</label> &raquo;
<input type='radio' name='new_status' value='3' id='st_resolved'><label for='st_resolved'>{% trans "Resolved" %}</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>{% trans "Closed" %}</label> </dd>
{% endifequal %}
{% ifequal ticket.status 3 %}
<dd><input type='radio' name='new_status' value='2' id='st_reopened'><label for='st_reopened'>Reopened</label> &laquo;
<input type='radio' name='new_status' value='3' id='st_resolved' checked='checked'><label for='st_resolved' class='active'>Resolved</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>Closed</label></dd>
<dd><input type='radio' name='new_status' value='2' id='st_reopened'><label for='st_reopened'>{% trans "Reopened" %}</label> &laquo;
<input type='radio' name='new_status' value='3' id='st_resolved' checked='checked'><label for='st_resolved' class='active'>{% trans "Resolved" %}</label> &raquo;
<input type='radio' name='new_status' value='4' id='st_closed'><label for='st_closed'>{% trans "Closed" %}</label></dd>
{% endifequal %}
{% ifequal ticket.status 4 %}
<dd><input type='radio' name='new_status' value='2' id='st_reopened'><label for='st_reopened'>Reopened</label> &laquo;
<input type='radio' name='new_status' value='4' id='st_closed' checked='checked'><label for='st_closed'>Closed</label></dd>
<dd><input type='radio' name='new_status' value='2' id='st_reopened'><label for='st_reopened'>{% trans "Reopened" %}</label> &laquo;
<input type='radio' name='new_status' value='4' id='st_closed' checked='checked'><label for='st_closed'>{% trans "Closed" %}</label></dd>
{% endifequal %}
<dt><label for='id_public'>Is this update public?</label> <span class='form_optional'>(Optional)</span></dt>
<dt><label for='id_public'>{% trans "Is this update public?" %}</label> <span class='form_optional'>(Optional)</span></dt>
<dd><input type='checkbox' name='public' value='1' checked='checked' /></dD>
<dd class='form_help_text'>If this is public, the submitter will be e-mailed your comment or resolution.</dd>
<dd class='form_help_text'>{% trans "If this is public, the submitter will be e-mailed your comment or resolution." %}</dd>
</dl>
<p id='ShowFurtherOptPara'><a href='#' id='ShowFurtherEditOptions'>Change Further Details &raquo;</a></p>
<p id='ShowFurtherOptPara'><a href='#' id='ShowFurtherEditOptions'>{% trans "Change Further Details &raquo;" %}</a></p>
<div id='FurtherEditOptions' style='display: none;'>
<dl>
<dt><label for='id_title'>Title</label></dt>
<dt><label for='id_title'>{% trans "Title" %}</label></dt>
<dd><input type='text' name='title' value='{{ ticket.title|escape }}' /></dd>
<dt><label for='id_owner'>Owner</label></dt>
<dd><select id='id_owner' name='owner'><option value='0'>Unassign</option>{% for u in active_users %}<option value='{{ u.id }}' {% ifequal u.id ticket.assigned_to.id %}selected{% endifequal %}>{{ u }}</option>{% endfor %}</select></dd>
<dt><label for='id_owner'>{% trans "Owner" %}</label></dt>
<dd><select id='id_owner' name='owner'><option value='0'>{% trans "Unassign" %}</option>{% for u in active_users %}<option value='{{ u.id }}' {% ifequal u.id ticket.assigned_to.id %}selected{% endifequal %}>{{ u }}</option>{% endfor %}</select></dd>
<dt><label for='id_priority'>Priority</label></dt>
<dt><label for='id_priority'>{% trans "Priority" %}</label></dt>
<dd><select id='id_priority' name='priority'>{% for p in priorities %}<option value='{{ p.0 }}'{% ifequal p.0 ticket.priority %} selected='selected'{% endifequal %}>{{ p.1 }}</option>{% endfor %}</select></dd>
</dl>
</div>
<p id='ShowFileUploadPara'><a href='#' id='ShowFileUpload'>Attach File(s) &raquo;</a></p>
<p id='ShowFileUploadPara'><a href='#' id='ShowFileUpload'>{% trans "Attach File(s) &raquo;" %}</a></p>
<div id='FileUpload' style='display: none;'>
<dl>
<dt><label for='id_file'>Attach a File</label></dt>
<dd><input type='file' name='attachment' id='file' /> <span class='AddAnotherFile'>(<a href='#'>Add Another File</a>)</span></dd>
<dt><label for='id_file'>{% trans "Attach a File" %}</label></dt>
<dd><input type='file' name='attachment' id='file' /> <span class='AddAnotherFile'>(<a href='#'>{% trans "Add Another File" %}</a>)</span></dd>
</dl>
</div>
</fieldset>
<input type='submit' value='Update This Ticket' />
<input type='submit' value='{% trans "Update This Ticket" %}' />
</form>

View File

@ -1,5 +1,5 @@
{% extends "helpdesk/base.html" %}
{% block helpdesk_title %}Ticket Listing{% endblock %}
{% extends "helpdesk/base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "Ticket Listing" %}{% endblock %}
{% block helpdesk_head %}
<script type='text/javascript' language='javascript' src='{{ MEDIA_URL }}/helpdesk/filter.js'></script>
<script type='text/javascript' language='javascript' src='{{ MEDIA_URL }}/helpdesk/hover.js'></script>
@ -9,58 +9,58 @@
{% load in_list %}
<form><select name='select' id='filterBuilderSelect'>
<option value='Sort'>Sorting</option>
<option value='Owner'>Owner</option>
<option value='Queue'>Queue</option>
<option value='Status'>Status</option>
<option value='Keywords'>Keywords</option>
<option value='Sort'>{% trans "Sorting" %}</option>
<option value='Owner'>{% trans "Owner" %}</option>
<option value='Queue'>{% trans "Queue" %}</option>
<option value='Status'>{% trans "Status" %}</option>
<option value='Keywords'>{% trans "Keywords" %}</option>
</select>
<input type='button' id='filterBuilderButton' value='+' /></form>
<form method='get' action='./'>
<div class='filterBox{% if sort %} filterBoxShow{% endif %}' id='filterBoxSort'>
<label for='id_sort'>Sorting</label> <select id='id_sort' name='sort'>
<option value='created'{% ifequal sort "created"%} selected='selected'{% endifequal %}>Created</option>
<option value='title'{% ifequal sort "title"%} selected='selected'{% endifequal %}>Title</option>
<option value='queue'{% ifequal sort "queue"%} selected='selected'{% endifequal %}>Queue</option>
<option value='status'{% ifequal sort "status"%} selected='selected'{% endifequal %}>Status</option>
<option value='priority'{% ifequal sort "priority"%} selected='selected'{% endifequal %}>Priority</option>
<option value='assigned_to'{% ifequal sort "assigned_to"%} selected='selected'{% endifequal %}>Owner</option>
<option value='created'{% ifequal sort "created"%} selected='selected'{% endifequal %}>{% trans "Created" %}</option>
<option value='title'{% ifequal sort "title"%} selected='selected'{% endifequal %}>{% trans "Title" %}</option>
<option value='queue'{% ifequal sort "queue"%} selected='selected'{% endifequal %}>{% trans "Queue" %}</option>
<option value='status'{% ifequal sort "status"%} selected='selected'{% endifequal %}>{% trans "Status" %}</option>
<option value='priority'{% ifequal sort "priority"%} selected='selected'{% endifequal %}>{% trans "Priority" %}</option>
<option value='assigned_to'{% ifequal sort "assigned_to"%} selected='selected'{% endifequal %}>{% trans "Owner" %}</option>
</select>
<input type='button' class='filterBuilderRemove' value='-' />
</div>
<div class='filterBox{% if owners %} filterBoxShow{% endif %}' id='filterBoxOwner'>
<label for='id_owners'>Owner(s)</label> <select id='id_owners' name='assigned_to' multiple='selected' size='5'>{% for u in user_choices %}<option value='{{ u.id }}'{% if u.id|in_list:owners %} selected='selected'{% endif %}>{{ u.username }}</option>{% endfor %}</select>
<label for='id_owners'>{% trans "Owner(s)" %}</label> <select id='id_owners' name='assigned_to' multiple='selected' size='5'>{% for u in user_choices %}<option value='{{ u.id }}'{% if u.id|in_list:owners %} selected='selected'{% endif %}>{{ u.username }}</option>{% endfor %}</select>
<input type='button' class='filterBuilderRemove' value='-' />
</div>
<div class='filterBox{% if queues %} filterBoxShow{% endif %}' id='filterBoxQueue'>
<label for='id_queues'>Queue(s)</label> <select id='id_queues' name='queue' multiple='selected' size='5'>{% for q in queue_choices %}<option value='{{ q.id }}'{% if q.id|in_list:queues %} selected='selected'{% endif %}>{{ q.title }}</option>{% endfor %}</select>
<label for='id_queues'>{% trans "Queue(s)" %}</label> <select id='id_queues' name='queue' multiple='selected' size='5'>{% for q in queue_choices %}<option value='{{ q.id }}'{% if q.id|in_list:queues %} selected='selected'{% endif %}>{{ q.title }}</option>{% endfor %}</select>
<input type='button' class='filterBuilderRemove' value='-' />
</div>
<div class='filterBox{% if statuses %} filterBoxShow{% endif %}' id='filterBoxStatus'>
<label for='id_statuses'>Status(es)</label> {% for s in status_choices %}<input type='checkbox' name='status' value='{{ s.0 }}'{% if s.0|in_list:statuses %} checked='checked'{% endif %}> {{ s.1 }}{% endfor %}
<label for='id_statuses'>{% trans "Status(es)" %}</label> {% for s in status_choices %}<input type='checkbox' name='status' value='{{ s.0 }}'{% if s.0|in_list:statuses %} checked='checked'{% endif %}> {{ s.1 }}{% endfor %}
<input type='button' class='filterBuilderRemove' value='-' />
</div>
<div class='filterBox{% if query %} filterBoxShow{% endif %}' id='filterBoxKeywords'>
<label for='id_query'>Keywords</label> <input type='text' name='q' value='{{ query }}' id='id_query' />
<label for='id_query'>{% trans "Keywords" %}</label> <input type='text' name='q' value='{{ query }}' id='id_query' />
<input type='button' class='filterBuilderRemove' value='-' />
</div>
<input type='submit' value='Go!' />
<input type='submit' value='{% trans "Apply Filter" %}' />
</form>
<table width='100%'>
<tr class='row_tablehead'><td colspan='7'>Tickets</td></tr>
<tr class='row_columnheads'><th>#</th><th>Pr</th><th>Title</th><th>Queue</th><th>Status</th><th>Created</th><th>Owner</th></tr>
<tr class='row_tablehead'><td colspan='7'>{% trans "Tickets" %}</td></tr>
<tr class='row_columnheads'><th>#</th><th>{% trans "Pr" %}</th><th>{% trans "Title" %}</th><th>{% trans "Queue" %}</th><th>{% trans "Status" %}</th><th>{% trans "Created" %}</th><th>{% trans "Owner" %}</th></tr>
{% if tickets %}{% for ticket in tickets %}
<tr class='row_{% cycle odd,even %} row_hover'>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
<td><img src='{{ ticket.get_priority_img }}' alt='Priority {{ ticket.priority }}' title='Priority {{ ticket.priority }}' height='16' width='16' /></td>
<td><img src='{{ ticket.get_priority_img }}' alt='{% trans "Priority {{ ticket.priority }}" %}' title='{% trans "Priority {{ ticket.priority }}" %}' height='16' width='16' /></td>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></th>
<td>{{ ticket.queue }}</td>
<td>{{ ticket.get_status }}</td>
@ -68,7 +68,7 @@
<td>{{ ticket.get_assigned_to }}</td>
</tr>
{% endfor %}{% else %}
<tr class='row_odd'><td colspan='5'>No Tickets Match Your Selection</td></tr>
<tr class='row_odd'><td colspan='5'>{% trans "No Tickets Match Your Selection" %}</td></tr>
{% endif %}
</table>

View File

@ -0,0 +1,9 @@
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "Logged Out" %}{% endblock %}
{% block helpdesk_body %}{% blocktrans %}
<h2>Logged Out</h2>
<p>Thanks for being here. Hopefully you've helped resolve a few tickets and make the world a better place.</p>
{% endblocktrans %}{% endblock %}

View File

@ -1,20 +1,20 @@
{% extends "helpdesk/public_base.html" %}
{% block helpdesk_title %}Helpdesk Login{% endblock %}
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_title %}{% trans "Helpdesk Login" %}{% endblock %}
{% block helpdesk_body %}
<h2>Login</h2>
<h2>{% trans "Login" %}</h2>
<p>To log in and begin responding to cases, simply enter your username and password below.</p>
<p>{% trans "To log in and begin responding to cases, simply enter your username and password below." %}</p>
<form method='post' action='./'>
{% if form.has_errors %}<p>Your username and password didn't match. Please try again.</p>{% endif %}
{% if form.has_errors %}<p>{% trans "Your username and password didn't match. Please try again." %}</p>{% endif %}
<dl>
<dt><label>Username</label></dt>
<dt><label>{% trans "Username" %}</label></dt>
<dd>{{ form.username }}</dd>
<dt><label>Password</label></dt>
<dt><label>{% trans "Password" %}</label></dt>
<dd>{{ form.password }}</dd>
</dl>
<input type='submit' value='Login' />
<input type='submit' value='{% trans "Login" %}' />
<input type="hidden" name="next" value="{% if next %}{{ next }}{% else %}../{% endif %}" />
</form>
{% endblock %}

View File

@ -1,9 +0,0 @@
{% extends "helpdesk/public_base.html" %}
{% block helpdesk_title %}Helpdesk{% endblock %}
{% block helpdesk_body %}
<h2>Logout</h2>
<p>Thanks for being here. Hopefully you've helped resolve a few tickets and make the world a better place.</p>
{% endblock %}

View File

@ -15,9 +15,10 @@ from django.db.models import Q
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.shortcuts import render_to_response, get_object_or_404
from django.template import loader, Context, RequestContext
from django.utils.translation import ugettext as _
from helpdesk.forms import TicketForm, PublicTicketForm
from helpdesk.lib import send_templated_mail, line_chart, bar_chart
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment
def dashboard(request):
@ -43,7 +44,7 @@ def dashboard(request):
GROUP BY queue, name
ORDER BY q.id;
""")
dash_tickets = cursor.dictfetchall()
dash_tickets = query_to_dict(cursor.fetchall(), cursor.description)
return render_to_response('helpdesk/dashboard.html',
RequestContext(request, {
@ -92,7 +93,7 @@ def view_ticket(request, ticket_id):
owner = 0
else:
owner = ticket.assigned_to.id
request.POST = {'new_status': Ticket.CLOSED_STATUS, 'public': 1, 'owner': owner, 'title': ticket.title, 'comment': "Accepted resolution and closed ticket"}
request.POST = {'new_status': Ticket.CLOSED_STATUS, 'public': 1, 'owner': owner, 'title': ticket.title, 'comment': _('Accepted resolution and closed ticket')}
return update_ticket(request, ticket_id)
return render_to_response('helpdesk/ticket.html',
@ -126,11 +127,11 @@ def update_ticket(request, ticket_id):
if owner:
if owner != 0 and (ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to:
new_user = User.objects.get(id=owner)
f.title = 'Assigned to %s' % new_user.username
f.title = _('Assigned to %(username)s') % {'username': new_user.username}
ticket.assigned_to = new_user
reassigned = True
else:
f.title = 'Unassigned'
f.title = _('Unassigned')
ticket.assigned_to = None
if new_status != ticket.status:
@ -144,19 +145,19 @@ def update_ticket(request, ticket_id):
if not f.title:
if f.comment:
f.title = 'Comment'
f.title = _('Comment')
else:
f.title = 'Updated'
f.title = _('Updated')
f.save()
if title != ticket.title:
c = TicketChange(followup=f, field='Title', old_value=ticket.title, new_value=title)
c = TicketChange(followup=f, field=_('Title'), old_value=ticket.title, new_value=title)
c.save()
ticket.title = title
if priority != ticket.priority:
c = TicketChange(followup=f, field='Priority', old_value=ticket.priority, new_value=priority)
c = TicketChange(followup=f, field=_('Priority'), old_value=ticket.priority, new_value=priority)
c.save()
ticket.priority = priority
@ -315,7 +316,7 @@ def public_view(request):
RequestContext(request, {'ticket': t,}))
except:
t = False;
error_message = 'Invalid ticket ID or e-mail address. Please try again.'
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
return render_to_response('helpdesk/public_view_form.html',
RequestContext(request, {
@ -329,10 +330,10 @@ def hold_ticket(request, ticket_id, unhold=False):
if unhold:
ticket.on_hold = False
title = 'Ticket taken off hold'
title = _('Ticket taken off hold')
else:
ticket.on_hold = True
title = 'Ticket placed on hold'
title = _('Ticket placed on hold')
f = FollowUp(
ticket = ticket,
@ -368,15 +369,15 @@ def run_report(request, report):
priority_sql = []
priority_columns = []
for p in Ticket.PRIORITY_CHOICES:
priority_sql.append("COUNT(CASE t.priority WHEN '%s' THEN t.id END) AS \"%s\"" % (p[0], p[1]))
priority_columns.append("%s" % p[1])
priority_sql.append("COUNT(CASE t.priority WHEN '%s' THEN t.id END) AS \"%s\"" % (p[0], p[1]._proxy____unicode_cast()))
priority_columns.append("%s" % p[1]._proxy____unicode_cast())
priority_sql = ", ".join(priority_sql)
status_sql = []
status_columns = []
for s in Ticket.STATUS_CHOICES:
status_sql.append("COUNT(CASE t.status WHEN '%s' THEN t.id END) AS \"%s\"" % (s[0], s[1]))
status_columns.append("%s" % s[1])
status_sql.append("COUNT(CASE t.status WHEN '%s' THEN t.id END) AS \"%s\"" % (s[0], s[1]._proxy____unicode_cast()))
status_columns.append("%s" % s[1]._proxy____unicode_cast())
status_sql = ", ".join(status_sql)
queue_sql = []
@ -483,7 +484,7 @@ def run_report(request, report):
from django.db import connection
cursor = connection.cursor()
cursor.execute(sql)
report_output = cursor.dictfetchall()
report_output = query_to_dict(cursor.fetchall(), cursor.description)
data = []