mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-22 16:03:19 +01:00
* Enlarged Chart sizes to allow more data to be displayed
* Added superuser 'System settings' page with links to admin * Added ability to ignore e-mail addresses (using wildcards) from the e-mail parser * Added link to ignore email address from ticket details page (for superusers only) * Cleaned up report output by styling text & labels in the same way as tables in other views * Cleaned up dashboard lists to show text in place of tickets if no tickets are found * Added ability to sort in reverse order NOTE: REQUIRES A 'syncdb' TO CREATE THE EMAIL-IGNORE TABLES. No other DB changes were made.
This commit is contained in:
parent
5914e98d43
commit
c97a255155
6
forms.py
6
forms.py
@ -14,7 +14,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from helpdesk.lib import send_templated_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp
|
from helpdesk.models import Ticket, Queue, FollowUp, IgnoreEmail
|
||||||
|
|
||||||
class TicketForm(forms.Form):
|
class TicketForm(forms.Form):
|
||||||
queue = forms.ChoiceField(
|
queue = forms.ChoiceField(
|
||||||
@ -265,3 +265,7 @@ class UserSettingsForm(forms.Form):
|
|||||||
help_text=_('If a ticket is altered by the API, do you want to receive an e-mail?'),
|
help_text=_('If a ticket is altered by the API, do you want to receive an e-mail?'),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class EmailIgnoreForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = IgnoreEmail
|
||||||
|
10
lib.py
10
lib.py
@ -165,8 +165,8 @@ def line_chart(data):
|
|||||||
max = field
|
max = field
|
||||||
|
|
||||||
|
|
||||||
# Set width to '65px * number of months'.
|
# Set width to '65px * number of months + 100 for headings.'.
|
||||||
chart_url = 'http://chart.apis.google.com/chart?cht=lc&chs=%sx90&chd=t:' % (len(column_headings)*65)
|
chart_url = 'http://chart.apis.google.com/chart?cht=lc&chs=%sx150&chd=t:' % (len(column_headings)*65+100)
|
||||||
first_row = True
|
first_row = True
|
||||||
row_headings = []
|
row_headings = []
|
||||||
for row in data[1:]:
|
for row in data[1:]:
|
||||||
@ -210,8 +210,8 @@ def bar_chart(data):
|
|||||||
max = field
|
max = field
|
||||||
|
|
||||||
|
|
||||||
# Set width to '150px * number of months'.
|
# Set width to '220px * number of months'.
|
||||||
chart_url = 'http://chart.apis.google.com/chart?cht=bvg&chs=%sx90&chd=t:' % (len(column_headings) * 150)
|
chart_url = 'http://chart.apis.google.com/chart?cht=bvg&chs=%sx150&chd=t:' % (len(column_headings) * 220)
|
||||||
first_row = True
|
first_row = True
|
||||||
row_headings = []
|
row_headings = []
|
||||||
for row in data[1:]:
|
for row in data[1:]:
|
||||||
@ -276,6 +276,8 @@ def apply_query(queryset, params):
|
|||||||
queryset = queryset.filter(params['other_filter'])
|
queryset = queryset.filter(params['other_filter'])
|
||||||
|
|
||||||
if params.get('sorting', None):
|
if params.get('sorting', None):
|
||||||
|
if params.get('sortreverse', None):
|
||||||
|
params['sorting'] = "-%s" % params['sorting']
|
||||||
queryset = queryset.order_by(params['sorting'])
|
queryset = queryset.order_by(params['sorting'])
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
@ -20,10 +20,11 @@ from email.Utils import parseaddr
|
|||||||
|
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from helpdesk.lib import send_templated_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
from helpdesk.models import Queue, Ticket, FollowUp, Attachment
|
from helpdesk.models import Queue, Ticket, FollowUp, Attachment, IgnoreEmail
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@ -76,9 +77,11 @@ def process_queue(q):
|
|||||||
msgSize = msg.split(" ")[1]
|
msgSize = msg.split(" ")[1]
|
||||||
|
|
||||||
full_message = "\n".join(server.retr(msgNum)[1])
|
full_message = "\n".join(server.retr(msgNum)[1])
|
||||||
ticket_from_message(message=full_message, queue=q)
|
ticket = ticket_from_message(message=full_message, queue=q)
|
||||||
|
|
||||||
|
if ticket:
|
||||||
server.dele(msgNum)
|
server.dele(msgNum)
|
||||||
|
|
||||||
server.quit()
|
server.quit()
|
||||||
|
|
||||||
elif q.email_box_type == 'imap':
|
elif q.email_box_type == 'imap':
|
||||||
@ -94,8 +97,10 @@ def process_queue(q):
|
|||||||
status, data = server.search(None, 'ALL')
|
status, data = server.search(None, 'ALL')
|
||||||
for num in data[0].split():
|
for num in data[0].split():
|
||||||
status, data = server.fetch(num, '(RFC822)')
|
status, data = server.fetch(num, '(RFC822)')
|
||||||
ticket_from_message(message=data[0][1], queue=q)
|
ticket = ticket_from_message(message=data[0][1], queue=q)
|
||||||
|
if ticket:
|
||||||
server.store(num, '+FLAGS', '\\Deleted')
|
server.store(num, '+FLAGS', '\\Deleted')
|
||||||
|
|
||||||
server.expunge()
|
server.expunge()
|
||||||
server.close()
|
server.close()
|
||||||
server.logout()
|
server.logout()
|
||||||
@ -111,8 +116,10 @@ def ticket_from_message(message, queue):
|
|||||||
sender = message.get('from', _('Unknown Sender'))
|
sender = message.get('from', _('Unknown Sender'))
|
||||||
|
|
||||||
sender_email = parseaddr(sender)[1]
|
sender_email = parseaddr(sender)[1]
|
||||||
if sender_email.startswith('postmaster'):
|
|
||||||
sender_email = ''
|
for ignore in IgnoreEmail.objects.filter(Q(queues=queue) | Q(queues__isnull=True)):
|
||||||
|
if ignore.test(sender_email):
|
||||||
|
return False
|
||||||
|
|
||||||
regex = re.compile("^\[[A-Za-z0-9]+-\d+\]")
|
regex = re.compile("^\[[A-Za-z0-9]+-\d+\]")
|
||||||
if regex.match(subject):
|
if regex.match(subject):
|
||||||
@ -256,6 +263,8 @@ def ticket_from_message(message, queue):
|
|||||||
a.save()
|
a.save()
|
||||||
print " - %s" % file['filename']
|
print " - %s" % file['filename']
|
||||||
|
|
||||||
|
return ticket
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
process_email()
|
process_email()
|
||||||
|
65
models.py
65
models.py
@ -926,3 +926,68 @@ def create_usersettings(sender, created_models=[], instance=None, created=False,
|
|||||||
|
|
||||||
models.signals.post_syncdb.connect(create_usersettings)
|
models.signals.post_syncdb.connect(create_usersettings)
|
||||||
models.signals.post_save.connect(create_usersettings, sender=User)
|
models.signals.post_save.connect(create_usersettings, sender=User)
|
||||||
|
|
||||||
|
class IgnoreEmail(models.Model):
|
||||||
|
"""
|
||||||
|
This model lets us easily ignore e-mails from certain senders when
|
||||||
|
processing IMAP and POP3 mailboxes, eg mails from postmaster or from
|
||||||
|
known trouble-makers.
|
||||||
|
"""
|
||||||
|
queues = models.ManyToManyField(
|
||||||
|
Queue,
|
||||||
|
blank=True,
|
||||||
|
null=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.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
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@*.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
if not self.date:
|
||||||
|
self.date = datetime.now()
|
||||||
|
return super(IgnoreEmail, self).save()
|
||||||
|
|
||||||
|
def test(self, email):
|
||||||
|
"""
|
||||||
|
Possible situations:
|
||||||
|
1. Username & Domain both match
|
||||||
|
2. Username is wildcard, domain matches
|
||||||
|
3. Username matches, domain is wildcard
|
||||||
|
4. username & domain are both wildcards
|
||||||
|
5. Other (no match)
|
||||||
|
|
||||||
|
1-4 return True, 5 returns False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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] == "*":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
{% block helpdesk_body %}{% endblock %}
|
{% block helpdesk_body %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
<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> <a href='{% url helpdesk_user_settings %}'>{% trans "User Settings" %}</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> <a href='{% url helpdesk_user_settings %}'>{% trans "User Settings" %}</a> {% if user.is_superuser %}<a href='{% url helpdesk_system_settings %}'>{% trans "System Settings" %}</a>{% endif %}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include "helpdesk/debug.html" %}
|
{% include "helpdesk/debug.html" %}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block helpdesk_body %}
|
{% block helpdesk_body %}
|
||||||
|
|
||||||
<table width='30%' align='left'>
|
<table width='40%' align='left'>
|
||||||
<tr class='row_tablehead'><td colspan='4'>{% trans "Helpdesk Summary" %}</td></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>
|
<tr class='row_columnheads'><th>{% trans "Queue" %}</th><th>{% trans "Open" %}</th><th>{% trans "Resolved" %}</th></tr>
|
||||||
{% for queue in dash_tickets %}
|
{% for queue in dash_tickets %}
|
||||||
@ -17,7 +17,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p style='padding-left: 5px;'>Welcome to your Helpdesk Dashboard! From here you can quickly see your own tickets, and those tickets that have no owner. Why not pick up an orphan ticket and sort it out for a customer?</p>
|
<p style='margin-left: 42%;'>Welcome to your Helpdesk Dashboard! From here you can quickly see your own tickets, and those tickets that have no owner. Why not pick up an orphan ticket and sort it out for a customer?</p>
|
||||||
|
|
||||||
<br style='clear: both;' />
|
<br style='clear: both;' />
|
||||||
|
|
||||||
@ -34,6 +34,9 @@
|
|||||||
<td><span title='{{ ticket.modified|date:"r" }}'>{{ ticket.modified|timesince }}</span></td>
|
<td><span title='{{ ticket.modified|date:"r" }}'>{{ ticket.modified|timesince }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if not unassigned_tickets %}
|
||||||
|
<tr class='row_odd'><td colspan='5'>{% trans "You have no tickets assigned to you." %}</td></tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table width='100%'>
|
<table width='100%'>
|
||||||
@ -49,6 +52,9 @@
|
|||||||
<th><a href='{{ ticket.get_absolute_url }}?take'><span class='button button_take'>{% trans "Take" %}</span></a></th>
|
<th><a href='{{ ticket.get_absolute_url }}?take'><span class='button button_take'>{% trans "Take" %}</span></a></th>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if not unassigned_tickets %}
|
||||||
|
<tr class='row_odd'><td colspan='6'>{% trans "There are no unassigned tickets." %}</td></tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
27
templates/helpdesk/email_ignore_add.html
Normal file
27
templates/helpdesk/email_ignore_add.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}{% trans "Ignore E-Mail Address" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}{% blocktrans %}
|
||||||
|
<h2>Ignore E-Mail Address</h2>
|
||||||
|
|
||||||
|
<p>To ignore an e-mail address and prevent any emails from that address creating tickets automatically, enter the e-mail address below.</p>
|
||||||
|
|
||||||
|
<p>You can either enter a whole e-mail address such as <em>email@domain.com</em> or a portion of an e-mail address with a wildcard, such as <em>*@domain.com</em> or <em>user@*</em>.</p>{% endblocktrans %}
|
||||||
|
|
||||||
|
<form method='post' action='./'>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<dl>{% for field in form %}
|
||||||
|
<dt><label for='id_{{ field.name }}'>{{ field.label }}</label></dt>
|
||||||
|
<dd>{{ field }}</dd>
|
||||||
|
{% if field.errors %}<dd class='error'>{{ field.errors }}</dd>{% endif %}
|
||||||
|
{% if field.help_text %}<dd class='form_help_text'>{{ field.help_text }}</dd>{% endif %}
|
||||||
|
{% endfor %}</dl>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<input type='submit' value='{% trans "Ignore E-Mail Address" %}' />
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
14
templates/helpdesk/email_ignore_del.html
Normal file
14
templates/helpdesk/email_ignore_del.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}{% trans "Delete Ignored E-Mail Address" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}{% blocktrans with ignore.email_address as email_address %}
|
||||||
|
<h2>Un-Ignore E-Mail Address</h2>
|
||||||
|
|
||||||
|
<p>Are you sure you wish to stop removing this email address (<em>{{ email_address }}</em>) and allow their e-mails to automatically create tickets in your system? You can re-add this e-mail address at any time.<?p>
|
||||||
|
{% endblocktrans %}
|
||||||
|
|
||||||
|
{% blocktrans %}<p><a href='../../'>Keep Ignoring It</a></p>
|
||||||
|
|
||||||
|
<form method='post' action='./'><input type='submit' value='Stop Ignoring It' /></form>
|
||||||
|
{% endblocktrans %}{% endblock %}
|
28
templates/helpdesk/email_ignore_list.html
Normal file
28
templates/helpdesk/email_ignore_list.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}{% trans "Ignored E-Mail Addresses" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}{% blocktrans %}
|
||||||
|
<h2>Ignored E-Mail Addresses</h2>
|
||||||
|
|
||||||
|
<p>The following e-mail addresses are currently being ignored by the incoming e-mail processor. You can <a href='add/'>add a new e-mail address to the list</a> or delete any of the items below as required.</p>{% endblocktrans %}
|
||||||
|
|
||||||
|
<table width='100%'>
|
||||||
|
<thead>
|
||||||
|
<tr class='row_tablehead'><td colspan='5'>{% trans "Ignored E-Mail Addresses" %}</td></tr>
|
||||||
|
<tr class='row_columnheads'><th>{% trans "Name" %}</th><th>{% trans "E-Mail Address" %}</th><th>{% trans "Date Added" %}</th><th>{% trans "Queues" %}</th><th>{% trans "Delete" %}</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for ignore in ignore_list %}
|
||||||
|
<tr class='row_{% cycle odd,even %}'>
|
||||||
|
<td>{{ ignore.name }}</td>
|
||||||
|
<td>{{ ignore.email_address }}</td>
|
||||||
|
<td>{{ ignore.date }}</td>
|
||||||
|
<td>{% for queue in ignore.queues.all %}{{ queue.slug }}{% if not forloop.last %}, {% endif %}{% endfor %}{% if not ignore.queues.all %}All{% endif %}</td>
|
||||||
|
<td><a href='{% url helpdesk_email_ignore_del ignore.id %}'>Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -6,8 +6,10 @@
|
|||||||
<h2>{% trans "Reports & Statistics" %}</h2>
|
<h2>{% trans "Reports & Statistics" %}</h2>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>{% for h in headings %}<th>{{ h }}</th>{% endfor %}</tr>
|
<tr class='row_tablehead'><td colspan='{{ headings|length }}'>{{ title }}</td></tr>
|
||||||
{% for d in data %}<tr>{% for f in d %}<td>{{ f }}</td>{% endfor %}</tr>{% endfor %}
|
<tr class='row_columnheads'>{% for h in headings %}<th>{% if forloop.first %}{{ h|title }}{% else %}{{ h }}{% endif %}</th>{% endfor %}</tr>
|
||||||
|
{% for d in data %}
|
||||||
|
<tr class='row_{% cycle odd,even %}'>{% for f in d %}<td>{{ f }}</td>{% endfor %}</tr>{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% if chart %}<img src='{{ chart }}' />{% endif %}
|
{% if chart %}<img src='{{ chart }}' />{% endif %}
|
||||||
|
19
templates/helpdesk/system_settings.html
Normal file
19
templates/helpdesk/system_settings.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}{% trans "Change System Settings" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}{% blocktrans %}
|
||||||
|
<h2>System Settings</h2>
|
||||||
|
|
||||||
|
<p>The following items can be maintained by you or other superusers:</p>{% endblocktrans %}
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href='../ignore/'>{% trans "E-Mail Ignore list" %}</a></li>
|
||||||
|
<li><a href='/admin/helpdesk/queue/'>{% trans "Maintain Queues" %}</a></li>
|
||||||
|
<li><a href='/admin/helpdesk/presetreply/'>{% trans "Maintain Pre-Set Replies" %}</a></li>
|
||||||
|
<li><a href='/admin/helpdesk/kbcategory/'>{% trans "Maintain Knowledgebase Categories" %}</a></li>
|
||||||
|
<li><a href='/admin/helpdesk/kbitem/'>{% trans "Maintain Knowledgebase Items" %}</a></li>
|
||||||
|
<li><a href='/admin/helpdesk/emailtemplate/'>{% trans "Maintain E-Mail Templates" %}</a></li>
|
||||||
|
<li><a href='/admin/auth/user/'>{% trans "Maintain Users" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
<tr class='row_odd'>
|
<tr class='row_odd'>
|
||||||
<th>{% trans "Submitter E-Mail" %}</th>
|
<th>{% trans "Submitter E-Mail" %}</th>
|
||||||
<td>{{ ticket.submitter_email }}</td>
|
<td>{{ ticket.submitter_email }}{% if user.is_superuser %} <strong><a href='{% url helpdesk_email_ignore_add %}?email={{ ticket.submitter_email }}'>{% trans "Ignore" %}</a></strong>{% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class='row_even'>
|
<tr class='row_even'>
|
||||||
|
@ -43,6 +43,7 @@ $(document).ready(function() {
|
|||||||
<option value='priority'{% ifequal query_params.sorting "priority"%} selected='selected'{% endifequal %}>{% trans "Priority" %}</option>
|
<option value='priority'{% ifequal query_params.sorting "priority"%} selected='selected'{% endifequal %}>{% trans "Priority" %}</option>
|
||||||
<option value='assigned_to'{% ifequal query_params.sorting "assigned_to"%} selected='selected'{% endifequal %}>{% trans "Owner" %}</option>
|
<option value='assigned_to'{% ifequal query_params.sorting "assigned_to"%} selected='selected'{% endifequal %}>{% trans "Owner" %}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label for='id_sortreverse'>Reverse</label><input type='checkbox' name='sortreverse' id='id_sortreverse'{% if query_params.sortreverse %} checked='checked'{% endif %} />
|
||||||
<p class='filterHelp'>Ordering applied to tickets</p>
|
<p class='filterHelp'>Ordering applied to tickets</p>
|
||||||
<input type='button' class='filterBuilderRemove' value='-' />
|
<input type='button' class='filterBuilderRemove' value='-' />
|
||||||
</div>
|
</div>
|
||||||
|
17
urls.py
17
urls.py
@ -73,6 +73,18 @@ urlpatterns = patterns('helpdesk.views.staff',
|
|||||||
url(r'^settings/$',
|
url(r'^settings/$',
|
||||||
'user_settings',
|
'user_settings',
|
||||||
name='helpdesk_user_settings'),
|
name='helpdesk_user_settings'),
|
||||||
|
|
||||||
|
url(r'^ignore/$',
|
||||||
|
'email_ignore',
|
||||||
|
name='helpdesk_email_ignore'),
|
||||||
|
|
||||||
|
url(r'^ignore/add/$',
|
||||||
|
'email_ignore_add',
|
||||||
|
name='helpdesk_email_ignore_add'),
|
||||||
|
|
||||||
|
url(r'^ignore/delete/(?P<id>[0-9]+)/$',
|
||||||
|
'email_ignore_del',
|
||||||
|
name='helpdesk_email_ignore_del'),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += patterns('helpdesk.views.public',
|
urlpatterns += patterns('helpdesk.views.public',
|
||||||
@ -129,4 +141,9 @@ urlpatterns += patterns('',
|
|||||||
'django.views.generic.simple.direct_to_template',
|
'django.views.generic.simple.direct_to_template',
|
||||||
{'template': 'helpdesk/help_context.html',},
|
{'template': 'helpdesk/help_context.html',},
|
||||||
name='helpdesk_help_context'),
|
name='helpdesk_help_context'),
|
||||||
|
|
||||||
|
url(r'^system_settings/$',
|
||||||
|
'django.views.generic.simple.direct_to_template',
|
||||||
|
{'template': 'helpdesk/system_settings.html',},
|
||||||
|
name='helpdesk_system_settings'),
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ views/staff.py - The bulk of the application - provides most business logic and
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
@ -20,9 +20,14 @@ from django.shortcuts import render_to_response, get_object_or_404
|
|||||||
from django.template import loader, Context, RequestContext
|
from django.template import loader, Context, RequestContext
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from helpdesk.forms import TicketForm, UserSettingsForm
|
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm
|
||||||
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict, apply_query, safe_template_context
|
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict, apply_query, safe_template_context
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch
|
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
@ -199,7 +204,7 @@ def update_ticket(request, ticket_id):
|
|||||||
if f.new_status == Ticket.RESOLVED_STATUS:
|
if f.new_status == Ticket.RESOLVED_STATUS:
|
||||||
ticket.resolution = comment
|
ticket.resolution = comment
|
||||||
|
|
||||||
if ticket.submitter_email and ((f.comment != '' and public) or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))):
|
if ticket.submitter_email and public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))):
|
||||||
context = {
|
context = {
|
||||||
'ticket': ticket,
|
'ticket': ticket,
|
||||||
'queue': ticket.queue,
|
'queue': ticket.queue,
|
||||||
@ -287,6 +292,7 @@ def ticket_list(request):
|
|||||||
query_params = {
|
query_params = {
|
||||||
'filtering': {},
|
'filtering': {},
|
||||||
'sorting': None,
|
'sorting': None,
|
||||||
|
'sortreverse': False,
|
||||||
'keyword': None,
|
'keyword': None,
|
||||||
'other_filter': None,
|
'other_filter': None,
|
||||||
}
|
}
|
||||||
@ -308,7 +314,8 @@ def ticket_list(request):
|
|||||||
or request.GET.has_key('assigned_to')
|
or request.GET.has_key('assigned_to')
|
||||||
or request.GET.has_key('status')
|
or request.GET.has_key('status')
|
||||||
or request.GET.has_key('q')
|
or request.GET.has_key('q')
|
||||||
or request.GET.has_key('sort') ):
|
or request.GET.has_key('sort')
|
||||||
|
or request.GET.has_key('sortreverse') ):
|
||||||
|
|
||||||
# Fall-back if no querying is being done, force the list to only
|
# Fall-back if no querying is being done, force the list to only
|
||||||
# show open/reopened/resolved (not closed) cases sorted by creation
|
# show open/reopened/resolved (not closed) cases sorted by creation
|
||||||
@ -354,6 +361,9 @@ def ticket_list(request):
|
|||||||
sort = 'created'
|
sort = 'created'
|
||||||
query_params['sorting'] = sort
|
query_params['sorting'] = sort
|
||||||
|
|
||||||
|
sortreverse = request.GET.get('sortreverse', None)
|
||||||
|
query_params['sortreverse'] = sortreverse
|
||||||
|
|
||||||
tickets = apply_query(Ticket.objects.select_related(), query_params)
|
tickets = apply_query(Ticket.objects.select_related(), query_params)
|
||||||
|
|
||||||
import cPickle, base64
|
import cPickle, base64
|
||||||
@ -555,30 +565,37 @@ def run_report(request, report):
|
|||||||
if report == 'userpriority':
|
if report == 'userpriority':
|
||||||
sql = user_base_sql % priority_sql
|
sql = user_base_sql % priority_sql
|
||||||
columns = ['username'] + priority_columns
|
columns = ['username'] + priority_columns
|
||||||
|
title = 'User by Priority'
|
||||||
|
|
||||||
elif report == 'userqueue':
|
elif report == 'userqueue':
|
||||||
sql = user_base_sql % queue_sql
|
sql = user_base_sql % queue_sql
|
||||||
columns = ['username'] + queue_columns
|
columns = ['username'] + queue_columns
|
||||||
|
title = 'User by Queue'
|
||||||
|
|
||||||
elif report == 'userstatus':
|
elif report == 'userstatus':
|
||||||
sql = user_base_sql % status_sql
|
sql = user_base_sql % status_sql
|
||||||
columns = ['username'] + status_columns
|
columns = ['username'] + status_columns
|
||||||
|
title = 'User by Status'
|
||||||
|
|
||||||
elif report == 'usermonth':
|
elif report == 'usermonth':
|
||||||
sql = user_base_sql % month_sql
|
sql = user_base_sql % month_sql
|
||||||
columns = ['username'] + month_columns
|
columns = ['username'] + month_columns
|
||||||
|
title = 'User by Month'
|
||||||
|
|
||||||
elif report == 'queuepriority':
|
elif report == 'queuepriority':
|
||||||
sql = queue_base_sql % priority_sql
|
sql = queue_base_sql % priority_sql
|
||||||
columns = ['queue'] + priority_columns
|
columns = ['queue'] + priority_columns
|
||||||
|
title = 'Queue by Priority'
|
||||||
|
|
||||||
elif report == 'queuestatus':
|
elif report == 'queuestatus':
|
||||||
sql = queue_base_sql % status_sql
|
sql = queue_base_sql % status_sql
|
||||||
columns = ['queue'] + status_columns
|
columns = ['queue'] + status_columns
|
||||||
|
title = 'Queue by Status'
|
||||||
|
|
||||||
elif report == 'queuemonth':
|
elif report == 'queuemonth':
|
||||||
sql = queue_base_sql % month_sql
|
sql = queue_base_sql % month_sql
|
||||||
columns = ['queue'] + month_columns
|
columns = ['queue'] + month_columns
|
||||||
|
title = 'Queue by Month'
|
||||||
|
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
@ -604,8 +621,8 @@ def run_report(request, report):
|
|||||||
RequestContext(request, {
|
RequestContext(request, {
|
||||||
'headings': columns,
|
'headings': columns,
|
||||||
'data': data,
|
'data': data,
|
||||||
'sql': sql,
|
|
||||||
'chart': chart_url,
|
'chart': chart_url,
|
||||||
|
'title': title,
|
||||||
}))
|
}))
|
||||||
run_report = login_required(run_report)
|
run_report = login_required(run_report)
|
||||||
|
|
||||||
@ -638,6 +655,7 @@ def delete_saved_query(request, id):
|
|||||||
}))
|
}))
|
||||||
delete_saved_query = login_required(delete_saved_query)
|
delete_saved_query = login_required(delete_saved_query)
|
||||||
|
|
||||||
|
|
||||||
def user_settings(request):
|
def user_settings(request):
|
||||||
s = request.user.usersettings
|
s = request.user.usersettings
|
||||||
if request.POST:
|
if request.POST:
|
||||||
@ -653,3 +671,40 @@ def user_settings(request):
|
|||||||
'form': form,
|
'form': form,
|
||||||
}))
|
}))
|
||||||
user_settings = login_required(user_settings)
|
user_settings = login_required(user_settings)
|
||||||
|
|
||||||
|
|
||||||
|
def email_ignore(request):
|
||||||
|
return render_to_response('helpdesk/email_ignore_list.html',
|
||||||
|
RequestContext(request, {
|
||||||
|
'ignore_list': IgnoreEmail.objects.all(),
|
||||||
|
}))
|
||||||
|
email_ignore = superuser_required(email_ignore)
|
||||||
|
|
||||||
|
|
||||||
|
def email_ignore_add(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = EmailIgnoreForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
ignore = form.save()
|
||||||
|
return HttpResponseRedirect(reverse('helpdesk_email_ignore'))
|
||||||
|
else:
|
||||||
|
form = EmailIgnoreForm(request.GET)
|
||||||
|
|
||||||
|
return render_to_response('helpdesk/email_ignore_add.html',
|
||||||
|
RequestContext(request, {
|
||||||
|
'form': form,
|
||||||
|
}))
|
||||||
|
email_ignore_add = superuser_required(email_ignore_add)
|
||||||
|
|
||||||
|
|
||||||
|
def email_ignore_del(request, id):
|
||||||
|
ignore = get_object_or_404(IgnoreEmail, id=id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
ignore.delete()
|
||||||
|
return HttpResponseRedirect(reverse('helpdesk_email_ignore'))
|
||||||
|
else:
|
||||||
|
return render_to_response('helpdesk/email_ignore_del.html',
|
||||||
|
RequestContext(request, {
|
||||||
|
'ignore': ignore,
|
||||||
|
}))
|
||||||
|
email_ignore_del = superuser_required(email_ignore_del)
|
||||||
|
Loading…
Reference in New Issue
Block a user