Yeet old runner script as it was useless

Clean up code and styling
This commit is contained in:
Michał Gdula 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",
)