diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..394df32 --- /dev/null +++ b/src/config.py @@ -0,0 +1,57 @@ +import envyaml +import os +import logging +from logging import Formatter, StreamHandler +import json + +config = envyaml.EnvYAML(os.environ.get('CONFIG_PATH', 'config.yaml')) + +def init() -> None: + """ + Initializes the application and validates the config + """ + + initLogger() + + if config["app.scripts.path"] == "": + logging.error("Scripts path not set") + exit(1) + elif config["app.scripts.path"][-1] != "/": + logging.error("Scripts path does not end with a slash") + exit(1) + +def initLogger() -> None: + """ + Initializes the logger + """ + # style the logger output to look like uvicorn for root app + FORMAT = '%(asctime)-15s %(levelname)s %(message)s' + DATE_FORMAT = '%b %d %H:%M:%S' + formatter = Formatter(fmt=FORMAT, datefmt=DATE_FORMAT) + handler = StreamHandler() + handler.setFormatter(formatter) + logger = logging.getLogger() + + # remove default handler + logger.handlers = [] + logger.addHandler(handler) + + logging.basicConfig(level=resolveLogLevel(config["app.log.level"])) + +def resolveLogLevel(level: str) -> int: + """ + Resolves a log level from a string + """ + if level == 'debug': + return logging.DEBUG + elif level == 'info': + return logging.INFO + elif level == 'warning': + return logging.WARNING + elif level == 'error': + return logging.ERROR + elif level == 'critical': + return logging.CRITICAL + else: + logging.warning("Invalid log level. Using INFO as default") + return logging.INFO diff --git a/src/config.yaml b/src/config.yaml new file mode 100644 index 0000000..ab9e000 --- /dev/null +++ b/src/config.yaml @@ -0,0 +1,7 @@ +app: + log: + level: "debug" + scripts: + # Where uploaded scripts are to be stored + path: "./scripts/" + diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..d53a70e --- /dev/null +++ b/src/main.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from config import init +from router.upload import router as uploadRouter + +init() + +app = FastAPI() + +app.include_router(uploadRouter) diff --git a/src/router/__init__.py b/src/router/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/router/upload.py b/src/router/upload.py new file mode 100644 index 0000000..4e2c981 --- /dev/null +++ b/src/router/upload.py @@ -0,0 +1,46 @@ +from fastapi import APIRouter, UploadFile, File +from config import config, resolveLogLevel +from uuid import uuid4 +import magic +import logging + +# set logging level +logging.basicConfig(level=resolveLogLevel(config["app.log.level"])) + +router = APIRouter( + prefix="/upload", + tags=["upload"], + responses={404: {"description": "Not found"}}, + ) + +@router.post("/") +async def upload(file: UploadFile): + """ + Upload a python script to be stored + """ + + logging.debug(f"File name : {file.filename}") + + # Check if the file is a python script + if not file.filename.endswith(".py"): + return {"error": "File is not a python script"} + + logging.debug(f"File content type : {file.content_type}") + + if file.content_type != "text/x-python": + return {"error": "File is not a python script"} + + # reset file pointer + await file.seek(0) + + scriptDirectory = config["app.scripts.path"] + + # Get UUID file name + uuid = uuid4() + + # Write the file to the script directory + with open(scriptDirectory + str(uuid), "wb") as buffer: + buffer.write(file.file.read()) + + return {"uuid": str(uuid)} +