mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-06-29 03:26:16 +00:00
Change database structure
Update naming to something more useful Date filled in automatically
This commit is contained in:
parent
bf083a85ad
commit
4627498b8d
11 changed files with 83 additions and 89 deletions
|
@ -54,7 +54,7 @@ def create_app(test_config=None):
|
||||||
# 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.sqlite'),
|
DATABASE=os.path.join(app.instance_path, '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'],
|
||||||
|
|
|
@ -3,9 +3,7 @@ OnlyLegs - Authentication
|
||||||
User registration, login and logout and locking access to pages behind a login
|
User registration, login and logout and locking access to pages behind a login
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from uuid import uuid4
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime as dt
|
|
||||||
|
|
||||||
from flask import Blueprint, flash, redirect, request, url_for, abort, jsonify
|
from flask import Blueprint, flash, redirect, request, url_for, abort, jsonify
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
|
@ -34,7 +32,7 @@ def login():
|
||||||
|
|
||||||
user = db_session.query(db.Users).filter_by(username=username).first()
|
user = db_session.query(db.Users).filter_by(username=username).first()
|
||||||
|
|
||||||
if not user and 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)
|
||||||
error.append('Username or Password is incorrect!')
|
error.append('Username or Password is incorrect!')
|
||||||
|
|
||||||
|
@ -45,7 +43,7 @@ def login():
|
||||||
|
|
||||||
logging.info('User %s logged in from %s', username, request.remote_addr)
|
logging.info('User %s logged in from %s', username, request.remote_addr)
|
||||||
flash(['Logged in successfully!', '4'])
|
flash(['Logged in successfully!', '4'])
|
||||||
return 'gwa gwa'
|
return 'ok', 200
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/register', methods=['POST'])
|
@blueprint.route('/register', methods=['POST'])
|
||||||
|
@ -87,16 +85,16 @@ def register():
|
||||||
|
|
||||||
# If there are errors, return them
|
# If there are errors, return them
|
||||||
if error:
|
if error:
|
||||||
return jsonify(error)
|
print(error)
|
||||||
|
return jsonify(error), 400
|
||||||
|
|
||||||
register_user = db.Users(alt_id=str(uuid4()), username=username, email=email,
|
register_user = db.Users(username=username, email=email,
|
||||||
password=generate_password_hash(password, method='sha256'),
|
password=generate_password_hash(password, method='sha256'))
|
||||||
created_at=dt.utcnow())
|
|
||||||
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 'gwa gwa'
|
return 'ok', 200
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/logout')
|
@blueprint.route('/logout')
|
||||||
|
@ -106,4 +104,5 @@ def logout():
|
||||||
Clear the current session, including the stored user id
|
Clear the current session, including the stored user id
|
||||||
"""
|
"""
|
||||||
logout_user()
|
logout_user()
|
||||||
|
flash(['Goodbye!!!', '4'])
|
||||||
return redirect(url_for('gallery.index'))
|
return redirect(url_for('gallery.index'))
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
"""
|
"""
|
||||||
OnlyLegs - Database models and functions for SQLAlchemy
|
OnlyLegs - Database models and functions for SQLAlchemy
|
||||||
"""
|
"""
|
||||||
|
from uuid import uuid4
|
||||||
import os
|
import os
|
||||||
import platformdirs
|
import platformdirs
|
||||||
|
from datetime import datetime as dt
|
||||||
|
|
||||||
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey, PickleType
|
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey, PickleType
|
||||||
from sqlalchemy.orm import declarative_base, relationship
|
from sqlalchemy.orm import declarative_base, relationship
|
||||||
|
@ -11,7 +13,7 @@ from flask_login import UserMixin
|
||||||
|
|
||||||
|
|
||||||
USER_DIR = platformdirs.user_config_dir('onlylegs')
|
USER_DIR = platformdirs.user_config_dir('onlylegs')
|
||||||
DB_PATH = os.path.join(USER_DIR, 'gallery.sqlite')
|
DB_PATH = os.path.join(USER_DIR, 'instance', 'gallery.sqlite3')
|
||||||
|
|
||||||
|
|
||||||
# In the future, I want to add support for other databases
|
# In the future, I want to add support for other databases
|
||||||
|
@ -28,11 +30,12 @@ class Users (base, UserMixin): # pylint: disable=too-few-public-methods, C0103
|
||||||
|
|
||||||
# Gallery used information
|
# Gallery used information
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
alt_id = Column(String, unique=True, nullable=False)
|
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)
|
username = Column(String, unique=True, nullable=False)
|
||||||
email = Column(String, unique=True, nullable=False)
|
email = Column(String, unique=True, nullable=False)
|
||||||
password = Column(String, nullable=False)
|
password = Column(String, nullable=False)
|
||||||
created_at = Column(DateTime, nullable=False)
|
joined_at = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
|
|
||||||
posts = relationship('Posts', backref='users')
|
posts = relationship('Posts', backref='users')
|
||||||
groups = relationship('Groups', backref='users')
|
groups = relationship('Groups', backref='users')
|
||||||
|
@ -51,20 +54,16 @@ class Posts (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
author_id = Column(Integer, ForeignKey('users.id'))
|
author_id = Column(Integer, ForeignKey('users.id'))
|
||||||
created_at = Column(DateTime, nullable=False)
|
created_at = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
|
filename = Column(String, unique=True, nullable=False)
|
||||||
file_name = Column(String, unique=True, nullable=False)
|
mimetype = Column(String, nullable=False)
|
||||||
file_type = Column(String, nullable=False)
|
exif = Column(PickleType, nullable=False)
|
||||||
|
colours = Column(PickleType, nullable=False)
|
||||||
image_exif = Column(PickleType, nullable=False)
|
description = Column(String, nullable=False)
|
||||||
image_colours = Column(PickleType, nullable=False)
|
alt = Column(String, nullable=False)
|
||||||
|
|
||||||
post_description = Column(String, nullable=False)
|
|
||||||
post_alt = Column(String, nullable=False)
|
|
||||||
|
|
||||||
junction = relationship('GroupJunction', backref='posts')
|
junction = relationship('GroupJunction', backref='posts')
|
||||||
|
|
||||||
|
|
||||||
class Groups (base): # pylint: disable=too-few-public-methods, C0103
|
class Groups (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
"""
|
"""
|
||||||
Group table
|
Group table
|
||||||
|
@ -76,7 +75,7 @@ class Groups (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
description = Column(String, nullable=False)
|
description = Column(String, nullable=False)
|
||||||
author_id = Column(Integer, ForeignKey('users.id'))
|
author_id = Column(Integer, ForeignKey('users.id'))
|
||||||
created_at = Column(DateTime, nullable=False)
|
created_at = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
|
|
||||||
junction = relationship('GroupJunction', backref='groups')
|
junction = relationship('GroupJunction', backref='groups')
|
||||||
|
|
||||||
|
@ -89,7 +88,7 @@ class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
__tablename__ = 'group_junction'
|
__tablename__ = 'group_junction'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
date_added = Column(DateTime, nullable=False)
|
date_added = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
group_id = Column(Integer, ForeignKey('groups.id'))
|
group_id = Column(Integer, ForeignKey('groups.id'))
|
||||||
post_id = Column(Integer, ForeignKey('posts.id'))
|
post_id = Column(Integer, ForeignKey('posts.id'))
|
||||||
|
|
||||||
|
@ -105,8 +104,8 @@ class Logs (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
user_id = Column(Integer, ForeignKey('users.id'))
|
user_id = Column(Integer, ForeignKey('users.id'))
|
||||||
ip_address = Column(String, nullable=False)
|
ip_address = Column(String, nullable=False)
|
||||||
code = Column(Integer, nullable=False)
|
code = Column(Integer, nullable=False)
|
||||||
msg = Column(String, nullable=False)
|
note = Column(String, nullable=False)
|
||||||
created_at = Column(DateTime, nullable=False)
|
created_at = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
|
|
||||||
|
|
||||||
class Bans (base): # pylint: disable=too-few-public-methods, C0103
|
class Bans (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
|
@ -118,8 +117,8 @@ class Bans (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
ip_address = Column(String, nullable=False)
|
ip_address = Column(String, nullable=False)
|
||||||
code = Column(Integer, nullable=False)
|
code = Column(Integer, nullable=False)
|
||||||
msg = Column(String, nullable=False)
|
note = Column(String, nullable=False)
|
||||||
created_at = Column(DateTime, nullable=False)
|
banned_at = Column(DateTime, nullable=False, default=dt.utcnow())
|
||||||
|
|
||||||
|
|
||||||
# check if database file exists, if not create it
|
# check if database file exists, if not create it
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% block nav_groups %}selected{% endblock %}
|
{% block nav_groups %}selected{% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{% if images %}
|
{% if images %}
|
||||||
<meta name="theme-color" content="rgb({{ images.0.image_colours.0.0 }}{{ images.0.image_colours.0.1 }}{{ images.0.image_colours.0.2 }})"/>
|
<meta name="theme-color" content="rgb({{ images.0.colours.0.0 }}{{ images.0.colours.0.1 }}{{ images.0.colours.0.2 }})"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -175,7 +175,7 @@
|
||||||
<style>
|
<style>
|
||||||
{% if images %}
|
{% if images %}
|
||||||
.banner::after {
|
.banner::after {
|
||||||
box-shadow: 0 calc(var(--rad) * -1) 0 0 rgb({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }});
|
box-shadow: 0 calc(var(--rad) * -1) 0 0 rgb({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }});
|
||||||
}
|
}
|
||||||
.banner-content p {
|
.banner-content p {
|
||||||
color: {{ text_colour }} !important;
|
color: {{ text_colour }} !important;
|
||||||
|
@ -185,16 +185,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner-filter {
|
.banner-filter {
|
||||||
background: linear-gradient(90deg, rgb({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}), rgba({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}, 0.3)) !important;
|
background: linear-gradient(90deg, rgb({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }}), rgba({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }}, 0.3)) !important;
|
||||||
}
|
}
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
.banner-filter {
|
.banner-filter {
|
||||||
background: linear-gradient(180deg, rgba({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}, 0.8), rgba({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}, 0.5)) !important;
|
background: linear-gradient(180deg, rgba({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }}, 0.8), rgba({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }}, 0.5)) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation {
|
.navigation {
|
||||||
background-color: rgb({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}) !important;
|
background-color: rgb({{ images.0.colours.0.0 }}, {{ images.0.colours.0.1 }}, {{ images.0.colours.0.2 }}) !important;
|
||||||
}
|
}
|
||||||
.navigation-item > svg {
|
.navigation-item > svg {
|
||||||
fill: {{ text_colour }} !important;
|
fill: {{ text_colour }} !important;
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if images %}
|
{% if images %}
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<img src="{{ url_for('api.file', file_name=images.0.file_name ) }}?r=prev" onload="imgFade(this)" style="opacity:0;"/>
|
<img src="{{ url_for('api.file', file_name=images.0.filename ) }}?r=prev" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
<span class="banner-filter"></span>
|
<span class="banner-filter"></span>
|
||||||
<div class="banner-content">
|
<div class="banner-content">
|
||||||
<p class="banner-info">By {{ group.author_username }} - {{ images|length }} Images</p>
|
<p class="banner-info">By {{ group.author_username }} - {{ images|length }} Images</p>
|
||||||
|
@ -266,7 +266,7 @@
|
||||||
<p class="image-subtitle"></p>
|
<p class="image-subtitle"></p>
|
||||||
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
<img alt="{{ image.post_alt }}" data-src="{{ url_for('api.file', file_name=image.file_name) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
<img alt="{{ image.alt }}" data-src="{{ url_for('api.file', file_name=image.filename) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% block nav_groups %}selected{% endblock %}
|
{% block nav_groups %}selected{% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{% if images %}
|
{% if images %}
|
||||||
<meta name="theme-color" content="rgb({{ images.0.image_colours.0.0 }}{{ images.0.image_colours.0.1 }}{{ images.0.image_colours.0.2 }})"/>
|
<meta name="theme-color" content="rgb({{ images.0.colours.0.0 }}{{ images.0.colours.0.1 }}{{ images.0.colours.0.2 }})"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if current_user.is_authenticated %}
|
{% if current_user.is_authenticated %}
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
<div class="images size-{{ group.images|length }}">
|
<div class="images size-{{ group.images|length }}">
|
||||||
{% if group.images|length > 0 %}
|
{% if group.images|length > 0 %}
|
||||||
{% for image in group.images %}
|
{% for image in group.images %}
|
||||||
<img data-src="{{ url_for('api.file', file_name=image.file_name) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load" class="data-{{ loop.index }}"/>
|
<img data-src="{{ url_for('api.file', file_name=image.filename) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load" class="data-{{ loop.index }}"/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='error.png') }}" class="loaded"/>
|
<img src="{{ url_for('static', filename='error.png') }}" class="loaded"/>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
{% block wrapper_class %}image-wrapper{% endblock %}
|
{% block wrapper_class %}image-wrapper{% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<meta property="og:image" content="{{ url_for('api.file', file_name=image.file_name) }}"/>
|
<meta property="og:image" content="{{ url_for('api.file', file_name=image.filename) }}"/>
|
||||||
<meta name="theme-color" content="rgb({{ image.image_colours.0.0 }}{{ image.image_colours.0.1 }}{{ image.image_colours.0.2 }})"/>
|
<meta name="theme-color" content="rgb({{ image.colours.0.0 }}{{ image.colours.0.1 }}{{ image.colours.0.2 }})"/>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function imageFullscreenOff() {
|
function imageFullscreenOff() {
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
function imageFullscreenOn() {
|
function imageFullscreenOn() {
|
||||||
let fullscreen = document.querySelector('.image-fullscreen')
|
let fullscreen = document.querySelector('.image-fullscreen')
|
||||||
|
|
||||||
fullscreen.querySelector('img').src = '{{ url_for('api.file', file_name=image.file_name) }}';
|
fullscreen.querySelector('img').src = '{{ url_for('api.file', file_name=image.filename) }}';
|
||||||
|
|
||||||
document.querySelector("html").style.overflow = "hidden";
|
document.querySelector("html").style.overflow = "hidden";
|
||||||
fullscreen.style.display = 'flex';
|
fullscreen.style.display = 'flex';
|
||||||
|
@ -80,31 +80,31 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.background span {
|
.background span {
|
||||||
background-image: linear-gradient(to top, rgba({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }}, 1), transparent);
|
background-image: linear-gradient(to top, rgba({{ image.colours.0.0 }}, {{ image.colours.0.1 }}, {{ image.colours.0.2 }}, 1), transparent);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<img src="{{ url_for('api.file', file_name=image.file_name) }}?r=prev" alt="{{ image.post_alt }}" onload="imgFade(this)" style="opacity:0;"/>
|
<img src="{{ url_for('api.file', file_name=image.filename) }}?r=prev" alt="{{ image.alt }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-fullscreen" onclick="imageFullscreenOff()">
|
<div class="image-fullscreen" onclick="imageFullscreenOff()">
|
||||||
<img src="" alt="{{ image.post_alt }}"/>
|
<img src="" alt="{{ image.alt }}"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-grid">
|
<div class="image-grid">
|
||||||
<div class="image-container" id="image-container">
|
<div class="image-container" id="image-container">
|
||||||
<img
|
<img
|
||||||
src="{{ url_for('api.file', file_name=image.file_name) }}?r=prev"
|
src="{{ url_for('api.file', file_name=image.filename) }}?r=prev"
|
||||||
alt="{{ image.post_alt }}"
|
alt="{{ image.alt }}"
|
||||||
onload="imgFade(this)"
|
onload="imgFade(this)"
|
||||||
style="opacity: 0;"
|
style="opacity: 0;"
|
||||||
onerror="this.src='{{ url_for('static', filename='error.png')}}'"
|
onerror="this.src='{{ url_for('static', filename='error.png')}}'"
|
||||||
{% if "File" in image.image_exif %}
|
{% if "File" in image.exif %}
|
||||||
width="{{ image.image_exif.File.Width.raw }}"
|
width="{{ image.exif.File.Width.raw }}"
|
||||||
height="{{ image.image_exif.File.Height.raw }}"
|
height="{{ image.exif.File.Height.raw }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -136,7 +136,7 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z"></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,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z"></path></svg>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<a class="pill-item" href="/api/file/{{ image.file_name }}" download onclick="addNotification('Download started!', 4)">
|
<a class="pill-item" href="/api/file/{{ image.filename }}" download onclick="addNotification('Download started!', 4)">
|
||||||
<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>
|
||||||
<span class="tool-tip">
|
<span class="tool-tip">
|
||||||
Download
|
Download
|
||||||
|
@ -210,7 +210,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="img-colours">
|
<div class="img-colours">
|
||||||
{% for col in image.image_colours %}
|
{% for col in image.colours %}
|
||||||
<span style="background-color: rgb({{col.0}}, {{col.1}}, {{col.2}})"></span>
|
<span style="background-color: rgb({{col.0}}, {{col.1}}, {{col.2}})"></span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -226,7 +226,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for tag in image.image_exif %}
|
{% for tag in image.exif %}
|
||||||
<div class="info-tab">
|
<div class="info-tab">
|
||||||
<div class="info-header">
|
<div class="info-header">
|
||||||
{% if tag == 'Photographer' %}
|
{% if tag == 'Photographer' %}
|
||||||
|
@ -251,17 +251,17 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="info-table">
|
<div class="info-table">
|
||||||
<table>
|
<table>
|
||||||
{% for subtag in image.image_exif[tag] %}
|
{% for subtag in image.exif[tag] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ subtag }}</td>
|
<td>{{ subtag }}</td>
|
||||||
{% if image.image_exif[tag][subtag]['formatted'] %}
|
{% if image.exif[tag][subtag]['formatted'] %}
|
||||||
{% if image.image_exif[tag][subtag]['type'] == 'date' %}
|
{% if image.exif[tag][subtag]['type'] == 'date' %}
|
||||||
<td><span class="time">{{ image.image_exif[tag][subtag]['formatted'] }}</span></td>
|
<td><span class="time">{{ image.exif[tag][subtag]['formatted'] }}</span></td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td>{{ image.image_exif[tag][subtag]['formatted'] }}</td>
|
<td>{{ image.exif[tag][subtag]['formatted'] }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif image.image_exif[tag][subtag]['raw'] %}
|
{% elif image.exif[tag][subtag]['raw'] %}
|
||||||
<td>{{ image.image_exif[tag][subtag]['raw'] }}</td>
|
<td>{{ image.exif[tag][subtag]['raw'] }}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="empty-table">Oops, an error</td>
|
<td class="empty-table">Oops, an error</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
{% if images %}
|
{% if images %}
|
||||||
<div class="gallery-grid">
|
<div class="gallery-grid">
|
||||||
{% for image in images %}
|
{% for image in images %}
|
||||||
<a id="image-{{ image.id }}" class="gallery-item" href="{{ url_for('gallery.image', image_id=image.id) }}" style="background-color: rgb({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }})">
|
<a id="image-{{ image.id }}" class="gallery-item" href="{{ url_for('gallery.image', image_id=image.id) }}" style="background-color: rgb({{ image.colours.0.0 }}, {{ image.colours.0.1 }}, {{ image.colours.0.2 }})">
|
||||||
<div class="image-filter">
|
<div class="image-filter">
|
||||||
<p class="image-subtitle"></p>
|
<p class="image-subtitle"></p>
|
||||||
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
<img fetchpriority="low" alt="{{ image.post_alt }}" data-src="{{ url_for('api.file', file_name=image.file_name) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
<img fetchpriority="low" alt="{{ image.alt }}" data-src="{{ url_for('api.file', file_name=image.filename) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
<div class="banner-small">
|
<div class="banner-small">
|
||||||
<div class="banner-content">
|
<div class="banner-content">
|
||||||
<h1 class="banner-header">{{ user.username }}</h1>
|
<h1 class="banner-header">{{ user.username }}</h1>
|
||||||
<p class="banner-info">Member since <span class="time">{{ user.created_at }}</span></p>
|
<p class="banner-info">Member since <span class="time">{{ user.joined_at }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if images %}
|
{% if images %}
|
||||||
<div class="gallery-grid">
|
<div class="gallery-grid">
|
||||||
{% for image in images %}
|
{% for image in images %}
|
||||||
<a id="image-{{ image.id }}" class="gallery-item" href="{{ url_for('gallery.image', image_id=image.id) }}" style="background-color: rgb({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }})">
|
<a id="image-{{ image.id }}" class="gallery-item" href="{{ url_for('gallery.image', image_id=image.id) }}" style="background-color: rgb({{ image.colours.0.0 }}, {{ image.colours.0.1 }}, {{ image.colours.0.2 }})">
|
||||||
<div class="image-filter">
|
<div class="image-filter">
|
||||||
<p class="image-subtitle"></p>
|
<p class="image-subtitle"></p>
|
||||||
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
<p class="image-title"><span class="time">{{ image.created_at }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
<img fetchpriority="low" alt="{{ image.post_alt }}" data-src="{{ url_for('api.file', file_name=image.file_name) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
<img fetchpriority="low" alt="{{ image.alt }}" data-src="{{ url_for('api.file', file_name=image.filename) }}?r=thumb" onload="this.classList.add('loaded');" id="lazy-load"/>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,10 +5,9 @@ from uuid import uuid4
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime as dt
|
|
||||||
import platformdirs
|
import platformdirs
|
||||||
|
|
||||||
from flask import Blueprint, send_from_directory, abort, flash, jsonify, request, current_app
|
from flask import Blueprint, send_from_directory, abort, flash, request, current_app
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
@ -65,7 +64,7 @@ def upload():
|
||||||
|
|
||||||
# Get file extension, generate random name and set file path
|
# Get file extension, generate random name and set file path
|
||||||
img_ext = pathlib.Path(form_file.filename).suffix.replace('.', '').lower()
|
img_ext = pathlib.Path(form_file.filename).suffix.replace('.', '').lower()
|
||||||
img_name = "GWAGWA_"+str(uuid4())
|
img_name = "GWAGWA_" + str(uuid4())
|
||||||
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img_name+'.'+img_ext)
|
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img_name+'.'+img_ext)
|
||||||
|
|
||||||
# Check if file extension is allowed
|
# Check if file extension is allowed
|
||||||
|
@ -85,13 +84,12 @@ def upload():
|
||||||
|
|
||||||
# Save to database
|
# Save to database
|
||||||
query = db.Posts(author_id=current_user.id,
|
query = db.Posts(author_id=current_user.id,
|
||||||
created_at=dt.utcnow(),
|
filename=img_name + '.' + img_ext,
|
||||||
file_name=img_name+'.'+img_ext,
|
mimetype=img_ext,
|
||||||
file_type=img_ext,
|
exif=img_exif,
|
||||||
image_exif=img_exif,
|
colours=img_colors,
|
||||||
image_colours=img_colors,
|
description=form['description'],
|
||||||
post_description=form['description'],
|
alt=form['alt'])
|
||||||
post_alt=form['alt'])
|
|
||||||
|
|
||||||
db_session.add(query)
|
db_session.add(query)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
@ -115,13 +113,13 @@ def delete_image(image_id):
|
||||||
|
|
||||||
# Delete file
|
# Delete file
|
||||||
try:
|
try:
|
||||||
os.remove(os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name))
|
os.remove(os.path.join(current_app.config['UPLOAD_FOLDER'], img.filename))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logging.warning('File not found: %s, already deleted or never existed', img.file_name)
|
logging.warning('File not found: %s, already deleted or never existed', img.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.file_name.rsplit('.')[0]
|
cache_name = img.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)
|
||||||
|
|
||||||
|
@ -136,7 +134,7 @@ def delete_image(image_id):
|
||||||
# Commit all changes
|
# Commit all changes
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
logging.info('Removed image (%s) %s', image_id, img.file_name)
|
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'])
|
||||||
return 'Gwa Gwa'
|
return 'Gwa Gwa'
|
||||||
|
|
||||||
|
@ -149,8 +147,7 @@ def create_group():
|
||||||
"""
|
"""
|
||||||
new_group = db.Groups(name=request.form['name'],
|
new_group = db.Groups(name=request.form['name'],
|
||||||
description=request.form['description'],
|
description=request.form['description'],
|
||||||
author_id=current_user.id,
|
author_id=current_user.id)
|
||||||
created_at=dt.utcnow())
|
|
||||||
|
|
||||||
db_session.add(new_group)
|
db_session.add(new_group)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
@ -180,8 +177,7 @@ def modify_group():
|
||||||
.filter_by(group_id=group_id, post_id=image_id)
|
.filter_by(group_id=group_id, post_id=image_id)
|
||||||
.first()):
|
.first()):
|
||||||
db_session.add(db.GroupJunction(group_id=group_id,
|
db_session.add(db.GroupJunction(group_id=group_id,
|
||||||
post_id=image_id,
|
post_id=image_id))
|
||||||
date_added=dt.utcnow()))
|
|
||||||
elif request.form['action'] == 'remove':
|
elif request.form['action'] == 'remove':
|
||||||
(db_session.query(db.GroupJunction)
|
(db_session.query(db.GroupJunction)
|
||||||
.filter_by(group_id=group_id, post_id=image_id)
|
.filter_by(group_id=group_id, post_id=image_id)
|
||||||
|
|
|
@ -37,8 +37,8 @@ def groups():
|
||||||
# For each image, get the image data and add it to the group item
|
# For each image, get the image data and add it to the group item
|
||||||
group.images = []
|
group.images = []
|
||||||
for image in images:
|
for image in images:
|
||||||
group.images.append(db_session.query(db.Posts.file_name, db.Posts.post_alt,
|
group.images.append(db_session.query(db.Posts.filename, db.Posts.alt,
|
||||||
db.Posts.image_colours, db.Posts.id)
|
db.Posts.colours, db.Posts.id)
|
||||||
.filter(db.Posts.id == image[0])
|
.filter(db.Posts.id == image[0])
|
||||||
.first())
|
.first())
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def group(group_id):
|
||||||
# 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))'
|
||||||
if images:
|
if images:
|
||||||
text_colour = contrast.contrast(images[0].image_colours[0],
|
text_colour = contrast.contrast(images[0].colours[0],
|
||||||
'rgb(var(--fg-black))',
|
'rgb(var(--fg-black))',
|
||||||
'rgb(var(--fg-white))')
|
'rgb(var(--fg-white))')
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ def index():
|
||||||
"""
|
"""
|
||||||
Home page of the website, shows the feed of the latest images
|
Home page of the website, shows the feed of the latest images
|
||||||
"""
|
"""
|
||||||
images = db_session.query(db.Posts.file_name,
|
images = db_session.query(db.Posts.filename,
|
||||||
db.Posts.post_alt,
|
db.Posts.alt,
|
||||||
db.Posts.image_colours,
|
db.Posts.colours,
|
||||||
db.Posts.created_at,
|
db.Posts.created_at,
|
||||||
db.Posts.id).order_by(db.Posts.id.desc()).all()
|
db.Posts.id).order_by(db.Posts.id.desc()).all()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue