diff --git a/README b/README index 17e2bf1f..7b98cfe8 100644 --- a/README +++ b/README @@ -11,6 +11,7 @@ Jutda Helpdesk - A Django powered ticket tracker for small enterprise. 3. Installation 4. Initial Configuration 5. API Usage +6. Thank You ######################### 1. Licensing @@ -104,7 +105,7 @@ LICENSE.JQUERY and LICENSE.NICEDIT for their respective license terms. Don't forget to set the relevant Django environment variables in your crontab: - */5 * * * * DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/get_email.py + */5 * * * * /path/to/helpdesksite/manage.py get_email This will run the e-mail import every 5 minutes @@ -114,7 +115,7 @@ LICENSE.JQUERY and LICENSE.NICEDIT for their respective license terms. 4. If you wish to automatically escalate tickets based on their age, set up a cronjob to run scripts/escalate_tickets.py on a regular basis: - 0 * * * * DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/escalate_tickets.py + 0 * * * * /path/to/helpdesksite/manage.py escalate_tickets.py This will run the escalation process hourly, using the 'Escalation Hours' setting for each queue to determine which tickets to escalate. @@ -123,7 +124,7 @@ LICENSE.JQUERY and LICENSE.NICEDIT for their respective license terms. the dates manually via the Admin, or setup a cronjob to run scripts/create_escalation_exclusions.py on a regular basis: - 0 0 * * 0 DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/create_escalation_exclusions.py --days saturday,sunday --verbose + 0 0 * * 0 /path/to/helpdesksite/manage.py create_escalation_exclusions.py --days saturday,sunday --verbose This will, on a weekly basis, create exclusions for the coming weekend. @@ -138,3 +139,18 @@ you to create and alter tickets from 3rd party software and systems. For usage instructions and command syntax, see the file templates/helpdesk/api_help.html, or visit http://helpdesk/api/help/. + +######################### +6. Thank You +######################### + +While this started as a project to suit my own needs, since publishing the +code a number of people have made some fantastic improvements and provided +bug fixes and updates as the Django codebase has moved on and caused small +portions of this application to break. + +To these people, my sincere thanks: + +David Clymer +Chris Etcp +Nikolay Panov diff --git a/forms.py b/forms.py index d87e5539..73f40a4f 100644 --- a/forms.py +++ b/forms.py @@ -57,7 +57,7 @@ class TicketForm(forms.Form): try: u = User.objects.get(id=self.cleaned_data['assigned_to']) t.assigned_to = u - except: + except User.DoesNotExist: t.assigned_to = None t.save() diff --git a/scripts/__init__.py b/management/__init__.py similarity index 100% rename from scripts/__init__.py rename to management/__init__.py diff --git a/management/commands/__init__.py b/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/scripts/create_escalation_exclusions.py b/management/commands/create_escalation_exclusions.py similarity index 61% rename from scripts/create_escalation_exclusions.py rename to management/commands/create_escalation_exclusions.py index 27e16bda..e497e15a 100644 --- a/scripts/create_escalation_exclusions.py +++ b/management/commands/create_escalation_exclusions.py @@ -13,6 +13,58 @@ from django.db.models import Q from helpdesk.models import EscalationExclusion, Queue import sys, getopt +from django.core.management.base import BaseCommand, CommandError +from optparse import make_option + +class Command(BaseCommand): + def __init__(self): + BaseCommand.__init__(self) + + self.option_list += ( + make_option( + '--days', '-d', + help='Days of week (monday, tuesday, etc)'), + make_option( + '--occurrences', '-o', + type='int', + default=1, + help='Occurrences: How many weeks ahead to exclude this day'), + make_option( + '--queues', '-q', + help='Queues to include (default: all). Use queue slugs'), + make_option( + '--verbose', '-v', + action='store_true', + default=False, + help='Display a list of dates excluded'), + ) + + def handle(self, *args, **options): + days = options['days'] + occurrences = options['occurrences'] + verbose = False + queue_slugs = options['queues'] + queues = [] + + if options['verbose']: + verbose = True + + # this should already be handled by optparse + if not occurrences: occurrences = 1 + if not (days and occurrences): + raise CommandError('One or more occurrences must be specified.') + + if queue_slugs is not None: + queue_set = queue_slugs.split(',') + for queue in queue_set: + try: + q = Queue.objects.get(slug__exact=queue) + except Queue.DoesNotExist: + raise CommandError("Queue %s does not exist." % queue) + queues.append(q) + + create_exclusions(days=days, occurrences=occurrences, verbose=verbose, queues=queues) + day_names = { 'monday': 0, 'tuesday': 1, @@ -88,7 +140,7 @@ if __name__ == '__main__': for queue in queue_set: try: q = Queue.objects.get(slug__exact=queue) - except: + except Queue.DoesNotExist: print "Queue %s does not exist." % queue sys.exit(2) queues.append(q) diff --git a/scripts/escalate_tickets.py b/management/commands/escalate_tickets.py similarity index 75% rename from scripts/escalate_tickets.py rename to management/commands/escalate_tickets.py index e4970f7f..885926c6 100644 --- a/scripts/escalate_tickets.py +++ b/management/commands/escalate_tickets.py @@ -15,6 +15,45 @@ from django.utils.translation import ugettext as _ from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange from helpdesk.lib import send_templated_mail + +from django.core.management.base import BaseCommand +from optparse import make_option + +class Command(BaseCommand): + def __init__(self): + BaseCommand.__init__(self) + + self.option_list += ( + make_option( + '--queues', '-q', + help='Queues to include (default: all). Use queue slugs'), + make_option( + '--verbose', '-v', + action='store_true', + default=False, + help='Display a list of dates excluded'), + ) + + def handle(self, *args, **options): + verbose = False + queue_slugs = None + queues = [] + + if options['verbose']: + verbose = True + if options['queues']: + queue_slugs = options['queues'] + + if queue_slugs is not None: + queue_set = queue_slugs.split(',') + for queue in queue_set: + try: + q = Queue.objects.get(slug__exact=queue) + except Queue.DoesNotExist: + raise CommandError("Queue %s does not exist." % queue) + queues.append(queue) + + escalate_tickets(queues=queues, verbose=verbose) def escalate_tickets(queues, verbose): """ Only include queues with escalation configured """ @@ -47,7 +86,7 @@ def escalate_tickets(queues, verbose): context = { 'ticket': t, - 'queue': queue, + 'queue': q, } if t.submitter_email: @@ -106,7 +145,7 @@ if __name__ == '__main__': for queue in queue_set: try: q = Queue.objects.get(slug__exact=queue) - except: + except Queue.DoesNotExist: print "Queue %s does not exist." % queue sys.exit(2) queues.append(queue) diff --git a/scripts/get_email.py b/management/commands/get_email.py similarity index 95% rename from scripts/get_email.py rename to management/commands/get_email.py index 94147dc0..a457d3e8 100644 --- a/scripts/get_email.py +++ b/management/commands/get_email.py @@ -19,6 +19,12 @@ from helpdesk.lib import send_templated_mail from django.core.files.base import ContentFile +from django.core.management.base import BaseCommand + +class Command(BaseCommand): + def handle(self, *args, **options): + process_email() + def process_email(): for q in Queue.objects.filter(email_box_type__isnull=False, allow_email_submission=True): if not q.email_box_last_check: q.email_box_last_check = datetime.now()-timedelta(minutes=30) @@ -89,7 +95,7 @@ def ticket_from_message(message, queue): counter = 0 files = [] for part in message.walk(): - if part.get_main_type() == 'multipart': + if part.get_content_maintype() == 'multipart': continue name = part.get_param("name") @@ -97,7 +103,7 @@ def ticket_from_message(message, queue): if part.get_content_maintype() == 'text' and name == None: body = part.get_payload() else: - if name == None: + if not name: ext = mimetypes.guess_extension(part.get_content_type()) name = "part-%i%s" % (counter, ext) files.append({'filename': name, 'content': part.get_payload(decode=True), 'type': part.get_content_type()}) @@ -110,7 +116,7 @@ def ticket_from_message(message, queue): try: t = Ticket.objects.get(id=ticket) new = False - except: + except Ticket.DoesNotExist: ticket = None priority = 3 diff --git a/templates/helpdesk/public_view_ticket.html b/templates/helpdesk/public_view_ticket.html index b5f91457..b9fea7c6 100644 --- a/templates/helpdesk/public_view_ticket.html +++ b/templates/helpdesk/public_view_ticket.html @@ -13,7 +13,7 @@ - + diff --git a/templatetags/ticket_to_link.py b/templatetags/ticket_to_link.py index 0211e74d..403118a2 100644 --- a/templatetags/ticket_to_link.py +++ b/templatetags/ticket_to_link.py @@ -41,7 +41,7 @@ def num_to_link(text): url = reverse('helpdesk_view', args=[number]) try: ticket = Ticket.objects.get(id=number) - except: + except Ticket.DoesNotExist: ticket = None if ticket: diff --git a/views/api.py b/views/api.py index 243fcc85..34e7d602 100644 --- a/views/api.py +++ b/views/api.py @@ -107,7 +107,7 @@ class API: try: u = User.objects.get(username=username) return api_return(STATUS_OK, "%s" % u.id) - except: + except User.DoesNotExist: return api_return(STATUS_ERROR, "Invalid username provided") @@ -117,7 +117,7 @@ class API: try: ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False)) - except: + except Ticket.DoesNotExist: return api_return(STATUS_ERROR, "Invalid ticket ID") ticket.delete() @@ -127,7 +127,7 @@ class API: def api_public_hold_ticket(self): try: ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False)) - except: + except Ticket.DoesNotExist: return api_return(STATUS_ERROR, "Invalid ticket ID") ticket.on_hold = True @@ -139,7 +139,7 @@ class API: def api_public_unhold_ticket(self): try: ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False)) - except: + except Ticket.DoesNotExist: return api_return(STATUS_ERROR, "Invalid ticket ID") ticket.on_hold = False @@ -151,7 +151,7 @@ class API: def api_public_add_followup(self): try: ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False)) - except: + except Ticket.DoesNotExist: return api_return(STATUS_ERROR, "Invalid ticket ID") message = self.request.POST.get('message', None) @@ -191,7 +191,7 @@ class API: def api_public_resolve(self): try: ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False)) - except: + except Ticket.DoesNotExist: return api_return(STATUS_ERROR, "Invalid ticket ID") resolution = self.request.POST.get('resolution', None) diff --git a/views/public.py b/views/public.py index 66312da9..6f6462ba 100644 --- a/views/public.py +++ b/views/public.py @@ -48,7 +48,7 @@ def view_ticket(request): t = Ticket.objects.get(id=ticket_id, queue__slug__iexact=queue, submitter_email__iexact=email) return render_to_response('helpdesk/public_view_ticket.html', RequestContext(request, {'ticket': t,})) - except: + except Ticket.DoesNotExist: t = False; error_message = _('Invalid ticket ID or e-mail address. Please try again.')
{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]
{% blocktrans %}Queue: {{ ticket.queue }}{% endblocktrans %}
{% blocktrans with ticket.queue as queue_name %}Queue: {{ queue_name }}{% endblocktrans %}
{% trans "Submitted On" %}