From 2eec988815269d0900c51743dc12562258f50e4d Mon Sep 17 00:00:00 2001 From: Fluffy-Bean Date: Sun, 12 Mar 2023 12:29:29 +0000 Subject: [PATCH] Move prechecks to run file Add Verbose option Cleanup run file --- gallery/__init__.py | 34 ++++---- gallery/db.py | 13 +++- gallery/templates/index.html | 2 +- gallery/theme_manager.py | 21 ++--- pyproject.toml | 2 +- run.py | 34 ++++---- setup/args.py | 30 +++++++ gallery/setup.py => setup/configuration.py | 91 +++++++++++++++------- 8 files changed, 149 insertions(+), 78 deletions(-) create mode 100644 setup/args.py rename gallery/setup.py => setup/configuration.py (53%) diff --git a/gallery/__init__.py b/gallery/__init__.py index 10c34b9..21d4960 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -16,28 +16,13 @@ from flask import Flask, render_template # Configuration from dotenv import load_dotenv import platformdirs -import yaml +from yaml import FullLoader, load -from . import theme_manager -from . import setup - - -# Run setup checks -setup.SetupApp() USER_DIR = platformdirs.user_config_dir('onlylegs') -# Get environment variables -load_dotenv(os.path.join(USER_DIR, '.env')) -print("Loaded environment variables") -# Get config file -with open(os.path.join(USER_DIR, 'conf.yml'), encoding='utf-8') as f: - conf = yaml.load(f, Loader=yaml.FullLoader) - print("Loaded gallery config") - - -def create_app(test_config=None): +def create_app(test_config=None, verbose=False): """ Create and configure the main app """ @@ -45,6 +30,17 @@ def create_app(test_config=None): assets = Environment() cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 300}) compress = Compress() + + # Get environment variables + load_dotenv(os.path.join(USER_DIR, '.env')) + if verbose: + print("Loaded environment variables") + + # Get config file + with open(os.path.join(USER_DIR, 'conf.yml'), encoding='utf-8') as f: + conf = load(f, Loader=FullLoader) + if verbose: + print("Loaded gallery config") # App configuration app.config.from_mapping( @@ -67,7 +63,9 @@ def create_app(test_config=None): pass # Load theme - theme_manager.CompileTheme('default', app.root_path) + from . import theme_manager + theme_manager.CompileTheme('default', app.root_path, verbose) + # Bundle JS files js = Bundle('js/*.js', output='gen/packed.js') assets.register('js_all', js) diff --git a/gallery/db.py b/gallery/db.py index 0b3a543..cd5946e 100644 --- a/gallery/db.py +++ b/gallery/db.py @@ -5,13 +5,16 @@ import os import platformdirs from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType -from sqlalchemy.orm import declarative_base, relationship, backref, mapped_column +from sqlalchemy.orm import declarative_base, relationship + + +USER_DIR = platformdirs.user_config_dir('onlylegs') +DB_PATH = os.path.join(USER_DIR, 'gallery.sqlite') -path_to_db = os.path.join(platformdirs.user_config_dir('onlylegs'), 'gallery.sqlite') -engine = create_engine(f'sqlite:///{path_to_db}', echo=False) # engine = create_engine('postgresql://username:password@host:port/database_name', echo=False) # engine = create_engine('mysql://username:password@host:port/database_name', echo=False) +engine = create_engine(f'sqlite:///{DB_PATH}', echo=False) base = declarative_base() @@ -130,4 +133,6 @@ class Bans (base): # pylint: disable=too-few-public-methods, C0103 created_at = Column(DateTime, nullable=False) -base.metadata.create_all(engine) +# check if database file exists, if not create it +if not os.path.isfile(DB_PATH): + base.metadata.create_all(engine) \ No newline at end of file diff --git a/gallery/templates/index.html b/gallery/templates/index.html index bc1ad52..3da78d4 100644 --- a/gallery/templates/index.html +++ b/gallery/templates/index.html @@ -28,7 +28,7 @@ {% else %}
-

No image!

+

