aboutsummaryrefslogtreecommitdiffstats
path: root/servo/views/api.py
diff options
context:
space:
mode:
authorFilipp Lepalaan <filipp@mac.com>2015-08-04 10:11:24 +0300
committerFilipp Lepalaan <filipp@mac.com>2015-08-04 10:11:24 +0300
commit63b0fc6269b38edf7234b9f151b80d81f614c0a3 (patch)
tree555de3068f33f8dddb4619349bbea7d9b7c822fd /servo/views/api.py
downloadServo-63b0fc6269b38edf7234b9f151b80d81f614c0a3.tar.gz
Servo-63b0fc6269b38edf7234b9f151b80d81f614c0a3.tar.bz2
Servo-63b0fc6269b38edf7234b9f151b80d81f614c0a3.zip
Initial commit
First public commit
Diffstat (limited to 'servo/views/api.py')
-rw-r--r--servo/views/api.py401
1 files changed, 401 insertions, 0 deletions
diff --git a/servo/views/api.py b/servo/views/api.py
new file mode 100644
index 0000000..87234f3
--- /dev/null
+++ b/servo/views/api.py
@@ -0,0 +1,401 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2013, First Party Software
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+import json
+from django.utils import timezone
+from django.http import HttpResponse
+from django.core.exceptions import FieldError
+from django.core.serializers import serialize
+from django.shortcuts import get_object_or_404
+from django.views.generic.detail import DetailView
+
+from rest_framework.response import Response
+
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.authentication import TokenAuthentication, SessionAuthentication
+from rest_framework.decorators import (api_view, authentication_classes, permission_classes)
+
+from servo.api.serializers import *
+
+from servo.models import *
+
+
+def dumps(obj):
+ import datetime
+ data = {}
+ for f in obj.api_fields:
+ value = getattr(obj, f)
+ if type(value) in (datetime.datetime, datetime.date,):
+ value = value.isoformat()
+ data[f] = value
+ return json.dumps(data)
+
+
+class OrderStatusView(DetailView):
+
+ model = Order
+
+ def get(self, *args):
+ args = self.request.GET
+ if not args.get('q'):
+ error = {'error': 'Need parameter for query'}
+ return HttpResponse(json.dumps(error),
+ status=400,
+ content_type='application/json')
+
+ self.code = args.get('q')
+ self.object = get_object_or_404(Order, code=self.code)
+ context = self.get_context_data(object=self.object)
+ return self.render_to_response(context)
+
+ def render_to_response(self, context, **response_kwargs):
+ out = {
+ 'order': self.object.code,
+ 'status': self.object.get_status_name(),
+ 'status_description': self.object.get_status_description(),
+ }
+
+ if Configuration.conf('checkin_timeline'):
+ timeline = []
+ for i in self.object.orderstatus_set.exclude(status=None):
+ status = {'badge': i.get_badge()}
+ status['status'] = i.status.title
+ status['started_at'] = i.started_at.isoformat()
+ status['description'] = i.status.description
+ timeline.append(status)
+
+ out['timeline'] = timeline
+
+ return HttpResponse(json.dumps(out), content_type='application/json')
+
+
+def tags(request):
+ results = Tag.objects.filter(**request.GET.dict())
+ data = results.distinct().values_list("title", flat=True)
+ return HttpResponse(json.dumps(list(data)), content_type='application/json')
+
+
+def statuses(request):
+ from servo.models import Status
+ results = Status.objects.all()
+ data = serialize('json', results)
+ return HttpResponse(data, content_type='application/json')
+
+
+def locations(request):
+ queryset = Location.objects.all()
+ serializer = 'json'
+ if request.META['HTTP_USER_AGENT'].startswith('curl'):
+ serializer = 'yaml'
+ data = serialize(serializer, queryset)
+ return HttpResponse(data)
+
+
+@api_view(['GET'])
+@authentication_classes((SessionAuthentication, TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def users(request):
+ query = request.GET.dict()
+ queryset = User.active.filter(**query)
+ data = list(queryset.values_list("full_name", flat=True))
+ return HttpResponse(json.dumps(data), content_type='application/json')
+
+
+def places(request):
+ places = Order.objects.exclude(place=None)
+ places = places.order_by("place").distinct("place").values_list('place', flat=True)
+ return HttpResponse(json.dumps(list(places)), content_type='application/json')
+
+
+def queues(request):
+ queryset = Queue.objects.all()
+ data = serialize('json', queryset, fields=('pk', 'title'))
+ return HttpResponse(data, content_type='application/json')
+
+
+def json_response(data):
+ return HttpResponse(json.dumps(data), content_type='application/json')
+
+
+def ok(message):
+ msg = json.dumps(dict(ok=message))
+ return HttpResponse(msg, content_type='application/json')
+
+
+def error(message):
+ msg = json.dumps(dict(error=str(message)))
+ return HttpResponse(msg, content_type='application/json')
+
+
+def client_error(message):
+ msg = json.dumps(dict(error=str(message)))
+ return HttpResponse(msg, content_type='application/json', status=400)
+
+
+def create_order(request):
+ try:
+ data = json.loads(request.body)
+ except ValueError as e:
+ return client_error('Malformed request: %s' % e)
+
+ cdata = data.get('customer')
+ problem = data.get('problem')
+
+ if not cdata:
+ return client_error('Cannot create order without customer info')
+
+ if not problem:
+ return client_error('Cannot create order without problem description')
+
+ try:
+ customer, created = Customer.objects.get_or_create(
+ name=cdata['name'],
+ email=cdata['email']
+ )
+ except Exception as e:
+ return client_error('Invalid customer details: %s' % e)
+
+ if request.user.customer:
+ customer.parent = request.user.customer
+
+ if cdata.get('city'):
+ customer.city = cdata.get('city')
+
+ if cdata.get('phone'):
+ customer.phone = cdata.get('phone')
+
+ if cdata.get('zip_code'):
+ customer.zip_code = cdata.get('zip_code')
+
+ if cdata.get('street_address'):
+ customer.street_address = cdata.get('street_address')
+
+ customer.save()
+
+ order = Order(created_by=request.user, customer=customer)
+ order.save()
+
+ note = Note(created_by=request.user, body=problem, is_reported=True)
+ note.order = order
+ note.save()
+
+ if data.get('attachment'):
+ import base64
+ from servo.models import Attachment
+ from django.core.files.base import ContentFile
+
+ attachment = data.get('attachment')
+
+ try:
+ filename = attachment.get('name')
+ content = base64.b64decode(attachment.get('data'))
+ except Exception as e:
+ return client_error('Invalid file data: %s' %e)
+
+ content = ContentFile(content, filename)
+ attachment = Attachment(content=content, content_object=note)
+ attachment.save()
+ attachment.content.save(filename, content)
+ note.attachments.add(attachment)
+
+ if data.get('device'):
+
+ try:
+ GsxAccount.default(request.user)
+ except Exception as e:
+ pass
+
+ ddata = data.get('device')
+
+ try:
+ device = order.add_device_sn(ddata.get('sn'), request.user)
+ except Exception as e:
+ device = Device(sn=ddata.get('sn', ''))
+ device.description = ddata.get('description', '')
+ device.save()
+ order.add_device(device)
+
+ for a in ddata.get('accessories', []):
+ a = Accessory(name=a, order=order, device=device)
+ a.save()
+
+ return ok(order.code)
+
+
+@api_view(['GET', 'POST', 'PUT'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def orders(request, code=None, pk=None):
+ """
+ This is the orders API
+ """
+ from servo.api.serializers import OrderSerializer
+
+ if request.method == 'POST':
+ return create_order(request)
+
+ if request.method == 'PUT':
+ return error('Method not yet implemented')
+
+ if request.GET.get('q'):
+ results = Order.objects.filter(**request.GET)
+
+ if pk:
+ order = Order.objects.get(pk=pk)
+ serializer = OrderSerializer(order, context={'request': request})
+ return Response(serializer.data)
+
+ if code:
+ order = Order.objects.get(code=code)
+ if order.status:
+ order.status_description = order.status.status.description
+ serializer = OrderSerializer(order, context={'request': request})
+ return Response(serializer.data)
+
+ orders = Order.objects.none()
+ serializer = OrderSerializer(orders, many=True, context={'request': request})
+ return Response(serializer.data)
+
+
+def messages(request):
+ """
+ Responds to SMS status updates
+ """
+ from servo.messaging.sms import SMSJazzProvider, HQSMSProvider
+
+ if not request.GET.get('id'):
+ return HttpResponse('Thanks, but no thanks')
+
+ m = get_object_or_404(Message, code=request.GET['id'])
+ gw = Configuration.conf('sms_gateway')
+ statusmap = HQSMSProvider.STATUSES
+
+ if gw == 'jazz':
+ statusmap = SMSJazzProvider.STATUSES
+
+ status = statusmap[request.GET['status']]
+ m.status = status[0]
+ m.error = status[1]
+
+ if m.status == 'DELIVERED':
+ m.received_at = timezone.now()
+
+ if m.status == 'FAILED':
+ if m.note.order:
+ uid = Configuration.conf('imap_act')
+ if uid:
+ user = User.objects.get(pk=uid)
+ m.note.order.notify('sms_failed', m.error, user)
+
+ m.save()
+
+ return HttpResponse('OK')
+
+
+def device_models(request):
+ data = Device.objects.order_by("description").distinct("description")
+ return json_response(list(data.values_list("description", flat=True)))
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def warranty(request):
+ from servo.api.serializers import DeviceSerializer
+ sn = request.GET.get('sn')
+
+ if not sn:
+ return error('Need query parameter for warranty lookup')
+
+ try:
+ GsxAccount.default(request.user)
+ except Exception as e:
+ return error('Cannot connect to GSX (check user name and password)')
+
+ try:
+ result = Device.from_gsx(sn, cached=False)
+ serializer = DeviceSerializer(result, context={'request': request})
+ return Response(serializer.data)
+ except Exception as e:
+ return error(e)
+
+
+@api_view(['GET'])
+def order_status(request):
+ from servo.api.serializers import OrderStatusSerializer
+ code = request.GET.get('q')
+ try:
+ result = Order.objects.get(code=code)
+ #serializer = OrderStatusSerializer(result)
+ return Response(serializer.data)
+ except Exception as e:
+ return (error(e))
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def notes(request, pk=None):
+ if pk:
+ note = Note.objects.get(pk=pk)
+ serializer = NoteSerializer(note, context={'request': request})
+ return Response(serializer.data)
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def order_items(request, pk):
+ item = ServiceOrderItem.objects.get(pk=pk)
+ serializer = ServiceOrderItemSerializer(item, context={'request': request})
+ return Response(serializer.data)
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def user_detail(request, pk):
+ user = User.objects.get(pk=pk)
+ serializer = UserSerializer(user, context={'request': request})
+ return Response(serializer.data)
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def customers(request, pk=None):
+ customer = Customer.objects.get(pk=pk)
+ serializer = CustomerSerializer(customer, context={'request': request})
+ return Response(serializer.data)
+
+
+@api_view(['GET'])
+@authentication_classes((TokenAuthentication,))
+@permission_classes((IsAuthenticated,))
+def devices(request, pk=None):
+ device = Device.objects.get(pk=pk)
+ serializer = DeviceSerializer(device, context={'request': request})
+ return Response(serializer.data)