mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2024-12-29 10:56:10 +00:00
Switch to Flask-SQLAlchemy
Add FLask-Migrate for next step in the Migration 😉
This commit is contained in:
parent
7d0078ea9a
commit
7c553e99b8
|
@ -2,41 +2,31 @@
|
||||||
Onlylegs Gallery
|
Onlylegs Gallery
|
||||||
This is the main app file, it loads all the other files and sets up the app
|
This is the main app file, it loads all the other files and sets up the app
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Import system modules
|
# Import system modules
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Flask
|
# Flask
|
||||||
from flask_compress import Compress
|
from flask_assets import Bundle
|
||||||
from flask_caching import Cache
|
|
||||||
from flask_assets import Environment, Bundle
|
|
||||||
from flask_login import LoginManager
|
|
||||||
from flask import Flask, render_template, abort
|
from flask import Flask, render_template, abort
|
||||||
from werkzeug.exceptions import HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
|
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 import api
|
||||||
|
from gallery import auth
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
import platformdirs
|
import platformdirs
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from yaml import safe_load
|
from yaml import safe_load
|
||||||
|
|
||||||
# Import database
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
from gallery import db
|
|
||||||
|
|
||||||
|
|
||||||
USER_DIR = platformdirs.user_config_dir("onlylegs")
|
USER_DIR = platformdirs.user_config_dir("onlylegs")
|
||||||
|
|
||||||
|
|
||||||
db_session = sessionmaker(bind=db.engine)
|
def create_app(): # pylint: disable=R0914
|
||||||
db_session = db_session()
|
|
||||||
login_manager = LoginManager()
|
|
||||||
assets = Environment()
|
|
||||||
cache = Cache(config={"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_TIMEOUT": 300})
|
|
||||||
compress = Compress()
|
|
||||||
|
|
||||||
|
|
||||||
def create_app(test_config=None): # pylint: disable=R0914
|
|
||||||
"""
|
"""
|
||||||
Create and configure the main app
|
Create and configure the main app
|
||||||
"""
|
"""
|
||||||
|
@ -54,7 +44,7 @@ def create_app(test_config=None): # pylint: disable=R0914
|
||||||
# App configuration
|
# App configuration
|
||||||
app.config.from_mapping(
|
app.config.from_mapping(
|
||||||
SECRET_KEY=os.environ.get("FLASK_SECRET"),
|
SECRET_KEY=os.environ.get("FLASK_SECRET"),
|
||||||
DATABASE=os.path.join(app.instance_path, "gallery.sqlite3"),
|
SQLALCHEMY_DATABASE_URI=("sqlite:///gallery.sqlite3"),
|
||||||
UPLOAD_FOLDER=os.path.join(USER_DIR, "uploads"),
|
UPLOAD_FOLDER=os.path.join(USER_DIR, "uploads"),
|
||||||
ALLOWED_EXTENSIONS=conf["upload"]["allowed-extensions"],
|
ALLOWED_EXTENSIONS=conf["upload"]["allowed-extensions"],
|
||||||
MAX_CONTENT_LENGTH=1024 * 1024 * conf["upload"]["max-size"],
|
MAX_CONTENT_LENGTH=1024 * 1024 * conf["upload"]["max-size"],
|
||||||
|
@ -63,10 +53,8 @@ def create_app(test_config=None): # pylint: disable=R0914
|
||||||
WEBSITE_CONF=conf["website"],
|
WEBSITE_CONF=conf["website"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if test_config is None:
|
db.init_app(app)
|
||||||
app.config.from_pyfile("config.py", silent=True)
|
migrate.init_app(app, db)
|
||||||
else:
|
|
||||||
app.config.from_mapping(test_config)
|
|
||||||
|
|
||||||
login_manager.init_app(app)
|
login_manager.init_app(app)
|
||||||
login_manager.login_view = "gallery.index"
|
login_manager.login_view = "gallery.index"
|
||||||
|
@ -74,7 +62,7 @@ def create_app(test_config=None): # pylint: disable=R0914
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
def load_user(user_id):
|
def load_user(user_id):
|
||||||
return db_session.query(db.Users).filter_by(alt_id=user_id).first()
|
return Users.query.filter_by(alt_id=user_id).first()
|
||||||
|
|
||||||
@login_manager.unauthorized_handler
|
@login_manager.unauthorized_handler
|
||||||
def unauthorized():
|
def unauthorized():
|
||||||
|
@ -82,23 +70,6 @@ def create_app(test_config=None): # pylint: disable=R0914
|
||||||
msg = "You are not authorized to view this page!!!!"
|
msg = "You are not authorized to view this page!!!!"
|
||||||
return render_template("error.html", error=error, msg=msg), error
|
return render_template("error.html", error=error, msg=msg), error
|
||||||
|
|
||||||
scripts = Bundle(
|
|
||||||
"js/*.js",
|
|
||||||
filters="jsmin",
|
|
||||||
output="gen/js.js",
|
|
||||||
depends="js/*.js"
|
|
||||||
)
|
|
||||||
|
|
||||||
styles = Bundle(
|
|
||||||
"sass/*.sass",
|
|
||||||
filters="libsass, cssmin",
|
|
||||||
output="gen/styles.css",
|
|
||||||
depends="sass/**/*.sass",
|
|
||||||
)
|
|
||||||
|
|
||||||
assets.register("scripts", scripts)
|
|
||||||
assets.register("styles", styles)
|
|
||||||
|
|
||||||
# Error handlers, if the error is not a HTTP error, return 500
|
# Error handlers, if the error is not a HTTP error, return 500
|
||||||
@app.errorhandler(Exception)
|
@app.errorhandler(Exception)
|
||||||
def error_page(err): # noqa
|
def error_page(err): # noqa
|
||||||
|
@ -109,30 +80,30 @@ def create_app(test_config=None): # pylint: disable=R0914
|
||||||
err.code,
|
err.code,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Load login, registration and logout manager
|
scripts = Bundle("js/*.js", filters="jsmin", output="gen/js.js", depends="js/*.js")
|
||||||
from gallery import auth
|
|
||||||
|
|
||||||
|
styles = Bundle(
|
||||||
|
"sass/*.sass",
|
||||||
|
filters="libsass, cssmin",
|
||||||
|
output="gen/styles.css",
|
||||||
|
depends="sass/**/*.sass",
|
||||||
|
)
|
||||||
|
|
||||||
|
assets.register("scripts", scripts)
|
||||||
|
assets.register("styles", styles)
|
||||||
|
|
||||||
|
# Load all the blueprints
|
||||||
app.register_blueprint(auth.blueprint)
|
app.register_blueprint(auth.blueprint)
|
||||||
|
|
||||||
# Load the API
|
|
||||||
from gallery import api
|
|
||||||
|
|
||||||
app.register_blueprint(api.blueprint)
|
app.register_blueprint(api.blueprint)
|
||||||
|
|
||||||
# Load the different views
|
|
||||||
from gallery.views import index, image, group, settings, profile
|
|
||||||
|
|
||||||
app.register_blueprint(index.blueprint)
|
app.register_blueprint(index.blueprint)
|
||||||
app.register_blueprint(image.blueprint)
|
app.register_blueprint(image.blueprint)
|
||||||
app.register_blueprint(group.blueprint)
|
app.register_blueprint(group.blueprint)
|
||||||
app.register_blueprint(profile.blueprint)
|
app.register_blueprint(profile.blueprint)
|
||||||
app.register_blueprint(settings.blueprint)
|
app.register_blueprint(settings.blueprint)
|
||||||
|
|
||||||
# Log to file that the app has started
|
|
||||||
logging.info("Gallery started successfully!")
|
|
||||||
|
|
||||||
# Initialize extensions and return app
|
|
||||||
assets.init_app(app)
|
assets.init_app(app)
|
||||||
cache.init_app(app)
|
cache.init_app(app)
|
||||||
compress.init_app(app)
|
compress.init_app(app)
|
||||||
|
|
||||||
|
logging.info("Gallery started successfully!")
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -14,16 +14,14 @@ from flask_login import login_required, current_user
|
||||||
|
|
||||||
from colorthief import ColorThief
|
from colorthief import ColorThief
|
||||||
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
from gallery.extensions import db
|
||||||
|
from gallery.models import Posts, Groups, GroupJunction
|
||||||
|
|
||||||
from gallery import db
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/file/<file_name>", methods=["GET"])
|
@blueprint.route("/file/<file_name>", methods=["GET"])
|
||||||
|
@ -87,7 +85,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 = db.Posts(
|
query = Posts(
|
||||||
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,
|
||||||
|
@ -97,8 +95,8 @@ def upload():
|
||||||
alt=form["alt"],
|
alt=form["alt"],
|
||||||
)
|
)
|
||||||
|
|
||||||
db_session.add(query)
|
db.session.add(query)
|
||||||
db_session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return "Gwa Gwa" # Return something so the browser doesn't show an error
|
return "Gwa Gwa" # Return something so the browser doesn't show an error
|
||||||
|
|
||||||
|
@ -109,7 +107,7 @@ def delete_image(image_id):
|
||||||
"""
|
"""
|
||||||
Deletes an image from the server and database
|
Deletes an image from the server and database
|
||||||
"""
|
"""
|
||||||
img = db_session.query(db.Posts).filter_by(id=image_id).first()
|
img = Posts.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 img is None:
|
||||||
|
@ -131,16 +129,15 @@ def delete_image(image_id):
|
||||||
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)
|
||||||
|
|
||||||
# Delete from database
|
post = Posts.query.filter_by(id=image_id).first()
|
||||||
db_session.query(db.Posts).filter_by(id=image_id).delete()
|
db.session.delete(post)
|
||||||
|
|
||||||
# Remove all entries in junction table
|
groups = GroupJunction.query.filter_by(post_id=image_id).all()
|
||||||
groups = db_session.query(db.GroupJunction).filter_by(post_id=image_id).all()
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
db_session.delete(group)
|
db.session.delete(group)
|
||||||
|
|
||||||
# Commit all changes
|
# 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, img.filename)
|
||||||
flash(["Image was all in Le Head!", "1"])
|
flash(["Image was all in Le Head!", "1"])
|
||||||
|
@ -153,14 +150,14 @@ def create_group():
|
||||||
"""
|
"""
|
||||||
Creates a group
|
Creates a group
|
||||||
"""
|
"""
|
||||||
new_group = db.Groups(
|
new_group = Groups(
|
||||||
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
db_session.add(new_group)
|
db.session.add(new_group)
|
||||||
db_session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return ":3"
|
return ":3"
|
||||||
|
|
||||||
|
@ -175,7 +172,7 @@ def modify_group():
|
||||||
image_id = request.form["image"]
|
image_id = request.form["image"]
|
||||||
action = request.form["action"]
|
action = request.form["action"]
|
||||||
|
|
||||||
group = db_session.query(db.Groups).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)
|
||||||
|
@ -183,20 +180,12 @@ def modify_group():
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
if action == "add":
|
if action == "add":
|
||||||
if not (
|
if not GroupJunction.query.filter_by(group_id=group_id, post_id=image_id).first():
|
||||||
db_session.query(db.GroupJunction)
|
db.session.add(GroupJunction(group_id=group_id, post_id=image_id))
|
||||||
.filter_by(group_id=group_id, post_id=image_id)
|
|
||||||
.first()
|
|
||||||
):
|
|
||||||
db_session.add(db.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).first())
|
||||||
db_session.query(db.GroupJunction)
|
|
||||||
.filter_by(group_id=group_id, post_id=image_id)
|
|
||||||
.delete()
|
|
||||||
)
|
|
||||||
|
|
||||||
db_session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return ":3"
|
return ":3"
|
||||||
|
|
||||||
|
@ -208,16 +197,21 @@ def delete_group():
|
||||||
"""
|
"""
|
||||||
group_id = request.form["group"]
|
group_id = request.form["group"]
|
||||||
|
|
||||||
group = db_session.query(db.Groups).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)
|
||||||
|
|
||||||
db_session.query(db.Groups).filter_by(id=group_id).delete()
|
group_del = Groups.query.filter_by(id=group_id).first()
|
||||||
db_session.query(db.GroupJunction).filter_by(group_id=group_id).delete()
|
db.session.delete(group_del)
|
||||||
db_session.commit()
|
|
||||||
|
junction_del = GroupJunction.query.filter_by(group_id=group_id).all()
|
||||||
|
for junction in junction_del:
|
||||||
|
db.session.delete(junction)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
flash(["Group yeeted!", "1"])
|
flash(["Group yeeted!", "1"])
|
||||||
return ":3"
|
return ":3"
|
||||||
|
|
|
@ -10,13 +10,11 @@ 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 sqlalchemy.orm import sessionmaker
|
from gallery.extensions import db
|
||||||
from gallery import db
|
from gallery.models import Users
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("auth", __name__, url_prefix="/auth")
|
blueprint = Blueprint("auth", __name__, url_prefix="/auth")
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/login", methods=["POST"])
|
@blueprint.route("/login", methods=["POST"])
|
||||||
|
@ -30,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 = db_session.query(db.Users).filter_by(username=username).first()
|
user = Users.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)
|
||||||
|
@ -79,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 = db_session.query(db.Users).filter_by(username=username).first()
|
user_exists = Users.query.filter_by(username=username).first()
|
||||||
if user_exists:
|
if user_exists:
|
||||||
error.append("User already exists!")
|
error.append("User already exists!")
|
||||||
|
|
||||||
|
@ -93,8 +91,8 @@ def register():
|
||||||
email=email,
|
email=email,
|
||||||
password=generate_password_hash(password, method="sha256"),
|
password=generate_password_hash(password, method="sha256"),
|
||||||
)
|
)
|
||||||
db_session.add(register_user)
|
db.session.add(register_user)
|
||||||
db_session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
logging.info("User %s registered", username)
|
logging.info("User %s registered", username)
|
||||||
return "ok", 200
|
return "ok", 200
|
||||||
|
|
153
gallery/db.py
153
gallery/db.py
|
@ -1,153 +0,0 @@
|
||||||
"""
|
|
||||||
OnlyLegs - Database models and ions for SQLAlchemy
|
|
||||||
"""
|
|
||||||
from uuid import uuid4
|
|
||||||
import os
|
|
||||||
import platformdirs
|
|
||||||
|
|
||||||
from sqlalchemy import (
|
|
||||||
create_engine,
|
|
||||||
Column,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
DateTime,
|
|
||||||
ForeignKey,
|
|
||||||
PickleType,
|
|
||||||
func,
|
|
||||||
)
|
|
||||||
from sqlalchemy.orm import declarative_base, relationship
|
|
||||||
from flask_login import UserMixin
|
|
||||||
|
|
||||||
|
|
||||||
USER_DIR = platformdirs.user_config_dir("onlylegs")
|
|
||||||
DB_PATH = os.path.join(USER_DIR, "instance", "gallery.sqlite3")
|
|
||||||
|
|
||||||
|
|
||||||
# In the future, I want to add support for other databases
|
|
||||||
engine = create_engine(f"sqlite:///{DB_PATH}", echo=False)
|
|
||||||
base = declarative_base()
|
|
||||||
|
|
||||||
|
|
||||||
class Users(base, UserMixin): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
User table
|
|
||||||
Joins with post, groups, session and log
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "users"
|
|
||||||
|
|
||||||
# Gallery used information
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
alt_id = Column(String, unique=True, nullable=False, default=str(uuid4()))
|
|
||||||
profile_picture = Column(String, nullable=True, default=None)
|
|
||||||
username = Column(String, unique=True, nullable=False)
|
|
||||||
email = Column(String, unique=True, nullable=False)
|
|
||||||
password = Column(String, nullable=False)
|
|
||||||
joined_at = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
|
|
||||||
posts = relationship("Posts", backref="users")
|
|
||||||
groups = relationship("Groups", backref="users")
|
|
||||||
log = relationship("Logs", backref="users")
|
|
||||||
|
|
||||||
def get_id(self):
|
|
||||||
return str(self.alt_id)
|
|
||||||
|
|
||||||
|
|
||||||
class Posts(base): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
Post table
|
|
||||||
Joins with group_junction
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "posts"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
author_id = Column(Integer, ForeignKey("users.id"))
|
|
||||||
created_at = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
filename = Column(String, unique=True, nullable=False)
|
|
||||||
mimetype = Column(String, nullable=False)
|
|
||||||
exif = Column(PickleType, nullable=False)
|
|
||||||
colours = Column(PickleType, nullable=False)
|
|
||||||
description = Column(String, nullable=False)
|
|
||||||
alt = Column(String, nullable=False)
|
|
||||||
|
|
||||||
junction = relationship("GroupJunction", backref="posts")
|
|
||||||
|
|
||||||
|
|
||||||
class Groups(base): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
Group table
|
|
||||||
Joins with group_junction
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "groups"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
name = Column(String, nullable=False)
|
|
||||||
description = Column(String, nullable=False)
|
|
||||||
author_id = Column(Integer, ForeignKey("users.id"))
|
|
||||||
created_at = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
|
|
||||||
junction = relationship("GroupJunction", backref="groups")
|
|
||||||
|
|
||||||
|
|
||||||
class GroupJunction(base): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
Junction table for posts and groups
|
|
||||||
Joins with posts and groups
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "group_junction"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
date_added = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
group_id = Column(Integer, ForeignKey("groups.id"))
|
|
||||||
post_id = Column(Integer, ForeignKey("posts.id"))
|
|
||||||
|
|
||||||
|
|
||||||
class Logs(base): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
Log table
|
|
||||||
Joins with user
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "logs"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"))
|
|
||||||
ip_address = Column(String, nullable=False)
|
|
||||||
code = Column(Integer, nullable=False)
|
|
||||||
note = Column(String, nullable=False)
|
|
||||||
created_at = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Bans(base): # pylint: disable=too-few-public-methods, C0103
|
|
||||||
"""
|
|
||||||
Bans table
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "bans"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
ip_address = Column(String, nullable=False)
|
|
||||||
code = Column(Integer, nullable=False)
|
|
||||||
note = Column(String, nullable=False)
|
|
||||||
banned_at = Column(
|
|
||||||
DateTime, nullable=False, server_default=func.now() # pylint: disable=E1102
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# check if database file exists, if not create it
|
|
||||||
if not os.path.isfile(DB_PATH):
|
|
||||||
base.metadata.create_all(engine)
|
|
||||||
print("Database created")
|
|
13
gallery/extensions.py
Normal file
13
gallery/extensions.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_migrate import Migrate
|
||||||
|
from flask_login import LoginManager
|
||||||
|
from flask_assets import Environment
|
||||||
|
from flask_compress import Compress
|
||||||
|
from flask_caching import Cache
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
migrate = Migrate()
|
||||||
|
login_manager = LoginManager()
|
||||||
|
assets = Environment()
|
||||||
|
compress = Compress()
|
||||||
|
cache = Cache(config={"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_TIMEOUT": 300})
|
138
gallery/models.py
Normal file
138
gallery/models.py
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
"""
|
||||||
|
OnlyLegs - Database models and ions for SQLAlchemy
|
||||||
|
"""
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from flask_login import UserMixin
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
Junction table for posts and groups
|
||||||
|
Joins with posts and groups
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "group_junction"
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
date_added = db.Column(
|
||||||
|
db.DateTime,
|
||||||
|
nullable=False,
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
Log table
|
||||||
|
Joins with user
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "logs"
|
||||||
|
|
||||||
|
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)
|
||||||
|
code = db.Column(db.Integer, nullable=False)
|
||||||
|
note = db.Column(db.String, nullable=False)
|
||||||
|
created_at = db.Column(
|
||||||
|
db.DateTime,
|
||||||
|
nullable=False,
|
||||||
|
server_default=db.func.now(), # pylint: disable=E1102
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Bans(db.Model): # pylint: disable=too-few-public-methods, C0103
|
||||||
|
"""
|
||||||
|
Bans table
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "bans"
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
ip_address = db.Column(db.String, nullable=False)
|
||||||
|
code = db.Column(db.Integer, nullable=False)
|
||||||
|
note = db.Column(db.String, nullable=False)
|
||||||
|
banned_at = db.Column(
|
||||||
|
db.DateTime,
|
||||||
|
nullable=False,
|
||||||
|
server_default=db.func.now(), # pylint: disable=E1102
|
||||||
|
)
|
|
@ -5,14 +5,11 @@ 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 sqlalchemy.orm import sessionmaker
|
from gallery.models import Posts, Users, GroupJunction, Groups
|
||||||
from gallery import db
|
|
||||||
from gallery.utils import contrast
|
from gallery.utils import contrast
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("group", __name__, url_prefix="/group")
|
blueprint = Blueprint("group", __name__, url_prefix="/group")
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/", methods=["GET"])
|
@blueprint.route("/", methods=["GET"])
|
||||||
|
@ -20,21 +17,21 @@ def groups():
|
||||||
"""
|
"""
|
||||||
Group overview, shows all image groups
|
Group overview, shows all image groups
|
||||||
"""
|
"""
|
||||||
groups = db_session.query(db.Groups).all()
|
groups = Groups.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 = (
|
||||||
db_session.query(db.Users.username)
|
Users.query.with_entities(Users.username)
|
||||||
.filter(db.Users.id == group.author_id)
|
.filter(Users.id == group.author_id)
|
||||||
.first()[0]
|
.first()[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the 3 most recent images
|
# Get the 3 most recent images
|
||||||
images = (
|
images = (
|
||||||
db_session.query(db.GroupJunction.post_id)
|
GroupJunction.query.with_entities(GroupJunction.post_id)
|
||||||
.filter(db.GroupJunction.group_id == group.id)
|
.filter(GroupJunction.group_id == group.id)
|
||||||
.order_by(db.GroupJunction.date_added.desc())
|
.order_by(GroupJunction.date_added.desc())
|
||||||
.limit(3)
|
.limit(3)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,10 +39,10 @@ def groups():
|
||||||
group.images = []
|
group.images = []
|
||||||
for image in images:
|
for image in images:
|
||||||
group.images.append(
|
group.images.append(
|
||||||
db_session.query(
|
Posts.query.with_entities(
|
||||||
db.Posts.filename, db.Posts.alt, db.Posts.colours, db.Posts.id
|
Posts.filename, Posts.alt, Posts.colours, Posts.id
|
||||||
)
|
)
|
||||||
.filter(db.Posts.id == image[0])
|
.filter(Posts.id == image[0])
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,32 +55,30 @@ 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 = db_session.query(db.Groups).filter(db.Groups.id == group_id).first()
|
group = Groups.query.filter(Groups.id == group_id).first()
|
||||||
|
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, "Group not found! D:")
|
abort(404, "Group not found! D:")
|
||||||
|
|
||||||
# Get the group's author username
|
# Get the group's author username
|
||||||
group.author_username = (
|
group.author_username = (
|
||||||
db_session.query(db.Users.username)
|
Users.query.with_entities(Users.username)
|
||||||
.filter(db.Users.id == group.author_id)
|
.filter(Users.id == group.author_id)
|
||||||
.first()[0]
|
.first()[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get all images in the group from the junction table
|
# Get all images in the group from the junction table
|
||||||
junction = (
|
junction = (
|
||||||
db_session.query(db.GroupJunction.post_id)
|
GroupJunction.query.with_entities(GroupJunction.post_id)
|
||||||
.filter(db.GroupJunction.group_id == group_id)
|
.filter(GroupJunction.group_id == group_id)
|
||||||
.order_by(db.GroupJunction.date_added.desc())
|
.order_by(GroupJunction.date_added.desc())
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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(
|
images.append(Posts.query.filter(Posts.id == image[0]).first())
|
||||||
db_session.query(db.Posts).filter(db.Posts.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))"
|
||||||
|
@ -103,21 +98,21 @@ 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 = db_session.query(db.Posts).filter(db.Posts.id == image_id).first()
|
image = Posts.query.filter(Posts.id == image_id).first()
|
||||||
if image is None:
|
if image is None:
|
||||||
abort(404, "Image not found")
|
abort(404, "Image not found")
|
||||||
|
|
||||||
# Get the image's author username
|
# Get the image's author username
|
||||||
image.author_username = (
|
image.author_username = (
|
||||||
db_session.query(db.Users.username)
|
Users.query.with_entities(Users.username)
|
||||||
.filter(db.Users.id == image.author_id)
|
.filter(Users.id == image.author_id)
|
||||||
.first()[0]
|
.first()[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get all groups the image is in
|
# Get all groups the image is in
|
||||||
groups = (
|
groups = (
|
||||||
db_session.query(db.GroupJunction.group_id)
|
GroupJunction.query.with_entities(GroupJunction.group_id)
|
||||||
.filter(db.GroupJunction.post_id == image_id)
|
.filter(GroupJunction.post_id == image_id)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -125,24 +120,24 @@ 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(
|
||||||
db_session.query(db.Groups.id, db.Groups.name)
|
Groups.query.with_entities(Groups.id, Groups.name)
|
||||||
.filter(db.Groups.id == group[0])
|
.filter(Groups.id == group[0])
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the next and previous images in the group
|
# Get the next and previous images in the group
|
||||||
next_url = (
|
next_url = (
|
||||||
db_session.query(db.GroupJunction.post_id)
|
GroupJunction.query.with_entities(GroupJunction.post_id)
|
||||||
.filter(db.GroupJunction.group_id == group_id)
|
.filter(GroupJunction.group_id == group_id)
|
||||||
.filter(db.GroupJunction.post_id > image_id)
|
.filter(GroupJunction.post_id > image_id)
|
||||||
.order_by(db.GroupJunction.date_added.asc())
|
.order_by(GroupJunction.date_added.asc())
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
prev_url = (
|
prev_url = (
|
||||||
db_session.query(db.GroupJunction.post_id)
|
GroupJunction.query.with_entities(GroupJunction.post_id)
|
||||||
.filter(db.GroupJunction.group_id == group_id)
|
.filter(GroupJunction.group_id == group_id)
|
||||||
.filter(db.GroupJunction.post_id < image_id)
|
.filter(GroupJunction.post_id < image_id)
|
||||||
.order_by(db.GroupJunction.date_added.desc())
|
.order_by(GroupJunction.date_added.desc())
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,10 @@ from math import ceil
|
||||||
|
|
||||||
from flask import Blueprint, abort, render_template, url_for, current_app
|
from flask import Blueprint, abort, render_template, url_for, current_app
|
||||||
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
from gallery.models import Posts, Users, GroupJunction, Groups
|
||||||
from gallery import db
|
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("image", __name__, url_prefix="/image")
|
blueprint = Blueprint("image", __name__, url_prefix="/image")
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/<int:image_id>")
|
@blueprint.route("/<int:image_id>")
|
||||||
|
@ -20,21 +17,21 @@ 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 = db_session.query(db.Posts).filter(db.Posts.id == image_id).first()
|
image = Posts.query.filter(Posts.id == image_id).first()
|
||||||
if not image:
|
if not image:
|
||||||
abort(404, "Image not found :<")
|
abort(404, "Image not found :<")
|
||||||
|
|
||||||
# Get the image's author username
|
# Get the image's author username
|
||||||
image.author_username = (
|
image.author_username = (
|
||||||
db_session.query(db.Users.username)
|
Users.query.with_entities(Users.username)
|
||||||
.filter(db.Users.id == image.author_id)
|
.filter(Users.id == image.author_id)
|
||||||
.first()[0]
|
.first()[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the image's groups
|
# Get the image's groups
|
||||||
groups = (
|
groups = (
|
||||||
db_session.query(db.GroupJunction.group_id)
|
GroupJunction.query.with_entities(GroupJunction.group_id)
|
||||||
.filter(db.GroupJunction.post_id == image_id)
|
.filter(GroupJunction.post_id == image_id)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,23 +39,23 @@ def image(image_id):
|
||||||
image.groups = []
|
image.groups = []
|
||||||
for group in groups:
|
for group in groups:
|
||||||
image.groups.append(
|
image.groups.append(
|
||||||
db_session.query(db.Groups.id, db.Groups.name)
|
Groups.query.with_entities(Groups.name, Groups.id)
|
||||||
.filter(db.Groups.id == group[0])
|
.filter(Groups.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 = (
|
||||||
db_session.query(db.Posts.id)
|
Posts.query.with_entities(Posts.id)
|
||||||
.filter(db.Posts.id > image_id)
|
.filter(Posts.id > image_id)
|
||||||
.order_by(db.Posts.id.asc())
|
.order_by(Posts.id.asc())
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
prev_url = (
|
prev_url = (
|
||||||
db_session.query(db.Posts.id)
|
Posts.query.with_entities(Posts.id)
|
||||||
.filter(db.Posts.id < image_id)
|
.filter(Posts.id < image_id)
|
||||||
.order_by(db.Posts.id.desc())
|
.order_by(Posts.id.desc())
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,7 +66,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 = db_session.query(db.Posts.id).order_by(db.Posts.id.desc()).all()
|
total_images = Posts.query.with_entities(Posts.id).order_by(Posts.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,13 +6,10 @@ 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 sqlalchemy.orm import sessionmaker
|
from gallery.models import Posts
|
||||||
from gallery import db
|
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("gallery", __name__)
|
blueprint = Blueprint("gallery", __name__)
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/")
|
@blueprint.route("/")
|
||||||
|
@ -30,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 = db_session.query(db.Posts.id).count()
|
total_images = Posts.query.with_entities(Posts.id).count()
|
||||||
pages = ceil(max(total_images, limit) / limit)
|
pages = ceil(max(total_images, limit) / limit)
|
||||||
if page > pages:
|
if page > pages:
|
||||||
abort(
|
abort(
|
||||||
|
@ -41,14 +38,10 @@ def index():
|
||||||
|
|
||||||
# get the images for the current page
|
# get the images for the current page
|
||||||
images = (
|
images = (
|
||||||
db_session.query(
|
Posts.query.with_entities(
|
||||||
db.Posts.filename,
|
Posts.filename, Posts.alt, Posts.colours, Posts.created_at, Posts.id
|
||||||
db.Posts.alt,
|
|
||||||
db.Posts.colours,
|
|
||||||
db.Posts.created_at,
|
|
||||||
db.Posts.id,
|
|
||||||
)
|
)
|
||||||
.order_by(db.Posts.id.desc())
|
.order_by(Posts.id.desc())
|
||||||
.offset((page - 1) * limit)
|
.offset((page - 1) * limit)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.all()
|
.all()
|
||||||
|
|
|
@ -5,13 +5,10 @@ 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 sqlalchemy.orm import sessionmaker
|
from gallery.models import Posts, Users
|
||||||
from gallery import db
|
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("profile", __name__, url_prefix="/profile")
|
blueprint = Blueprint("profile", __name__, url_prefix="/profile")
|
||||||
db_session = sessionmaker(bind=db.engine)
|
|
||||||
db_session = db_session()
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/profile")
|
@blueprint.route("/profile")
|
||||||
|
@ -29,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 = db_session.query(db.Users).filter(db.Users.id == user_id).first()
|
user = Users.query.filter(Users.id == user_id).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
abort(404, "User not found :c")
|
abort(404, "User not found :c")
|
||||||
|
|
||||||
images = db_session.query(db.Posts).filter(db.Posts.author_id == user_id).all()
|
images = Posts.query.filter(Posts.author_id == user_id).all()
|
||||||
|
|
||||||
return render_template("profile.html", user=user, images=images)
|
return render_template("profile.html", user=user, images=images)
|
||||||
|
|
175
poetry.lock
generated
175
poetry.lock
generated
|
@ -1,5 +1,27 @@
|
||||||
# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alembic"
|
||||||
|
version = "1.10.3"
|
||||||
|
description = "A database migration tool for SQLAlchemy."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "alembic-1.10.3-py3-none-any.whl", hash = "sha256:b2e0a6cfd3a8ce936a1168320bcbe94aefa3f4463cd773a968a55071beb3cd37"},
|
||||||
|
{file = "alembic-1.10.3.tar.gz", hash = "sha256:32a69b13a613aeb7e8093f242da60eff9daed13c0df02fff279c1b06c32965d2"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
importlib-metadata = {version = "*", markers = "python_version < \"3.9\""}
|
||||||
|
importlib-resources = {version = "*", markers = "python_version < \"3.9\""}
|
||||||
|
Mako = "*"
|
||||||
|
SQLAlchemy = ">=1.3.0"
|
||||||
|
typing-extensions = ">=4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tz = ["python-dateutil"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "astroid"
|
name = "astroid"
|
||||||
version = "2.15.2"
|
version = "2.15.2"
|
||||||
|
@ -192,79 +214,6 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
graph = ["objgraph (>=1.7.2)"]
|
graph = ["objgraph (>=1.7.2)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dukpy"
|
|
||||||
version = "0.3.0"
|
|
||||||
description = "Simple JavaScript interpreter for Python"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47ed8813baf52ad3e3a7d4c7416173af0693bbfab1f3b685cbf0165e0e376769"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4b3a69977d89c83d74e64a5feb7264acb007c251e2eb83bc4e79c818b73b4fc"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:782e60979db86f7ae9d5e84185cf6c252954cbcfda982353dd30ff6a17fef0be"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3698f35c184b3319257d4d7bfa796ef109e8f78fc3cef8e22a3bf0f2d0eef774"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bd7f6ded168548d808e3a3ac97ccf98ee1a97c327e7e67c13229932f3c923f85"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e044f3e78881f3c1fc0b939349551a9be2e2519d4e670038ce497d7cc780c69"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-win32.whl", hash = "sha256:c1827f1f7282bb0cc329c7f687c0f58d87f5736777e553f483c26636e9bd1960"},
|
|
||||||
{file = "dukpy-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:d9697701eb1a01c0044479b3fa501685adc1a699ffe1acbb39b0b724bc1a7bac"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c189ae4b5c5deb2b576cd0b0ae0193dbd7e15a1499491b3798f3ed7aae8274b1"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:531db11c50326c1baa00711a8221995ec0935418c690d02a84ef9ce537968686"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c072d28ff58db698eb5bfa4556f59e5ce4d4f219b176c93375bfda87c117253f"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8171990e640625ad5876a0548072220ebd34c9f0705510144082ce34a2e777b"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:74e0a194e8908bfa64ea2e2e353cf28184d498ed675174a96d948ac2dd6db24e"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0aebd4be1109e58126ff4e959415f3198390b92dc48cf6144b97caeb786cf0df"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-win32.whl", hash = "sha256:ff24928cf9c14af226cf575640e2166611a79d8fd14ea498183ca7cd7ab349e5"},
|
|
||||||
{file = "dukpy-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:a96a600ce653c5fb9c7190af8c1e82b7d212709dfdd31ce65a2e328cbd923dd6"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:581bbd180a7d69149a1b3171d987a8d1eedf988ce3d138ca2e1730888012e41a"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0636f4658024033427907b3a67b9bbc9c405fd7ee1f924ec1b1eca070d7a6efb"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1628e9171e900d2b97e45a22709e68f91bb88ef8dbabfc0c1f4f92524eeb900e"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:2c1576a480656ee4bce9bb2f471623b894c8ab809617bdf08b8f547a990df063"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:87202891b5dd85053321b561173ebbe84ceab58f9cd4e6c028686e5793bfc976"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-win32.whl", hash = "sha256:6b2ef5b42a666d4cd73618dce1b9b182c02f15cf52598aef4047e0ecbed2f4ed"},
|
|
||||||
{file = "dukpy-0.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6e16d07a506e79af132a7d1b4d28b7846d1e980a8a965130bfe755f56922f35e"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7708973d15bc01c91e68195338f9db0a6d4b1e663e2a778da2db00b8c27e7488"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:218c26430b424cd2fa4a8a0e252acf835719ee2107937d01c7bbc15615b07e0d"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d1f25e485a77e1318b95db43717454001e412adec0ba268dfc8eecf3b893d45"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5a1614b73884c14a00b496384d2e793bfd07dfcac425eb1fe768e5b870118111"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005579d0e3fd7ab35e18138da3172baa59e3305f22a55fbe9961c67204b1ddd"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-win32.whl", hash = "sha256:e59a93c819cb818251e7d8ad0b548163227fec3b8485c4cdcecfac59abd9db87"},
|
|
||||||
{file = "dukpy-0.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d10c0cd5035e3e2dc27d193734537546f1910d2dc0ccd468bb510924313bbaa2"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3bee97f928e0477a197fcc66f25a8d46d1ebc7068ddda2f657445cced303111b"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bd7e8b90590122b92e8057052e485afdcc4a6145e50036cc55deac045dd6568f"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2feb5c2d05b3c9b8fafc9088c5c025a14c9e239f96abb1aa75ebc022f1777e9c"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09ae9309490fc578da96611fc50e46f02c32616e53f55f2bc9c864f67e6c759e"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf7412d2d6883fe0ff498cbdb0e67e16804972cf216c169d83aa8d5bad50d109"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a8e06c2402031e030924088b37bbde27cf43936bf8ff0ff65c9bdfd9bf4ae89c"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-win32.whl", hash = "sha256:d87b932a387d4015d9acdb99b94c788453b19b5aa5fd10584098e042d8c7118a"},
|
|
||||||
{file = "dukpy-0.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e31213f8cbbf85d0386f0ea0e478cd0e4dd918a8747d568a6936044dbd21330c"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:49f6390bbc47b618fdb19d7af89e73f643f308a2ab9f5d5e0eb161d4508f23c6"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a95ff658b7400e71acaab453359ea74d1a1625cebb937d0294a053b6aac3e507"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9087a3321649beb17f91afa6ffde991d477aa0029c3be5ce908369517ac85251"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6acc3a3ce997aef380f79f1985636d87701c1841707c0748ee5eff65e396f0b2"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1329be71ce19fdda899a0b59cd531b711adc0d30867488f7401b38b518415a9"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0c6ebf8e495f9750f2820cdedfe384621369ebef562ed52770d7a9f070e5991e"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-win32.whl", hash = "sha256:6ae877b9d439941e2afcaaaa410ef168c51e885f99665bf591b97a71eafaeb0f"},
|
|
||||||
{file = "dukpy-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:1a8df866eb0af6b55f1a27786f5217334a4e904fd04b7c285c4ee5b684072abe"},
|
|
||||||
{file = "dukpy-0.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b895adaab9feaec6e33ba221bcfc16bd50710b18346077b8cec06e843355fb6"},
|
|
||||||
{file = "dukpy-0.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2edf126a5c8da0b1ffc39381323d3129cf922d041c74c78402652c9efdf74c99"},
|
|
||||||
{file = "dukpy-0.3.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f0f517d245b69781ad91dcb6d9d1a9550b2dbb0d8b636b9e8899838780ad211"},
|
|
||||||
{file = "dukpy-0.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:99f76adf6f9c40b0501d7fffc1570a7b7dc4eaf8b2d3cb38ac738068ba2731e6"},
|
|
||||||
{file = "dukpy-0.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eca56334b67370427c503b65f21424d317b7560620e28809b4852828a9fcea54"},
|
|
||||||
{file = "dukpy-0.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3da5a1bc3ce7788ed05cc16fc67f9be5e187ed4f6fedcf1fd6574633a5230be"},
|
|
||||||
{file = "dukpy-0.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cb574f3b71545adbccbb7688059b1a63eca057c59ac00004a6de196eb95844a"},
|
|
||||||
{file = "dukpy-0.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b4b068796a4d81c37673e9d949a6307dbadc2cd6c2062b6010bd6561a24895fb"},
|
|
||||||
{file = "dukpy-0.3.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:87a9ea4cb2593220e0c6abc6a0b5849e940de78c1e464fe6a4339efe655fd3af"},
|
|
||||||
{file = "dukpy-0.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1185f27c920889a41e189ba8a2c76211ee84be1ea1bb4c1f7cc4343f9a1a3d2c"},
|
|
||||||
{file = "dukpy-0.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a60d5b3537800944cb6e8bedbf68a724dea92a6f9a8ce9a48530838e68478716"},
|
|
||||||
{file = "dukpy-0.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:157280c79833f223f3dc6effe8981525e68cd262e26947b2cddd57addac9a3d8"},
|
|
||||||
{file = "dukpy-0.3.0.tar.gz", hash = "sha256:ca5772e9373f3cf7772a711e65db765c4361dcf6d4e65c5d88cb879e9ee3f5a6"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
testing = ["mock", "pytest", "pytest-cov"]
|
|
||||||
webassets = ["webassets"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flask"
|
name = "flask"
|
||||||
version = "2.2.3"
|
version = "2.2.3"
|
||||||
|
@ -352,6 +301,39 @@ files = [
|
||||||
Flask = ">=1.0.4"
|
Flask = ">=1.0.4"
|
||||||
Werkzeug = ">=1.0.1"
|
Werkzeug = ">=1.0.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flask-migrate"
|
||||||
|
version = "4.0.4"
|
||||||
|
description = "SQLAlchemy database migrations for Flask applications using Alembic."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "Flask-Migrate-4.0.4.tar.gz", hash = "sha256:73293d40b10ac17736e715b377e7b7bde474cb8105165d77474df4c3619b10b3"},
|
||||||
|
{file = "Flask_Migrate-4.0.4-py3-none-any.whl", hash = "sha256:77580f27ab39bc68be4906a43c56d7674b45075bc4f883b1d0b985db5164d58f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
alembic = ">=1.9.0"
|
||||||
|
Flask = ">=0.9"
|
||||||
|
Flask-SQLAlchemy = ">=1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flask-sqlalchemy"
|
||||||
|
version = "3.0.3"
|
||||||
|
description = "Add SQLAlchemy support to your Flask application."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "Flask-SQLAlchemy-3.0.3.tar.gz", hash = "sha256:2764335f3c9d7ebdc9ed6044afaf98aae9fa50d7a074cef55dde307ec95903ec"},
|
||||||
|
{file = "Flask_SQLAlchemy-3.0.3-py3-none-any.whl", hash = "sha256:add5750b2f9cd10512995261ee2aa23fab85bd5626061aa3c564b33bb4aa780a"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Flask = ">=2.2"
|
||||||
|
SQLAlchemy = ">=1.4.18"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "greenlet"
|
name = "greenlet"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
|
@ -449,14 +431,14 @@ tornado = ["tornado (>=0.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "importlib-metadata"
|
name = "importlib-metadata"
|
||||||
version = "6.2.0"
|
version = "6.2.1"
|
||||||
description = "Read metadata from Python packages"
|
description = "Read metadata from Python packages"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "importlib_metadata-6.2.0-py3-none-any.whl", hash = "sha256:8388b74023a138c605fddd0d47cb81dd706232569f56c9aca7d9c7fdb54caeba"},
|
{file = "importlib_metadata-6.2.1-py3-none-any.whl", hash = "sha256:f65e478a7c2177bd19517a3a15dac094d253446d8690c5f3e71e735a04312374"},
|
||||||
{file = "importlib_metadata-6.2.0.tar.gz", hash = "sha256:9127aad2f49d7203e7112098c12b92e4fd1061ccd18548cdfdc49171a8c073cc"},
|
{file = "importlib_metadata-6.2.1.tar.gz", hash = "sha256:5a66966b39ff1c14ef5b2d60c1d842b0141fefff0f4cc6365b4bc9446c652807"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
@ -467,6 +449,25 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker
|
||||||
perf = ["ipython"]
|
perf = ["ipython"]
|
||||||
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
|
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "importlib-resources"
|
||||||
|
version = "5.12.0"
|
||||||
|
description = "Read resources from Python packages"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"},
|
||||||
|
{file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||||
|
testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "isort"
|
name = "isort"
|
||||||
version = "5.12.0"
|
version = "5.12.0"
|
||||||
|
@ -587,6 +588,26 @@ files = [
|
||||||
{file = "libsass-0.22.0.tar.gz", hash = "sha256:3ab5ad18e47db560f4f0c09e3d28cf3bb1a44711257488ac2adad69f4f7f8425"},
|
{file = "libsass-0.22.0.tar.gz", hash = "sha256:3ab5ad18e47db560f4f0c09e3d28cf3bb1a44711257488ac2adad69f4f7f8425"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mako"
|
||||||
|
version = "1.2.4"
|
||||||
|
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"},
|
||||||
|
{file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
MarkupSafe = ">=0.9.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
babel = ["Babel"]
|
||||||
|
lingua = ["lingua"]
|
||||||
|
testing = ["pytest"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markupsafe"
|
name = "markupsafe"
|
||||||
version = "2.1.2"
|
version = "2.1.2"
|
||||||
|
@ -1115,4 +1136,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "8ff06b3873e6466deca84a8258f87f8aa250072d02e30564fbd554e826754e61"
|
content-hash = "88387c49c901feebd4685ee75f6b79c0bbc8cc9c1a64798cd0394b140e165603"
|
||||||
|
|
|
@ -9,19 +9,20 @@ readme = ".github/README.md"
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.8"
|
||||||
Flask = "^2.2.2"
|
Flask = "^2.2.2"
|
||||||
|
Flask-Sqlalchemy = "^3.0.3"
|
||||||
|
Flask-Migrate = "^4.0.4"
|
||||||
Flask-Compress = "^1.13"
|
Flask-Compress = "^1.13"
|
||||||
Flask-Caching = "^2.0.2"
|
Flask-Caching = "^2.0.2"
|
||||||
Flask-Assets = "^2.0"
|
Flask-Assets = "^2.0"
|
||||||
Flask-Login = "^0.6.2"
|
Flask-Login = "^0.6.2"
|
||||||
SQLAlchemy = "^2.0.3"
|
|
||||||
python-dotenv = "^0.21.0"
|
python-dotenv = "^0.21.0"
|
||||||
gunicorn = "^20.1.0"
|
gunicorn = "^20.1.0"
|
||||||
pyyaml = "^6.0"
|
pyyaml = "^6.0"
|
||||||
libsass = "^0.22.0"
|
|
||||||
colorthief = "^0.2.1"
|
colorthief = "^0.2.1"
|
||||||
Pillow = "^9.4.0"
|
Pillow = "^9.4.0"
|
||||||
platformdirs = "^3.0.0"
|
platformdirs = "^3.0.0"
|
||||||
pylint = "^2.16.3"
|
pylint = "^2.16.3"
|
||||||
|
libsass = "^0.22.0"
|
||||||
jsmin = "^3.0.1"
|
jsmin = "^3.0.1"
|
||||||
cssmin = "^0.2.0"
|
cssmin = "^0.2.0"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue