make django-helpdesk more customizable + bug fixes:

- look at settings.py for all new options regarding customization.
- settings can be accessed inside the templates via the new
  templatetag 'load_helpdesk_settings'

- allow editing of personal followups, but only if followup does not
  contain any ticketchanges - otherwise this information is lost after
  the editing.
- add 'delete' link to attachments
- link to list of closed tickets in queue overview
- add 'closed & resolved' section to dashboard
- hide 'pre-set reply' box if no pre-set replies are found.
- use 'SelectDateWidget' for custom DateField

- fix how we update followups so that attachments don't get deleted
- fix bug where resolution emails contained the solution 'None'
- fix stats crashing bug
- fix locale bug
This commit is contained in:
Andreas Kotowicz 2011-11-19 09:34:07 +01:00
parent 6e33408a7d
commit cb34b1933a
15 changed files with 237 additions and 36 deletions

View File

@ -11,6 +11,7 @@ from datetime import datetime
from StringIO import StringIO
from django import forms
from django.forms import extras
from django.conf import settings
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
@ -195,6 +196,7 @@ class TicketForm(forms.Form):
fieldclass = forms.BooleanField
elif field.data_type == 'date':
fieldclass = forms.DateField
instanceargs['widget'] = extras.SelectDateWidget
elif field.data_type == 'time':
fieldclass = forms.TimeField
elif field.data_type == 'datetime':

View File

@ -54,7 +54,13 @@ def send_templated_mail(template_name, email_context, recipients, sender=None, b
import os
context = Context(email_context)
if hasattr(context['queue'], 'locale'):
locale = getattr(context['queue'], 'locale', '')
else:
locale = context['queue'].get('locale', 'en')
if not locale:
locale = 'en'
t = None
try:

View File

@ -28,5 +28,59 @@ if type(DEFAULT_USER_SETTINGS) != type(dict()):
'tickets_per_page': 25
}
''' generic options - visible on all pages '''
# redirect to login page instead of the default homepage when users visits "/"?
HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = getattr(settings, 'HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT', False)
# show knowledgebase links?
HELPDESK_KB_ENABLED = getattr(settings, 'HELPDESK_KB_ENABLED', True)
# show extended navigation by default, to all users, irrespective of staff status?
HELPDESK_NAVIGATION_ENABLED = getattr(settings, 'HELPDESK_NAVIGATION_ENABLED', False)
# show 'stats' link in navigation bar?
HELPDESK_NAVIGATION_STATS_ENABLED = getattr(settings, 'HELPDESK_NAVIGATION_STATS_ENABLED', True)
# set this to an email address inside your organization and a footer below
# the 'Powered by django-helpdesk' will be shown, telling the user whom to contact
# in case they have technical problems.
HELPDESK_SUPPORT_PERSON = getattr(settings, 'HELPDESK_SUPPORT_PERSON', False)
''' options for public pages '''
# show 'view a ticket' section on public page?
HELPDESK_VIEW_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC', True)
# show 'submit a ticket' section on public page?
HELPDESK_SUBMIT_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_SUBMIT_A_TICKET_PUBLIC', True)
''' options for update_ticket views '''
# allow non-staff users to interact with tickets? this will also change how 'staff_member_required'
# in staff.py will be defined.
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = getattr(settings, 'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE', False)
# show edit buttons in ticket follow ups.
HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings, 'HELPDESK_HIDE_EDIT_BUTTON_FOLLOW_UP', True)
# show ticket edit button on top of ticket description.
HELPDESK_SHOW_EDIT_BUTTON_TICKET_TOP = getattr(settings, 'HELPDESK_SHOW_EDIT_BUTTON_TICKET_TOP', True)
# show ticket delete button on top of ticket description.
HELPDESK_SHOW_DELETE_BUTTON_TICKET_TOP = getattr(settings, 'HELPDESK_SHOW_DELETE_BUTTON_TICKET_TOP', True)
# show hold / unhold button on top of ticket description.
HELPDESK_SHOW_HOLD_BUTTON_TICKET_TOP = getattr(settings, 'HELPDESK_SHOW_HOLD_BUTTON_TICKET_TOP', True)
# make all updates public by default? this will hide the 'is this update public' checkbox
HELPDESK_UPDATE_PUBLIC_DEFAULT = getattr(settings, 'HELPDESK_UPDATE_PUBLIC_DEFAULT', True)
''' options for dashboard '''
# show delete button next to unassigned tickets
HELPDESK_DASHBOARD_SHOW_DELETE_UNASSIGNED = getattr(settings, 'HELPDESK_DASHBOARD_SHOW_DELETE_UNASSIGNED', True)
''' options for footer '''
# show 'API' link at bottom of page
HELPDESK_FOOTER_SHOW_API_LINK = getattr(settings, 'HELPDESK_FOOTER_SHOW_API_LINK', True)

