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

@ -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)