from urllib.parse import urlparse from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden import cv2 import numpy as np import base64 import os from django.views.decorators.csrf import csrf_exempt import json import datetime 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 IdentityCheckMessage, IdentityCheckCode 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 checkIdentity(request): if request.method != "POST": response = { "pass": False, "code": IdentityCheckCode.INVALID_REQUEST_METHOD.value, "message": IdentityCheckMessage.INVALID_REQUEST_METHOD.value, } return HttpResponseForbidden(json.dumps(response)) try: data = json.loads(request.body) idFront = data.get("idfront", "") or data.get("base64_image", "") shareId = data.get("shareId", "") except json.JSONDecodeError: response = { "pass": False, "code": IdentityCheckCode.INVALID_JSON.value, "message": IdentityCheckMessage.INVALID_JSON.value, } return HttpResponseBadRequest(json.dumps(response)) if idFront == "" or shareId == "": response = { "pass": False, "code": IdentityCheckCode.MISSING_PARAMETERS.value, "message": IdentityCheckMessage.MISSING_PARAMETERS.value, } return HttpResponseBadRequest(json.dumps(response)) 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 HttpResponse(json.dumps(response)) 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 HttpResponse(json.dumps(response)) try: verified, distance = 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), } return HttpResponse(json.dumps(response)) except Exception: response = { "pass": False, "code": IdentityCheckCode.FAILED_LOAD_FACE_IMAGE.value, "message": IdentityCheckMessage.FAILED_LOAD_FACE_IMAGE.value, } return HttpResponse(json.dumps(response)) if not verified: response = { "pass": False, "code": IdentityCheckCode.FACE_VERIFICATION_FAILED.value, "message": IdentityCheckMessage.FACE_VERIFICATION_FAILED.value, "distance": float(distance), } return HttpResponse(json.dumps(response)) 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() response = { "pass": True, "code": IdentityCheckCode.SUCCESS.value, "message": IdentityCheckMessage.SUCCESS.value, "distance": float(distance), } return HttpResponse(json.dumps(response))