View File

@ -1,2 +1,5 @@
{% load i18n %}
{% trans "Powered by <a href='https://github.com/rossp/django-helpdesk'>django-helpdesk</a>." %}
{% if helpdesk_settings.HELPDESK_SUPPORT_PERSON %}
<p>{% trans "For technical support please contact:" %} <a href='mailto:{{ helpdesk_settings.HELPDESK_SUPPORT_PERSON }}'>{{ helpdesk_settings.HELPDESK_SUPPORT_PERSON }}</a></p>
{% endif %}

View File

@ -1,5 +1,7 @@
{% load i18n %}
{% load saved_queries %}
{% load load_helpdesk_settings %}
{% with request|load_helpdesk_settings as helpdesk_settings %}
{% with request|saved_queries as user_saved_queries_ %}
<!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">
@ -51,10 +53,15 @@
</div>
<div id='footer'>
<p>{% include "helpdesk/attribution.html" %}<a href='{% url helpdesk_rss_index %}'><img src='{{ STATIC_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>
<p>{% include "helpdesk/attribution.html" %}
<a href='{% url helpdesk_rss_index %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "RSS Feeds" %}' border='0' />{% trans "RSS Feeds" %}</a>
{% if helpdesk_settings.HELPDESK_FOOTER_SHOW_API_LINK %}<a href='{% url helpdesk_api_help %}'>{% trans "API" %}</a>{% endif %}
<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>
{% include "helpdesk/debug.html" %}
</body>
</html>
{% endwith %}
{% endwith %}

View File

