diff --git a/app.py b/app.py index 102ea8d..f391183 100644 --- a/app.py +++ b/app.py @@ -1,16 +1,23 @@ +import atexit import http import inspect +import os +from mailbox import FormatError from typing import Union -from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.schedulers.background import BackgroundScheduler +from firebase_admin.auth import UserNotFoundError, UserRecord from flask import (Blueprint, Flask, Response, jsonify, request) from flask_cors import CORS +from werkzeug.datastructures import ImmutableMultiDict, FileStorage +from werkzeug.utils import secure_filename +import file_manager import firebase_manager import generic_executor -import atexit app = Flask(__name__) +app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000 * 1000 cors = CORS(app, origins="*") apiBP = Blueprint('apiBP', 'BPapi') @@ -28,7 +35,7 @@ def generic_response_maker(status_code: http.HTTPStatus, _message: str = None) - case http.HTTPStatus.ACCEPTED: message = jsonify({'message': 'Action successful.'}) case http.HTTPStatus.BAD_REQUEST: - message = jsonify({'message': 'Bad Request, the property you tried to modify is not valid.'}) + message = jsonify({'message': 'Bad Request.'}) case http.HTTPStatus.NOT_FOUND: message = jsonify({'message': 'Server not found.'}) case http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE: @@ -118,6 +125,59 @@ def dynamic_route_handler(path): return generic_response_maker(http.HTTPStatus.BAD_REQUEST, str(e)) +# [!] This route is specific and has to remain out of the dynamic route handler. +@apiBP.route('/Upload', methods=['POST']) +def upload(): + form = request.form + token: str or None = form.get('token') + name: str or None = form.get('name') + files: ImmutableMultiDict[str, FileStorage] = request.files + + try: + if not form: + raise FormatError(0) + if not files: + raise FormatError(1) + if not token: + raise KeyError('token') + if not name: + raise KeyError('name') + + data: dict = {'token': token} + user: UserRecord = authenticate_request(data) + user_id: str = user.uid + + for _, file in files.items(): + filename = file.filename + internal_path = file_manager.get_path_from_extension(filename) + if internal_path is None: + continue + filename = secure_filename(filename) + file.save(os.path.join(f"users/{user_id}/{name}/{internal_path}", filename)) + + except FormatError as e: + match e: + case 0: + return generic_response_maker(http.HTTPStatus.BAD_REQUEST, "No FormData found in the payload.") + case 1: + return generic_response_maker(http.HTTPStatus.NOT_ACCEPTABLE, "No file(s) were uploaded.") + + except FileNotFoundError as e: + return generic_response_maker(http.HTTPStatus.CONFLICT, "Please launch the server at least once.") + + except KeyError as e: + return f"Missing parameter {e} in FormData.", http.HTTPStatus.BAD_REQUEST + + except UserNotFoundError as e: + return str(e), http.HTTPStatus.BAD_REQUEST + + except Exception as e: + file_manager.log_error(type(e).__name__, str(e)) + return generic_response_maker(http.HTTPStatus.BAD_REQUEST, f"{type(e).__name__}, {str(e)}") + + return generic_response_maker(http.HTTPStatus.OK, "Successfully uploaded files !") + + def exit_safety() -> None: firebase_manager.set_servers_not_running() return