Move prechecks to run file

Add Verbose option
Cleanup run file
This commit is contained in:
Michał 2023-03-12 12:29:29 +00:00
parent 800ba38241
commit 2eec988815
8 changed files with 149 additions and 78 deletions

View file

@ -16,28 +16,13 @@ from flask import Flask, render_template
# Configuration # Configuration
from dotenv import load_dotenv from dotenv import load_dotenv
import platformdirs 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') 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 def create_app(test_config=None, verbose=False):
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):
""" """
Create and configure the main app Create and configure the main app
""" """
@ -45,6 +30,17 @@ def create_app(test_config=None):
assets = Environment() assets = Environment()
cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 300}) cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 300})
compress = Compress() 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 configuration
app.config.from_mapping( app.config.from_mapping(
@ -67,7 +63,9 @@ def create_app(test_config=None):
pass pass
# Load theme # Load theme
theme_manager.CompileTheme('default', app.root_path) from . import theme_manager
theme_manager.CompileTheme('default', app.root_path, verbose)
# Bundle JS files # Bundle JS files
js = Bundle('js/*.js', output='gen/packed.js') js = Bundle('js/*.js', output='gen/packed.js')
assets.register('js_all', js) assets.register('js_all', js)

View file

@ -5,13 +5,16 @@ import os
import platformdirs import platformdirs
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType 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('postgresql://username:password@host:port/database_name', echo=False)
# engine = create_engine('mysql://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() base = declarative_base()
@ -130,4 +133,6 @@ class Bans (base): # pylint: disable=too-few-public-methods, C0103
created_at = Column(DateTime, nullable=False) 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)

View file

@ -28,7 +28,7 @@
</div> </div>
{% else %} {% else %}
<div class="big-text"> <div class="big-text">
<h1>No image!</h1> <h1>No images</h1>
{% if g.user %} {% if g.user %}
<p>You can get started by uploading an image!</p> <p>You can get started by uploading an image!</p>
{% else %} {% else %}

View file

@ -12,13 +12,14 @@ class CompileTheme:
""" """
Compiles the theme into the static folder 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 Initialize the theme manager
Compiles the theme into the static folder and loads the fonts 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_path = os.path.join(app_path, 'themes', theme_name)
theme_dest = os.path.join(app_path, 'static', 'theme') theme_dest = os.path.join(app_path, 'static', 'theme')
@ -30,11 +31,11 @@ class CompileTheme:
self.load_sass(theme_path, theme_dest) self.load_sass(theme_path, theme_dest)
self.load_fonts(theme_path, theme_dest) self.load_fonts(theme_path, theme_dest)
now = datetime.now() if verbose:
print(f"{now.hour}:{now.minute}:{now.second} - Done!\n") print(f"{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second} - Done!\n")
@staticmethod @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 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) print("Failed to compile!\n", err)
sys.exit(1) sys.exit(1)
print("Compiled successfully!") if verbose:
print("Compiled successfully!")
@staticmethod @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 Copy the fonts folder to the static folder
""" """
@ -68,7 +70,6 @@ class CompileTheme:
font_dest = os.path.join(font_dest, 'fonts') font_dest = os.path.join(font_dest, 'fonts')
if os.path.exists(font_dest): if os.path.exists(font_dest):
print("Updating fonts...")
try: try:
shutil.rmtree(font_dest) shutil.rmtree(font_dest)
except Exception as err: except Exception as err:
@ -77,7 +78,9 @@ class CompileTheme:
try: try:
shutil.copytree(source_path, font_dest) shutil.copytree(source_path, font_dest)
print("Copied new fonts!")
except Exception as err: except Exception as err:
print("Failed to copy fonts!\n", err) print("Failed to copy fonts!\n", err)
sys.exit(1) sys.exit(1)
if verbose:
print("Fonts copied successfully!")

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "onlylegs" name = "onlylegs"
version = "23.03.11" version = "23.03.12"
description = "Gallery built for fast and simple image management" description = "Gallery built for fast and simple image management"
authors = ["Fluffy-Bean <michal-gdula@protonmail.com>"] authors = ["Fluffy-Bean <michal-gdula@protonmail.com>"]
license = "MIT" license = "MIT"

34
run.py
View file

