1+ import asyncio
12import datetime
23import os
34import random
45import string
6+ from concurrent .futures import ThreadPoolExecutor
7+ from functools import partial
58from typing import Final
69
710import aiofiles
1720 ApproveStatuses ,
1821)
1922from calendar_backend .settings import get_settings
23+ from PIL import Image
24+ from io import BytesIO
25+
2026
2127settings = get_settings ()
2228
@@ -80,6 +86,7 @@ async def upload_lecturer_photo(lecturer_id: int, session: Session, file: Upload
8086 path = os .path .join (settings .STATIC_PATH , "photo" , "lecturer" , f"{ random_string } .{ ext } " )
8187 async with aiofiles .open (path , 'wb' ) as out_file :
8288 content = await file .read ()
89+ await async_image_process (content )
8390 await out_file .write (content )
8491 approve_status = ApproveStatuses .APPROVED if not settings .REQUIRE_REVIEW_PHOTOS else ApproveStatuses .PENDING
8592 photo = Photo (
@@ -92,3 +99,19 @@ async def upload_lecturer_photo(lecturer_id: int, session: Session, file: Upload
9299 lecturer .avatar_id = lecturer .last_photo .id if lecturer .last_photo else lecturer .avatar_id
93100 session .flush ()
94101 return photo
102+
103+
104+ def process_image (image_bytes : bytes ) -> None :
105+ with Image .open (BytesIO (image_bytes )) as image :
106+ try :
107+ image .verify ()
108+ except SyntaxError :
109+ raise HTTPException (status_code = 422 , detail = "Corrupted file" )
110+
111+
112+ thread_pool = ThreadPoolExecutor ()
113+
114+
115+ async def async_image_process (image_bytes : bytes ) -> None :
116+ loop = asyncio .get_event_loop ()
117+ await loop .run_in_executor (thread_pool , partial (process_image , image_bytes ))
0 commit comments