Big bugfix release - addresses a number of issues introduced in recent Django

updates, and other bugs in the codebase. Many thanks to David Clymer and
Chris Etcp for reporting these bugs and then providing fixes.

Tickets closed:

#3: BUG E-Mail Script Incompatible with Python 2.5
#4: BUG Failure on empty attachments
#5: ENHANCEMENT Run scripts as command extensions [Backwards Compatible]
#7: BUG Cannot view tickets when not logged in
#8: BUG Overly broad error handling

Note that #5 is backwards-incompatible, as you need to change any CRON or 
scheduler entries for the 'get_email.py', 'escalate_tickets.py' or 
'create_escalation_exclusions.py' scripts. See the README file for the new 
commands.
This commit is contained in:
Ross Poulton 2008-08-18 21:29:31 +00:00
parent 4583d1c7c8
commit cea6394b70
11 changed files with 132 additions and 19 deletions

22
README
View File

@ -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 <http://djangopeople.net/vezult/>
Chris Etcp
Nikolay Panov

View File

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

View File

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@
<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'>{% blocktrans %}Queue: {{ ticket.queue }}{% endblocktrans %}</th></tr>
<tr class='row_columnheads'><th colspan='2'>{% blocktrans with ticket.queue as queue_name %}Queue: {{ queue_name }}{% endblocktrans %}</th></tr>
<tr class='row_odd'>
<th>{% trans "Submitted On" %}</th>

View File

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

View File

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

View File

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