@ -5,28 +5,20 @@ print("""
| |_| | | | | | |_| | |__| __/ (_| \__ \ | |_| | | | | | |_| | |__| __/ (_| \__ \
\___/|_| |_|_|\__, |_____\___|\__, |___/ \___/|_| |_|_|\__, |_____\___|\__, |___/
|___/ |___/ |___/ |___/
Created by Fluffy Bean - Version 23.03.11 Created by Fluffy Bean - Version 23.03.12
""") """)
from setup.args import PORT, ADDRESS, WORKERS, DEBUG, VERBOSE
import argparse from setup.configuration import Configuration
parser = argparse.ArgumentParser(description='Run the OnlyLegs gallery') # Run prechecks
parser.add_argument('-p', '--port', type=int, default=5000, help='Port to run on') Configuration(verbose=VERBOSE)
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
if args.debug: if DEBUG:
from gallery import create_app 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: else:
from gunicorn.app.base import Application from gunicorn.app.base import Application
from gunicorn import util from gunicorn import util
@ -49,8 +41,12 @@ else:
return 'OnlyLegs' return 'OnlyLegs'
def load(self): 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

30
setup/args.py Normal file
View file

@ -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

View file

@ -7,36 +7,37 @@ import sys
import platformdirs import platformdirs
import logging import logging
import yaml import yaml
import re
USER_DIR = platformdirs.user_config_dir('onlylegs') USER_DIR = platformdirs.user_config_dir('onlylegs')
class SetupApp: class Configuration:
""" """
Setup the application on first run Setup the application on first run
""" """
def __init__(self): def __init__(self, verbose=False):
""" """
Main setup function 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): if not os.path.exists(USER_DIR):
self.make_dir() self.make_dir()
# Check if the .env file exists
if not os.path.exists(os.path.join(USER_DIR, '.env')): if not os.path.exists(os.path.join(USER_DIR, '.env')):
self.make_env() self.make_env()
# Check if the conf.yml file exists
if not os.path.exists(os.path.join(USER_DIR, 'conf.yml')): if not os.path.exists(os.path.join(USER_DIR, 'conf.yml')):
self.make_yaml() self.make_yaml()
self.logging_config()
if self.requires_restart: # Load the config files
print("WARNING: You need to restart and edit the config files before running the app again!") self.logging_config()
print("You can find the config files at:", USER_DIR)
sys.exit()
@staticmethod @staticmethod
def make_dir(): def make_dir():
@ -46,11 +47,11 @@ class SetupApp:
try: try:
os.makedirs(USER_DIR) os.makedirs(USER_DIR)
os.makedirs(os.path.join(USER_DIR, 'instance')) os.makedirs(os.path.join(USER_DIR, 'instance'))
print("Created user directory at:", USER_DIR)
except Exception as err: except Exception as err:
print("Error creating user directory:", err) print("Error creating user directory:", err)
sys.exit(1) sys.exit(1)
print("Created user directory at:", USER_DIR)
@staticmethod @staticmethod
def make_env(): def make_env():
@ -58,55 +59,93 @@ class SetupApp:
Create the .env file with default values Create the .env file with default values
""" """
env_conf = { env_conf = {
'FLASK_SECRET': 'dev', 'FLASK_SECRET': os.urandom(32).hex(),
} }
try: try:
with open(os.path.join(USER_DIR, '.env'), encoding='utf-8', mode='w+') as file: with open(os.path.join(USER_DIR, '.env'), encoding='utf-8', mode='w+') as file:
for key, value in env_conf.items(): for key, value in env_conf.items():
file.write(f"{key}={value}\n") file.write(f"{key}={value}\n")
print("Created environment variables")
except Exception as err: except Exception as err:
print("Error creating environment variables:", err) print("Error creating environment variables:", err)
sys.exit(1) 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 @staticmethod
def make_yaml(): def make_yaml():
""" """
Create the YAML config file with default values 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 = { yaml_conf = {
'admin': { 'admin': {
'name': 'Real Person', 'name': '%s' % name,
'username': 'User', 'username': '%s' % username,
'email': 'real-email@some.place' 'email': '%s' % email,
}, },
'upload': { 'upload': {
'allowed-extensions': { 'allowed-extensions': {
'jpg': 'jpeg', 'jpg': 'jpeg',
'jpeg': 'jpeg', 'jpeg': 'jpeg',
'png': 'png', 'png': 'png',
'webp': 'webp' 'webp': 'webp',
}, },
'max-size': 69, 'max-size': 69,
'rename': 'GWA_\{\{username\}\}_\{\{time\}\}' 'rename': 'GWA_{{username}}_{{time}}',
}, },
'website': { 'website': {
'name': 'OnlyLegs', 'name': 'OnlyLegs',
'motto': 'Gwa Gwa', 'motto': 'A gallery built for fast and simple image management. You can change this in the settings',
'language': 'english' 'language': 'en',
} }
} }
try: try:
with open(os.path.join(USER_DIR, 'conf.yml'), encoding='utf-8', mode='w+') as file: 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) yaml.dump(yaml_conf, file, default_flow_style=False)
print("Created default gallery config")
except Exception as err: except Exception as err:
print("Error creating default gallery config:", err) print("Error creating default gallery config:", err)
sys.exit(1) 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 @staticmethod
def logging_config(): def logging_config():