Switch to Flask_Login for user/session management

This commit is contained in:
Michał Gdula 2023-04-03 18:04:49 +00:00
parent 33f475e828
commit 4e50a66514
10 changed files with 127 additions and 168 deletions

View file

@ -11,6 +11,7 @@ import logging
from flask_compress import Compress
from flask_caching import Cache
from flask_assets import Environment, Bundle
from flask_login import LoginManager
from flask import Flask, render_template, abort
from werkzeug.exceptions import HTTPException
@ -19,18 +20,26 @@ import platformdirs
from dotenv import load_dotenv
from yaml import safe_load
# Import database
from sqlalchemy.orm import sessionmaker
from gallery import db
USER_DIR = platformdirs.user_config_dir('onlylegs')
db_session = sessionmaker(bind=db.engine)
db_session = db_session()
login_manager = LoginManager()
assets = Environment()
cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 300})
compress = Compress()
def create_app(test_config=None):
"""
Create and configure the main app
"""
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()
# Get environment variables
load_dotenv(os.path.join(USER_DIR, '.env'))
@ -56,6 +65,13 @@ def create_app(test_config=None):
else:
app.config.from_mapping(test_config)
login_manager.init_app(app)
login_manager.login_view = 'gallery.index'
@login_manager.user_loader
def load_user(user_id):
return db_session.query(db.Users).filter_by(id=user_id).first()
# Load JS assets
# TODO: disable caching for sass files as it makes it hard to work on when it is enabled
assets.register('js_pre', Bundle('js/pre/*.js', output='gen/pre_packed.js'))

View file

@ -3,17 +3,15 @@ OnlyLegs - Authentication
User registration, login and logout and locking access to pages behind a login
"""
import re
import uuid
import logging
from datetime import datetime as dt
import functools
from flask import Blueprint, flash, g, redirect, request, session, url_for, abort, jsonify
from flask import Blueprint, flash, redirect, request, url_for, abort, jsonify
from werkzeug.security import check_password_hash, generate_password_hash
from sqlalchemy.orm import sessionmaker
from sqlalchemy import exc
from flask_login import login_user, logout_user, login_required
from sqlalchemy.orm import sessionmaker
from gallery import db
@ -22,42 +20,30 @@ db_session = sessionmaker(bind=db.engine)
db_session = db_session()
def login_required(view):
@blueprint.route('/login', methods=['POST'])
def login():
"""
Decorator to check if a user is logged in before accessing a page
Log in a registered user by adding the user id to the session
"""
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None or session.get('uuid') is None:
logging.error('Authentication failed')
session.clear()
return redirect(url_for('gallery.index'))
error = []
username = request.form['username'].strip()
password = request.form['password'].strip()
return view(**kwargs)
user = db_session.query(db.Users).filter_by(username=username).first()
return wrapped_view
if not user and not check_password_hash(user.password, password):
logging.error('Login attempt from %s', username, request.remote_addr)
error.append('Username or Password is incorrect!')
if error:
abort(403)
@blueprint.before_app_request
def load_logged_in_user():
"""
Runs before every request and checks if a user is logged in
"""
user_id = session.get('user_id')
user_uuid = session.get('uuid')
login_user(user)
if user_id is None or user_uuid is None:
g.user = None
session.clear()
else:
is_alive = db_session.query(db.Sessions).filter_by(session_uuid=user_uuid).first()
if is_alive is None:
logging.info('Session expired')
flash(['Session expired!', '3'])
session.clear()
else:
g.user = db_session.query(db.Users).filter_by(id=user_id).first()
logging.info('User %s logged in from %s', username, request.remote_addr)
flash(['Logged in successfully!', '4'])
return 'gwa gwa'
@blueprint.route('/register', methods=['POST'])
@ -65,17 +51,18 @@ def register():
"""
Register a new user
"""
error = []
# Thanks Fennec for reminding me to strip out the whitespace lol
username = request.form['username'].strip()
email = request.form['email'].strip()
password = request.form['password'].strip()
password_repeat = request.form['password-repeat'].strip()
error = []
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')
# Validate the form
if not username or not username_regex.match(username):
error.append('Username is invalid!')
@ -91,75 +78,30 @@ def register():
error.append('Enter password again!')
elif password_repeat != password:
error.append('Passwords do not match!')
user_exists = db_session.query(db.Users).filter_by(username=username).first()
if user_exists:
error.append('User already exists!')
# If there are errors, return them
if error:
return jsonify(error)
try:
register_user = db.Users(username=username,
email=email,
password=generate_password_hash(password),
created_at=dt.utcnow())
db_session.add(register_user)
db_session.commit()
except exc.IntegrityError:
return f'User {username} is already registered!'
register_user = db.Users(username=username, email=email,
password=generate_password_hash(password, method='sha256'),
created_at=dt.utcnow())
db_session.add(register_user)
db_session.commit()
logging.info('User %s registered', username)
return 'gwa gwa'
@blueprint.route('/login', methods=['POST'])
def login():
"""
Log in a registered user by adding the user id to the session
"""
username = request.form['username'].strip()
password = request.form['password'].strip()
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)
error.append('Username or Password is incorrect!')
elif not check_password_hash(user.password, password):
logging.error('User %s entered wrong password. Login attempt from %s',
username, request.remote_addr)
error.append('Username or Password is incorrect!')
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())
db_session.add(session_query)
db_session.commit()
except Exception as err:
logging.error('User %s could not be logged in: %s', username, err)
abort(500)
logging.info('User %s logged in from %s', username, request.remote_addr)
flash(['Logged in successfully!', '4'])
return 'gwa gwa'
@blueprint.route('/logout')
@login_required
def logout():
"""
Clear the current session, including the stored user id
"""
logging.info('User (%s) %s logged out', session.get('user_id'), g.user.username)
session.clear()
logout_user()
return redirect(url_for('gallery.index'))

View file

@ -8,6 +8,8 @@ from sqlalchemy import (
create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType)
from sqlalchemy.orm import declarative_base, relationship
from flask_login import UserMixin
USER_DIR = platformdirs.user_config_dir('onlylegs')
DB_PATH = os.path.join(USER_DIR, 'gallery.sqlite')
@ -18,7 +20,7 @@ engine = create_engine(f'sqlite:///{DB_PATH}', echo=False)
base = declarative_base()
class Users (base): # pylint: disable=too-few-public-methods, C0103
class Users (base, UserMixin): # pylint: disable=too-few-public-methods, C0103
"""
User table
Joins with post, groups, session and log

