Update database

Correctly link user to their posts and groups
Change the table names to Group, Post and User
Remove unused Bans and Logs table, possibly will return later
This commit is contained in:
Michał 2023-04-12 15:16:43 +00:00
parent 9a21064dd5
commit d36699bd1f
12 changed files with 185 additions and 270 deletions

View file

@ -17,8 +17,8 @@ from werkzeug.exceptions import HTTPException
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from gallery.extensions import db, migrate, login_manager, assets, compress, cache from gallery.extensions import db, migrate, login_manager, assets, compress, cache
from gallery.models import Users
from gallery.views import index, image, group, settings, profile from gallery.views import index, image, group, settings, profile
from gallery.models import User
from gallery import api from gallery import api
from gallery import auth from gallery import auth
@ -44,7 +44,7 @@ def create_app(): # pylint: disable=R0914
with app.app_context(): with app.app_context():
db.create_all() db.create_all()
register_user = Users( register_user = User(
username=app.config["ADMIN_CONF"]["username"], username=app.config["ADMIN_CONF"]["username"],
email=app.config["ADMIN_CONF"]["email"], email=app.config["ADMIN_CONF"]["email"],
password=generate_password_hash('changeme!', method="sha256"), password=generate_password_hash('changeme!', method="sha256"),
@ -81,7 +81,7 @@ def create_app(): # pylint: disable=R0914
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
return Users.query.filter_by(alt_id=user_id).first() return User.query.filter_by(alt_id=user_id).first()
@login_manager.unauthorized_handler @login_manager.unauthorized_handler
def unauthorized(): def unauthorized():

View file

@ -14,7 +14,7 @@ from flask_login import login_required, current_user
from colorthief import ColorThief from colorthief import ColorThief
from gallery.extensions import db from gallery.extensions import db
from gallery.models import Posts, Groups, GroupJunction from gallery.models import Post, Group, GroupJunction
from gallery.utils import metadata as mt from gallery.utils import metadata as mt
from gallery.utils.generate_image import generate_thumbnail from gallery.utils.generate_image import generate_thumbnail
@ -83,7 +83,7 @@ def upload():
img_colors = ColorThief(img_path).get_palette(color_count=3) # Get color palette img_colors = ColorThief(img_path).get_palette(color_count=3) # Get color palette
# Save to database # Save to database
query = Posts( query = Post(
author_id=current_user.id, author_id=current_user.id,
filename=img_name + "." + img_ext, filename=img_name + "." + img_ext,
mimetype=img_ext, mimetype=img_ext,
@ -105,39 +105,33 @@ def delete_image(image_id):
""" """
Deletes an image from the server and database Deletes an image from the server and database
""" """
img = Posts.query.filter_by(id=image_id).first() post = Post.query.filter_by(id=image_id).first()
# Check if image exists and if user is allowed to delete it (author) # Check if image exists and if user is allowed to delete it (author)
if img is None: if post is None:
abort(404) abort(404)
if img.author_id != current_user.id: if post.author_id != current_user.id:
abort(403) abort(403)
# Delete file # Delete file
try: try:
os.remove(os.path.join(current_app.config["UPLOAD_FOLDER"], img.filename)) os.remove(os.path.join(current_app.config["UPLOAD_FOLDER"], post.filename))
except FileNotFoundError: except FileNotFoundError:
logging.warning( logging.warning(
"File not found: %s, already deleted or never existed", img.filename "File not found: %s, already deleted or never existed", post.filename
) )
# Delete cached files # Delete cached files
cache_path = os.path.join(platformdirs.user_config_dir("onlylegs"), "cache") cache_path = os.path.join(platformdirs.user_config_dir("onlylegs"), "cache")
cache_name = img.filename.rsplit(".")[0] cache_name = post.filename.rsplit(".")[0]
for cache_file in pathlib.Path(cache_path).glob(cache_name + "*"): for cache_file in pathlib.Path(cache_path).glob(cache_name + "*"):
os.remove(cache_file) os.remove(cache_file)
post = Posts.query.filter_by(id=image_id).first() GroupJunction.query.filter_by(post_id=image_id).delete()
db.session.delete(post) db.session.delete(post)
groups = GroupJunction.query.filter_by(post_id=image_id).all()
for group in groups:
db.session.delete(group)
# Commit all changes
db.session.commit() db.session.commit()
logging.info("Removed image (%s) %s", image_id, img.filename) logging.info("Removed image (%s) %s", image_id, post.filename)
flash(["Image was all in Le Head!", "1"]) flash(["Image was all in Le Head!", "1"])
return "Gwa Gwa" return "Gwa Gwa"
@ -148,7 +142,7 @@ def create_group():
""" """
Creates a group Creates a group
""" """
new_group = Groups( new_group = Group(
name=request.form["name"], name=request.form["name"],
description=request.form["description"], description=request.form["description"],
author_id=current_user.id, author_id=current_user.id,
@ -170,25 +164,18 @@ def modify_group():
image_id = request.form["image"] image_id = request.form["image"]
action = request.form["action"] action = request.form["action"]
group = Groups.query.filter_by(id=group_id).first() group = db.get_or_404(Group, group_id)
image = db.get_or_404(Post, image_id)
if group is None: if group.author_id != current_user.id:
abort(404)
elif group.author_id != current_user.id:
abort(403) abort(403)
if action == "add": if action == "add" and not GroupJunction.query.filter_by(group_id=group_id, post_id=image_id).first():
if not GroupJunction.query.filter_by( db.session.add(GroupJunction(group_id=group_id, post_id=image_id))
group_id=group_id, post_id=image_id
).first():
db.session.add(GroupJunction(group_id=group_id, post_id=image_id))
elif request.form["action"] == "remove": elif request.form["action"] == "remove":
db.session.delete( GroupJunction.query.filter_by(group_id=group_id, post_id=image_id).delete()
GroupJunction.query.filter_by(group_id=group_id, post_id=image_id).first()
)
db.session.commit() db.session.commit()
return ":3" return ":3"
@ -198,21 +185,15 @@ def delete_group():
Deletes a group Deletes a group
""" """
group_id = request.form["group"] group_id = request.form["group"]
group = Group.query.filter_by(id=group_id).first()
group = Groups.query.filter_by(id=group_id).first()
if group is None: if group is None:
abort(404) abort(404)
elif group.author_id != current_user.id: elif group.author_id != current_user.id:
abort(403) abort(403)
group_del = Groups.query.filter_by(id=group_id).first() GroupJunction.query.filter_by(group_id=group_id).delete()
db.session.delete(group_del) db.session.delete(group)
junction_del = GroupJunction.query.filter_by(group_id=group_id).all()
for junction in junction_del:
db.session.delete(junction)
db.session.commit() db.session.commit()
flash(["Group yeeted!", "1"]) flash(["Group yeeted!", "1"])

View file

@ -11,7 +11,7 @@ from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import login_user, logout_user, login_required from flask_login import login_user, logout_user, login_required
from gallery.extensions import db from gallery.extensions import db
from gallery.models import Users from gallery.models import User
blueprint = Blueprint("auth", __name__, url_prefix="/auth") blueprint = Blueprint("auth", __name__, url_prefix="/auth")
@ -28,7 +28,7 @@ def login():
password = request.form["password"].strip() password = request.form["password"].strip()
remember = bool(request.form["remember-me"]) remember = bool(request.form["remember-me"])
user = Users.query.filter_by(username=username).first() user = User.query.filter_by(username=username).first()
if not user or not check_password_hash(user.password, password): if not user or not check_password_hash(user.password, password):
logging.error("Login attempt from %s", request.remote_addr) logging.error("Login attempt from %s", request.remote_addr)
@ -77,7 +77,7 @@ def register():
elif password_repeat != password: elif password_repeat != password:
error.append("Passwords do not match!") error.append("Passwords do not match!")
user_exists = Users.query.filter_by(username=username).first() user_exists = User.query.filter_by(username=username).first()
if user_exists: if user_exists:
error.append("User already exists!") error.append("User already exists!")
@ -86,7 +86,7 @@ def register():
print(error) print(error)
return jsonify(error), 400 return jsonify(error), 400
register_user = Users( register_user = User(
username=username, username=username,
email=email, email=email,
password=generate_password_hash(password, method="sha256"), password=generate_password_hash(password, method="sha256"),

View file

@ -2,137 +2,99 @@
OnlyLegs - Database models and ions for SQLAlchemy OnlyLegs - Database models and ions for SQLAlchemy
""" """
from uuid import uuid4 from uuid import uuid4
from flask_login import UserMixin from flask_login import UserMixin
from .extensions import db from .extensions import db
class Users(db.Model, UserMixin): # pylint: disable=too-few-public-methods, C0103
"""
User table
Joins with post, groups, session and log
"""
__tablename__ = "users"
# Gallery used information
id = db.Column(db.Integer, primary_key=True)
alt_id = db.Column(db.String, unique=True, nullable=False, default=str(uuid4()))
profile_picture = db.Column(db.String, nullable=True, default=None)
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
joined_at = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(), # pylint: disable=E1102
)
posts = db.relationship("Posts", backref="users")
groups = db.relationship("Groups", backref="users")
log = db.relationship("Logs", backref="users")
def get_id(self):
return str(self.alt_id)
class Posts(db.Model): # pylint: disable=too-few-public-methods, C0103
"""
Post table
Joins with group_junction
"""
__tablename__ = "posts"
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.Integer, db.ForeignKey("users.id"))
created_at = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(), # pylint: disable=E1102
)
filename = db.Column(db.String, unique=True, nullable=False)
mimetype = db.Column(db.String, nullable=False)
exif = db.Column(db.PickleType, nullable=False)
colours = db.Column(db.PickleType, nullable=False)
description = db.Column(db.String, nullable=False)
alt = db.Column(db.String, nullable=False)
junction = db.relationship("GroupJunction", backref="posts")
class Groups(db.Model): # pylint: disable=too-few-public-methods, C0103
"""
Group table
Joins with group_junction
"""
__tablename__ = "groups"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
description = db.Column(db.String, nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey("users.id"))
created_at = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(), # pylint: disable=E1102
)
junction = db.relationship("GroupJunction", backref="groups")
class GroupJunction(db.Model): # pylint: disable=too-few-public-methods, C0103 class GroupJunction(db.Model): # pylint: disable=too-few-public-methods, C0103
""" """
Junction table for posts and groups Junction table for posts and groups
Joins with posts and groups Joins with posts and groups
""" """
__tablename__ = "group_junction" __tablename__ = "group_junction"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey("group.id"))
post_id = db.Column(db.Integer, db.ForeignKey("post.id"))
date_added = db.Column( date_added = db.Column(
db.DateTime, db.DateTime,
nullable=False, nullable=False,
server_default=db.func.now(), # pylint: disable=E1102 server_default=db.func.now(), # pylint: disable=E1102
) )
group_id = db.Column(db.Integer, db.ForeignKey("groups.id"))
post_id = db.Column(db.Integer, db.ForeignKey("posts.id"))
class Logs(db.Model): # pylint: disable=too-few-public-methods, C0103 class Post(db.Model): # pylint: disable=too-few-public-methods, C0103
""" """
Log table Post table
Joins with user
""" """
__tablename__ = "post"
__tablename__ = "logs"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
ip_address = db.Column(db.String, nullable=False) author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
code = db.Column(db.Integer, nullable=False)
note = db.Column(db.String, nullable=False) filename = db.Column(db.String, unique=True, nullable=False)
mimetype = db.Column(db.String, nullable=False)
exif = db.Column(db.PickleType, nullable=False)
colours = db.Column(db.PickleType, nullable=False)
description = db.Column(db.String, nullable=False)
alt = db.Column(db.String, nullable=False)
created_at = db.Column( created_at = db.Column(
db.DateTime, db.DateTime,
nullable=False, nullable=False,
server_default=db.func.now(), # pylint: disable=E1102 server_default=db.func.now(), # pylint: disable=E1102
) )
junction = db.relationship("GroupJunction", backref="posts")
class Group(db.Model): # pylint: disable=too-few-public-methods, C0103
class Bans(db.Model): # pylint: disable=too-few-public-methods, C0103
""" """
Bans table Group table
""" """
__tablename__ = "group"
__tablename__ = "bans"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
ip_address = db.Column(db.String, nullable=False)
code = db.Column(db.Integer, nullable=False) name = db.Column(db.String, nullable=False)
note = db.Column(db.String, nullable=False) description = db.Column(db.String, nullable=False)
banned_at = db.Column(
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
created_at = db.Column(
db.DateTime, db.DateTime,
nullable=False, nullable=False,
server_default=db.func.now(), # pylint: disable=E1102 server_default=db.func.now(), # pylint: disable=E1102
) )
junction = db.relationship("GroupJunction", backref="groups")
class User(db.Model, UserMixin): # pylint: disable=too-few-public-methods, C0103
"""
User table
"""
__tablename__ = "user"
# Gallery used information
id = db.Column(db.Integer, primary_key=True)
alt_id = db.Column(db.String, unique=True, nullable=False, default=str(uuid4()))
profile_picture = db.Column(db.String, nullable=True, default=None)
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
joined_at = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(), # pylint: disable=E1102
)
posts = db.relationship('Post', backref='author')
groups = db.relationship('Group', backref='author')
def get_id(self):
return str(self.alt_id)

View file

@ -15,7 +15,7 @@
} }
} }
{% if current_user.id == group.author_id %} {% if current_user.id == group.author.id %}
function groupDelete() { function groupDelete() {
cancelBtn = document.createElement('button'); cancelBtn = document.createElement('button');
cancelBtn.classList.add('btn-block'); cancelBtn.classList.add('btn-block');
@ -223,7 +223,7 @@
<img src="{{ url_for('api.file', file_name=images.0.filename ) }}?r=prev" onload="imgFade(this)" style="opacity:0;" alt="{% if images.0.alt %}{{ images.0.alt }}{% else %}Group Banner{% endif %}"/> <img src="{{ url_for('api.file', file_name=images.0.filename ) }}?r=prev" onload="imgFade(this)" style="opacity:0;" alt="{% if images.0.alt %}{{ images.0.alt }}{% else %}Group Banner{% endif %}"/>
<span class="banner-filter"></span> <span class="banner-filter"></span>
<div class="banner-content"> <div class="banner-content">
<p class="banner-info"><a href="{{ url_for('profile.profile', id=group.author_id) }}" class="link">By {{ group.author_username }}</a></p> <p class="banner-info"><a href="{{ url_for('profile.profile', id=group.author.id) }}" class="link">By {{ group.author.username }}</a></p>
<h1 class="banner-header">{{ group.name }}</h1> <h1 class="banner-header">{{ group.name }}</h1>
<p class="banner-subtitle">{{ images|length }} Images · {{ group.description }}</p> <p class="banner-subtitle">{{ images|length }} Images · {{ group.description }}</p>
<div class="pill-row"> <div class="pill-row">
@ -232,7 +232,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,112v96a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V112A16,16,0,0,1,56,96H80a8,8,0,0,1,0,16H56v96H200V112H176a8,8,0,0,1,0-16h24A16,16,0,0,1,216,112ZM93.66,69.66,120,43.31V136a8,8,0,0,0,16,0V43.31l26.34,26.35a8,8,0,0,0,11.32-11.32l-40-40a8,8,0,0,0-11.32,0l-40,40A8,8,0,0,0,93.66,69.66Z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,112v96a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V112A16,16,0,0,1,56,96H80a8,8,0,0,1,0,16H56v96H200V112H176a8,8,0,0,1,0-16h24A16,16,0,0,1,216,112ZM93.66,69.66,120,43.31V136a8,8,0,0,0,16,0V43.31l26.34,26.35a8,8,0,0,0,11.32-11.32l-40-40a8,8,0,0,0-11.32,0l-40,40A8,8,0,0,0,93.66,69.66Z"></path></svg>
</button> </button>
</div> </div>
{% if current_user.id == group.author_id %} {% if current_user.id == group.author.id %}
<div> <div>
<button class="pill-item pill__critical" onclick="groupDelete()"> <button class="pill-item pill__critical" onclick="groupDelete()">
<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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg> <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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
@ -249,14 +249,14 @@
<div class="banner-small"> <div class="banner-small">
<div class="banner-content"> <div class="banner-content">
<h1 class="banner-header">{{ group.name }}</h1> <h1 class="banner-header">{{ group.name }}</h1>
<p class="banner-info">By {{ group.author_username }}</p> <p class="banner-info">By {{ group.author.username }}</p>
<div class="pill-row"> <div class="pill-row">
<div> <div>
<button class="pill-item" onclick="groupShare()"> <button class="pill-item" onclick="groupShare()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,112v96a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V112A16,16,0,0,1,56,96H80a8,8,0,0,1,0,16H56v96H200V112H176a8,8,0,0,1,0-16h24A16,16,0,0,1,216,112ZM93.66,69.66,120,43.31V136a8,8,0,0,0,16,0V43.31l26.34,26.35a8,8,0,0,0,11.32-11.32l-40-40a8,8,0,0,0-11.32,0l-40,40A8,8,0,0,0,93.66,69.66Z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M216,112v96a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V112A16,16,0,0,1,56,96H80a8,8,0,0,1,0,16H56v96H200V112H176a8,8,0,0,1,0-16h24A16,16,0,0,1,216,112ZM93.66,69.66,120,43.31V136a8,8,0,0,0,16,0V43.31l26.34,26.35a8,8,0,0,0,11.32-11.32l-40-40a8,8,0,0,0-11.32,0l-40,40A8,8,0,0,0,93.66,69.66Z"></path></svg>
</button> </button>
</div> </div>
{% if current_user.id == group.author_id %} {% if current_user.id == group.author.id %}
<div> <div>
<button class="pill-item pill__critical" onclick="groupDelete()"> <button class="pill-item pill__critical" onclick="groupDelete()">
<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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg> <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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>

View file

@ -27,7 +27,7 @@
} }
} }
{% if current_user.id == image.author_id %} {% if current_user.id == image.author.id %}
function imageDelete() { function imageDelete() {
cancelBtn = document.createElement('button'); cancelBtn = document.createElement('button');
cancelBtn.classList.add('btn-block'); cancelBtn.classList.add('btn-block');
@ -120,7 +120,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Zm-42.34-61.66a8,8,0,0,1,0,11.32l-24,24a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L120,164.69V120a8,8,0,0,1,16,0v44.69l10.34-10.35A8,8,0,0,1,157.66,154.34Z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Zm-42.34-61.66a8,8,0,0,1,0,11.32l-24,24a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L120,164.69V120a8,8,0,0,1,16,0v44.69l10.34-10.35A8,8,0,0,1,157.66,154.34Z"></path></svg>
</a> </a>
</div> </div>
{% if current_user.id == image.author_id %} {% if current_user.id == image.author.id %}
<div> <div>
<button class="pill-item pill__critical" onclick="imageDelete()"> <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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg> <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-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
@ -155,7 +155,7 @@
<table> <table>
<tr> <tr>
<td>Author</td> <td>Author</td>
<td><a href="{{ url_for('profile.profile', id=image.author_id) }}" class="link">{{ image.author_username }}</a></td> <td><a href="{{ url_for('profile.profile', id=image.author.id) }}" class="link">{{ image.author.username }}</a></td>
</tr> </tr>
<tr> <tr>
<td>Upload date</td> <td>Upload date</td>

View file

@ -70,7 +70,7 @@
<div class="navigation"> <div class="navigation">
<!--<img src="{{url_for('static', filename='icon.png')}}" alt="Logo" class="logo" onload="this.style.opacity=1;" style="opacity:0">--> <!--<img src="{{url_for('static', filename='icon.png')}}" alt="Logo" class="logo" onload="this.style.opacity=1;" style="opacity:0">-->
<a href="{{url_for('gallery.index')}}{% block page_index %}{% endblock %}" class="navigation-item {% block nav_home %}{% endblock %}"> <a href="{{ url_for('gallery.index') }}{% block page_index %}{% endblock %}" class="navigation-item {% block nav_home %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M208,32H80A16,16,0,0,0,64,48V64H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V192h16a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM80,48H208v69.38l-16.7-16.7a16,16,0,0,0-22.62,0L93.37,176H80Zm96,160H48V80H64v96a16,16,0,0,0,16,16h96ZM104,88a16,16,0,1,1,16,16A16,16,0,0,1,104,88Z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M208,32H80A16,16,0,0,0,64,48V64H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V192h16a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM80,48H208v69.38l-16.7-16.7a16,16,0,0,0-22.62,0L93.37,176H80Zm96,160H48V80H64v96a16,16,0,0,0,16,16h96ZM104,88a16,16,0,1,1,16,16A16,16,0,0,1,104,88Z"></path></svg>
<span class="tool-tip"> <span class="tool-tip">
Home Home
@ -78,7 +78,7 @@
</span> </span>
</a> </a>
<a href="{{url_for('group.groups')}}" class="navigation-item {% block nav_groups %}{% endblock %}"> <a href="{{ url_for('group.groups') }}" class="navigation-item {% block nav_groups %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M245,110.64A16,16,0,0,0,232,104H216V88a16,16,0,0,0-16-16H130.67L102.94,51.2a16.14,16.14,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V208h0a8,8,0,0,0,8,8H211.1a8,8,0,0,0,7.59-5.47l28.49-85.47A16.05,16.05,0,0,0,245,110.64ZM93.34,64l27.73,20.8a16.12,16.12,0,0,0,9.6,3.2H200v16H146.43a16,16,0,0,0-8.88,2.69l-20,13.31H69.42a15.94,15.94,0,0,0-14.86,10.06L40,166.46V64Z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M245,110.64A16,16,0,0,0,232,104H216V88a16,16,0,0,0-16-16H130.67L102.94,51.2a16.14,16.14,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V208h0a8,8,0,0,0,8,8H211.1a8,8,0,0,0,7.59-5.47l28.49-85.47A16.05,16.05,0,0,0,245,110.64ZM93.34,64l27.73,20.8a16.12,16.12,0,0,0,9.6,3.2H200v16H146.43a16,16,0,0,0-8.88,2.69l-20,13.31H69.42a15.94,15.94,0,0,0-14.86,10.06L40,166.46V64Z"></path></svg>
<span class="tool-tip"> <span class="tool-tip">
Groups Groups
@ -87,66 +87,66 @@
</a> </a>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<button class="navigation-item {% block nav_upload %}{% endblock %}" onclick="toggleUploadTab()"> <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> <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"> <span class="tool-tip">
Upload 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> <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> </span>
</button> </button>
{% endif %} {% endif %}
<span class="navigation-spacer"></span> <span class="navigation-spacer"></span>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<a href="{{url_for('profile.profile')}}" class="navigation-item {% block nav_profile %}{% endblock %}"> <a href="{{ url_for('profile.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> <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"> <span class="tool-tip">
Profile 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> <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> </span>
</a> </a>
<a href="{{url_for('settings.general')}}" class="navigation-item {% block nav_settings %}{% endblock %}"> <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> <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"> <span class="tool-tip">
Settings 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> <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> </span>
</a> </a>
{% else %} {% else %}
<button class="navigation-item {% block nav_login %}{% endblock %}" onclick="showLogin()"> <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> <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"> <span class="tool-tip">
Login 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> <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> </span>
</button> </button>
{% endif %} {% endif %}
</div> </div>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<div class="upload-panel"> <div class="upload-panel">
<span class="click-off" onclick="closeUploadTab()"></span> <span class="click-off" onclick="closeUploadTab()"></span>
<div class="container"> <div class="container">
<span id="dragIndicator"></span> <span id="dragIndicator"></span>
<h3>Upload stuffs</h3> <h3>Upload stuffs</h3>
<p>May the world see your stuff 👀</p> <p>May the world see your stuff 👀</p>
<form id="uploadForm"> <form id="uploadForm">
<button class="fileDrop-block" type="button"> <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> <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> <span class="status">Choose or Drop file</span>
<input type="file" id="file" tab-index="-1"/> <input type="file" id="file" tab-index="-1"/>
</button> </button>
<input class="input-block" type="text" placeholder="alt" id="alt"/> <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="description" id="description"/>
<input class="input-block" type="text" placeholder="tags" id="tags"/> <input class="input-block" type="text" placeholder="tags" id="tags"/>
<button class="btn-block" type="submit">Upload</button> <button class="btn-block primary" type="submit">Upload</button>
</form> </form>
<div class="upload-jobs"></div> <div class="upload-jobs"></div>
</div>
</div> </div>
</div>
{% endif %} {% endif %}
<div class="content"> <div class="content">

View file

@ -121,7 +121,7 @@
{% for group in groups %} {% for group in groups %}
<a id="group-{{ group.id }}" class="group-item" href="{{ url_for('group.group', group_id=group.id) }}" {% if group.images|length > 0 %} style="background-color: rgba({{ group.images.0.colours.0.0 }}, {{ group.images.0.colours.0.1 }}, {{ group.images.0.colours.0.2 }}, 0.4);" {% endif %}> <a id="group-{{ group.id }}" class="group-item" href="{{ url_for('group.group', group_id=group.id) }}" {% if group.images|length > 0 %} style="background-color: rgba({{ group.images.0.colours.0.0 }}, {{ group.images.0.colours.0.1 }}, {{ group.images.0.colours.0.2 }}, 0.4);" {% endif %}>
<div class="image-filter"> <div class="image-filter">
<p class="image-subtitle">By {{ group.author_username }}</p> <p class="image-subtitle">By {{ group.author.username }}</p>
<p class="image-title">{{ group.name }}</p> <p class="image-title">{{ group.name }}</p>
</div> </div>
<div class="images size-{{ group.images|length }}"> <div class="images size-{{ group.images|length }}">

View file

@ -5,7 +5,8 @@ sounds more limiting that it actually is in this gallery
""" """
from flask import Blueprint, abort, render_template, url_for from flask import Blueprint, abort, render_template, url_for
from gallery.models import Posts, Users, GroupJunction, Groups from gallery.models import Post, User, GroupJunction, Group
from gallery.extensions import db
from gallery.utils import contrast from gallery.utils import contrast
@ -17,19 +18,20 @@ def groups():
""" """
Group overview, shows all image groups Group overview, shows all image groups
""" """
groups = Groups.query.all() groups = Group.query.all()
# For each group, get the 3 most recent images # For each group, get the 3 most recent images
for group in groups: for group in groups:
group.author_username = ( group.author_username = (
Users.query.with_entities(Users.username) User.query.with_entities(User.username)
.filter(Users.id == group.author_id) .filter(User.id == group.author_id)
.first()[0] .first()[0]
) )
# Get the 3 most recent images # Get the 3 most recent images
images = ( images = (
GroupJunction.query.with_entities(GroupJunction.post_id) GroupJunction.query
.with_entities(GroupJunction.post_id)
.filter(GroupJunction.group_id == group.id) .filter(GroupJunction.group_id == group.id)
.order_by(GroupJunction.date_added.desc()) .order_by(GroupJunction.date_added.desc())
.limit(3) .limit(3)
@ -39,10 +41,9 @@ def groups():
group.images = [] group.images = []
for image in images: for image in images:
group.images.append( group.images.append(
Posts.query.with_entities( Post.query
Posts.filename, Posts.alt, Posts.colours, Posts.id .with_entities(Post.filename, Post.alt, Post.colours, Post.id)
) .filter(Post.id == image[0])
.filter(Posts.id == image[0])
.first() .first()
) )
@ -55,21 +56,12 @@ def group(group_id):
Group view, shows all images in a group Group view, shows all images in a group
""" """
# Get the group, if it doesn't exist, 404 # Get the group, if it doesn't exist, 404
group = Groups.query.filter(Groups.id == group_id).first() group = db.get_or_404(Group, group_id, description="Group not found! D:")
if group is None:
abort(404, "Group not found! D:")
# Get the group's author username
group.author_username = (
Users.query.with_entities(Users.username)
.filter(Users.id == group.author_id)
.first()[0]
)
# Get all images in the group from the junction table # Get all images in the group from the junction table
junction = ( junction = (
GroupJunction.query.with_entities(GroupJunction.post_id) GroupJunction.query
.with_entities(GroupJunction.post_id)
.filter(GroupJunction.group_id == group_id) .filter(GroupJunction.group_id == group_id)
.order_by(GroupJunction.date_added.desc()) .order_by(GroupJunction.date_added.desc())
.all() .all()
@ -78,7 +70,7 @@ def group(group_id):
# Get the image data for each image in the group # Get the image data for each image in the group
images = [] images = []
for image in junction: for image in junction:
images.append(Posts.query.filter(Posts.id == image[0]).first()) images.append(Post.query.filter(Post.id == image[0]).first())
# Check contrast for the first image in the group for the banner # Check contrast for the first image in the group for the banner
text_colour = "rgb(var(--fg-black))" text_colour = "rgb(var(--fg-black))"
@ -98,16 +90,7 @@ def group_post(group_id, image_id):
Image view, shows the image and its metadata from a specific group Image view, shows the image and its metadata from a specific group
""" """
# Get the image, if it doesn't exist, 404 # Get the image, if it doesn't exist, 404
image = Posts.query.filter(Posts.id == image_id).first() image = db.get_or_404(Post, image_id, description="Image not found :<")
if image is None:
abort(404, "Image not found")
# Get the image's author username
image.author_username = (
Users.query.with_entities(Users.username)
.filter(Users.id == image.author_id)
.first()[0]
)
# Get all groups the image is in # Get all groups the image is in
groups = ( groups = (
@ -120,8 +103,8 @@ def group_post(group_id, image_id):
image.groups = [] image.groups = []
for group in groups: for group in groups:
image.groups.append( image.groups.append(
Groups.query.with_entities(Groups.id, Groups.name) Group.query.with_entities(Group.id, Group.name)
.filter(Groups.id == group[0]) .filter(Group.id == group[0])
.first() .first()
) )

View file

@ -2,10 +2,9 @@
Onlylegs - Image View Onlylegs - Image View
""" """
from math import ceil from math import ceil
from flask import Blueprint, render_template, url_for, current_app
from flask import Blueprint, abort, render_template, url_for, current_app from gallery.models import Post, GroupJunction, Group
from gallery.extensions import db
from gallery.models import Posts, Users, GroupJunction, Groups
blueprint = Blueprint("image", __name__, url_prefix="/image") blueprint = Blueprint("image", __name__, url_prefix="/image")
@ -17,45 +16,36 @@ def image(image_id):
Image view, shows the image and its metadata Image view, shows the image and its metadata
""" """
# Get the image, if it doesn't exist, 404 # Get the image, if it doesn't exist, 404
image = Posts.query.filter(Posts.id == image_id).first() image = db.get_or_404(Post, image_id, description="Image not found :<")
if not image:
abort(404, "Image not found :<")
# Get the image's author username # Get all groups the image is in
image.author_username = (
Users.query.with_entities(Users.username)
.filter(Users.id == image.author_id)
.first()[0]
)
# Get the image's groups
groups = ( groups = (
GroupJunction.query.with_entities(GroupJunction.group_id) GroupJunction.query.with_entities(GroupJunction.group_id)
.filter(GroupJunction.post_id == image_id) .filter(GroupJunction.post_id == image_id)
.all() .all()
) )
# For each group, get the group data and add it to the image item # Get the group data for each group the image is in
image.groups = [] image.groups = []
for group in groups: for group in groups:
image.groups.append( image.groups.append(
Groups.query.with_entities(Groups.name, Groups.id) Group.query.with_entities(Group.id, Group.name)
.filter(Groups.id == group[0]) .filter(Group.id == group[0])
.first() .first()
) )
# Get the next and previous images # Get the next and previous images
# Check if there is a group ID set # Check if there is a group ID set
next_url = ( next_url = (
Posts.query.with_entities(Posts.id) Post.query.with_entities(Post.id)
.filter(Posts.id > image_id) .filter(Post.id > image_id)
.order_by(Posts.id.asc()) .order_by(Post.id.asc())
.first() .first()
) )
prev_url = ( prev_url = (
Posts.query.with_entities(Posts.id) Post.query.with_entities(Post.id)
.filter(Posts.id < image_id) .filter(Post.id < image_id)
.order_by(Posts.id.desc()) .order_by(Post.id.desc())
.first() .first()
) )
@ -66,7 +56,7 @@ def image(image_id):
prev_url = url_for("image.image", image_id=prev_url[0]) prev_url = url_for("image.image", image_id=prev_url[0])
# Yoink all the images in the database # Yoink all the images in the database
total_images = Posts.query.with_entities(Posts.id).order_by(Posts.id.desc()).all() total_images = Post.query.with_entities(Post.id).order_by(Post.id.desc()).all()
limit = current_app.config["UPLOAD_CONF"]["max-load"] limit = current_app.config["UPLOAD_CONF"]["max-load"]
# If the number of items is less than the limit, no point of calculating the page # If the number of items is less than the limit, no point of calculating the page

View file

@ -6,7 +6,7 @@ from math import ceil
from flask import Blueprint, render_template, request, current_app from flask import Blueprint, render_template, request, current_app
from werkzeug.exceptions import abort from werkzeug.exceptions import abort
from gallery.models import Posts from gallery.models import Post
blueprint = Blueprint("gallery", __name__) blueprint = Blueprint("gallery", __name__)
@ -27,7 +27,7 @@ def index():
# get the total number of images in the database # get the total number of images in the database
# calculate the total number of pages, and make sure the page number is valid # calculate the total number of pages, and make sure the page number is valid
total_images = Posts.query.with_entities(Posts.id).count() total_images = Post.query.with_entities(Post.id).count()
pages = ceil(max(total_images, limit) / limit) pages = ceil(max(total_images, limit) / limit)
if page > pages: if page > pages:
abort( abort(
@ -38,10 +38,9 @@ def index():
# get the images for the current page # get the images for the current page
images = ( images = (
Posts.query.with_entities( Post.query
Posts.filename, Posts.alt, Posts.colours, Posts.created_at, Posts.id .with_entities( Post.filename, Post.alt, Post.colours, Post.created_at, Post.id)
) .order_by(Post.id.desc())
.order_by(Posts.id.desc())
.offset((page - 1) * limit) .offset((page - 1) * limit)
.limit(limit) .limit(limit)
.all() .all()

View file

@ -5,7 +5,7 @@ from flask import Blueprint, render_template, request
from werkzeug.exceptions import abort from werkzeug.exceptions import abort
from flask_login import current_user from flask_login import current_user
from gallery.models import Posts, Users from gallery.models import Post, User
blueprint = Blueprint("profile", __name__, url_prefix="/profile") blueprint = Blueprint("profile", __name__, url_prefix="/profile")
@ -26,11 +26,11 @@ def profile():
abort(404, "You must be logged in to view your own profile!") abort(404, "You must be logged in to view your own profile!")
# Get the user's data # Get the user's data
user = Users.query.filter(Users.id == user_id).first() user = User.query.filter(User.id == user_id).first()
if not user: if not user:
abort(404, "User not found :c") abort(404, "User not found :c")
images = Posts.query.filter(Posts.author_id == user_id).all() images = Post.query.filter(Post.author_id == user_id).all()
return render_template("profile.html", user=user, images=images) return render_template("profile.html", user=user, images=images)