From 688149d6af45f9fdf78f9327e5f6d1e1ca3a071f Mon Sep 17 00:00:00 2001 From: Matt Hills Date: Mon, 7 Oct 2024 23:16:42 -0400 Subject: [PATCH] initial commit --- .gitignore | 4 ++ Dockerfile | 7 +++ requirements.txt | 17 +++++++ src/app.py | 57 +++++++++++++++++++++++ src/utils/mLogger.py | 105 +++++++++++++++++++++++++++++++++++++++++++ src/wsgi.py | 4 ++ 6 files changed, 194 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 requirements.txt create mode 100644 src/app.py create mode 100644 src/utils/mLogger.py create mode 100644 src/wsgi.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad257c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +tmp/ +venv/ + +*.log \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..140af89 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.8-slim +WORKDIR /app +COPY ./src /app +COPY requirements.txt /app/requirements.txt +RUN pip install -r /app/requirements.txt +EXPOSE 7777 +CMD ["gunicorn", "wsgi:app", "--bind", "0.0.0.0:7777"] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1d85079 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,17 @@ +blinker==1.8.2 +certifi==2024.8.30 +charset-normalizer==3.3.2 +click==8.1.7 +Flask==3.0.3 +Flask-Uploads==0.2.1 +gunicorn==23.0.0 +idna==3.10 +importlib_metadata==8.5.0 +itsdangerous==2.2.0 +Jinja2==3.1.4 +MarkupSafe==3.0.0 +packaging==24.1 +requests==2.32.3 +urllib3==2.2.3 +Werkzeug==3.0.4 +zipp==3.20.2 diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..092b0fc --- /dev/null +++ b/src/app.py @@ -0,0 +1,57 @@ +import os +import uuid +from flask import Flask, request, jsonify, send_from_directory +from werkzeug.utils import secure_filename +import requests +import utils.mLogger as log + +app = Flask(__name__) +app.config['UPLOAD_FOLDER'] = 'tmp/uploads' + +if not os.path.exists(app.config['UPLOAD_FOLDER']): + os.makedirs(app.config['UPLOAD_FOLDER']) + +# TinyURL API for generating short URLs +def generate_tiny_url(long_url): + response = requests.get(f'http://tinyurl.com/api-create.php?url={long_url}') + return response.text if response.status_code == 200 else None + +# Route for file uploads +@app.route('/upload', methods=['POST']) +def upload_file(): + if 'file' not in request.files: + log.e("No File Part") + return jsonify({'error': 'No file part'}), 400 + + file = request.files['file'] + if file.filename == '': + log.e("No selected file") + return jsonify({'error': 'No selected file'}), 400 + + filename = secure_filename(file.filename) + file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + log.i(f"File upload: {file_path}") + file.save(file_path) + + # Generate a download link + download_url = request.host_url + 'download/' + filename + tiny_url = generate_tiny_url(download_url) + + return jsonify({'tiny_url': tiny_url}), 200 + +# Route for downloading the file (one-time) +@app.route('/download/', methods=['GET']) +def download_file(filename): + file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + + if os.path.exists(file_path): + # Serve the file and then delete it + response = send_from_directory(app.config['UPLOAD_FOLDER'], filename) + os.remove(file_path) + return response + else: + return jsonify({'error': 'File not found'}), 404 + +if __name__ == '__main__': + log.i("Running flask in debug...") + app.run(debug=True, host="0.0.0.0", port=7777) \ No newline at end of file diff --git a/src/utils/mLogger.py b/src/utils/mLogger.py new file mode 100644 index 0000000..7b0c1ff --- /dev/null +++ b/src/utils/mLogger.py @@ -0,0 +1,105 @@ +import datetime as dt +import inspect +import os + +''' + Constants +''' +LOG_FILE_NAME = "AngelEyes" +LEVEL_INFO = 1 +LEVEL_WARNING = 2 +LEVEL_ERROR = 3 +LEVEL_DEBUG = 4 +LEVEL_VERBOSE = 5 +DEBUG_LOG_LEVEL = LEVEL_DEBUG + + +''' + writeLogMessage(): Write event to text file and to screen depending on log level + level = int, LEVEL_* constant + msg = str, Log event message +''' +def get_caller(): + frames = inspect.stack() + current_file = os.path.basename(__file__) # Gets the filename of the logging module + for frame in frames: + module_path = frame.filename + module_name = os.path.basename(module_path) + # Continue until the module name is not the logger module itself + if module_name != current_file: + return module_name.replace('.py', '') + return "Unknown" + +def writeLogMessage(level, msg): + + if DEBUG_LOG_LEVEL == None: + raise Exception("mattLog - Specify a Log level. I.e. mattLog.DEBUG_LOG_LEVEL = mattlog.LEVEL_WARNING.") + if LOG_FILE_NAME == None: + raise Exception("mattLog - Specify a Log FileName. I.e. mattLog.LOG_FILE_NAME = \"log.txt\"") + + now = dt.datetime.now() + y = now.year + m = now.month + d = now.day + caller = get_caller() + logLevel = levelToString(level) + logFileName = f'{y}{m}{d}_{LOG_FILE_NAME}' + event = f"{now}|{logLevel}|{caller}::{msg}" + + + ## Determine what should be printed to the screen + if DEBUG_LOG_LEVEL >= level: + print(event) + + ## Always Write to log + f = open(f"{logFileName}.log", "a") + f.write(f"{event} \n") + f.close() + +''' + levelToString(): to transalte log level to string + level = int LEVEL_* constant +''' +def levelToString(level): + strLevel = None + if level == LEVEL_INFO: strLevel = "I" + if level == LEVEL_WARNING: strLevel = "W" + if level == LEVEL_ERROR: strLevel = "E" + if level == LEVEL_DEBUG: strLevel = "D" + if level == LEVEL_VERBOSE: strLevel = "V" + + if strLevel == None:raise Exception("MATTLOG: LOG LEVEL NOT FOUND.") + + return strLevel + +''' + i/e/w/d/v/(): Helper Methods for each log level + msg = String message +''' +def i(msg): + writeLogMessage(LEVEL_INFO, msg) + +def e(msg): + writeLogMessage(LEVEL_ERROR, msg) + +def w(msg): + writeLogMessage(LEVEL_WARNING, msg) + +def d(msg): + writeLogMessage(LEVEL_DEBUG, msg) + +def v(msg): + writeLogMessage(LEVEL_VERBOSE, msg) + +''' + Run tests if script is directly executed. +''' +if __name__ == "__main__": + LOG_FILE_NAME = "TestLog" + DEBUG_LOG_LEVEL = LEVEL_VERBOSE + + i("Testing Info") + w("Testing Warn") + e("Testing Err") + d("Testing Debug") + v("Testing Verbose") \ No newline at end of file diff --git a/src/wsgi.py b/src/wsgi.py new file mode 100644 index 0000000..3c1465a --- /dev/null +++ b/src/wsgi.py @@ -0,0 +1,4 @@ +from app import app + +if __name__ == '__main__': + app.run() \ No newline at end of file