View file

@ -75,7 +75,7 @@
{% else %}
<div class="big-text">
<h1>*crickets chirping*</h1>
{% if g.user %}
{% if current_user.is_authenticated %}
<p>Add some images to the group!</p>
{% else %}
<p>Login to start managing this image group!</p>

View file

@ -43,7 +43,7 @@
{% else %}
<div class="big-text">
<h1>*crickets chirping*</h1>
{% if g.user %}
{% if current_user.is_authenticated %}
<p>You can get started by creating a new image group!</p>
{% else %}
<p>Login to start seeing anything here!</p>

View file

@ -33,7 +33,7 @@
}
}
{% if g.user.id == image.author_id %}
{% if current_user.id == image.author_id %}
cancelBtn = document.createElement('button');
cancelBtn.classList.add('btn-block');
cancelBtn.innerHTML = 'nuuuuuuuu';
@ -144,7 +144,7 @@
</span>
</a>
</div>
{% if g.user.id == image.author_id %}
{% if current_user.id == image.author_id %}
<div>
<button class="pill-item pill__critical" onclick="imageDelete()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM112,168a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm0-120H96V40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8Z"></path></svg>

View file

@ -26,15 +26,15 @@
media="(prefers-color-scheme: dark)"/>
{% assets "js_pre" %}
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}
{% assets "js_post" %}
<script type="text/javascript" src="{{ ASSET_URL }}" defer></script>
<script type="text/javascript" src="{{ ASSET_URL }}" defer></script>
{% endassets %}
{% assets "styles" %}
<link rel="stylesheet" href="{{ ASSET_URL }}" type="text/css" defer>
<link rel="stylesheet" href="{{ ASSET_URL }}" type="text/css" defer>
{% endassets %}
{% block head %}{% endblock %}
@ -46,9 +46,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M184,216a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,216Zm45.66-101.66-96-96a8,8,0,0,0-11.32,0l-96,96A8,8,0,0,0,32,128H72v24a8,8,0,0,0,8,8h96a8,8,0,0,0,8-8V128h40a8,8,0,0,0,5.66-13.66ZM176,176H80a8,8,0,0,0,0,16h96a8,8,0,0,0,0-16Z"></path></svg>
</button>
{% if request.path == "/" %}
<button class="info-button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm-4,48a12,12,0,1,1-12,12A12,12,0,0,1,124,72Zm12,112a16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40a8,8,0,0,1,0,16Z"></path></svg>
</button>
<button class="info-button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm-4,48a12,12,0,1,1-12,12A12,12,0,0,1,124,72Zm12,112a16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40a8,8,0,0,1,0,16Z"></path></svg>
</button>
{% endif %}
<div class="pop-up">
@ -80,67 +80,67 @@
</span>
</a>
{% if g.user %}
<button class="navigation-item {% block nav_upload %}{% endblock %}" onclick="toggleUploadTab()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M74.34,77.66a8,8,0,0,1,0-11.32l48-48a8,8,0,0,1,11.32,0l48,48a8,8,0,0,1-11.32,11.32L136,43.31V128a8,8,0,0,1-16,0V43.31L85.66,77.66A8,8,0,0,1,74.34,77.66ZM240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16h68a4,4,0,0,1,4,4v3.46c0,13.45,11,24.79,24.46,24.54A24,24,0,0,0,152,128v-4a4,4,0,0,1,4-4h68A16,16,0,0,1,240,136Zm-40,32a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
<span class="tool-tip">
Upload
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</button>
{% if current_user.is_authenticated %}
<button class="navigation-item {% block nav_upload %}{% endblock %}" onclick="toggleUploadTab()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M74.34,77.66a8,8,0,0,1,0-11.32l48-48a8,8,0,0,1,11.32,0l48,48a8,8,0,0,1-11.32,11.32L136,43.31V128a8,8,0,0,1-16,0V43.31L85.66,77.66A8,8,0,0,1,74.34,77.66ZM240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16h68a4,4,0,0,1,4,4v3.46c0,13.45,11,24.79,24.46,24.54A24,24,0,0,0,152,128v-4a4,4,0,0,1,4-4h68A16,16,0,0,1,240,136Zm-40,32a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
<span class="tool-tip">
Upload
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</button>
{% endif %}
<span class="navigation-spacer"></span>
{% if g.user %}
<a href="{{url_for('gallery.profile')}}" class="navigation-item {% block nav_profile %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M231.73,221.94A8,8,0,0,1,224,232H160A8,8,0,0,1,152.27,222a40,40,0,0,1,17.11-23.33,32,32,0,1,1,45.24,0A40,40,0,0,1,231.73,221.94ZM216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16h80a8,8,0,0,0,0-16H40V64H93.33l27.74,20.8a16.12,16.12,0,0,0,9.6,3.2H216v32a8,8,0,0,0,16,0V88A16,16,0,0,0,216,72Z"></path></svg>
<span class="tool-tip">
Profile
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</a>
<a href="{{url_for('settings.general')}}" class="navigation-item {% block nav_settings %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,130.16q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.6,107.6,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.29,107.29,0,0,0-26.25-10.86,8,8,0,0,0-7.06,1.48L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.6,107.6,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06ZM128,168a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z"></path></svg>
<span class="tool-tip">
Settings
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</a>
{% if current_user.is_authenticated %}
<a href="{{url_for('gallery.profile')}}" class="navigation-item {% block nav_profile %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M231.73,221.94A8,8,0,0,1,224,232H160A8,8,0,0,1,152.27,222a40,40,0,0,1,17.11-23.33,32,32,0,1,1,45.24,0A40,40,0,0,1,231.73,221.94ZM216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16h80a8,8,0,0,0,0-16H40V64H93.33l27.74,20.8a16.12,16.12,0,0,0,9.6,3.2H216v32a8,8,0,0,0,16,0V88A16,16,0,0,0,216,72Z"></path></svg>
<span class="tool-tip">
Profile
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</a>
<a href="{{url_for('settings.general')}}" class="navigation-item {% block nav_settings %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,130.16q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.6,107.6,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.29,107.29,0,0,0-26.25-10.86,8,8,0,0,0-7.06,1.48L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.6,107.6,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06ZM128,168a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z"></path></svg>
<span class="tool-tip">
Settings
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</a>
{% else %}
<button class="navigation-item {% block nav_login %}{% endblock %}" onclick="showLogin()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M141.66,133.66l-40,40A8,8,0,0,1,88,168V136H24a8,8,0,0,1,0-16H88V88a8,8,0,0,1,13.66-5.66l40,40A8,8,0,0,1,141.66,133.66ZM192,32H136a8,8,0,0,0,0,16h56V208H136a8,8,0,0,0,0,16h56a16,16,0,0,0,16-16V48A16,16,0,0,0,192,32Z"></path></svg>
<span class="tool-tip">
Login
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</button>
<button class="navigation-item {% block nav_login %}{% endblock %}" onclick="showLogin()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M141.66,133.66l-40,40A8,8,0,0,1,88,168V136H24a8,8,0,0,1,0-16H88V88a8,8,0,0,1,13.66-5.66l40,40A8,8,0,0,1,141.66,133.66ZM192,32H136a8,8,0,0,0,0,16h56V208H136a8,8,0,0,0,0,16h56a16,16,0,0,0,16-16V48A16,16,0,0,0,192,32Z"></path></svg>
<span class="tool-tip">
Login
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M168,48V208a8,8,0,0,1-13.66,5.66l-80-80a8,8,0,0,1,0-11.32l80-80A8,8,0,0,1,168,48Z"></path></svg>
</span>
</button>
{% endif %}
</div>
{% if g.user %}
<div class="upload-panel">
<span class="click-off" onclick="closeUploadTab()"></span>
<div class="container">
<span id="dragIndicator"></span>
<h3>Upload stuffs</h3>
<p>May the world see your stuff 👀</p>
<form id="uploadForm">
<button class="fileDrop-block" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H80a8,8,0,0,1,0,16H32v64H224V136H176a8,8,0,0,1,0-16h48A16,16,0,0,1,240,136ZM85.66,77.66,120,43.31V128a8,8,0,0,0,16,0V43.31l34.34,34.35a8,8,0,0,0,11.32-11.32l-48-48a8,8,0,0,0-11.32,0l-48,48A8,8,0,0,0,85.66,77.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
<span class="status">Choose or Drop file</span>
<input type="file" id="file" tab-index="-1"/>
</button>
{% if current_user.is_authenticated %}
<div class="upload-panel">
<span class="click-off" onclick="closeUploadTab()"></span>
<div class="container">
<span id="dragIndicator"></span>
<h3>Upload stuffs</h3>
<p>May the world see your stuff 👀</p>
<form id="uploadForm">
<button class="fileDrop-block" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H80a8,8,0,0,1,0,16H32v64H224V136H176a8,8,0,0,1,0-16h48A16,16,0,0,1,240,136ZM85.66,77.66,120,43.31V128a8,8,0,0,0,16,0V43.31l34.34,34.35a8,8,0,0,0,11.32-11.32l-48-48a8,8,0,0,0-11.32,0l-48,48A8,8,0,0,0,85.66,77.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
<span class="status">Choose or Drop file</span>
<input type="file" id="file" tab-index="-1"/>
</button>
<input class="input-block" type="text" placeholder="alt" id="alt"/>
<input class="input-block" type="text" placeholder="description" id="description"/>
<input class="input-block" type="text" placeholder="tags" id="tags"/>
<button class="btn-block" type="submit">Upload</button>
</form>
<div class="upload-jobs"></div>
</div>
<input class="input-block" type="text" placeholder="alt" id="alt"/>
<input class="input-block" type="text" placeholder="description" id="description"/>
<input class="input-block" type="text" placeholder="tags" id="tags"/>
<button class="btn-block" type="submit">Upload</button>
</form>
<div class="upload-jobs"></div>
</div>
</div>
{% endif %}
<div class="content">

