import json import datetime import cv2 import numpy as np import base64 import os from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.conf import settings from django.core.files.base import ContentFile from proctoring.models.image import Image from proctoring.models.imageTypes import ImageTypes from proctoring.services.face_compare_v2 import compare_id_images, FaceVerificationError from proctoring.services.identity_messages import IdentityCheckCode, IdentityCheckMessage from proctoring.services.id_extraction import extract_name_from_id from urllib.parse import urlparse def _storage_path_from_url(full_url: str) -> str: """ Convert a full URL like https://cdn.example.com/proctoring_images/123/identity-check/face/xxx.jpg into a storage path: proctoring_images/123/identity-check/face/xxx.jpg """ parsed = urlparse(full_url) return parsed.path.lstrip("/") @csrf_exempt def check_id(request): if request.method != "POST": response = { "code": IdentityCheckCode.INVALID_REQUEST_METHOD.value, "message": IdentityCheckMessage.INVALID_REQUEST_METHOD.value, } return JsonResponse(response, status=403) try: data = json.loads(request.body) idFront = data.get("idfront", "") or data.get("base64_image", "") shareId = data.get("shareId", "") except json.JSONDecodeError: response = { "code": IdentityCheckCode.INVALID_JSON.value, "message": IdentityCheckMessage.INVALID_JSON.value, } return JsonResponse(response, status=400) if idFront == "" or shareId == "": response = { "code": IdentityCheckCode.MISSING_PARAMETERS.value, "message": IdentityCheckMessage.MISSING_PARAMETERS.value, } return JsonResponse(response, status=400) face_image_obj = ( Image.objects .filter(shareId=shareId, type=ImageTypes.FaceCheck) .order_by('-id') .first() ) if face_image_obj is None: response = { "pass": False, "code": IdentityCheckCode.NO_FACE_IMAGE.value, "message": IdentityCheckMessage.NO_FACE_IMAGE.value, } return JsonResponse(response, status=200) try: storage_path = _storage_path_from_url(face_image_obj.path) with settings.s3_storage.open(storage_path, mode='rb') as f: face_bytes = f.read() userFace_base64 = base64.b64encode(face_bytes).decode('utf-8') except Exception: response = { "pass": False, "code": IdentityCheckCode.FAILED_LOAD_FACE_IMAGE.value, "message": IdentityCheckMessage.FAILED_LOAD_FACE_IMAGE.value, } return JsonResponse(response, status=200) try: result = compare_id_images( id_card_image_base64=idFront, id_holder_image_base64=userFace_base64, ) except FaceVerificationError as e: response = { "pass": False, "code": IdentityCheckCode.FACE_VERIFICATION_FAILED.value, "message": str(e), "face_not_found": False, } return JsonResponse(response, status=200) face_ok = (result["status"] == "ok") verified = result["verified"] distance = result["distance"] try: extracted_name = extract_name_from_id(idFront) except Exception: response = { "pass": False, "code": IdentityCheckCode.NAME_EXTRACTION_FAILED.value, "message": IdentityCheckMessage.NAME_EXTRACTION_FAILED.value, } return JsonResponse(response, status=200) imgWidth = 240 imgHeight = 135 frontImg_bytes = base64.b64decode(idFront) frontImg_np = np.frombuffer(frontImg_bytes, dtype=np.uint8) frontImg = cv2.imdecode(frontImg_np, cv2.IMREAD_COLOR) frontImg = cv2.resize(frontImg, (imgWidth, imgHeight), interpolation=cv2.INTER_AREA) idFront_save = cv2.imencode(".jpg", frontImg)[1].tobytes() save_folder = os.path.join("proctoring_images", shareId) identity_folder = os.path.join(save_folder, "identity-check", "id") frontFilename = "Front {date:%Y-%m-%d_%H.%M.%S}.jpg".format( date=datetime.datetime.now() ) frontFilepath = os.path.join(identity_folder, frontFilename) frontContent_file = ContentFile(idFront_save, name=frontFilename) frontFilepath = settings.s3_storage.save(frontFilepath, frontContent_file) frontImage = Image( path=f"{settings.AWS_S3_ACCESS_DOMAIN}/{frontFilepath}", personCount=0, prohibitedObjectsCount=0, type=ImageTypes.IdCheck, shareId=shareId ) frontImage.save() if not (face_ok and verified and extracted_name): response = { "pass": False, "code": IdentityCheckCode.IDENTITY_MISMATCH.value, "message": IdentityCheckMessage.IDENTITY_MISMATCH.value, "distance": float(distance), "verified": bool(verified), } return JsonResponse(response, status=200) response = { "pass": True, "code": IdentityCheckCode.SUCCESS.value, "message": IdentityCheckMessage.SUCCESS.value, "distance": float(distance), "verified": bool(verified), } return JsonResponse(response, status=200)