131cb27d16
Django project: employees, locations, visit_manager, it_manager, mattermost_connector and stub connectors (ad, mail, portal).
117 lines
4.0 KiB
Python
117 lines
4.0 KiB
Python
# apps/attendance/api/views.py
|
|
"""
|
|
REST API для регистрации посещений с PPOS/терминалов.
|
|
"""
|
|
import base64
|
|
from django.core.files.base import ContentFile
|
|
from rest_framework import serializers, status
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from ..services import register_attendance
|
|
from ..models import AttendanceLog
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Serializers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class AttendanceCreateSerializer(serializers.Serializer):
|
|
employee_id = serializers.IntegerField()
|
|
location_id = serializers.IntegerField()
|
|
direction = serializers.ChoiceField(choices=['in', 'out'])
|
|
# Фото передаётся как base64-строка (multipart тоже поддерживается — см. ниже)
|
|
photo_b64 = serializers.CharField(write_only=True)
|
|
device_id = serializers.CharField(required=False, default='')
|
|
|
|
def validate_photo_b64(self, value: str) -> bytes:
|
|
try:
|
|
# Убираем data URI prefix если есть
|
|
if ',' in value:
|
|
value = value.split(',', 1)[1]
|
|
return base64.b64decode(value)
|
|
except Exception:
|
|
raise serializers.ValidationError('Невалидный base64')
|
|
|
|
|
|
class AttendanceLogSerializer(serializers.ModelSerializer):
|
|
photo_thumb = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = AttendanceLog
|
|
fields = [
|
|
'id', 'employee_id', 'location_id', 'direction',
|
|
'timestamp', 'photo', 'photo_thumb', 'device_id',
|
|
]
|
|
|
|
def get_photo_thumb(self, obj):
|
|
return obj.photo_thumb_b64
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Views
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class AttendanceRegisterView(APIView):
|
|
"""
|
|
POST /api/attendance/register/
|
|
Принимает фото в base64, создаёт запись посещения.
|
|
"""
|
|
|
|
def post(self, request):
|
|
serializer = AttendanceCreateSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
data = serializer.validated_data
|
|
|
|
log = register_attendance(
|
|
employee_id=data['employee_id'],
|
|
location_id=data['location_id'],
|
|
direction=data['direction'],
|
|
photo_bytes=data['photo_b64'],
|
|
device_id=data.get('device_id', ''),
|
|
ip_address=request.META.get('REMOTE_ADDR'),
|
|
)
|
|
|
|
return Response(
|
|
AttendanceLogSerializer(log).data,
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class AttendanceListView(APIView):
|
|
"""
|
|
GET /api/attendance/?employee_id=&date=YYYY-MM-DD&location_id=
|
|
Список записей с превью (без оригиналов фото — только thumb в base64).
|
|
"""
|
|
|
|
def get(self, request):
|
|
qs = AttendanceLog.objects.select_related('employee', 'location')
|
|
|
|
if emp := request.query_params.get('employee_id'):
|
|
qs = qs.filter(employee_id=emp)
|
|
if loc := request.query_params.get('location_id'):
|
|
qs = qs.filter(location_id=loc)
|
|
if date := request.query_params.get('date'):
|
|
qs = qs.filter(timestamp__date=date)
|
|
|
|
qs = qs.order_by('-timestamp')[:200]
|
|
return Response(AttendanceLogSerializer(qs, many=True).data)
|
|
|
|
|
|
class AttendancePhotoView(APIView):
|
|
"""
|
|
GET /api/attendance/<uuid>/photo/
|
|
Возвращает оригинал фото (redirect к MEDIA_URL или streaming).
|
|
"""
|
|
from django.http import HttpResponseRedirect
|
|
|
|
def get(self, request, pk):
|
|
from django.http import HttpResponseRedirect, Http404
|
|
try:
|
|
log = AttendanceLog.objects.get(pk=pk)
|
|
except AttendanceLog.DoesNotExist:
|
|
raise Http404
|
|
if not log.photo:
|
|
raise Http404
|
|
return HttpResponseRedirect(log.photo.url)
|