mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2024-12-29 10:56:10 +00:00
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:
parent
9a21064dd5
commit
d36699bd1f
|
@ -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():
|
||||||
|
|
|
@ -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"])
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 }}">
|
||||||
|
|
|
@ -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()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue