django-helpdesk/views/api.py
Ross Poulton 3f8fc2cd68 * Added force_insert and force_update parameters to model save() overrides (as per Django rev 8670)
* Added 'UserSettings' model to provide a user profile system independent of existing Django user profiles, for two reasons:  1) Avoids users having to update settings.py and 2) Allows jutda-helpdesk to integrate with websites who already use a User Profile
* Settings added in this revision allow a user to control e-mail alerts, and to determine whether they see the dashboard or ticket list at login.
* New 'Settings' link in page footer for signed-in users
* Logout now takes you to the Helpdesk homepage
* Fixed file attachment bug in management/commands/get_email.py which seemed to have been un-done (fixes issue # 4.

Jutda-helpdesk is now compatible with Django 1.0!
2008-09-09 08:32:01 +00:00

295 lines
8.8 KiB
Python

""" ..
Jutda Helpdesk - A Django powered ticket tracker for small enterprise.
(c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details.
api.py - Wrapper around API calls, and core functions to provide complete
API to third party applications.
The API documentation can be accessed by visiting http://helpdesk/api/help/
(obviously, substitute helpdesk for your Jutda Helpdesk URI), or by reading
through templates/helpdesk/help_api.html.
"""
from datetime import datetime
from django import forms
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import loader, Context
from django.utils import simplejson
from helpdesk.forms import TicketForm
from helpdesk.lib import send_templated_mail
from helpdesk.models import Ticket, Queue, FollowUp
STATUS_OK = 200
STATUS_ERROR = 400
STATUS_ERROR_NOT_FOUND = 404
STATUS_ERROR_PERMISSIONS = 403
STATUS_ERROR_BADMETHOD = 405
def api(request, method):
"""
Regardless of any other paramaters, we provide a help screen
to the user if they requested one.
If the user isn't looking for help, then we enforce a few conditions:
* The request must be sent via HTTP POST
* The request must contain a 'user' and 'password' which
must be valid users
* The method must match one of the public methods of the API class.
"""
if method == 'help':
return render_to_response('helpdesk/help_api.html')
if request.method != 'POST':
return api_return(STATUS_ERROR_BADMETHOD)
# TODO: Move away from having the username & password in every request.
request.user = authenticate(
username=request.POST.get('user', False),
password=request.POST.get('password'),
)
if request.user is None:
return api_return(STATUS_ERROR_PERMISSIONS)
api = API(request)
if hasattr(api, 'api_public_%s' % method):
return getattr(api, 'api_public_%s' % method)()
return api_return(STATUS_ERROR)
def api_return(status, text='', json=False):
content_type = 'text/plain'
if status == STATUS_OK and json:
content_type = 'text/json'
if text is None:
if status == STATUS_ERROR:
text = 'Error'
elif status == STATUS_ERROR_NOT_FOUND:
text = 'Resource Not Found'
elif status == STATUS_ERROR_PERMISSIONS:
text = 'Invalid username or password'
elif status == STATUS_ERROR_BADMETHOD:
text = 'Invalid request method'
elif status == STATUS_OK:
text = 'OK'
r = HttpResponse(status=status, content=text, content_type=content_type)
if status == STATUS_ERROR_BADMETHOD:
r.Allow = 'POST'
return r
class API:
def __init__(self, request):
self.request = request
def api_public_create_ticket(self):
form = TicketForm(self.request.POST)
form.fields['queue'].choices = [[q.id, q.title] for q in Queue.objects.all()]
form.fields['assigned_to'].choices = [[u.id, u.username] for u in User.objects.filter(is_active=True)]
if form.is_valid():
ticket = form.save(user=self.request.user)
return api_return(STATUS_OK, "%s" % ticket.id)
else:
return api_return(STATUS_ERROR, text=form.errors.as_text())
def api_public_list_queues(self):
return api_return(STATUS_OK, simplejson.dumps([{"id": "%s" % q.id, "title": "%s" % q.title} for q in Queue.objects.all()]), json=True)
def api_public_find_user(self):
username = self.request.POST.get('username', False)
try:
u = User.objects.get(username=username)
return api_return(STATUS_OK, "%s" % u.id)
except User.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid username provided")
def api_public_delete_ticket(self):
if not self.request.POST.get('confirm', False):
return api_return(STATUS_ERROR, "No confirmation provided")
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
except Ticket.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid ticket ID")
ticket.delete()
return api_return(STATUS_OK)
def api_public_hold_ticket(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
except Ticket.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid ticket ID")
ticket.on_hold = True
ticket.save()
return api_return(STATUS_OK)
def api_public_unhold_ticket(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
except Ticket.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid ticket ID")
ticket.on_hold = False
ticket.save()
return api_return(STATUS_OK)
def api_public_add_followup(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
except Ticket.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid ticket ID")
message = self.request.POST.get('message', None)
public = self.request.POST.get('public', 'n')
if public not in ['y', 'n']:
return api_return(STATUS_ERROR, "Invalid 'public' flag")
if not message:
return api_return(STATUS_ERROR, "Blank message")
f = FollowUp(
ticket=ticket,
date=datetime.now(),
comment=message,
user=self.request.user,
title='Comment Added',
)
if public:
f.public = True
f.save()
context = {
'ticket': ticket,
'queue': ticket.queue,
'comment': f.comment,
}
if public and ticket.submitter_email:
send_templated_mail(
'updated_submitter',
context,
recipients=ticket.submitter_email,
sender=ticket.queue.from_address,
fail_silently=True,
)
if ticket.queue.updated_ticket_cc:
send_templated_mail(
'updated_cc',
context,
recipients=ticket.queue.updated_ticket_cc,
sender=ticket.queue.from_address,
fail_silently=True,
)
if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False):
send_templated_mail(
'updated_owner',
context,
recipients=ticket.assigned_to.email,
sender=ticket.queue.from_address,
fail_silently=True,
)
ticket.save()
return api_return(STATUS_OK)
def api_public_resolve(self):
try:
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
except Ticket.DoesNotExist:
return api_return(STATUS_ERROR, "Invalid ticket ID")
resolution = self.request.POST.get('resolution', None)
if not resolution:
return api_return(STATUS_ERROR, "Blank resolution")
f = FollowUp(
ticket=ticket,
date=datetime.now(),
comment=resolution,
user=self.request.user,
title='Resolved',
public=True,
)
f.save()
context = {
'ticket': ticket,
'queue': ticket.queue,
'resolution': f.comment,
}
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
if ticket.submitter_email:
send_templated_mail(
'resolved_submitter',
context,
recipients=ticket.submitter_email,
sender=ticket.queue.from_address,
fail_silently=True,
)
if ticket.queue.updated_ticket_cc:
send_templated_mail(
'resolved_cc',
context,
recipients=ticket.queue.updated_ticket_cc,
sender=ticket.queue.from_address,
fail_silently=True,
)
if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False):
send_templated_mail(
'resolved_resolved',
context,
recipients=ticket.assigned_to.email,
sender=ticket.queue.from_address,
fail_silently=True,
)
ticket.resoltuion = f.comment
ticket.status = Ticket.RESOLVED_STATUS
ticket.save()
return api_return(STATUS_OK)