forked from extern/django-helpdesk
dfb821336e
text to assist with future translation efforts. I've no doubt missed a few. Also we don't have a "Change Language" view in here, unsure if this should be a helpdesk function or a function of the parent project. * Updated svn:ignore to ignore .pyc files * Added new function to replace cursor.dictfetchall() which is available in psycopg1 but not psycopg2. New function should work across other database systems, but is untested.
228 lines
7.8 KiB
Python
228 lines
7.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/api_help.html.
|
|
"""
|
|
from datetime import datetime
|
|
from django.utils import simplejson
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.contrib.auth import authenticate
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import render_to_response
|
|
from django.template import loader, Context
|
|
from django import newforms as forms
|
|
|
|
from helpdesk.lib import send_templated_mail
|
|
from helpdesk.models import Ticket, Queue, FollowUp
|
|
from helpdesk.forms import TicketForm
|
|
|
|
STATUS_OK = 200
|
|
|
|
STATUS_ERROR = 400
|
|
STATUS_ERROR_NOT_FOUND = 404
|
|
STATUS_ERROR_PERMISSIONS = 403
|
|
STATUS_ERROR_BADMETHOD = 405
|
|
|
|
def api(request, method):
|
|
if method == 'help':
|
|
""" Regardless of any other paramaters, we provide a help screen
|
|
to the user if they requested one. """
|
|
return render_to_response('helpdesk/api_help.html')
|
|
|
|
"""
|
|
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 request.method != 'POST':
|
|
return api_return(STATUS_ERROR_BADMETHOD)
|
|
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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)
|