2008-08-19 10:50:38 +02:00
|
|
|
""" ..
|
2008-02-06 05:36:07 +01:00
|
|
|
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.
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
The API documentation can be accessed by visiting http://helpdesk/api/help/
|
2008-02-06 05:36:07 +01:00
|
|
|
(obviously, substitute helpdesk for your Jutda Helpdesk URI), or by reading
|
2008-08-29 11:11:02 +02:00
|
|
|
through templates/helpdesk/help_api.html.
|
2008-02-06 05:36:07 +01:00
|
|
|
"""
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
from datetime import datetime
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
from django import forms
|
2008-02-06 05:36:07 +01:00
|
|
|
from django.contrib.auth import authenticate
|
2008-08-19 10:50:38 +02:00
|
|
|
from django.contrib.auth.models import User
|
2008-02-06 05:36:07 +01:00
|
|
|
from django.http import HttpResponse
|
|
|
|
from django.shortcuts import render_to_response
|
|
|
|
from django.template import loader, Context
|
2008-08-19 10:50:38 +02:00
|
|
|
from django.utils import simplejson
|
2008-02-06 05:36:07 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
from helpdesk.forms import TicketForm
|
2008-04-02 01:26:12 +02:00
|
|
|
from helpdesk.lib import send_templated_mail
|
2008-02-06 05:36:07 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
def api(request, method):
|
2008-02-06 05:36:07 +01:00
|
|
|
"""
|
2008-08-19 10:50:38 +02:00
|
|
|
Regardless of any other paramaters, we provide a help screen
|
|
|
|
to the user if they requested one.
|
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
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.
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
"""
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
if method == 'help':
|
2008-08-29 11:11:02 +02:00
|
|
|
return render_to_response('helpdesk/help_api.html')
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
if request.method != 'POST':
|
|
|
|
return api_return(STATUS_ERROR_BADMETHOD)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
# TODO: Move away from having the username & password in every request.
|
|
|
|
request.user = authenticate(
|
|
|
|
username=request.POST.get('user', False),
|
2008-08-20 03:57:41 +02:00
|
|
|
password=request.POST.get('password'),
|
|
|
|
)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
if request.user is None:
|
|
|
|
return api_return(STATUS_ERROR_PERMISSIONS)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
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'
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
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'
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
r = HttpResponse(status=status, content=text, content_type=content_type)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
if status == STATUS_ERROR_BADMETHOD:
|
|
|
|
r.Allow = 'POST'
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
return r
|
|
|
|
|
|
|
|
|
|
|
|
class API:
|
|
|
|
def __init__(self, request):
|
|
|
|
self.request = request
|
|
|
|
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
def api_public_create_ticket(self):
|
2008-02-06 23:47:46 +01:00
|
|
|
form = TicketForm(self.request.POST)
|
2008-02-06 05:36:07 +01:00
|
|
|
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)]
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
if form.is_valid():
|
|
|
|
ticket = form.save(user=self.request.user)
|
|
|
|
return api_return(STATUS_OK, "%s" % ticket.id)
|
|
|
|
else:
|
2008-02-06 23:47:46 +01:00
|
|
|
return api_return(STATUS_ERROR, text=form.errors.as_text())
|
2008-02-06 05:36:07 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
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)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
def api_public_find_user(self):
|
|
|
|
username = self.request.POST.get('username', False)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
try:
|
|
|
|
u = User.objects.get(username=username)
|
|
|
|
return api_return(STATUS_OK, "%s" % u.id)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-08-18 23:29:31 +02:00
|
|
|
except User.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
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))
|
2008-08-18 23:29:31 +02:00
|
|
|
except Ticket.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
return api_return(STATUS_ERROR, "Invalid ticket ID")
|
|
|
|
|
|
|
|
ticket.delete()
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
return api_return(STATUS_OK)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
def api_public_hold_ticket(self):
|
|
|
|
try:
|
|
|
|
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
|
2008-08-18 23:29:31 +02:00
|
|
|
except Ticket.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
return api_return(STATUS_ERROR, "Invalid ticket ID")
|
|
|
|
|
|
|
|
ticket.on_hold = True
|
|
|
|
ticket.save()
|
|
|
|
|
|
|
|
return api_return(STATUS_OK)
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
def api_public_unhold_ticket(self):
|
|
|
|
try:
|
|
|
|
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
|
2008-08-18 23:29:31 +02:00
|
|
|
except Ticket.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
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))
|
2008-08-18 23:29:31 +02:00
|
|
|
except Ticket.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
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")
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
f = FollowUp(
|
|
|
|
ticket=ticket,
|
|
|
|
date=datetime.now(),
|
|
|
|
comment=message,
|
|
|
|
user=self.request.user,
|
|
|
|
title='Comment Added',
|
|
|
|
)
|
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
if public:
|
|
|
|
f.public = True
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
f.save()
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
context = {
|
|
|
|
'ticket': ticket,
|
|
|
|
'queue': ticket.queue,
|
|
|
|
'comment': f.comment,
|
|
|
|
}
|
2009-08-11 11:02:48 +02:00
|
|
|
|
|
|
|
messages_sent_to = []
|
2008-02-06 05:36:07 +01:00
|
|
|
|
|
|
|
if public and ticket.submitter_email:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'updated_submitter',
|
|
|
|
context,
|
|
|
|
recipients=ticket.submitter_email,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2009-08-11 11:02:48 +02:00
|
|
|
messages_sent_to.append(ticket.submitter_email)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2009-09-09 10:47:48 +02:00
|
|
|
if public:
|
|
|
|
for cc in ticket.ticketcc_set.all():
|
|
|
|
if cc.email_address not in messages_sent_to:
|
|
|
|
send_templated_mail(
|
|
|
|
'updated_submitter',
|
|
|
|
context,
|
|
|
|
recipients=cc.email_address,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
|
|
|
messages_sent_to.append(cc.email_address)
|
|
|
|
|
2009-08-11 11:02:48 +02:00
|
|
|
if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'updated_cc',
|
|
|
|
context,
|
|
|
|
recipients=ticket.queue.updated_ticket_cc,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2009-08-11 11:02:48 +02:00
|
|
|
messages_sent_to.append(ticket.queue.updated_ticket_cc)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2009-08-11 11:02:48 +02:00
|
|
|
if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'updated_owner',
|
|
|
|
context,
|
|
|
|
recipients=ticket.assigned_to.email,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2008-02-06 05:36:07 +01:00
|
|
|
|
|
|
|
ticket.save()
|
|
|
|
|
|
|
|
return api_return(STATUS_OK)
|
|
|
|
|
|
|
|
|
|
|
|
def api_public_resolve(self):
|
|
|
|
try:
|
|
|
|
ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
|
2008-08-18 23:29:31 +02:00
|
|
|
except Ticket.DoesNotExist:
|
2008-02-06 05:36:07 +01:00
|
|
|
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")
|
2008-08-19 10:50:38 +02:00
|
|
|
|
|
|
|
f = FollowUp(
|
|
|
|
ticket=ticket,
|
|
|
|
date=datetime.now(),
|
|
|
|
comment=resolution,
|
|
|
|
user=self.request.user,
|
|
|
|
title='Resolved',
|
|
|
|
public=True,
|
|
|
|
)
|
2008-02-06 05:36:07 +01:00
|
|
|
f.save()
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
context = {
|
|
|
|
'ticket': ticket,
|
|
|
|
'queue': ticket.queue,
|
|
|
|
'resolution': f.comment,
|
|
|
|
}
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
2009-08-11 11:02:48 +02:00
|
|
|
|
|
|
|
messages_sent_to = []
|
2008-02-06 05:36:07 +01:00
|
|
|
|
2008-02-06 23:47:46 +01:00
|
|
|
if ticket.submitter_email:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'resolved_submitter',
|
|
|
|
context,
|
|
|
|
recipients=ticket.submitter_email,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2009-08-11 11:02:48 +02:00
|
|
|
messages_sent_to.append(ticket.submitter_email)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2009-09-09 10:47:48 +02:00
|
|
|
for cc in ticket.ticketcc_set.all():
|
|
|
|
if cc.email_address not in messages_sent_to:
|
|
|
|
send_templated_mail(
|
|
|
|
'resolved_submitter',
|
|
|
|
context,
|
|
|
|
recipients=cc.email_address,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
|
|
|
messages_sent_to.append(cc.email_address)
|
|
|
|
|
2009-08-11 11:02:48 +02:00
|
|
|
if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'resolved_cc',
|
|
|
|
context,
|
|
|
|
recipients=ticket.queue.updated_ticket_cc,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2009-08-11 11:02:48 +02:00
|
|
|
messages_sent_to.append(ticket.queue.updated_ticket_cc)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2009-08-11 11:02:48 +02:00
|
|
|
if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
|
2008-08-19 10:50:38 +02:00
|
|
|
send_templated_mail(
|
|
|
|
'resolved_resolved',
|
|
|
|
context,
|
|
|
|
recipients=ticket.assigned_to.email,
|
|
|
|
sender=ticket.queue.from_address,
|
|
|
|
fail_silently=True,
|
|
|
|
)
|
2008-02-06 05:36:07 +01:00
|
|
|
|
|
|
|
ticket.resoltuion = f.comment
|
2008-02-06 23:47:46 +01:00
|
|
|
ticket.status = Ticket.RESOLVED_STATUS
|
2008-02-06 05:36:07 +01:00
|
|
|
|
|
|
|
ticket.save()
|
|
|
|
|
|
|
|
return api_return(STATUS_OK)
|
2008-08-19 10:50:38 +02:00
|
|
|
|