diff --git a/.gitignore b/.gitignore index a52b68f..82f01cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Remove all development files gallery/user/uploads/* +gallery/user/conf.yml +gallery/user/conf.json gallery/static/theme/* .idea diff --git a/gallery/__init__.py b/gallery/__init__.py index 046877b..8dcf6e8 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -12,6 +12,7 @@ Created by Fluffy Bean - Version 110123 import time import sys import os +import yaml # Import flask from flask import * @@ -26,13 +27,19 @@ def create_app(test_config=None): # Get environment variables load_dotenv(os.path.join(app.root_path, 'user', '.env')) + + # Get config file + with open(os.path.join(app.root_path, 'user', 'conf.yml'), 'r') as f: + conf = yaml.load(f, Loader=yaml.FullLoader) + print("Loaded config") + print(conf['upload']['allowed-extensions']) # App configuration app.config.from_mapping( SECRET_KEY=os.environ.get('FLASK_SECRET'), DATABASE=os.path.join(app.instance_path, 'gallery.sqlite'), UPLOAD_FOLDER=os.path.join(app.root_path, 'user', 'uploads'), - ALLOWED_EXTENSIONS=os.environ.get('FLASK_EXTENSIONS'), + ALLOWED_EXTENSIONS=conf['upload']['allowed-extensions'], ) if test_config is None: diff --git a/gallery/gallery.py b/gallery/gallery.py index c7500a2..ba5e1bc 100644 --- a/gallery/gallery.py +++ b/gallery/gallery.py @@ -5,8 +5,6 @@ from gallery.auth import login_required from gallery.db import get_db import os import datetime -from PIL import Image -from PIL.ExifTags import TAGS dt = datetime.datetime.now() blueprint = Blueprint('gallery', __name__) @@ -41,9 +39,11 @@ def upload(): if not file: flash('No selected file') return abort(404) - if secure_filename(file.filename).lower().split('.')[-1] in current_app.config['ALLOWED_EXTENSIONS']: - file_name = f"GWAGWA_{dt.year}{dt.month}{dt.day}-{dt.microsecond}.{secure_filename(file.filename).lower().split('.')[-1]}" - file.save(os.path.join(current_app.config['UPLOAD_FOLDER']+'/original', file_name)) + if not secure_filename(file.filename).lower().split('.')[-1] in current_app.config['ALLOWED_EXTENSIONS']: + abort(403) + + file_name = file_name = f"GWAGWA_{dt.year}{dt.month}{dt.day}-{dt.microsecond}.{secure_filename(file.filename).lower().split('.')[-1]}" + file.save(os.path.join(current_app.config['UPLOAD_FOLDER']+'/original', file_name)) db = get_db() db.execute( diff --git a/gallery/image.py b/gallery/image.py index 7c4787c..a9ab4bd 100644 --- a/gallery/image.py +++ b/gallery/image.py @@ -1,7 +1,6 @@ from flask import Blueprint, flash, g, redirect, render_template, request, url_for, jsonify, current_app from werkzeug.exceptions import abort from werkzeug.utils import secure_filename -from gallery.auth import login_required from gallery.db import get_db import os import datetime @@ -63,21 +62,25 @@ def image(id): abort(404) # Get exif data from image - file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name'])) - raw_exif = file.getexif() - human_exif = {} - - for tag in raw_exif: - name = TAGS.get(tag, tag) - value = raw_exif.get(tag) + try: + file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name'])) + raw_exif = file.getexif() + human_exif = {} - if isinstance(value, bytes): - value = value.decode() + for tag in raw_exif: + name = TAGS.get(tag, tag) + value = raw_exif.get(tag) + + if isinstance(value, bytes): + value = value.decode() + + human_exif[name] = value - human_exif[name] = value - - if len(human_exif) == 0: + if len(human_exif) == 0: + human_exif = False + except: + # Cringe, no file present human_exif = False # All in le head - return render_template('image.html', image=image, exif=human_exif) \ No newline at end of file + return render_template('image.html', image=image, exif=human_exif, file=file) \ No newline at end of file diff --git a/gallery/static/images/error.png b/gallery/static/images/error.png new file mode 100644 index 0000000..8f7cc08 Binary files /dev/null and b/gallery/static/images/error.png differ diff --git a/gallery/templates/image.html b/gallery/templates/image.html index 6733180..4cd0ba8 100644 --- a/gallery/templates/image.html +++ b/gallery/templates/image.html @@ -5,30 +5,44 @@ {% endblock %} {% block content %} +
+ +
+
- - +
+
+
{% if g.user['id'] == image['author_id'] %} @@ -37,27 +51,30 @@ + Delete -
{% endif %}
+ {% if image['description'] != '' %} +
+

Description

+

{{ image['description'] }}

+
+ {% endif %}

Info

-

{{ image['file_name'] }}

-

{{ image['id'] }}

-

{{ image['author_id'] }}

-

{{ image['created_at'] }}

-

{{ image['description'] }}

+

Filename: {{ image['file_name'] }}

+

Image ID: {{ image['id'] }}

+

Author: {{ image['author_id'] }}

+

Upload date: {{ image['created_at'] }}

+

Dimensions: {{ file['width'] }}x{{ file['height'] }}

{% if exif is not false %}
@@ -69,14 +86,19 @@ {% endif %}
{% endblock %} \ No newline at end of file diff --git a/gallery/user/example.yml b/gallery/user/example.yml new file mode 100644 index 0000000..93e9350 --- /dev/null +++ b/gallery/user/example.yml @@ -0,0 +1,21 @@ +# THIS IS AN EXAMPLE CONFIG, RENAME THIS TO conf.yml TO USE + +admin: + name: Real Person + username: User + email: real-email@some.place + +upload: + allowed-extensions: + - png + - jpg + - jpeg + - webp + max-size: 69MB + rename: GWA_{{username}}_{{time}} + +website: + name: OnlyLegs + motto: Gwa Gwa + language: english # Placeholder for future language support endevours + diff --git a/gallery/user/themes/default/buttons/img-tool.scss b/gallery/user/themes/default/buttons/img-tool.scss index 5e0f08e..054d717 100644 --- a/gallery/user/themes/default/buttons/img-tool.scss +++ b/gallery/user/themes/default/buttons/img-tool.scss @@ -5,6 +5,8 @@ width: 2.5rem; height: 2.5rem; + position: relative; + border: none; background-color: transparent; color: $white100; @@ -18,12 +20,49 @@ cursor: pointer; color: $green; + + .tool-tip { + opacity: 1; + top: -2.5rem; + //transition-delay: 0.5s; + } } } .tool-btn--evil { color: $red; + span { + background-color: $red; + } + &:hover { color: $white100; } +} + +.tool-tip { + margin: 0; + padding: 0.5rem 0.75rem; + + width: auto; + + display: block; + + position: absolute; + top: -1.7rem; + left: 0; + transform: translateX(calc(-50% + 1.25rem )); + + font-family: $font-body; + font-size: 1rem; + font-weight: 600; + + background-color: $black300; + color: $white100; + opacity: 0; + border-radius: $rad; + + transition: opacity 0.2s cubic-bezier(.76,0,.17,1), top 0.2s cubic-bezier(.76,0,.17,1); + + pointer-events: none; } \ No newline at end of file diff --git a/gallery/user/themes/default/buttons/up.scss b/gallery/user/themes/default/buttons/up.scss index 613bfc2..ec73f18 100644 --- a/gallery/user/themes/default/buttons/up.scss +++ b/gallery/user/themes/default/buttons/up.scss @@ -1,9 +1,9 @@ #topButton { margin: 0; - padding: 0.25rem; + padding: 0.5rem; - width: 3rem; - height: 3rem; + width: 2.5rem; + height: 2.5rem; position: fixed; bottom: 0.75rem; diff --git a/gallery/user/themes/default/style.scss b/gallery/user/themes/default/style.scss index b3bf8ce..26c5dfd 100644 --- a/gallery/user/themes/default/style.scss +++ b/gallery/user/themes/default/style.scss @@ -236,6 +236,56 @@ } +.image__fullscreen { + margin: 0; + padding: 0 0 0 3.5rem; + + width: 100%; + height: 100dvh; + + position: fixed; + top: -100%; + left: 0; + + display: flex; + opacity: 0; // hide + + background-color: rgba($black100, 0.8); + backdrop-filter: blur(1rem); + z-index: 21; + + box-sizing: border-box; + + img { + margin: auto; + padding: 0; + + width: auto; + height: auto; + max-width: calc(100% - 1rem); + max-height: calc(100% - 1rem); + + object-fit: contain; + object-position: center; + + transform: scale(0.8); + + border-radius: $rad; + } +} +.image__fullscreen--active { + top: 0; + + opacity: 1; // show + + transition: opacity 0.3s cubic-bezier(.79, .14, .15, .86); + + img { + transform: scale(1); + transition: transform 0.2s cubic-bezier(.68,-0.55,.27,1.55); + } +} + .image__container { margin: 0; padding: 0; @@ -259,15 +309,12 @@ max-width: 100%; height: 100%; - max-height: 75vh; - - background: linear-gradient(-45deg, $black100, $black400 40%, $black100); - background-size: 400% 400%; - border-radius: $rad; - animation: imgLoading 10s ease infinite; + max-height: 69vh; object-fit: contain; object-position: center; + + border-radius: $rad; } } diff --git a/gallery/user/themes/default/ui/main.scss b/gallery/user/themes/default/ui/main.scss index 711c3cd..5aa6aa1 100644 --- a/gallery/user/themes/default/ui/main.scss +++ b/gallery/user/themes/default/ui/main.scss @@ -47,7 +47,7 @@ main { height: 100%; background-image: linear-gradient(to bottom, #00000000, rgba($black100, 1)); - backdrop-filter: blur(0.5rem); + backdrop-filter: blur(1rem); z-index: +1; } diff --git a/gallery/user/themes/default/ui/nav.scss b/gallery/user/themes/default/ui/nav.scss index 97981f1..8c372b2 100644 --- a/gallery/user/themes/default/ui/nav.scss +++ b/gallery/user/themes/default/ui/nav.scss @@ -18,7 +18,7 @@ nav { color: $white100; box-sizing: border-box; - z-index: 2; + z-index: 69; transition: width 0.4s cubic-bezier(.76,0,.17,1), background-color 0.3s ease-in-out; div {