147 lines
5.2 KiB
Python
147 lines
5.2 KiB
Python
import logging
|
|
from urllib.parse import quote
|
|
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import get_object_or_404
|
|
from drf_spectacular.types import OpenApiTypes
|
|
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
|
from rest_framework import status
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from common.logstorm_client import LogStormClient, LogStormClientError
|
|
|
|
from ..serializers import (
|
|
AttendanceDayEventSerializer,
|
|
)
|
|
from ..support import _day_event_records_visible_to, _employee_attendance_aliases
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AttendanceRecordDayEventsAPIView(APIView):
|
|
serializer_class = AttendanceDayEventSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get_record(self, request, record_id):
|
|
return get_object_or_404(
|
|
_day_event_records_visible_to(request.user).select_related("employee"),
|
|
pk=record_id,
|
|
)
|
|
|
|
def get(self, request, record_id):
|
|
record = self.get_record(request, record_id)
|
|
try:
|
|
events = LogStormClient().get_attendance_day_events(
|
|
employee_id=str(record.employee_id),
|
|
record_date=record.date,
|
|
aliases=_employee_attendance_aliases(record),
|
|
)
|
|
except LogStormClientError as exc:
|
|
logger.warning(
|
|
"LogStorm attendance day event retrieval failed",
|
|
extra={
|
|
"event": "attendance.logstorm.day_events_failed",
|
|
"attendance_record_id": record.id,
|
|
"employee_id": record.employee_id,
|
|
"record_date": record.date,
|
|
"upstream_status_code": exc.status_code,
|
|
"error_type": type(exc).__name__,
|
|
},
|
|
)
|
|
return Response(
|
|
{"detail": str(exc), "error": "logstorm_unavailable"},
|
|
status=status.HTTP_502_BAD_GATEWAY,
|
|
)
|
|
|
|
return Response(
|
|
[
|
|
self._with_proxy_photo_url(request, record, event)
|
|
for event in events
|
|
if isinstance(event, dict)
|
|
]
|
|
)
|
|
|
|
@staticmethod
|
|
def _with_proxy_photo_url(request, record, event):
|
|
result = dict(event)
|
|
event_key = str(result.get("event_key") or "")
|
|
if result.get("has_photo") and event_key:
|
|
result["photo_url"] = (
|
|
f"/api/v1/attendance/records/{record.id}/day-events/"
|
|
f"{quote(event_key)}/photo/"
|
|
)
|
|
else:
|
|
result["photo_url"] = None
|
|
return result
|
|
|
|
|
|
class AttendanceRecordDayEventPhotoAPIView(APIView):
|
|
serializer_class = AttendanceDayEventSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get_record(self, request, record_id):
|
|
return get_object_or_404(
|
|
_day_event_records_visible_to(request.user).select_related("employee"),
|
|
pk=record_id,
|
|
)
|
|
|
|
@extend_schema(
|
|
responses={
|
|
200: OpenApiResponse(
|
|
response=OpenApiTypes.BINARY,
|
|
description="Фотография события прохода",
|
|
)
|
|
}
|
|
)
|
|
def get(self, request, record_id, event_key):
|
|
record = self.get_record(request, record_id)
|
|
client = LogStormClient()
|
|
try:
|
|
events = client.get_attendance_day_events(
|
|
employee_id=str(record.employee_id),
|
|
record_date=record.date,
|
|
aliases=_employee_attendance_aliases(record),
|
|
)
|
|
event = next(
|
|
(
|
|
item
|
|
for item in events
|
|
if isinstance(item, dict)
|
|
and str(item.get("event_key")) == str(event_key)
|
|
),
|
|
None,
|
|
)
|
|
if not event or not event.get("has_photo"):
|
|
return Response(
|
|
{"detail": "Event photo not found"},
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
photo_response = client.get_attendance_event_photo(event_key)
|
|
except LogStormClientError as exc:
|
|
if exc.status_code == status.HTTP_404_NOT_FOUND:
|
|
return Response(
|
|
{"detail": "Event photo not found"},
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
logger.warning(
|
|
"LogStorm attendance event photo retrieval failed",
|
|
extra={
|
|
"event": "attendance.logstorm.event_photo_failed",
|
|
"attendance_record_id": record.id,
|
|
"employee_id": record.employee_id,
|
|
"upstream_status_code": exc.status_code,
|
|
"error_type": type(exc).__name__,
|
|
},
|
|
)
|
|
return Response(
|
|
{"detail": str(exc), "error": "logstorm_unavailable"},
|
|
status=status.HTTP_502_BAD_GATEWAY,
|
|
)
|
|
|
|
return HttpResponse(
|
|
photo_response.content,
|
|
content_type=photo_response.headers.get("Content-Type", "image/jpeg"),
|
|
)
|