Yeet old runner script as it was useless

Clean up code and styling
This commit is contained in:
Michał 2023-09-26 13:43:00 +01:00
parent 8a4fe891ef
commit 9821db72c6
12 changed files with 348 additions and 437 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

156
onlylegs/utils/startup.py Normal file
View file

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

118
poetry.lock generated
View file

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

View file

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

View file

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

View file

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

View file

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