View file

@ -8,7 +8,7 @@
<div class="banner-content">
<h1>Profile</h1>
<p>Hello {{ g.user['username'] }}</p>
<p>Hello {{ current_user.username }}</p>
</div>
</div>

View file

@ -8,13 +8,14 @@ import logging
from datetime import datetime as dt
import platformdirs
from flask import Blueprint, send_from_directory, abort, flash, jsonify, request, g, current_app
from flask import Blueprint, send_from_directory, abort, flash, jsonify, request, current_app
from werkzeug.utils import secure_filename
from flask_login import login_required, current_user
from colorthief import ColorThief
from sqlalchemy.orm import sessionmaker
from gallery.auth import login_required
from gallery import db
from gallery.utils import metadata as mt
@ -83,7 +84,7 @@ def upload():
img_colors = ColorThief(img_path).get_palette(color_count=3) # Get color palette
# Save to database
query = db.Posts(author_id=g.user.id,
query = db.Posts(author_id=current_user.id,
created_at=dt.utcnow(),
file_name=img_name+'.'+img_ext,
file_type=img_ext,
@ -109,7 +110,7 @@ def delete_image(image_id):
# Check if image exists and if user is allowed to delete it (author)
if img is None:
abort(404)
if img.author_id != g.user.id:
if img.author_id != current_user.id:
abort(403)
# Delete file
@ -148,7 +149,7 @@ def create_group():
"""
new_group = db.Groups(name=request.form['name'],
description=request.form['description'],
author_id=g.user.id,
author_id=current_user.id,
created_at=dt.utcnow())
db_session.add(new_group)
@ -170,7 +171,7 @@ def modify_group():
if group is None:
abort(404)
elif group.author_id != g.user.id:
elif group.author_id != current_user.id:
abort(403)
if request.form['action'] == 'add':

View file

@ -2,9 +2,7 @@
OnlyLegs - Settings page
"""
from flask import Blueprint, render_template
from gallery.auth import login_required
from flask_login import login_required
blueprint = Blueprint('settings', __name__, url_prefix='/settings')