Source code for ferrosoft.apps.befundung.api.views

import logging
import traceback

from rest_framework import viewsets, permissions, status
from rest_framework.response import Response
from rest_framework.reverse import reverse

from ferrosoft.apps.befundung.api.serializers import (
    ExaminationSerializer,
)
from ferrosoft.apps.befundung.models import (
    Examination,
    create_log,
    ExaminationRequest,
    ExaminationPhotoRequest,
)
from ferrosoft.apps.date_time import now_utc
from ferrosoft.apps.ferrobase.services.taskqueue import (
    background_task_tenant,
    TaskQueueError,
)


[docs] class ExaminationViewSet(viewsets.ModelViewSet): """ API endpoint for examination reports of materials. """ queryset = Examination.objects.all() serializer_class = ExaminationSerializer permission_classes = [permissions.IsAuthenticated]
[docs] def create(self, request, *args, **kwargs): weighing_slip_id = "" try: payload, weighing_slip_id = self.save_request(request) serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): create_log( "invalid examination data, weighing_slip_id={}; errors={}".format( weighing_slip_id, serializer.errors ) ) background_task_tenant( "ferrosoft.apps.befundung.request.report_examination_errors", str(payload.pk), serializer.errors, reverse( "befundung:replay_request", args=[payload.pk], request=request ), ) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) exam = serializer.save() weighing_slip_id = exam.weighing_slip_id task_id = background_task_tenant( "ferrosoft.apps.befundung.request.report_examination", str(exam.pk) ) create_log( "enqueued examination for processing, weighing_slip_id=%s; task_id=%s" % ( weighing_slip_id, task_id, ) ) headers = self.get_success_headers(serializer.data) return Response( serializer.data, status=status.HTTP_201_CREATED, headers=headers ) except TaskQueueError as e: logging.exception("could not enqueue examination for processing") create_log( "could not enqueue examination for processing: weighing_slip_id=%s; error=%s\n%s" % (weighing_slip_id, str(e), traceback.format_exc()) ) return Response( {"error": "task queue unavailable"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) except Exception as e: logging.exception("unexpected error during examination processing") create_log( "cannot create examination: weighing_slip_id=%s; error=%s\n%s" % (weighing_slip_id, str(e), traceback.format_exc()) ) return Response( {"error": "unexpected error"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, )
[docs] def save_request(self, request) -> (ExaminationRequest, str): # Save request for replay function. PowerApp sometimes sends unexpected data, # breaking API contract, and it cannot be fixed on the other side. # # Photos are removed from ExaminationRequest, because it's a lot of data, # which would render replay function unusable. Therefore, photos are stored # separate. data = request.data if not isinstance(data, dict): # Even though PowerApps sometimes sends garbage inside the payload, # whole payload should never be garbage. raise ValueError("Received garbage request") photos = data.pop("photos", []) weighing_slip_id = data.get("weighing_slip_id", "") payload = ExaminationRequest.objects.create( creation_date=now_utc(), weighing_slip_id=weighing_slip_id, payload=data, ) if len(photos) > 0: ExaminationPhotoRequest.objects.create( request=payload, payload=photos, ) # Restore popped photos to request, for serializer to pick it up. request.data["photos"] = photos return payload, weighing_slip_id