import os import pathlib from typing import List import marshmallow as ma from flask_smorest.fields import Upload from werkzeug.datastructures import FileStorage import uuid from ..app import Application from ..config import APISettings from ..logic.csv_processor import process_csv, FileTypeInvalidError from . import formatter_routes as blp APP = Application.get_instance() def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in APISettings.ALLOWED_EXTENSIONS class MultipartFormSchema(ma.Schema): username = ma.fields.String(required=True) friendcode = ma.fields.String(required=False) class MultipartFileSchema(ma.Schema): servantdata = Upload() cedata = Upload() @blp.route("/upload", methods=["POST"]) @blp.arguments(MultipartFormSchema, location="form") @blp.arguments(MultipartFileSchema, location="files") @blp.response(200) def upload_file(form: dict[str, str], files: dict[str, FileStorage]): filepaths: List[pathlib.Path] = [] returndata = { "username": form["username"], "friendcode": form.get("friendcode", "") } for name, file in files.items(): if name not in ("servantdata", "cedata"): return { "status": 406, "message": "Invalid form sent" }, 406 filepath = APISettings.FILE_SAVE_DIRECTORY / f"{uuid.uuid4()}.csv" file.save(filepath) if os.stat(filepath).st_size < 1 or not allowed_file(file.filename): filepath.unlink() continue filepaths.append(filepath) if len(filepaths) == 0: return { "status": 406, "message": "No files provided" }, 406 try: for f in filepaths: result = process_csv(f) returndata = returndata | result f.unlink() except FileTypeInvalidError: for f in filepaths: f.unlink() return { "status": 500, "message": "Error whilst parsing uploaded file - please contact Firq on Fate/Sacc Order" }, 406 return returndata