add: accept and extract zip photo archives

main^2
rrr-marble 4 years ago
parent 7df1ff3503
commit 36cd3297af

@ -1,4 +1,4 @@
from fastapi import FastAPI, File, UploadFile, Depends from fastapi import FastAPI, File, UploadFile, Depends, BackgroundTasks
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.security import HTTPBasic, HTTPBasicCredentials from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.middleware.cors import CORSMiddleware # CORS from fastapi.middleware.cors import CORSMiddleware # CORS
@ -7,12 +7,14 @@ from secrets import compare_digest
from datetime import datetime from datetime import datetime
from uuid import uuid4 from uuid import uuid4
import sqlite3 import sqlite3
import zipfile
# use database residing here # use database residing here
DB_LOCATION = ( DB_LOCATION = (
"../testbox/photovoter.dblite" # Q: any allowances for this being not OUR database? "../testbox/photovoter.dblite" # Q: any allowances for this being not OUR database?
) )
DATA_LOCATION = "/tmp/123"
app = FastAPI() app = FastAPI()
security = HTTPBasic() security = HTTPBasic()
@ -178,24 +180,66 @@ async def photo_points():
@app.post( @app.post(
"/upload_pictures/", "/upload_pictures/",
responses={ responses={
202: {"description": "Archive accepted into processing"},
401: {"description": "Authentication is required to access this resource"}, 401: {"description": "Authentication is required to access this resource"},
415: {"description": "Cannot process uploaded archive"}, 415: {"description": "Cannot process uploaded archive"},
}, },
) )
async def upload_pictures( async def upload_pictures(
credentials: HTTPBasicCredentials = Depends(security), file: UploadFile = File(...) background_tasks: BackgroundTasks,
credentials: HTTPBasicCredentials = Depends(security),
file: UploadFile = File(...),
): ):
"""Интерфейс для загрузки фотографий""" """Интерфейс для загрузки фотографий"""
"""Условно кладём в браузер zip с фотографиями и он их потихоньку ест. """Условно кладём в браузер zip с фотографиями и он их потихоньку ест.
Доступ к этому интерфейсу, наверное, лучше ограничить паролем или как-нибудь ещё. Доступ к этому интерфейсу, наверное, лучше ограничить паролем или как-нибудь ещё.
Пока исходим из предположения, что только я буду загружать фотографии.""" Пока исходим из предположения, что только я буду загружать фотографии.
"""
# check authenticity # check authenticity
correct_username = compare_digest(credentials.username, "1") correct_username = compare_digest(credentials.username, "1")
correct_password = compare_digest(credentials.password, "1") correct_password = compare_digest(credentials.password, "1")
if not (correct_username and correct_password): if not (correct_username and correct_password):
return JSONResponse(status_code=401) return JSONResponse(status_code=401)
# slurp the zip # slurp the zip
# *detach from the interface, if possible if not zipfile.is_zipfile(file.file):
return JSONResponse(status_code=415)
# detach from the interface
# unpack zip # unpack zip
tasks = BackgroundTasks()
tasks.add_task(
unpack_pictures_zip,
file=file,
time=datetime.utcnow().replace(microsecond=0).isoformat(),
)
# feed the pictures to util/import_photos.py # feed the pictures to util/import_photos.py
return {"filename": file.filename} return JSONResponse("Accepted", background=tasks)
def unpack_pictures_zip(file: UploadFile, time):
"""
Unpack and process zip archived photo
Extract pictures in the DATA_LOCATION/processing
#TODO: and feed them to util/import_photos.py
#TODO: Walk the nested DATA_LOCATION/processing ourselves
Uses: DATA_LOCATION
"""
# we only call this function sporadically, so import here
import os
print(f"Accepted {file.filename} at {time} into processing")
os.chdir(DATA_LOCATION)
os.mkdir("processing")
os.chdir("processing")
# using private ._file field is a dirty hack, but
# SpooledTemporaryFile does not implement seekable
# required by zipfile 'r' mode
# https://bugs.python.org/issue26175
with zipfile.ZipFile(file.file._file) as photo_zip:
problem_files = photo_zip.testzip()
if problem_files is not None:
print(f"Errors in {file.filename} accepted at {time}: {problem_files}")
photo_zip.extractall()
photo_zip.close()
print(f"Succesfully processed {file.filename} accepted at {time}")

Loading…
Cancel
Save