# -*- coding: utf-8 -*- 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 username 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)