import uuid from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form from fastapi.responses import Response from psycopg import AsyncConnection from mm_api.db import get_conn from mm_api.dependencies import current_user from pydantic import BaseModel import mm_api.services.kyc as svc import mm_api.services.permission as perm_svc router = APIRouter(prefix="/kyc", tags=["kyc"]) ALLOWED_MIME = {"image/jpeg", "image/png"} MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB class RejectRequest(BaseModel): note: str async def _require_kyc_perm(action: str, user: dict, conn: AsyncConnection): if not await perm_svc.can(conn, user["id"], action, "kyc", is_admin=True): raise HTTPException(403, "Yetersiz yetki") def _validate_file(file: UploadFile): if file.content_type not in ALLOWED_MIME: raise HTTPException(400, f"Geçersiz dosya türü: {file.content_type}") @router.post("/submit", status_code=201) async def submit( tc_kimlik: str = Form(..., min_length=11, max_length=11, pattern=r"^\d{11}$"), id_front: UploadFile = File(...), id_back: UploadFile = File(...), selfie: UploadFile = File(...), user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): for f in (id_front, id_back, selfie): _validate_file(f) req_uuid = str(uuid.uuid4()) front_data = await id_front.read() back_data = await id_back.read() selfie_data = await selfie.read() for data, name in ((front_data, "id_front"), (back_data, "id_back"), (selfie_data, "selfie")): if len(data) > MAX_FILE_SIZE: raise HTTPException(400, f"{name} dosyası 5MB'dan büyük olamaz") front_path = svc.save_file_encrypted(req_uuid, "id_front", front_data) back_path = svc.save_file_encrypted(req_uuid, "id_back", back_data) selfie_path = svc.save_file_encrypted(req_uuid, "selfie", selfie_data) try: return await svc.submit(conn, user["id"], tc_kimlik, front_path, back_path, selfie_path) except ValueError as e: svc.delete_request_files(req_uuid) raise HTTPException(400, str(e)) @router.get("/pending") async def list_pending( user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): await _require_kyc_perm("view", user, conn) return await svc.list_pending(conn) @router.post("/{request_id}/view-token") async def get_view_token( request_id: int, user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): await _require_kyc_perm("view", user, conn) req = await svc.get_request(conn, request_id) if not req: raise HTTPException(404, "Başvuru bulunamadı") token = await svc.create_view_token(conn, request_id, user["id"]) return {"view_token": token, "expires_in": 600} @router.get("/view/{token}/{file_type}") async def view_file( token: str, file_type: str, conn: AsyncConnection = Depends(get_conn), ): if file_type not in ("id_front", "id_back", "selfie"): raise HTTPException(400, "Geçersiz dosya türü") req = await svc.consume_view_token(conn, token) if not req: raise HTTPException(404, "Geçersiz veya süresi dolmuş token") path_key = f"{file_type}_path" data = svc.read_file_encrypted(req[path_key]) return Response(content=data, media_type="image/jpeg") @router.post("/{request_id}/approve") async def approve( request_id: int, user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): await _require_kyc_perm("approve", user, conn) try: return await svc.approve(conn, request_id, user["id"]) except ValueError as e: raise HTTPException(400, str(e)) @router.post("/{request_id}/reject") async def reject( request_id: int, data: RejectRequest, user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): await _require_kyc_perm("reject", user, conn) try: return await svc.reject(conn, request_id, user["id"], data.note) except ValueError as e: raise HTTPException(400, str(e)) @router.get("/users/{user_id}/tc") async def get_tc( user_id: int, user: dict = Depends(current_user), conn: AsyncConnection = Depends(get_conn), ): """Adli soruşturma endpoint'i — TC kimlik nosunu döner.""" if not await perm_svc.can(conn, user["id"], "view", "kyc", is_admin=True): raise HTTPException(403, "Yetersiz yetki") tc = await svc.get_tc_kimlik(conn, user_id) if tc is None: raise HTTPException(404, "Kimlik bilgisi bulunamadı") return {"user_id": user_id, "tc_kimlik": tc}