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

View file

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

View file

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

View file

@ -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!")

View file

@ -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 <michal-gdula@protonmail.com>"]
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
""")
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

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 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():