No images

{% if g.user %}

You can get started by uploading an image!

{% else %} diff --git a/gallery/theme_manager.py b/gallery/theme_manager.py index f8fb22a..36f98fd 100644 --- a/gallery/theme_manager.py +++ b/gallery/theme_manager.py @@ -12,13 +12,14 @@ class CompileTheme: """ Compiles the theme into the static folder """ - def __init__(self, theme_name, app_path): + def __init__(self, theme_name, app_path, verbose=False): """ Initialize the theme manager Compiles the theme into the static folder and loads the fonts """ - print(f"Loading '{theme_name}' theme...") + if verbose: + print(f"Loading '{theme_name}' theme...") theme_path = os.path.join(app_path, 'themes', theme_name) theme_dest = os.path.join(app_path, 'static', 'theme') @@ -30,11 +31,11 @@ class CompileTheme: self.load_sass(theme_path, theme_dest) self.load_fonts(theme_path, theme_dest) - now = datetime.now() - print(f"{now.hour}:{now.minute}:{now.second} - Done!\n") + if verbose: + print(f"{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second} - Done!\n") @staticmethod - def load_sass(source_path, css_dest): + def load_sass(source_path, css_dest, verbose=False): """ Compile the sass (or scss) file into css and save it to the static folder """ @@ -56,10 +57,11 @@ class CompileTheme: print("Failed to compile!\n", err) sys.exit(1) - print("Compiled successfully!") + if verbose: + print("Compiled successfully!") @staticmethod - def load_fonts(source_path, font_dest): + def load_fonts(source_path, font_dest, verbose=False): """ Copy the fonts folder to the static folder """ @@ -68,7 +70,6 @@ class CompileTheme: font_dest = os.path.join(font_dest, 'fonts') if os.path.exists(font_dest): - print("Updating fonts...") try: shutil.rmtree(font_dest) except Exception as err: @@ -77,7 +78,9 @@ class CompileTheme: try: shutil.copytree(source_path, font_dest) - print("Copied new fonts!") except Exception as err: print("Failed to copy fonts!\n", err) sys.exit(1) + + if verbose: + print("Fonts copied successfully!") diff --git a/pyproject.toml b/pyproject.toml index 47c85c7..4ce7350 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "onlylegs" -version = "23.03.11" +version = "23.03.12" description = "Gallery built for fast and simple image management" authors = ["Fluffy-Bean "] license = "MIT" diff --git a/run.py b/run.py index e62b4dd..8e73f21 100644 --- a/run.py +++ b/run.py @@ -5,28 +5,20 @@ print(""" | |_| | | | | | |_| | |__| __/ (_| \__ \ \___/|_| |_|_|\__, |_____\___|\__, |___/ |___/ |___/ -Created by Fluffy Bean - Version 23.03.11 +Created by Fluffy Bean - Version 23.03.12 """) - -import argparse +from setup.args import PORT, ADDRESS, WORKERS, DEBUG, VERBOSE +from setup.configuration import Configuration -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='0.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', type=bool, default=False, help='Run as Flask app in debug mode') -args = parser.parse_args() - -PORT = args.port -ADDRESS = args.address -WORKERS = args.workers +# Run prechecks +Configuration(verbose=VERBOSE) -if args.debug: +if DEBUG: from gallery import create_app - create_app().run(host=ADDRESS, port=PORT, debug=True) + create_app(verbose=VERBOSE).run(host=ADDRESS, port=PORT, debug=True, threaded=True) else: from gunicorn.app.base import Application from gunicorn import util @@ -49,8 +41,12 @@ else: return 'OnlyLegs' def load(self): - return util.import_app('gallery:create_app()') + return util.import_app(f'gallery:create_app(verbose={VERBOSE})') + + options = { + 'bind': f'{ADDRESS}:{PORT}', + 'workers': WORKERS, + } + + OnlyLegs(options).run() - OnlyLegs({'bind': f'{ADDRESS}:{PORT}', 'workers': WORKERS}).run() - -# uwu diff --git a/setup/args.py b/setup/args.py new file mode 100644 index 0000000..ae3e7ab --- /dev/null +++ b/setup/args.py @@ -0,0 +1,30 @@ +""" +Startup arguments for the OnlyLegs gallery + + -p, --port: Port to run on (default: 5000) + -a, --address: Address to run on (default:0.0.0.0) + -w, --workers: Number of workers to run (default: 4) + + -d, --debug: Run as Flask app in debug mode (default: False) + -V, --verbose: 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='0.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') +parser.add_argument('-V', '--verbose', action='store_true', help='Show verbose output') +args = parser.parse_args() + + +PORT = args.port +ADDRESS = args.address +WORKERS = args.workers + +DEBUG = args.debug +VERBOSE = args.verbose \ No newline at end of file diff --git a/gallery/setup.py b/setup/configuration.py similarity index 53% rename from gallery/setup.py rename to setup/configuration.py index edf1941..c2964f3 100644 --- a/gallery/setup.py +++ b/setup/configuration.py @@ -7,36 +7,37 @@ import sys import platformdirs import logging import yaml +import re USER_DIR = platformdirs.user_config_dir('onlylegs') -class SetupApp: +class Configuration: """ Setup the application on first run """ - def __init__(self): + def __init__(self, verbose=False): """ Main setup function """ - print("Running setup...") + if verbose: + print("Running startup checks...") - self.requires_restart = False - + # 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() - - self.logging_config() - if self.requires_restart: - print("WARNING: You need to restart and edit the config files before running the app again!") - print("You can find the config files at:", USER_DIR) - sys.exit() + # Load the config files + self.logging_config() @staticmethod def make_dir(): @@ -46,11 +47,11 @@ class SetupApp: try: os.makedirs(USER_DIR) os.makedirs(os.path.join(USER_DIR, 'instance')) - - print("Created user directory at:", USER_DIR) except Exception as err: print("Error creating user directory:", err) sys.exit(1) + + print("Created user directory at:", USER_DIR) @staticmethod def make_env(): @@ -58,55 +59,93 @@ class SetupApp: Create the .env file with default values """ env_conf = { - 'FLASK_SECRET': 'dev', + 'FLASK_SECRET': os.urandom(32).hex(), } + try: 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("Created environment variables") except Exception as err: print("Error creating environment variables:", err) sys.exit(1) - - print("Generated default .env file, please edit!") + + print(""" + #################################################### + # PLEASE NOTE DOWN THE FLASK_SECRET KEY LOCARED IN # + # YOUR .config/onlylegs/.env FILE! A NEW KEY WAS # + # GENERATED FOR YOU! # + #################################################### + """) @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("No config file found, please enter the following information:") + while not is_correct: + try: + username = input("Admin username: ") + name = input("Admin name: ") + email = input("Admin email: ") + except ValueError: + print("Please enter valid values!") + + # 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 + _ = input("Is this correct? (y/n): ") + + if _ == 'y' or _ == 'Y': + is_correct = True + yaml_conf = { 'admin': { - 'name': 'Real Person', - 'username': 'User', - 'email': 'real-email@some.place' + 'name': '%s' % name, + 'username': '%s' % username, + 'email': '%s' % email, }, 'upload': { 'allowed-extensions': { 'jpg': 'jpeg', 'jpeg': 'jpeg', 'png': 'png', - 'webp': 'webp' + 'webp': 'webp', }, 'max-size': 69, - 'rename': 'GWA_\{\{username\}\}_\{\{time\}\}' + 'rename': 'GWA_{{username}}_{{time}}', }, 'website': { 'name': 'OnlyLegs', - 'motto': 'Gwa Gwa', - 'language': 'english' + 'motto': 'A gallery built for fast and simple image management. You can change this in the settings', + 'language': 'en', } } + try: 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("Created default gallery config") except Exception as err: print("Error creating default gallery config:", err) sys.exit(1) - print("Generated default YAML config, please edit!") + print("Generated config file, you can change these values in the settings of the app") @staticmethod def logging_config():