From 9821db72c6afc348dc0554444d9426b23e7bedc0 Mon Sep 17 00:00:00 2001 From: Fluffy-Bean <michal-gdula@protonmail.com> Date: Tue, 26 Sep 2023 13:43:00 +0100 Subject: [PATCH] Yeet old runner script as it was useless Clean up code and styling --- onlylegs/app.py | 115 ++++++------- onlylegs/config.py | 19 ++- onlylegs/static/js/imagePage.js | 41 ----- onlylegs/static/js/uploadTab.js | 77 +-------- .../static/sass/components/notification.sass | 28 +--- onlylegs/static/sass/style.sass | 6 +- onlylegs/utils/startup.py | 156 ++++++++++++++++++ poetry.lock | 118 ++++++++++++- pyproject.toml | 1 + setup/args.py | 33 ---- setup/configuration.py | 156 ------------------ setup/runner.py | 35 ---- 12 files changed, 348 insertions(+), 437 deletions(-) create mode 100644 onlylegs/utils/startup.py delete mode 100644 setup/args.py delete mode 100644 setup/configuration.py delete mode 100644 setup/runner.py diff --git a/onlylegs/app.py b/onlylegs/app.py index 0dd4349..75533d7 100644 --- a/onlylegs/app.py +++ b/onlylegs/app.py @@ -1,67 +1,55 @@ """ Onlylegs Gallery -This is the main app file, it loads all the other files and sets up the app +This is the main app file, checks on app stability and runs all da shit """ import os import logging from flask_assets import Bundle from flask_migrate import init as migrate_init - -from flask import Flask, render_template, abort +from flask import Flask, render_template, abort, request from werkzeug.exceptions import HTTPException -from werkzeug.security import generate_password_hash +from onlylegs.utils import startup from onlylegs.extensions import db, migrate, login_manager, assets, compress, cache -from onlylegs.config import INSTANCE_DIR, MIGRATIONS_DIR +from onlylegs.config import INSTANCE_DIR, MIGRATIONS_DIR, APPLICATION_ROOT from onlylegs.models import Users -from onlylegs.views import ( - index as view_index, - image as view_image, - group as view_group, - settings as view_settings, - profile as view_profile, + +from onlylegs.views.index import blueprint as view_index +from onlylegs.views.image import blueprint as view_image +from onlylegs.views.group import blueprint as view_group +from onlylegs.views.settings import blueprint as view_settings +from onlylegs.views.profile import blueprint as view_profile +from onlylegs.api import blueprint as api +from onlylegs.auth import blueprint as view_auth +from onlylegs.filters import blueprint as filters + + +logging.getLogger("werkzeug").disabled = True +logging.basicConfig( + filename=os.path.join(APPLICATION_ROOT, "only.log"), + level=logging.INFO, + datefmt="%Y-%m-%d %H:%M:%S", + format="%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s", + encoding="utf-8", ) -from onlylegs import api -from onlylegs import auth as view_auth -from onlylegs import filters + app = Flask(__name__, instance_path=INSTANCE_DIR) app.config.from_pyfile("config.py") -# DATABASE db.init_app(app) migrate.init_app(app, db, directory=MIGRATIONS_DIR) -# If database file doesn't exist, create it +# App Sanity Checks +startup.check_dirs() +startup.check_env() +startup.check_conf() + if not os.path.exists(os.path.join(INSTANCE_DIR, "gallery.sqlite3")): - print("Creating database") - with app.app_context(): - db.create_all() + startup.make_admin_user(app) + migrate_init(directory=MIGRATIONS_DIR) - register_user = Users( - username=app.config["ADMIN_CONF"]["username"], - email=app.config["ADMIN_CONF"]["email"], - password=generate_password_hash("changeme!", method="sha256"), - ) - db.session.add(register_user) - db.session.commit() - - print( - """ -#################################################### -# DEFAULT ADMIN USER GENERATED WITH GIVEN USERNAME # -# THE DEFAULT PASSWORD "changeme!" HAS BEEN USED, # -# PLEASE UPDATE IT IN THE SETTINGS! # -#################################################### - """ - ) - -# Check if migrations directory exists, if not create it -with app.app_context(): - if not os.path.exists(MIGRATIONS_DIR): - print("Creating migrations directory") - migrate_init(directory=MIGRATIONS_DIR) # LOGIN MANAGER # can also set session_protection to "strong" @@ -90,40 +78,41 @@ def error_page(err): """ if not isinstance(err, HTTPException): abort(500) - return ( - render_template("error.html", error=err.code, msg=err.description), - err.code, - ) + + if request.method == "GET": + return ( + render_template("error.html", error=err.code, msg=err.description), + err.code, + ) + else: + return str(err.code) + ": " + err.description, err.code # ASSETS assets.init_app(app) -scripts = Bundle( - "js/*.js", output="gen/js.js", depends="js/*.js" -) # filter jsmin is broken :c -styles = Bundle( +page_scripts = Bundle( + "js/*.js", filters="jsmin", output="gen/main.js", depends="js/*.js" +) +page_styling = Bundle( "sass/style.sass", filters="libsass, cssmin", output="gen/styles.css", depends="sass/**/*.sass", ) -assets.register("scripts", scripts) -assets.register("styles", styles) +assets.register("scripts", page_scripts) +assets.register("styles", page_styling) # BLUEPRINTS -app.register_blueprint(view_auth.blueprint) -app.register_blueprint(view_index.blueprint) -app.register_blueprint(view_image.blueprint) -app.register_blueprint(view_group.blueprint) -app.register_blueprint(view_profile.blueprint) -app.register_blueprint(view_settings.blueprint) - -app.register_blueprint(api.blueprint) - -# FILTERS -app.register_blueprint(filters.blueprint) +app.register_blueprint(view_auth) +app.register_blueprint(view_index) +app.register_blueprint(view_image) +app.register_blueprint(view_group) +app.register_blueprint(view_profile) +app.register_blueprint(view_settings) +app.register_blueprint(api) +app.register_blueprint(filters) # CACHE AND COMPRESS cache.init_app(app) diff --git a/onlylegs/config.py b/onlylegs/config.py index 06cd271..9bf47a1 100644 --- a/onlylegs/config.py +++ b/onlylegs/config.py @@ -9,16 +9,17 @@ from yaml import safe_load # Set dirs -user_dir = platformdirs.user_config_dir("onlylegs") -instance_dir = os.path.join(user_dir, "instance") +APPLICATION_ROOT = platformdirs.user_config_dir("onlylegs") # Load environment variables # print("Loading environment variables...") -load_dotenv(os.path.join(user_dir, ".env")) +load_dotenv(os.path.join(APPLICATION_ROOT, ".env")) # Load config from user dir # print("Loading config...") -with open(os.path.join(user_dir, "conf.yml"), encoding="utf-8", mode="r") as file: +with open( + os.path.join(APPLICATION_ROOT, "conf.yml"), encoding="utf-8", mode="r" +) as file: conf = safe_load(file) @@ -34,13 +35,13 @@ UPLOAD_CONF = conf["upload"] WEBSITE_CONF = conf["website"] # Directories -UPLOAD_FOLDER = os.path.join(user_dir, "media", "uploads") -CACHE_FOLDER = os.path.join(user_dir, "media", "cache") -PFP_FOLDER = os.path.join(user_dir, "media", "pfp") -MEDIA_FOLDER = os.path.join(user_dir, "media") +UPLOAD_FOLDER = os.path.join(APPLICATION_ROOT, "media", "uploads") +CACHE_FOLDER = os.path.join(APPLICATION_ROOT, "media", "cache") +PFP_FOLDER = os.path.join(APPLICATION_ROOT, "media", "pfp") +MEDIA_FOLDER = os.path.join(APPLICATION_ROOT, "media") # Database -INSTANCE_DIR = instance_dir +INSTANCE_DIR = os.path.join(APPLICATION_ROOT, "instance") MIGRATIONS_DIR = os.path.join(INSTANCE_DIR, "migrations") # App diff --git a/onlylegs/static/js/imagePage.js b/onlylegs/static/js/imagePage.js index a1eb24c..40209a7 100644 --- a/onlylegs/static/js/imagePage.js +++ b/onlylegs/static/js/imagePage.js @@ -14,47 +14,6 @@ function imageFullscreen() { } function imageShowOptionsPopup(obj) { - // let title = 'Options'; - // let subtitle = null; - // - // let body = document.createElement('div'); - // body.style.cssText = 'display: flex; flex-direction: column; gap: 0.5rem;'; - // - // let copyBtn = document.createElement('button'); - // copyBtn.classList.add('btn-block'); - // copyBtn.innerHTML = 'Copy URL'; - // copyBtn.onclick = () => { - // copyToClipboard(window.location.href) - // } - // - // let downloadBtn = document.createElement('a'); - // downloadBtn.classList.add('btn-block'); - // downloadBtn.innerHTML = 'Download'; - // downloadBtn.href = '/api/media/uploads/' + image_data["filename"]; - // downloadBtn.download = ''; - // - // body.appendChild(copyBtn); - // body.appendChild(downloadBtn); - // - // if (image_data["owner"]) { - // let editBtn = document.createElement('button'); - // editBtn.classList.add('btn-block'); - // editBtn.classList.add('critical'); - // editBtn.innerHTML = 'Edit'; - // editBtn.onclick = imageEditPopup; - // - // let deleteBtn = document.createElement('button'); - // deleteBtn.classList.add('btn-block'); - // deleteBtn.classList.add('critical'); - // deleteBtn.innerHTML = 'Delete'; - // deleteBtn.onclick = imageDeletePopup; - // - // body.appendChild(editBtn); - // body.appendChild(deleteBtn); - // } - // - // popupShow(title, subtitle, body, [popupCancelButton]); - showContextMenu(obj, [ { 'value': 'Edit', diff --git a/onlylegs/static/js/uploadTab.js b/onlylegs/static/js/uploadTab.js index a27e57f..2526a8a 100644 --- a/onlylegs/static/js/uploadTab.js +++ b/onlylegs/static/js/uploadTab.js @@ -141,41 +141,14 @@ function clearUpload() { } -// function createJob(file) { -// jobContainer = document.createElement("div"); -// jobContainer.classList.add("job"); - -// jobStatus = document.createElement("span"); -// jobStatus.classList.add("job__status"); -// jobStatus.innerHTML = "Uploading..."; - -// jobProgress = document.createElement("span"); -// jobProgress.classList.add("progress"); - -// jobImg = document.createElement("img"); -// jobImg.src = URL.createObjectURL(file); - -// jobImgFilter = document.createElement("span"); -// jobImgFilter.classList.add("img-filter"); - -// jobContainer.appendChild(jobStatus); -// jobContainer.appendChild(jobProgress); -// jobContainer.appendChild(jobImg); -// jobContainer.appendChild(jobImgFilter); - -// return jobContainer; -// } - - document.addEventListener('DOMContentLoaded', () => { // Function to upload images const uploadTab = document.querySelector(".upload-panel"); - if (!uploadTab) { return; } // If upload tab doesn't exist, don't run this code :3 + if (!uploadTab) { return } const uploadTabDrag = uploadTab.querySelector("#dragIndicator"); const uploadForm = uploadTab.querySelector('#uploadForm'); - // let jobList = document.querySelector(".upload-jobs"); const fileDrop = uploadForm.querySelector('.fileDrop-block'); const fileDropTitle = fileDrop.querySelector('.status'); @@ -228,54 +201,6 @@ document.addEventListener('DOMContentLoaded', () => { formData.append("description", fileDescription.value); formData.append("tags", fileTags.value); - // jobItem = createJob(fileUpload.files[0]); - // jobStatus = jobItem.querySelector(".job__status"); - - // Upload the information - // $.ajax({ - // url: '/api/upload', - // type: 'post', - // data: formData, - // contentType: false, - // processData: false, - // beforeSend: function () { - // // Add job to list - // jobList.appendChild(jobItem); - // }, - // success: function (response) { - // jobItem.classList.add("success"); - // jobStatus.innerHTML = "Uploaded successfully"; - // if (!document.querySelector(".upload-panel").classList.contains("open")) { - // addNotification("Image uploaded successfully", 1); - // } - // }, - // error: function (response) { - // jobItem.classList.add("critical"); - // switch (response.status) { - // case 500: - // jobStatus.innerHTML = "Server exploded, F's in chat"; - // break; - // case 400: - // case 404: - // jobStatus.innerHTML = "Error uploading. Blame yourself"; - // break; - // case 403: - // jobStatus.innerHTML = "None but devils play past here..."; - // break; - // case 413: - // jobStatus.innerHTML = "File too large!!!!!!"; - // break; - // default: - // jobStatus.innerHTML = "Error uploading file, blame someone"; - // break; - // } - // if (!document.querySelector(".upload-panel").classList.contains("open")) { - // addNotification("Error uploading file", 2); - // } - // }, - // }); - - fetch('/api/media/upload', { method: 'POST', body: formData diff --git a/onlylegs/static/sass/components/notification.sass b/onlylegs/static/sass/components/notification.sass index feea589..2a182dc 100644 --- a/onlylegs/static/sass/components/notification.sass +++ b/onlylegs/static/sass/components/notification.sass @@ -1,23 +1,15 @@ @keyframes notificationTimeout 0% - left: -100% - height: 3px - 90% - left: 0% - height: 3px - 95% - left: 0% - height: 0 + width: 0 100% - left: 0% - height: 0 + width: 100% @mixin notification($color) color: RGB($color) &::after background-color: RGB($color) - + .notifications margin: 0 padding: 0 @@ -60,17 +52,17 @@ &::after content: "" - width: 100% + width: 0 height: 3px position: absolute - bottom: 0px - left: 0px + bottom: 0 + left: 0 background-color: RGB($fg-white) z-index: +2 - animation: notificationTimeout 5.1s linear + animation: notificationTimeout 5.1s ease-out forwards &.success @include notification($success) @@ -89,7 +81,7 @@ margin: 0 max-height: 0 opacity: 0 - transform: translateX(100%) + transform: translateY(1rem) transition: all 0.4s ease-in-out, max-height 0.2s ease-in-out .sniffle__notification-icon @@ -133,10 +125,6 @@ .sniffle__notification width: 100% - - &.hide - opacity: 0 - transform: translateY(1rem) .sniffle__notification-time width: 100% diff --git a/onlylegs/static/sass/style.sass b/onlylegs/static/sass/style.sass index c363234..cbc602d 100644 --- a/onlylegs/static/sass/style.sass +++ b/onlylegs/static/sass/style.sass @@ -60,16 +60,18 @@ body padding: 0 0 3.5rem 0 main + margin: 0 0.5rem 0.5rem 0 display: flex flex-direction: column position: relative background: RGBA($white, 1) color: RGB($fg-black) - border-top-left-radius: $rad + border-radius: $rad overflow: hidden @media (max-width: $breakpoint) main - border-top-left-radius: 0 + margin: 0 + border-radius: 0 .error-page min-height: 100% diff --git a/onlylegs/utils/startup.py b/onlylegs/utils/startup.py new file mode 100644 index 0000000..a42730f --- /dev/null +++ b/onlylegs/utils/startup.py @@ -0,0 +1,156 @@ +""" +OnlyLegs - Setup +Runs when the app detects that there is no user directory +""" +import os +import re +import platformdirs +import yaml +from werkzeug.security import generate_password_hash +from onlylegs.extensions import db +from onlylegs.models import Users + + +APPLICATION_ROOT = platformdirs.user_config_dir("onlyLegs") +REQUIRED_DIRS = { + "root": APPLICATION_ROOT, + "instance": os.path.join(APPLICATION_ROOT, "instance"), + "media": os.path.join(APPLICATION_ROOT, "media"), + "uploads": os.path.join(APPLICATION_ROOT, "media", "uploads"), + "cache": os.path.join(APPLICATION_ROOT, "media", "cache"), + "pfp": os.path.join(APPLICATION_ROOT, "media", "pfp"), +} + +EMAIL_REGEX = re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b") +USERNAME_REGEX = re.compile(r"\b[A-Za-z0-9._%+-]+\b") + + +def check_dirs(): + """ + Create the user directory + """ + + for directory in REQUIRED_DIRS.values(): + if os.path.exists(directory): + print("User directory already exists at:", directory) + return + os.makedirs(directory) + print("Created directory at:", directory) + + +def check_env(): + """ + Create the .env file with default values + """ + if os.path.exists(os.path.join(APPLICATION_ROOT, ".env")): + print("Environment file already exists at:", APPLICATION_ROOT) + return + + env_conf = { + "FLASK_SECRET": os.urandom(32).hex(), + } + + with open( + os.path.join(APPLICATION_ROOT, ".env"), encoding="utf-8", mode="w+" + ) as file: + for key, value in env_conf.items(): + file.write(key + "=" + value + "\n") + + print( + "####################################################" + "# A NEW KEY WAS GENERATED FOR YOU! PLEASE NOTE #" + "# DOWN THE FLASK_SECRET KEY LOCATED IN YOUR #" + "# ~/.config/onlylegs/.env FOLDER! LOOSING THIS KEY #" + "# WILL RESULT IN YOU BEING UNABLE TO LOG IN! #" + "####################################################", + sep="\n", + ) + + +def check_conf(): + """ + Create the YAML config file with default values + """ + if os.path.exists(os.path.join(APPLICATION_ROOT, "conf.yml")): + print("Config file already exists at:", APPLICATION_ROOT) + return + + can_continue = False + username = "admin" + name = "Admin" + email = "admin@example.com" + + print("No config file found, please enter the following information:") + while can_continue: + username = input("Admin username: ") + name = input("Admin name: ") + email = input("Admin email: ") + + if not username or not USERNAME_REGEX.match(username): + print("Username is invalid!") + if not name: + print("Name is invalid!") + if not email or not EMAIL_REGEX.match(email): + print("Email is invalid!") + + # Check if user is happy with the values + is_correct = input("Is this correct? (Y/n): ").lower() + if is_correct == "y" or is_correct == "": + can_continue = True + + yaml_conf = { + "admin": { + "name": name, + "username": username, + "email": email, + }, + "upload": { + "allowed-extensions": { + "jpg": "jpeg", + "jpeg": "jpeg", + "png": "png", + "webp": "webp", + }, + "max-size": 69, + "max-load": 50, + "rename": "GWA_{{username}}_{{time}}", + }, + "website": { + "name": "OnlyLegs", + "motto": "A gallery built for fast and simple image management!", + "language": "en", + }, + } + + with open( + os.path.join(APPLICATION_ROOT, "conf.yml"), encoding="utf-8", mode="w+" + ) as file: + yaml.dump(yaml_conf, file, default_flow_style=False) + + print( + "####################################################" + "# A NEW CONFIG HAS BEEN GENERATED AT: #" + "# ~/.config/onlylegs/conf.yml #" + "####################################################", + sep="\n", + ) + + +def make_admin_user(app): + username = app.config["ADMIN_CONF"]["username"] + email = app.config["ADMIN_CONF"]["email"] + password = generate_password_hash("changeme!", method="scrypt") + + with app.app_context(): + db.create_all() + db.session.add(Users(username=username, email=email, password=password)) + db.session.commit() + + print( + "####################################################" + "# DEFAULT ADMIN USER GENERATED WITH GIVEN USERNAME #" + '# THE DEFAULT PASSWORD "changeme!" HAS BEEN USED, #' + "# PLEASE RESET IT IN THE SETTINGS! #" + "####################################################", + sep="\n", + ) diff --git a/poetry.lock b/poetry.lock index 8c1c926..3246c75 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "alembic" @@ -727,6 +727,22 @@ files = [ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] +[[package]] +name = "material-color-utilities-python" +version = "0.1.5" +description = "Python port of material-color-utilities used for Material You colors" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "material-color-utilities-python-0.1.5.tar.gz", hash = "sha256:3c6f02e7ce70595885447bdef37cf76fd3628c7c95fa2198d8174c269c951fae"}, + {file = "material_color_utilities_python-0.1.5-py2.py3-none-any.whl", hash = "sha256:48abd8695a1355ab3ad43fe314ca8664c66282a86fbf94a717571273bf422bdf"}, +] + +[package.dependencies] +Pillow = ">=9.2.0,<10.0.0" +regex = "*" + [[package]] name = "mccabe" version = "0.7.0" @@ -966,6 +982,104 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "regex" +version = "2023.8.8" +description = "Alternative regular expression module, to replace re." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"}, + {file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7"}, + {file = "regex-2023.8.8-cp310-cp310-win32.whl", hash = "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb"}, + {file = "regex-2023.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b"}, + {file = "regex-2023.8.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71"}, + {file = "regex-2023.8.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd"}, + {file = "regex-2023.8.8-cp311-cp311-win32.whl", hash = "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8"}, + {file = "regex-2023.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb"}, + {file = "regex-2023.8.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b"}, + {file = "regex-2023.8.8-cp36-cp36m-win32.whl", hash = "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7"}, + {file = "regex-2023.8.8-cp36-cp36m-win_amd64.whl", hash = "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236"}, + {file = "regex-2023.8.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7"}, + {file = "regex-2023.8.8-cp37-cp37m-win32.whl", hash = "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3"}, + {file = "regex-2023.8.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921"}, + {file = "regex-2023.8.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675"}, + {file = "regex-2023.8.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882"}, + {file = "regex-2023.8.8-cp38-cp38-win32.whl", hash = "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7"}, + {file = "regex-2023.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be"}, + {file = "regex-2023.8.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3"}, + {file = "regex-2023.8.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6"}, + {file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"}, + {file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"}, + {file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"}, +] + [[package]] name = "setuptools" version = "68.0.0" @@ -1232,4 +1346,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "96ec0d1f7b512afb05455262fa2de8c4f862bf68fdae513f8552dc30c6e5ab49" +content-hash = "11735dbbdd45dcc5085a04dbbd4e786dd8aeb4ba743f0c20294861e7b4c35dd0" diff --git a/pyproject.toml b/pyproject.toml index 3752e8a..ae79283 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ cssmin = "^0.2.0" pylint = "^2.16.3" black = "^23.3.0" cachetools = "^5.3.0" +material-color-utilities-python = "^0.1.5" [build-system] requires = ["poetry-core"] diff --git a/setup/args.py b/setup/args.py deleted file mode 100644 index a443338..0000000 --- a/setup/args.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Startup arguments for the OnlyLegs gallery - - -p, --port: Port to run on (default: 5000) - -a, --address: Address to run on (default: 127.0.0.0) - -w, --workers: Number of workers to run (default: 4) - - -d, --debug: Run as Flask app in debug mode (default: False) - -S, --scream: Show verbose output (default: False) - -h, --help: Show a help message -""" - -import argparse - - -parser = argparse.ArgumentParser(description="Run the OnlyLegs gallery") -parser.add_argument("-p", "--port", type=int, default=5000, help="Port to run on") -parser.add_argument( - "-a", "--address", type=str, default="127.0.0.0", help="Address to run on" -) -parser.add_argument( - "-w", "--workers", type=int, default=4, help="Number of workers to run" -) -parser.add_argument( - "-d", "--debug", action="store_true", help="Run as Flask app in debug mode" -) -args = parser.parse_args() - - -PORT = args.port -ADDRESS = args.address -WORKERS = args.workers -DEBUG = args.debug diff --git a/setup/configuration.py b/setup/configuration.py deleted file mode 100644 index 2727ce0..0000000 --- a/setup/configuration.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -OnlyLegs - Setup -Runs when the app detects that there is no user directory -""" -import os -import logging -import re -import platformdirs -import yaml - - -USER_DIR = platformdirs.user_config_dir("onlylegs") - - -class Configuration: - """ - Setup the application on first run - """ - - def __init__(self): - """ - Main setup function - """ - print("Running startup checks...") - - # Check if the user directory exists - if not os.path.exists(USER_DIR): - self.make_dir() - - # Check if the .env file exists - if not os.path.exists(os.path.join(USER_DIR, ".env")): - self.make_env() - - # Check if the conf.yml file exists - if not os.path.exists(os.path.join(USER_DIR, "conf.yml")): - self.make_yaml() - - # Load the config files - self.logging_config() - - @staticmethod - def make_dir(): - """ - Create the user directory - """ - os.makedirs(USER_DIR) - os.makedirs(os.path.join(USER_DIR, "instance")) - os.makedirs(os.path.join(USER_DIR, "media")) - os.makedirs(os.path.join(USER_DIR, "media", "uploads")) - os.makedirs(os.path.join(USER_DIR, "media", "cache")) - os.makedirs(os.path.join(USER_DIR, "media", "pfp")) - - print("Created user directory at:", USER_DIR) - - @staticmethod - def make_env(): - """ - Create the .env file with default values - """ - env_conf = { - "FLASK_SECRET": os.urandom(32).hex(), - } - - with open(os.path.join(USER_DIR, ".env"), encoding="utf-8", mode="w+") as file: - for key, value in env_conf.items(): - file.write(f"{key}={value}\n") - - print( - """ -#################################################### -# A NEW KEY WAS GENERATED FOR YOU! PLEASE NOTE # -# DOWN THE FLASK_SECRET KEY LOCATED IN YOUR # -# .config/onlylegs/.env FOLDER! LOOSING THIS KEY # -# WILL RESULT IN YOU BEING UNABLE TO LOG IN! # -#################################################### - """ - ) - - @staticmethod - def make_yaml(): - """ - Create the YAML config file with default values - """ - is_correct = False - email_regex = re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b") - username_regex = re.compile(r"\b[A-Za-z0-9._%+-]+\b") - - print("\nNo config file found, please enter the following information:") - while not is_correct: - username = input("Admin username: ") - name = input("Admin name: ") - email = input("Admin email: ") - - # Check if the values are valid - if not username or not username_regex.match(username): - print("Username is invalid!") - continue - - if not name: - print("Name is invalid!") - continue - - if not email or not email_regex.match(email): - print("Email is invalid!") - continue - - # Check if user is happy with the values - if input("Is this correct? (y/n): ").lower() == "y": - is_correct = True - - yaml_conf = { - "admin": { - "name": name, - "username": username, - "email": email, - }, - "upload": { - "allowed-extensions": { - "jpg": "jpeg", - "jpeg": "jpeg", - "png": "png", - "webp": "webp", - }, - "max-size": 69, - "max-load": 50, - "rename": "GWA_{{username}}_{{time}}", - }, - "website": { - "name": "OnlyLegs", - "motto": "A gallery built for fast and simple image management!", - "language": "en", - }, - } - - with open( - os.path.join(USER_DIR, "conf.yml"), encoding="utf-8", mode="w+" - ) as file: - yaml.dump(yaml_conf, file, default_flow_style=False) - - print( - "Generated config file, you can change these values in the settings of the app" - ) - - @staticmethod - def logging_config(): - """ - Set the logging config - """ - logging.getLogger("werkzeug").disabled = True - logging.basicConfig( - filename=os.path.join(USER_DIR, "only.log"), - level=logging.INFO, - datefmt="%Y-%m-%d %H:%M:%S", - format="%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s", - encoding="utf-8", - ) diff --git a/setup/runner.py b/setup/runner.py deleted file mode 100644 index 94cd827..0000000 --- a/setup/runner.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Gunicorn configuration file -""" -from gunicorn.app.base import Application -from gunicorn import util - - -class OnlyLegs(Application): - """ - Gunicorn application - """ - - # TODO: Make this not shit, thanks - def __init__(self, options={}): # skipcq: PYL-W0231 # pylint: disable=W0231 - self.usage = None - self.callable = None - self.options = options - self.do_load_config() - - def init(self, *args): - """ - Initialize the application - """ - cfg = {} - for setting, value in self.options.items(): - if setting.lower() in self.cfg.settings and value is not None: - cfg[setting.lower()] = value - return cfg - - @staticmethod - def prog(): # skipcq: PYL-E0202 # pylint: disable=E0202, C0116 - return "OnlyLegs" - - def load(self): - return util.import_app("onlylegs.app:app")