From 3ee287d6e3bfaf6f34a1d50e310c99508d9e1116 Mon Sep 17 00:00:00 2001 From: Fluffy-Bean Date: Sat, 11 Mar 2023 22:14:03 +0000 Subject: [PATCH] Add ALT text to images Correct static methods Tidy up code --- gallery/__init__.py | 11 +- gallery/api.py | 35 +-- gallery/auth.py | 18 +- gallery/db.py | 21 +- gallery/groups.py | 29 ++- gallery/metadata/__init__.py | 18 +- gallery/metadata/helpers.py | 6 +- gallery/metadata/mapping.py | 7 +- gallery/routing.py | 22 +- gallery/settings.py | 3 + gallery/setup.py | 26 +- gallery/static/js/login.js | 121 +++++++++ gallery/static/js/main.js | 246 ------------------ gallery/static/js/uploadTab.js | 128 +++++++++ gallery/templates/groups/group.html | 14 +- gallery/templates/groups/list.html | 26 +- gallery/templates/image.html | 19 +- gallery/templates/index.html | 10 +- gallery/theme_manager.py | 8 +- .../themes/default/components/gallery.sass | 45 ++-- .../components/image-view/info-tab.sass | 6 +- gallery/themes/default/style.sass | 36 +-- pyproject.toml | 2 +- 23 files changed, 427 insertions(+), 430 deletions(-) create mode 100644 gallery/static/js/login.js create mode 100644 gallery/static/js/uploadTab.js diff --git a/gallery/__init__.py b/gallery/__init__.py index 6599620..e8b31b8 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -5,7 +5,7 @@ | |_| | | | | | |_| | |__| __/ (_| \__ \ \___/|_| |_|_|\__, |_____\___|\__, |___/ |___/ |___/ -Created by Fluffy Bean - Version 23.03.10 +Created by Fluffy Bean - Version 23.03.11 """ # Import system modules @@ -46,7 +46,7 @@ def create_app(test_config=None): """ Create and configure the main app """ - app = Flask(__name__,instance_path=os.path.join(USER_DIR, 'instance')) + app = Flask(__name__, instance_path=os.path.join(USER_DIR, 'instance')) assets = Environment() cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 300}) compress = Compress() @@ -71,13 +71,11 @@ def create_app(test_config=None): except OSError: pass - # Load theme theme_manager.CompileTheme('default', app.root_path) # Bundle JS files js = Bundle('js/*.js', output='gen/packed.js') assets.register('js_all', js) - @app.errorhandler(403) @app.errorhandler(404) @@ -89,7 +87,6 @@ def create_app(test_config=None): msg = err.description return render_template('error.html', error=error, msg=msg), err.code - # Load login, registration and logout manager from . import auth app.register_blueprint(auth.blueprint) @@ -110,10 +107,8 @@ def create_app(test_config=None): # Load APIs from . import api app.register_blueprint(api.blueprint) - - - logging.info('Gallery started successfully!') + logging.info('Gallery started successfully!') assets.init_app(app) cache.init_app(app) diff --git a/gallery/api.py b/gallery/api.py index 84707b1..f6cff7c 100644 --- a/gallery/api.py +++ b/gallery/api.py @@ -19,7 +19,7 @@ from sqlalchemy.orm import sessionmaker from gallery.auth import login_required -from . import db # Import db to create a session +from . import db from . import metadata as mt @@ -39,15 +39,15 @@ def uploads(file): # Get args width = request.args.get('w', default=0, type=int) # Width of image height = request.args.get('h', default=0, type=int) # Height of image - filtered = request.args.get('f', default=False, type=bool) # Whether to apply filters - blur = request.args.get('b', default=False, type=bool) # Whether to force blur + filtered = request.args.get('f', default=False, type=bool) # Whether to apply filters + blur = request.args.get('b', default=False, type=bool) # Whether to force blur # if no args are passed, return the raw file if width == 0 and height == 0 and not filtered: if not os.path.exists(os.path.join(current_app.config['UPLOAD_FOLDER'], secure_filename(file))): abort(404) - return send_from_directory(current_app.config['UPLOAD_FOLDER'], file ,as_attachment=True) + return send_from_directory(current_app.config['UPLOAD_FOLDER'], file, as_attachment=True) # Of either width or height is 0, set it to the other value to keep aspect ratio if width > 0 and height == 0: @@ -60,7 +60,7 @@ def uploads(file): # Open image and set extension try: - img = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'],file)) + img = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], file)) except FileNotFoundError: logging.error('File not found: %s, possibly broken upload', file) abort(404) @@ -79,7 +79,7 @@ def uploads(file): # If has NSFW tag, blur image, etc. if filtered: - #img = img.filter(ImageFilter.GaussianBlur(20)) + # img = img.filter(ImageFilter.GaussianBlur(20)) pass # If forced to blur, blur image @@ -122,7 +122,7 @@ def upload(): img_name = "GWAGWA_"+str(uuid4()) img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img_name+'.'+img_ext) - if not img_ext in current_app.config['ALLOWED_EXTENSIONS'].keys(): + if img_ext not in current_app.config['ALLOWED_EXTENSIONS'].keys(): logging.info('File extension not allowed: %s', img_ext) abort(403) @@ -142,14 +142,14 @@ def upload(): # Save to database try: - query = db.Posts(author_id = g.user.id, - created_at = dt.utcnow(), - file_name = img_name+'.'+img_ext, - file_type = img_ext, - image_exif = img_exif, - image_colours = img_colors, - post_description = form_description, - post_alt = form_alt) + query = db.Posts(author_id=g.user.id, + created_at=dt.utcnow(), + file_name=img_name+'.'+img_ext, + file_type=img_ext, + image_exif=img_exif, + image_colours=img_colors, + post_description=form_description, + post_alt=form_alt) db_session.add(query) db_session.commit() @@ -159,6 +159,7 @@ def upload(): return 'Gwa Gwa' + @blueprint.route('/delete/', methods=['POST']) @login_required def delete_image(image_id): @@ -194,7 +195,7 @@ def delete_image(image_id): abort(500) logging.info('Removed image (%s) %s', image_id, img.file_name) - flash(['Image was all in Le Head!', 1]) + flash(['Image was all in Le Head!', 0]) return 'Gwa Gwa' @@ -268,7 +269,7 @@ def logfile(): """ Gets the log file and returns it as a JSON object """ - filename = logging.getLoggerClass().root.handlers[0].baseFilename + filename = 'only.log' log_dict = {} i = 0 diff --git a/gallery/auth.py b/gallery/auth.py index adce6f5..31c694c 100644 --- a/gallery/auth.py +++ b/gallery/auth.py @@ -1,5 +1,5 @@ """ -OnlyLegs - Authentification +OnlyLegs - Authentication User registration, login and logout and locking access to pages behind a login """ import re @@ -29,7 +29,7 @@ def login_required(view): @functools.wraps(view) def wrapped_view(**kwargs): if g.user is None or session.get('uuid') is None: - logging.error('Authentification failed') + logging.error('Authentication failed') session.clear() return redirect(url_for('gallery.index')) @@ -75,7 +75,6 @@ def register(): 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') - if not username or not username_regex.match(username): error.append('Username is invalid!') @@ -95,7 +94,6 @@ def register(): if error: return jsonify(error) - try: register_user = db.Users(username=username, email=email, @@ -124,7 +122,6 @@ def login(): user = db_session.query(db.Users).filter_by(username=username).first() error = [] - if user is None: logging.error('User %s does not exist. Login attempt from %s', username, request.remote_addr) @@ -137,18 +134,17 @@ def login(): if error: abort(403) - try: session.clear() session['user_id'] = user.id session['uuid'] = str(uuid.uuid4()) session_query = db.Sessions(user_id=user.id, - session_uuid=session.get('uuid'), - ip_address=request.remote_addr, - user_agent=request.user_agent.string, - active=True, - created_at=dt.utcnow()) + session_uuid=session.get('uuid'), + ip_address=request.remote_addr, + user_agent=request.user_agent.string, + active=True, + created_at=dt.utcnow()) db_session.add(session_query) db_session.commit() diff --git a/gallery/db.py b/gallery/db.py index 38eb061..0b3a543 100644 --- a/gallery/db.py +++ b/gallery/db.py @@ -1,6 +1,5 @@ """ -OnlyLegs - Database -Database models and functions for SQLAlchemy +OnlyLegs - Database models and functions for SQLAlchemy """ import os import platformdirs @@ -11,12 +10,12 @@ from sqlalchemy.orm import declarative_base, relationship, backref, mapped_colum 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(f'postgresql://username:password@host:port/database_name', echo=False) -# engine = create_engine(f'mysql://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) base = declarative_base() -class Users (base): # pylint: disable=too-few-public-methods, C0103 +class Users (base): # pylint: disable=too-few-public-methods, C0103 """ User table Joins with post, groups, session and log @@ -35,7 +34,7 @@ class Users (base): # pylint: disable=too-few-public-methods, C0103 log = relationship('Logs', backref='users') -class Posts (base): # pylint: disable=too-few-public-methods, C0103 +class Posts (base): # pylint: disable=too-few-public-methods, C0103 """ Post table Joins with group_junction @@ -58,7 +57,7 @@ class Posts (base): # pylint: disable=too-few-public-methods, C0103 junction = relationship('GroupJunction', backref='posts') -class Groups (base): # pylint: disable=too-few-public-methods, C0103 +class Groups (base): # pylint: disable=too-few-public-methods, C0103 """ Group table Joins with group_junction @@ -74,7 +73,7 @@ class Groups (base): # pylint: disable=too-few-public-methods, C0103 junction = relationship('GroupJunction', backref='groups') -class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103 +class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103 """ Junction table for posts and groups Joins with posts and groups @@ -87,7 +86,7 @@ class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103 post_id = Column(Integer, ForeignKey('posts.id')) -class Sessions (base): # pylint: disable=too-few-public-methods, C0103 +class Sessions (base): # pylint: disable=too-few-public-methods, C0103 """ Session table Joins with user @@ -103,7 +102,7 @@ class Sessions (base): # pylint: disable=too-few-public-methods, C0103 created_at = Column(DateTime, nullable=False) -class Logs (base): # pylint: disable=too-few-public-methods, C0103 +class Logs (base): # pylint: disable=too-few-public-methods, C0103 """ Log table Joins with user @@ -118,7 +117,7 @@ class Logs (base): # pylint: disable=too-few-public-methods, C0103 created_at = Column(DateTime, nullable=False) -class Bans (base): # pylint: disable=too-few-public-methods, C0103 +class Bans (base): # pylint: disable=too-few-public-methods, C0103 """ Bans table """ diff --git a/gallery/groups.py b/gallery/groups.py index e1b52a7..4e5a043 100644 --- a/gallery/groups.py +++ b/gallery/groups.py @@ -1,6 +1,6 @@ """ -Onlylegs - API endpoints -Used intermally by the frontend and possibly by other applications +Onlylegs - Image Groups +Why groups? Because I don't like calling these albums, sounds more limiting that it actually is """ import logging import json @@ -31,8 +31,10 @@ def groups(): thumbnail = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group.id).order_by(db.GroupJunction.date_added.desc()).first() if thumbnail is not None: - thumbnail_filename = db_session.query(db.Posts.file_name).filter(db.Posts.id == thumbnail[0]).first() - group.thumbnail = thumbnail_filename[0] + group.thumbnail = db_session.query(db.Posts.file_name, + db.Posts.post_alt, + db.Posts.image_colours, + db.Posts.id).filter(db.Posts.id == thumbnail[0]).first() else: group.thumbnail = None @@ -47,6 +49,8 @@ def group(group_id): if group is None: abort(404, 'Group not found') + + group.author_username = db_session.query(db.Users.username).filter(db.Users.id == group.author_id).first()[0] group_images = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).order_by(db.GroupJunction.date_added.desc()).all() @@ -75,15 +79,12 @@ def group_post(group_id, image_id): group = db_session.query(db.Groups).filter(db.Groups.id == group[0]).first() img.groups.append(group) - next = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id > image_id).order_by(db.GroupJunction.date_added.asc()).first() - prev = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id < image_id).order_by(db.GroupJunction.date_added.desc()).first() + next_url = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id > image_id).order_by(db.GroupJunction.date_added.asc()).first() + prev_url = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id < image_id).order_by(db.GroupJunction.date_added.desc()).first() - if next is not None: - next = url_for('group.group_post', group_id=group_id, image_id=next[0]) - if prev is not None: - prev = url_for('group.group_post', group_id=group_id, image_id=prev[0]) + if next_url is not None: + next_url = url_for('group.group_post', group_id=group_id, image_id=next_url[0]) + if prev_url is not None: + prev_url = url_for('group.group_post', group_id=group_id, image_id=prev_url[0]) - return render_template('image.html', - image=img, - next_url=next, - prev_url=prev) \ No newline at end of file + return render_template('image.html', image=img, next_url=next_url, prev_url=prev_url) \ No newline at end of file diff --git a/gallery/metadata/__init__.py b/gallery/metadata/__init__.py index 41698d5..af29de6 100644 --- a/gallery/metadata/__init__.py +++ b/gallery/metadata/__init__.py @@ -1,5 +1,5 @@ """ -OnlyLegs - Metatada Parser +OnlyLegs - Metadata Parser Parse metadata from images if available otherwise get some basic information from the file """ @@ -11,6 +11,7 @@ from PIL.ExifTags import TAGS from .helpers import * from .mapping import * + class Metadata: """ Metadata parser @@ -53,7 +54,8 @@ class Metadata: return None return self.format_data(self.encoded) - def format_data(self, encoded_exif): # pylint: disable=R0912 # For now, this is fine + @staticmethod + def format_data(encoded_exif): """ Formats the data into a dictionary """ @@ -66,15 +68,15 @@ class Metadata: # Thanks chatGPT xP for key, value in encoded_exif.items(): - for mapping_name, mapping in EXIF_MAPPING: - if key in mapping: - if len(mapping[key]) == 2: - exif[mapping_name][mapping[key][0]] = { + for mapping_name, mapping_val in EXIF_MAPPING: + if key in mapping_val: + if len(mapping_val[key]) == 2: + exif[mapping_name][mapping_val[key][0]] = { 'raw': value, - 'formatted': getattr(helpers, mapping[key][1])(value), + 'formatted': getattr(helpers, mapping_val[key][1])(value), } else: - exif[mapping_name][mapping[key][0]] = { + exif[mapping_name][mapping_val[key][0]] = { 'raw': value, } diff --git a/gallery/metadata/helpers.py b/gallery/metadata/helpers.py index 9115fb9..d3f98d9 100644 --- a/gallery/metadata/helpers.py +++ b/gallery/metadata/helpers.py @@ -4,6 +4,7 @@ Metadata formatting helpers """ from datetime import datetime + def human_size(value): """ Formats the size of a file in a human readable format @@ -276,7 +277,10 @@ def lens_specification(value): """ Maps the value of the lens specification to a human readable format """ - return str(value[0] / value[1]) + 'mm - ' + str(value[2] / value[3]) + 'mm' + try: + return str(value[0] / value[1]) + 'mm - ' + str(value[2] / value[3]) + 'mm' + except Exception as err: + return None def compression_type(value): diff --git a/gallery/metadata/mapping.py b/gallery/metadata/mapping.py index bbfedca..804374d 100644 --- a/gallery/metadata/mapping.py +++ b/gallery/metadata/mapping.py @@ -61,4 +61,9 @@ FILE_MAPPING = { 'RatingPercent': ['Rating Percent', 'rating_percent'], } -EXIF_MAPPING = [('Photographer', PHOTOGRAHER_MAPPING),('Camera', CAMERA_MAPPING),('Software', SOFTWARE_MAPPING),('File', FILE_MAPPING)] +EXIF_MAPPING = [ + ('Photographer', PHOTOGRAHER_MAPPING), + ('Camera', CAMERA_MAPPING), + ('Software', SOFTWARE_MAPPING), + ('File', FILE_MAPPING) +] diff --git a/gallery/routing.py b/gallery/routing.py index 315fd78..7e88c00 100644 --- a/gallery/routing.py +++ b/gallery/routing.py @@ -20,15 +20,17 @@ db_session = db_session() @blueprint.route('/') def index(): """ - Home page of the website, shows the feed of latest images + Home page of the website, shows the feed of the latest images """ images = db_session.query(db.Posts.file_name, + db.Posts.post_alt, db.Posts.image_colours, db.Posts.created_at, db.Posts.id).order_by(db.Posts.id.desc()).all() return render_template('index.html', images=images) + @blueprint.route('/image/') def image(image_id): """ @@ -47,15 +49,16 @@ def image(image_id): group = db_session.query(db.Groups).filter(db.Groups.id == group[0]).first() img.groups.append(group) - next = db_session.query(db.Posts.id).filter(db.Posts.id > image_id).order_by(db.Posts.id.asc()).first() - prev = db_session.query(db.Posts.id).filter(db.Posts.id < image_id).order_by(db.Posts.id.desc()).first() + next_url = db_session.query(db.Posts.id).filter(db.Posts.id > image_id).order_by(db.Posts.id.asc()).first() + prev_url = db_session.query(db.Posts.id).filter(db.Posts.id < image_id).order_by(db.Posts.id.desc()).first() - if next is not None: - next = url_for('gallery.image', image_id=next[0]) - if prev is not None: - prev = url_for('gallery.image', image_id=prev[0]) + if next_url is not None: + next_url = url_for('gallery.image', image_id=next_url[0]) + if prev_url is not None: + prev_url = url_for('gallery.image', image_id=prev_url[0]) + + return render_template('image.html', image=img, next_url=next_url, prev_url=prev_url) - return render_template('image.html', image=img, next_url=next, prev_url=prev) @blueprint.route('/profile') def profile(): @@ -64,9 +67,10 @@ def profile(): """ return render_template('profile.html', user_id='gwa gwa') + @blueprint.route('/profile/') def profile_id(user_id): """ Shows user ofa given id, displays their uploads and other info """ - return render_template('profile.html', user_id=user_id) \ No newline at end of file + return render_template('profile.html', user_id=user_id) diff --git a/gallery/settings.py b/gallery/settings.py index a4cd845..04da5e4 100644 --- a/gallery/settings.py +++ b/gallery/settings.py @@ -17,6 +17,7 @@ def general(): """ return render_template('settings/general.html') + @blueprint.route('/server') @login_required def server(): @@ -25,6 +26,7 @@ def server(): """ return render_template('settings/server.html') + @blueprint.route('/account') @login_required def account(): @@ -33,6 +35,7 @@ def account(): """ return render_template('settings/account.html') + @blueprint.route('/logs') @login_required def logs(): diff --git a/gallery/setup.py b/gallery/setup.py index db53218..9d28abd 100644 --- a/gallery/setup.py +++ b/gallery/setup.py @@ -8,8 +8,10 @@ import platformdirs import logging import yaml + USER_DIR = platformdirs.user_config_dir('onlylegs') + class SetupApp: """ Setup the application on first run @@ -36,7 +38,8 @@ class SetupApp: print("You can find the config files at:", USER_DIR) sys.exit() - def make_dir(self): + @staticmethod + def make_dir(): """ Create the user directory """ @@ -49,7 +52,8 @@ class SetupApp: print("Error creating user directory:", err) sys.exit(1) - def make_env(self): + @staticmethod + def make_env(): """ Create the .env file with default values """ @@ -67,7 +71,8 @@ class SetupApp: print("Generated default .env file, please edit!") - def make_yaml(self): + @staticmethod + def make_yaml(): """ Create the YAML config file with default values """ @@ -107,17 +112,18 @@ class SetupApp: print("Generated default YAML config, please edit!") - def logging_config(self): - LOGS_PATH = os.path.join(platformdirs.user_config_dir('onlylegs'), 'logs') + @staticmethod + def logging_config(): + logs_path = os.path.join(platformdirs.user_config_dir('onlylegs'), 'logs') - if not os.path.isdir(LOGS_PATH): - os.mkdir(LOGS_PATH) - print("Created logs directory at:", LOGS_PATH) + if not os.path.isdir(logs_path): + os.mkdir(logs_path) + print("Created logs directory at:", logs_path) logging.getLogger('werkzeug').disabled = True logging.basicConfig( - filename=os.path.join(LOGS_PATH, 'only.log'), + filename=os.path.join(logs_path, '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') \ No newline at end of file + encoding='utf-8') diff --git a/gallery/static/js/login.js b/gallery/static/js/login.js new file mode 100644 index 0000000..78bf5ca --- /dev/null +++ b/gallery/static/js/login.js @@ -0,0 +1,121 @@ +// Function to show login +function showLogin() { + popUpShow( + 'idk what to put here, just login please', + 'Need an account? Register!', + '', + '
\ + \ + \ +
' + ); +}; +// Function to login +function login(event) { + // AJAX takes control of subby form :3 + event.preventDefault(); + + let formUsername = document.querySelector("#username").value; + let formPassword = document.querySelector("#password").value; + + if (formUsername === "" || formPassword === "") { + addNotification("Please fill in all fields!!!!", 3); + return; + } + + // Make form + var formData = new FormData(); + formData.append("username", formUsername); + formData.append("password", formPassword); + + $.ajax({ + url: '/auth/login', + type: 'post', + data: formData, + contentType: false, + processData: false, + success: function (response) { + location.reload(); + }, + error: function (response) { + switch (response.status) { + case 500: + addNotification('Server exploded, F\'s in chat', 2); + break; + case 403: + addNotification('None but devils play past here... Wrong information', 2); + break; + default: + addNotification('Error logging in, blame someone', 2); + break; + } + } + }); +} +// Function to show register +function showRegister() { + popUpShow( + 'Who are you?', + 'Already have an account? Login!', + '', + '
\ + \ + \ + \ + \ +
' + ); +}; +// Function to register +function register(obj) { + // AJAX takes control of subby form + event.preventDefault(); + + let formUsername = document.querySelector("#username").value; + let formEmail = document.querySelector("#email").value; + let formPassword = document.querySelector("#password").value; + let formPasswordRepeat = document.querySelector("#password-repeat").value; + + if (formUsername === "" || formEmail === "" || formPassword === "" || formPasswordRepeat === "") { + addNotification("Please fill in all fields!!!!", 3); + return; + } + + // Make form + var formData = new FormData(); + formData.append("username", formUsername); + formData.append("email", formEmail); + formData.append("password", formPassword); + formData.append("password-repeat", formPasswordRepeat); + + $.ajax({ + url: '/auth/register', + type: 'post', + data: formData, + contentType: false, + processData: false, + success: function (response) { + if (response === "gwa gwa") { + addNotification('Registered successfully! Now please login to continue', 1); + showLogin(); + } else { + for (var i = 0; i < response.length; i++) { + addNotification(response[i], 2); + } + } + }, + error: function (response) { + switch (response.status) { + case 500: + addNotification('Server exploded, F\'s in chat', 2); + break; + case 403: + addNotification('None but devils play past here...', 2); + break; + default: + addNotification('Error logging in, blame someone', 2); + break; + } + } + }); +} \ No newline at end of file diff --git a/gallery/static/js/main.js b/gallery/static/js/main.js index 1f1cb62..85987a3 100644 --- a/gallery/static/js/main.js +++ b/gallery/static/js/main.js @@ -40,252 +40,6 @@ function loadOnView() { } } } -// Function to upload images -function uploadFile() { - // AJAX takes control of subby form - event.preventDefault(); - - const jobList = document.querySelector(".upload-jobs"); - - // Check for empty upload - if ($("#file").val() === "") { - addNotification("Please select a file to upload", 2); - } else { - // Make form - let formData = new FormData(); - formData.append("file", $("#file").prop("files")[0]); - formData.append("alt", $("#alt").val()); - formData.append("description", $("#description").val()); - formData.append("tags", $("#tags").val()); - formData.append("submit", $("#submit").val()); - - // Upload the information - $.ajax({ - url: '/api/upload', - type: 'post', - data: formData, - contentType: false, - processData: false, - beforeSend: function () { - 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").prop("files")[0]); - - jobImgFilter = document.createElement("span"); - jobImgFilter.classList.add("img-filter"); - - jobContainer.appendChild(jobStatus); - jobContainer.appendChild(jobProgress); - jobContainer.appendChild(jobImg); - jobContainer.appendChild(jobImgFilter); - jobList.appendChild(jobContainer); - }, - success: function (response) { - jobContainer.classList.add("success"); - jobStatus.innerHTML = "Uploaded!"; - if (!document.querySelector(".upload-panel").classList.contains("open")) { - addNotification("Image uploaded successfully", 1); - } - }, - error: function (response) { - jobContainer.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); - } - }, - }); - - // Empty values - $("#file").val(""); - $("#alt").val(""); - $("#description").val(""); - $("#tags").val(""); - } -}; -// open upload tab -function openUploadTab() { - // Stop scrolling - document.querySelector("html").style.overflow = "hidden"; - document.querySelector(".content").tabIndex = "-1"; - - // Open upload tab - const uploadTab = document.querySelector(".upload-panel"); - uploadTab.style.display = "block"; - - setTimeout(function () { - uploadTab.classList.add("open"); - }, 10); -} -// close upload tab -function closeUploadTab() { - // un-Stop scrolling - document.querySelector("html").style.overflow = "auto"; - document.querySelector(".content").tabIndex = ""; - - // Close upload tab - const uploadTab = document.querySelector(".upload-panel"); - uploadTab.classList.remove("open"); - - setTimeout(function () { - uploadTab.style.display = "none"; - }, 250); -} -// toggle upload tab -function toggleUploadTab() { - if (document.querySelector(".upload-panel").classList.contains("open")) { - closeUploadTab(); - } else { - openUploadTab(); - } -} -// Function to show login -function showLogin() { - popUpShow( - 'idk what to put here, just login please', - 'Need an account? Register!', - '', - '
\ - \ - \ -
' - ); -}; -// Function to login -function login(event) { - // AJAX takes control of subby form :3 - event.preventDefault(); - - let formUsername = document.querySelector("#username").value; - let formPassword = document.querySelector("#password").value; - - if (formUsername === "" || formPassword === "") { - addNotification("Please fill in all fields!!!!", 3); - return; - } - - // Make form - var formData = new FormData(); - formData.append("username", formUsername); - formData.append("password", formPassword); - - $.ajax({ - url: '/auth/login', - type: 'post', - data: formData, - contentType: false, - processData: false, - success: function (response) { - location.reload(); - }, - error: function (response) { - switch (response.status) { - case 500: - addNotification('Server exploded, F\'s in chat', 2); - break; - case 403: - addNotification('None but devils play past here... Wrong information', 2); - break; - default: - addNotification('Error logging in, blame someone', 2); - break; - } - } - }); -} -// Function to show register -function showRegister() { - popUpShow( - 'Who are you?', - 'Already have an account? Login!', - '', - '
\ - \ - \ - \ - \ -
' - ); -}; -// Function to register -function register(obj) { - // AJAX takes control of subby form - event.preventDefault(); - - let formUsername = document.querySelector("#username").value; - let formEmail = document.querySelector("#email").value; - let formPassword = document.querySelector("#password").value; - let formPasswordRepeat = document.querySelector("#password-repeat").value; - - if (formUsername === "" || formEmail === "" || formPassword === "" || formPasswordRepeat === "") { - addNotification("Please fill in all fields!!!!", 3); - return; - } - - // Make form - var formData = new FormData(); - formData.append("username", formUsername); - formData.append("email", formEmail); - formData.append("password", formPassword); - formData.append("password-repeat", formPasswordRepeat); - - $.ajax({ - url: '/auth/register', - type: 'post', - data: formData, - contentType: false, - processData: false, - success: function (response) { - if (response === "gwa gwa") { - addNotification('Registered successfully! Now please login to continue', 1); - showLogin(); - } else { - for (var i = 0; i < response.length; i++) { - addNotification(response[i], 2); - } - } - }, - error: function (response) { - switch (response.status) { - case 500: - addNotification('Server exploded, F\'s in chat', 2); - break; - case 403: - addNotification('None but devils play past here...', 2); - break; - default: - addNotification('Error logging in, blame someone', 2); - break; - } - } - }); -} window.onload = function () { loadOnView(); diff --git a/gallery/static/js/uploadTab.js b/gallery/static/js/uploadTab.js new file mode 100644 index 0000000..7963adc --- /dev/null +++ b/gallery/static/js/uploadTab.js @@ -0,0 +1,128 @@ +// Function to upload images +function uploadFile() { + // AJAX takes control of subby form + event.preventDefault(); + + const jobList = document.querySelector(".upload-jobs"); + + // Check for empty upload + if ($("#file").val() === "") { + addNotification("Please select a file to upload", 2); + } else { + // Make form + let formData = new FormData(); + formData.append("file", $("#file").prop("files")[0]); + formData.append("alt", $("#alt").val()); + formData.append("description", $("#description").val()); + formData.append("tags", $("#tags").val()); + formData.append("submit", $("#submit").val()); + + // Upload the information + $.ajax({ + url: '/api/upload', + type: 'post', + data: formData, + contentType: false, + processData: false, + beforeSend: function () { + 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").prop("files")[0]); + + jobImgFilter = document.createElement("span"); + jobImgFilter.classList.add("img-filter"); + + jobContainer.appendChild(jobStatus); + jobContainer.appendChild(jobProgress); + jobContainer.appendChild(jobImg); + jobContainer.appendChild(jobImgFilter); + jobList.appendChild(jobContainer); + }, + success: function (response) { + jobContainer.classList.add("success"); + jobStatus.innerHTML = "Uploaded!"; + if (!document.querySelector(".upload-panel").classList.contains("open")) { + addNotification("Image uploaded successfully", 1); + } + }, + error: function (response) { + jobContainer.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); + } + }, + }); + + // Empty values + $("#file").val(""); + $("#alt").val(""); + $("#description").val(""); + $("#tags").val(""); + } +}; + +// open upload tab +function openUploadTab() { + // Stop scrolling + document.querySelector("html").style.overflow = "hidden"; + document.querySelector(".content").tabIndex = "-1"; + + // Open upload tab + const uploadTab = document.querySelector(".upload-panel"); + uploadTab.style.display = "block"; + + setTimeout(function () { + uploadTab.classList.add("open"); + }, 10); +} + +// close upload tab +function closeUploadTab() { + // un-Stop scrolling + document.querySelector("html").style.overflow = "auto"; + document.querySelector(".content").tabIndex = ""; + + // Close upload tab + const uploadTab = document.querySelector(".upload-panel"); + uploadTab.classList.remove("open"); + + setTimeout(function () { + uploadTab.style.display = "none"; + }, 250); +} + +// toggle upload tab +function toggleUploadTab() { + if (document.querySelector(".upload-panel").classList.contains("open")) { + closeUploadTab(); + } else { + openUploadTab(); + } +} diff --git a/gallery/templates/groups/group.html b/gallery/templates/groups/group.html index c972a3e..3e216f9 100644 --- a/gallery/templates/groups/group.html +++ b/gallery/templates/groups/group.html @@ -17,7 +17,7 @@ {% else %} @@ -25,7 +25,7 @@ {% endif %} @@ -41,11 +41,11 @@ diff --git a/gallery/templates/groups/list.html b/gallery/templates/groups/list.html index 9862338..ebb059b 100644 --- a/gallery/templates/groups/list.html +++ b/gallery/templates/groups/list.html @@ -23,17 +23,23 @@ {% if groups %} {% else %} diff --git a/gallery/templates/image.html b/gallery/templates/image.html index 5415cc9..616c69b 100644 --- a/gallery/templates/image.html +++ b/gallery/templates/image.html @@ -4,18 +4,19 @@ {% block content %}
- + {{ image.post_alt }}
- + {{ image.post_alt }}
{{ image.post_alt }}
+
+ {% for col in image.image_colours %} + + {% endfor %} +
@@ -133,11 +139,6 @@
Image ID{{ image.created_at }}
-
- {% for col in image.image_colours %} - - {% endfor %} -
{% for group in image.groups %} @@ -251,7 +252,7 @@ 'DESTRUCTION!!!!!!', 'This will delete the image and all of its data!!! This action is irreversible!!!!! Are you sure you want to do this?????', '', - '' + '' ); }); function deleteImage() { diff --git a/gallery/templates/index.html b/gallery/templates/index.html index 80932f4..bc1ad52 100644 --- a/gallery/templates/index.html +++ b/gallery/templates/index.html @@ -18,11 +18,11 @@ diff --git a/gallery/theme_manager.py b/gallery/theme_manager.py index 73c5702..f62225e 100644 --- a/gallery/theme_manager.py +++ b/gallery/theme_manager.py @@ -8,7 +8,7 @@ from datetime import datetime import sass -class CompileTheme(): +class CompileTheme: """ Compiles the theme into the static folder """ @@ -33,7 +33,8 @@ class CompileTheme(): now = datetime.now() print(f"{now.hour}:{now.minute}:{now.second} - Done!\n") - def load_sass(self, source_path, css_dest): + @staticmethod + def load_sass(source_path, css_dest): """ Compile the sass (or scss) file into css and save it to the static folder """ @@ -54,7 +55,8 @@ class CompileTheme(): print("Compiled successfully!") - def load_fonts(self, source_path, font_dest): + @staticmethod + def load_fonts(source_path, font_dest): """ Copy the fonts folder to the static folder """ diff --git a/gallery/themes/default/components/gallery.sass b/gallery/themes/default/components/gallery.sass index 59abde1..5992eaf 100644 --- a/gallery/themes/default/components/gallery.sass +++ b/gallery/themes/default/components/gallery.sass @@ -44,35 +44,33 @@ transform: scale(1.05) // scale up transition: all 0.3s cubic-bezier(.79, .14, .15, .86) - > h2 - margin: 0 - padding: 0 + .image-title + margin: 0 - font-size: 1rem - font-weight: 600 + font-size: 1rem + font-weight: 600 - color: $primary + color: $primary - text-overflow: ellipsis - overflow: hidden + text-overflow: ellipsis + overflow: hidden - opacity: 0 // hide - transition: all 0.2s ease-in-out + opacity: 0 // hide + transition: all 0.2s ease-in-out - > p - margin: 0 - padding: 0 + .image-subtitle + margin: 0 - font-size: 0.8rem - font-weight: 500 + font-size: 0.8rem + font-weight: 500 - color: $white + color: $white - text-overflow: ellipsis - overflow: hidden + text-overflow: ellipsis + overflow: hidden - opacity: 0 // hide - transition: all 0.2s ease-in-out + opacity: 0 // hide + transition: all 0.2s ease-in-out img width: 100% @@ -95,13 +93,14 @@ padding-bottom: 100% &:hover - span + .image-filter bottom: 0 opacity: 1 transform: scale(1) - > h2, > p - opacity: 1 + .image-title, + .image-subtitle + opacity: 1 img transform: scale(1) diff --git a/gallery/themes/default/components/image-view/info-tab.sass b/gallery/themes/default/components/image-view/info-tab.sass index ce25d3d..f4e69ff 100644 --- a/gallery/themes/default/components/image-view/info-tab.sass +++ b/gallery/themes/default/components/image-view/info-tab.sass @@ -173,14 +173,14 @@ margin: 0 padding: 0 - width: 100% - height: 2rem + width: 1.5rem + height: 1.5rem display: flex justify-content: center align-items: center - border-radius: $rad-inner + border-radius: 50% // border: 1px solid $white .img-groups diff --git a/gallery/themes/default/style.sass b/gallery/themes/default/style.sass index a711cda..da2b4fd 100644 --- a/gallery/themes/default/style.sass +++ b/gallery/themes/default/style.sass @@ -48,7 +48,7 @@ html, body color: $black .big-text - height: 60vh + height: 20rem display: flex flex-direction: column @@ -102,38 +102,8 @@ html, body color: $white -footer - margin: 0 - padding: 0.25rem 1rem - - width: 100% - - display: flex - justify-content: center - align-items: center - gap: 1rem - - background-color: $white - - p - margin: 0 - padding: 0 - - font-size: 0.75rem - font-weight: 400 - text-align: center - - color: $black - - a - margin: 0 - padding: 0 - - font-size: 0.75rem - font-weight: 400 - text-align: center - - color: $primary +#contrast-check + transition: color 0.15s ease-in-out @media (max-width: $breakpoint) diff --git a/pyproject.toml b/pyproject.toml index 3f06105..47c85c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "onlylegs" -version = "23.03.10" +version = "23.03.11" description = "Gallery built for fast and simple image management" authors = ["Fluffy-Bean "] license = "MIT"