@ -6,13 +6,14 @@
{% block helpdesk_body %}
<table width='40%' align='left'>
<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_tablehead'><td colspan='5'>{% trans "Helpdesk Summary" %}</td></tr>
<tr class='row_columnheads'><th>{% trans "Queue" %}</th><th>{% trans "Open" %}</th><th>{% trans "Resolved" %}</th><th>{% trans "Closed" %}</th></tr>
{% for queue in dash_tickets %}
<tr class='row_{% cycle odd,even %} row_hover '>
<th><a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=1&status=2'>{{ queue.name }}</a></th>
<td>{% if queue.open %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=1&status=2'>{% endif %}{{ queue.open }}{% if queue.open %}</a>{% endif %}</td>
<td>{% if queue.resolved %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=3'>{% endif %}{{ queue.resolved }}{% if queue.resolved %}</a>{% endif %}</td>
<td align="center">{% if queue.open %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=1&status=2'>{% endif %}{{ queue.open }}{% if queue.open %}</a>{% endif %}</td>
<td align="center">{% if queue.resolved %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=3'>{% endif %}{{ queue.resolved }}{% if queue.resolved %}</a>{% endif %}</td>
<td align="center">{% if queue.closed %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=4'>{% endif %}{{ queue.closed }}{% if queue.closed %}</a>{% endif %}</td>
</tr>
{% endfor %}
</table>
@ -22,7 +23,7 @@
<br style='clear: both;' />
<table width='100%'>
<tr class='row_tablehead'><td colspan='6'>{% trans "Your Tickets" %}</td></tr>
<tr class='row_tablehead'><td colspan='6'>{% trans "Your Open 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'>
@ -39,6 +40,8 @@
{% endif %}
</table>
<br style='clear: both;' />
<table width='100%'>
<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>
@ -49,7 +52,7 @@
<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'><span class='button button_take'>{% trans "Take" %}</span></a> | <a href='{% url helpdesk_delete ticket.id %}'><span class='button button_delete'>{% trans "Delete" %}</span></a></th>
<th><a href='{{ ticket.get_absolute_url }}?take'><span class='button button_take'>{% trans "Take" %}</span></a> {% if helpdesk_settings.HELPDESK_DASHBOARD_SHOW_DELETE_UNASSIGNED %}| <a href='{% url helpdesk_delete ticket.id %}'><span class='button button_delete'>{% trans "Delete" %}</span></a>{% endif %}</th>
</tr>
{% endfor %}
{% if not unassigned_tickets %}
@ -57,4 +60,24 @@
{% endif %}
</table>
{% if user_tickets_closed_resolved %}
<br style='clear: both;' />
<table width='100%'>
<tr class='row_tablehead'><td colspan='6'>{% trans "Your closed & resolved 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_closed_resolved %}
<tr class='row_{% cycle odd,even %} row_hover'>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
<td>{{ ticket.get_priority_span }}</td>
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></th>
<td>{{ ticket.queue }}</td>
<td>{{ ticket.get_status }}</td>
<td><span title='{{ ticket.modified|date:"r" }}'>{{ ticket.modified|timesince }}</span></td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endblock %}

View File

@ -1,10 +1,12 @@
{% load i18n %}
{% if user.is_staff %}
{% if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED and user.is_authenticated or user.is_staff %}
<ul id="dropdown">
<li><a href='{% url helpdesk_dashboard %}'>{% 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>
{% if helpdesk_settings.HELPDESK_NAVIGATION_STATS_ENABLED %}
<li><a href='{% url helpdesk_report_index %}'>{% trans "Stats" %}</a></li>
{% endif %}
{% if user_saved_queries_ %}
<li class="headerlink"><a>Load Saved Query</a>
<ul>
@ -22,8 +24,12 @@
</ul>
{% else %}
<ul>
{% if helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
<li><a href='{% url helpdesk_home %}'>{% trans "Submit A Ticket" %}</a></li>
{% endif %}
{% if helpdesk_settings.HELPDESK_KB_ENABLED %}<li><a href='{% url helpdesk_kb_index %}'>{% trans "Knowledgebase" %}</a></li>{% endif %}
<li><a href='{% url login %}?next={% url helpdesk_dashboard %}'>{% trans "Log In" %}</a></li>
{% if not helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT or user.is_authenticated %}
<li>{% if user.is_authenticated %}<a href='{% url logout %}'>{% trans "Logout" %}</a>{% else %}<a href='{% url login %}?next={% url helpdesk_dashboard %}'>{% trans "Log In" %}</a>{% endif %}</li>
{% endif %}
</ul>
{% endif %}

View File

@ -1,4 +1,7 @@
{% load i18n %}<html>
{% load i18n %}
{% load load_helpdesk_settings %}
{% with request|load_helpdesk_settings as helpdesk_settings %}
<html>
<head>
<title>{% block helpdesk_title %}{% trans "Helpdesk" %}{% endblock %}</title>
<script src='{{ STATIC_URL }}helpdesk/jquery-1.5.min.js' type='text/javascript' language='javascript'></script>
@ -20,3 +23,4 @@
</div>{% include "helpdesk/debug.html" %}
</body>
</html>
{% endwith %}

View File

@ -1,6 +1,7 @@
{% extends "helpdesk/public_base.html" %}{% load i18n %}
{% block helpdesk_body %}
{% if helpdesk_settings.HELPDESK_VIEW_A_TICKET_PUBLIC %}
<h2>{% trans "View a Ticket" %}</h2>
<form method='get' action='{% url helpdesk_public_view %}'>
@ -16,7 +17,9 @@
<input type='submit' value='{% trans "View Ticket" %}' />
</fieldset>
{% csrf_token %}</form>
{% endif %}
{% if helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
<h2 name='submit'>{% trans "Submit a Ticket" %}</h2>
<p>{% trans "All fields are required. Please provide as descriptive a title and description as possible." %}</p>
@ -42,4 +45,10 @@
</fieldset>
{% csrf_token %}</form>
{% endif %}
{% if not helpdesk_settings.HELPDESK_VIEW_A_TICKET_PUBLIC and not helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
<h2>{% trans "Please use button at upper right to login first." %}</h2>
{% endif %}
{% endblock %}

View File

@ -51,7 +51,11 @@
<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'>({% trans "Private" %})</span>{% endif %}</span>
{% if helpdesk_settings.HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP %}
{% if followup.user and request.user == followup.user and not followup.ticketchange_set.all %}
<a href="{% url helpdesk_followup_edit ticket.id followup.id %}" class='followup-edit'><img width="60" height="15" title="Edit" alt="Edit" src="{{ STATIC_URL }}helpdesk/buttons/edit.png"></a>
{% endif %}
{% endif %}
</div>
<span class='followup-desc'>{% if followup.comment %}{{ followup.comment|force_escape|urlizetrunc:50|num_to_link|linebreaksbr }}{% endif %}</span>
{% for change in followup.ticketchange_set.all %}
@ -60,7 +64,11 @@
{% if forloop.last %}</div></ul>{% endif %}
{% endfor %}
{% for attachment in followup.attachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})</li>
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})
{% if followup.user and request.user == followup.user %}
<a href='{% url helpdesk_attachment_del ticket.id attachment.id %}'>delete</a>
{% endif %}
</li>
{% if forloop.last %}</ul></div>{% endif %}
{% endfor %}
</div>
@ -73,9 +81,11 @@
<fieldset>
<dl>
{% if preset_replies %}
<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'>{% 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>
{% endif %}
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
@ -109,9 +119,13 @@
<input type='radio' name='new_status' value='5' id='st_duplicate' checked='checked'><label for='st_duplicate'>{% trans "Duplicate" %}</label></dd>
{% endifequal %}
{% if helpdesk_settings.HELPDESK_UPDATE_PUBLIC_DEFAULT %}
<input type='hidden' name='public' value='1'>
{% else %}
<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><input type='checkbox' name='public' value='1' checked='checked' /></dd>
<dd class='form_help_text'>{% trans "If this is public, the submitter will be e-mailed your comment or resolution." %}</dd>
{% endif %}
</dl>
<p id='ShowFurtherOptPara'><a href='#' id='ShowFurtherEditOptions'>{% trans "Change Further Details &raquo;" %}</a></p>

View File

@ -1,6 +1,15 @@
{% load i18n %}
<table width='100%'>
<tr class='row_tablehead'><td colspan='2'>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}] <span class='ticket_toolbar'><a href='{% url helpdesk_edit ticket.id %}'><img src='{{ STATIC_URL }}helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a><a href='{% url helpdesk_delete ticket.id %}'><img src='{{ STATIC_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 %}</span></td></tr>
<tr class='row_tablehead'><td colspan='2'>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}] <span class='ticket_toolbar'>
{% if helpdesk_settings.HELPDESK_SHOW_EDIT_BUTTON_TICKET_TOP %}
<a href='{% url helpdesk_edit ticket.id %}'><img src='{{ STATIC_URL }}helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a>
{% endif %}
{% if helpdesk_settings.HELPDESK_SHOW_DELETE_BUTTON_TICKET_TOP %}
<a href='{% url helpdesk_delete ticket.id %}'><img src='{{ STATIC_URL }}helpdesk/buttons/delete.png' alt='Delete' title='Delete' width='60' height='15' /></a>
{% endif %}
{% if helpdesk_settings.HELPDESK_SHOW_HOLD_BUTTON_TICKET_TOP %}
{% if ticket.on_hold %}<a href='unhold/'>{% trans "Unhold" %}</a>{% else %}<a href='hold/'>{% trans "Hold" %}</a>{% endif %}
{% endif %}</span></td></tr>
<tr class='row_columnheads'><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
<tr class='{% cycle 'row_odd' 'row_even' as rowcolors %}'>

View File

@ -0,0 +1,21 @@
"""
django-helpdesk - A Django powered ticket tracker for small enterprise.
templatetags/load_helpdesk_settings.py - returns the settings as defined in
django-helpdesk/helpdesk/settings.py
"""
from django.template import Library
from helpdesk import settings as helpdesk_settings_config
def load_helpdesk_settings(request):
try:
return helpdesk_settings_config
except Exception, e:
import sys
print >> sys.stderr, "'load_helpdesk_settings' template tag (django-helpdesk) crashed with following error:"
print >> sys.stderr, e
return ''
register = Library()
register.filter('load_helpdesk_settings', load_helpdesk_settings)

View File

@ -81,6 +81,10 @@ urlpatterns = patterns('helpdesk.views.staff',
'ticket_dependency_del',
name='helpdesk_ticket_dependency_del'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/attachment_delete/(?P<attachment_id>[0-9]+)/$',
'attachment_del',
name='helpdesk_attachment_del'),
url(r'^raw/(?P<type>\w+)/$',
'raw_details',
name='helpdesk_raw'),

View File

@ -22,7 +22,10 @@ from helpdesk.models import Ticket, Queue, UserSettings
def homepage(request):
if request.user.is_staff:
if not request.user.is_authenticated() and helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT:
return HttpResponseRedirect(reverse('login'))
if (request.user.is_staff or (request.user.is_authenticated() and helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE)):
try:
if getattr(request.user.usersettings.settings, 'login_view_ticketlist', False):
return HttpResponseRedirect(reverse('helpdesk_list'))

View File

@ -28,14 +28,20 @@ from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTi
from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
from helpdesk.settings import HAS_TAG_SUPPORT
from helpdesk import settings as helpdesk_settings
if HAS_TAG_SUPPORT:
from tagging.models import Tag, TaggedItem
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)
if helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
# treat 'normal' users like 'staff'
staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active)
else:
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):
"""
@ -44,12 +50,18 @@ def dashboard(request):
with options for them to 'Take' ownership of said tickets.
"""
# open & reopened tickets
tickets = Ticket.objects.filter(
assigned_to=request.user,
).exclude(
status=Ticket.CLOSED_STATUS,
status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS],
)
# closed & resolved tickets
tickets_closed_resolved = Ticket.objects.filter(
assigned_to=request.user,
status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS])
unassigned_tickets = Ticket.objects.filter(
assigned_to__isnull=True,
).exclude(
@ -67,7 +79,8 @@ def dashboard(request):
SELECT q.id as queue,
q.title AS name,
COUNT(CASE t.status WHEN '1' THEN t.id WHEN '2' THEN t.id END) AS open,
COUNT(CASE t.status WHEN '3' THEN t.id END) AS resolved
COUNT(CASE t.status WHEN '3' THEN t.id END) AS resolved,
COUNT(CASE t.status WHEN '4' THEN t.id END) AS closed
FROM helpdesk_ticket t,
helpdesk_queue q
WHERE q.id = t.queue_id
@ -79,6 +92,7 @@ def dashboard(request):
return render_to_response('helpdesk/dashboard.html',
RequestContext(request, {
'user_tickets': tickets,
'user_tickets_closed_resolved': tickets_closed_resolved,
'unassigned_tickets': unassigned_tickets,
'dash_tickets': dash_tickets,
}))
@ -127,9 +141,18 @@ def followup_edit(request, ticket_id, followup_id, ):
new_status = form.cleaned_data['new_status']
#will save previous date
old_date = followup.date
followup.delete()
new_followup = FollowUp(title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status, )
# keep old user if one did exist before.
if followup.user:
new_followup.user = followup.user
new_followup.save()
# get list of old attachments & link them to new_followup
attachments = Attachment.objects.filter(followup = followup)
for attachment in attachments:
attachment.followup = new_followup
attachment.save()
# delete old followup
followup.delete()
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
def view_ticket(request, ticket_id):
@ -169,7 +192,7 @@ def view_ticket(request, ticket_id):
return render_to_response('helpdesk/ticket.html',
RequestContext(request, {
'ticket': ticket,
'active_users': User.objects.filter(is_active=True).filter(is_staff=True).order_by('username'),
'active_users': User.objects.filter(is_active=True).order_by('username'),
'priorities': Ticket.PRIORITY_CHOICES,
'preset_replies': PreSetReply.objects.filter(Q(queues=ticket.queue) | Q(queues__isnull=True)),
'tags_enabled': HAS_TAG_SUPPORT,
@ -178,7 +201,7 @@ view_ticket = staff_member_required(view_ticket)
def update_ticket(request, ticket_id, public=False):
if not (public or (request.user.is_authenticated() and request.user.is_active and request.user.is_staff)):
if not (public or (request.user.is_authenticated() and request.user.is_active and (request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))):
return HttpResponseForbidden(_('Sorry, you need to login to do that.'))
ticket = get_object_or_404(Ticket, id=ticket_id)
@ -195,6 +218,10 @@ def update_ticket(request, ticket_id, public=False):
# comment.
from django.template import loader, Context
context = safe_template_context(ticket)
# this line sometimes creates problems if code is sent as a comment.
# if comment contains some django code, like "why does {% if bla %} crash",
# then the following line will give us a crash, since django expects {% if %}
# to be closed with an {% endif %} tag.
comment = loader.get_template_from_string(comment).render(Context(context))
if owner is None and ticket.assigned_to:
@ -202,7 +229,7 @@ def update_ticket(request, ticket_id, public=False):
f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment)
if request.user.is_staff:
if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
f.user = request.user
f.public = public
@ -217,9 +244,11 @@ def update_ticket(request, ticket_id, public=False):
}
ticket.assigned_to = new_user
reassigned = True
elif owner == 0 and ticket.assigned_to is not None:
f.title = _('Unassigned')
ticket.assigned_to = None
# This makes no sense to me. Why should we ever remove the 'assigned to'
# value?
#elif owner == 0 and ticket.assigned_to is not None:
# f.title = _('Unassigned')
# ticket.assigned_to = None
if new_status != ticket.status:
ticket.status = new_status
@ -289,7 +318,7 @@ def update_ticket(request, ticket_id, public=False):
c.save()
ticket.tags = tags
if f.new_status == Ticket.RESOLVED_STATUS:
if new_status == Ticket.RESOLVED_STATUS:
ticket.resolution = comment
messages_sent_to = []
@ -377,7 +406,7 @@ def update_ticket(request, ticket_id, public=False):
ticket.save()
if request.user.is_staff:
if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
return HttpResponseRedirect(ticket.get_absolute_url())
else:
return HttpResponseRedirect(ticket.ticket_url)
@ -419,11 +448,11 @@ def mass_update(request):
f = FollowUp(ticket=t, date=datetime.now(), title=_('Closed in bulk update'), public=True, user=request.user, new_status=Ticket.CLOSED_STATUS)
f.save()
# Send email to Submitter, Owner, Queue CC
context = {
'ticket': t,
'queue': t.queue,
'resolution': t.resolution,
}
context = safe_template_context(t)
context.update(
resolution = t.resolution,
queue = t.queue,
)
messages_sent_to = []
@ -833,7 +862,7 @@ def run_report(request, report):
month = 1
if (year > last_year) or (month > last_month and year >= last_year):
working = False
periods.append("%s %s" % (months[month], year))
periods.append("%s %s" % (months[month - 1], year))
if report == 'userpriority':
title = _('User by Priority')
@ -1087,3 +1116,10 @@ def ticket_dependency_del(request, ticket_id, dependency_id):
}))
ticket_dependency_del = staff_member_required(ticket_dependency_del)
def attachment_del(request, ticket_id, attachment_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
attachment = get_object_or_404(Attachment, id=attachment_id)
attachment.delete()
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket_id]))
attachment_del = staff_member_required(attachment_del)