mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2024-12-29 10:56:10 +00:00
Move most of the processing into the upload
This commit is contained in:
parent
970d3dcf66
commit
0a27d79a82
|
@ -6,11 +6,13 @@ from uuid import uuid4
|
|||
import os
|
||||
import io
|
||||
import logging
|
||||
from datetime import datetime as dt
|
||||
|
||||
from flask import (
|
||||
Blueprint, current_app, send_from_directory, send_file, request, g, abort, flash, jsonify)
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from colorthief import ColorThief
|
||||
from PIL import Image, ImageOps # ImageFilter
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
|
@ -103,12 +105,15 @@ def upload():
|
|||
"""
|
||||
form_file = request.files['file']
|
||||
form = request.form
|
||||
form_description = form['description']
|
||||
form_alt = form['alt']
|
||||
|
||||
if not form_file:
|
||||
return abort(404)
|
||||
|
||||
img_ext = os.path.splitext(form_file.filename)[-1].replace('.', '').lower()
|
||||
img_name = f"GWAGWA_{str(uuid4())}.{img_ext}"
|
||||
img_name = "GWAGWA_"+str(uuid4())
|
||||
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img_name+'.'+img_ext)
|
||||
|
||||
if not img_ext in current_app.config['ALLOWED_EXTENSIONS'].keys():
|
||||
logging.info('File extension not allowed: %s', img_ext)
|
||||
|
@ -117,22 +122,35 @@ def upload():
|
|||
if os.path.isdir(current_app.config['UPLOAD_FOLDER']) is False:
|
||||
os.mkdir(current_app.config['UPLOAD_FOLDER'])
|
||||
|
||||
# Save to database
|
||||
try:
|
||||
db_session.add(db.posts(img_name, form['description'], form['alt'], g.user.id))
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
logging.error('Could not save to database: %s', err)
|
||||
abort(500)
|
||||
|
||||
# Save file
|
||||
try:
|
||||
form_file.save(
|
||||
os.path.join(current_app.config['UPLOAD_FOLDER'], img_name))
|
||||
form_file.save(img_path)
|
||||
except Exception as err:
|
||||
logging.error('Could not save file: %s', err)
|
||||
abort(500)
|
||||
|
||||
# Get metadata and colors
|
||||
img_exif = mt.Metadata(img_path).yoink()
|
||||
img_colors = ColorThief(img_path).get_palette(color_count=3)
|
||||
|
||||
# Save to database
|
||||
try:
|
||||
query = db.Posts(author_id = g.user.id,
|
||||
created_at = dt.now(),
|
||||
file_name = img_name+'.'+img_ext,
|
||||
file_type = img_ext,
|
||||
image_exif = img_exif,
|
||||
image_colours = img_colors,
|
||||
post_description = form_description,
|
||||
post_alt = form_alt)
|
||||
|
||||
db_session.add(query)
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
logging.error('Could not save to database: %s', err)
|
||||
abort(500)
|
||||
|
||||
return 'Gwa Gwa'
|
||||
|
||||
|
||||
|
@ -142,7 +160,7 @@ def remove(img_id):
|
|||
"""
|
||||
Deletes an image from the server and database
|
||||
"""
|
||||
img = db_session.query(db.posts).filter_by(id=img_id).first()
|
||||
img = db_session.query(db.Posts).filter_by(id=img_id).first()
|
||||
|
||||
if img is None:
|
||||
abort(404)
|
||||
|
@ -159,7 +177,7 @@ def remove(img_id):
|
|||
abort(500)
|
||||
|
||||
try:
|
||||
db_session.query(db.posts).filter_by(id=img_id).delete()
|
||||
db_session.query(db.Posts).filter_by(id=img_id).delete()
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
logging.error('Could not remove from database: %s', err)
|
||||
|
@ -175,7 +193,7 @@ def metadata(img_id):
|
|||
"""
|
||||
Yoinks metadata from an image
|
||||
"""
|
||||
img = db_session.query(db.posts).filter_by(id=img_id).first()
|
||||
img = db_session.query(db.Posts).filter_by(id=img_id).first()
|
||||
|
||||
if img is None:
|
||||
abort(404)
|
||||
|
|
|
@ -5,6 +5,7 @@ User registration, login and logout and locking access to pages behind a login
|
|||
import re
|
||||
import uuid
|
||||
import logging
|
||||
from datetime import datetime as dt
|
||||
|
||||
import functools
|
||||
from flask import Blueprint, flash, g, redirect, request, session, url_for, abort, jsonify
|
||||
|
@ -49,14 +50,14 @@ def load_logged_in_user():
|
|||
g.user = None
|
||||
session.clear()
|
||||
else:
|
||||
is_alive = db_session.query(db.sessions).filter_by(session_uuid=user_uuid).first()
|
||||
is_alive = db_session.query(db.Sessions).filter_by(session_uuid=user_uuid).first()
|
||||
|
||||
if is_alive is None:
|
||||
logging.info('Session expired')
|
||||
flash(['Session expired!', '3'])
|
||||
session.clear()
|
||||
else:
|
||||
g.user = db_session.query(db.users).filter_by(id=user_id).first()
|
||||
g.user = db_session.query(db.Users).filter_by(id=user_id).first()
|
||||
|
||||
|
||||
@blueprint.route('/register', methods=['POST'])
|
||||
|
@ -96,7 +97,11 @@ def register():
|
|||
|
||||
|
||||
try:
|
||||
db_session.add(db.users(username, email, generate_password_hash(password)))
|
||||
register_user = db.Users(username=username,
|
||||
email=email,
|
||||
password=generate_password_hash(password),
|
||||
created_at=dt.now())
|
||||
db_session.add(register_user)
|
||||
db_session.commit()
|
||||
except exc.IntegrityError:
|
||||
return f'User {username} is already registered!'
|
||||
|
@ -116,7 +121,7 @@ def login():
|
|||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
|
||||
user = db_session.query(db.users).filter_by(username=username).first()
|
||||
user = db_session.query(db.Users).filter_by(username=username).first()
|
||||
error = []
|
||||
|
||||
|
||||
|
@ -138,11 +143,14 @@ def login():
|
|||
session['user_id'] = user.id
|
||||
session['uuid'] = str(uuid.uuid4())
|
||||
|
||||
db_session.add(db.sessions(user.id,
|
||||
session.get('uuid'),
|
||||
request.remote_addr,
|
||||
request.user_agent.string,
|
||||
1))
|
||||
session_query = db.Sessions(user_id=user.id,
|
||||
session_uuid=session.get('uuid'),
|
||||
ip_address=request.remote_addr,
|
||||
user_agent=request.user_agent.string,
|
||||
active=True,
|
||||
created_at=dt.now())
|
||||
|
||||
db_session.add(session_query)
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
logging.error('User %s could not be logged in: %s', username, err)
|
||||
|
|
|
@ -6,8 +6,8 @@ import os
|
|||
from datetime import datetime
|
||||
import platformdirs
|
||||
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey
|
||||
from sqlalchemy.orm import declarative_base, relationship
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType
|
||||
from sqlalchemy.orm import declarative_base, relationship, backref, mapped_column
|
||||
|
||||
|
||||
path_to_db = os.path.join(platformdirs.user_config_dir('onlylegs'), 'gallery.sqlite')
|
||||
|
@ -15,7 +15,7 @@ engine = create_engine(f'sqlite:///{path_to_db}', echo=False)
|
|||
base = declarative_base()
|
||||
|
||||
|
||||
class users (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class Users (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
User table
|
||||
Joins with post, groups, session and log
|
||||
|
@ -28,19 +28,13 @@ class users (base): # pylint: disable=too-few-public-methods, C0103
|
|||
password = Column(String, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
posts = relationship('posts')
|
||||
groups = relationship('groups')
|
||||
session = relationship('sessions')
|
||||
log = relationship('logs')
|
||||
|
||||
def __init__(self, username, email, password):
|
||||
self.username = username
|
||||
self.email = email
|
||||
self.password = password
|
||||
self.created_at = datetime.now()
|
||||
posts = relationship('Posts', backref='users')
|
||||
groups = relationship('Groups', backref='users')
|
||||
session = relationship('Sessions', backref='users')
|
||||
log = relationship('Logs', backref='users')
|
||||
|
||||
|
||||
class posts (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class Posts (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
Post table
|
||||
Joins with group_junction
|
||||
|
@ -48,23 +42,22 @@ class posts (base): # pylint: disable=too-few-public-methods, C0103
|
|||
__tablename__ = 'posts'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
file_name = Column(String, unique=True, nullable=False)
|
||||
description = Column(String, nullable=False)
|
||||
alt = Column(String, nullable=False)
|
||||
author_id = Column(Integer, ForeignKey('users.id'))
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
file_name = Column(String, unique=True, nullable=False)
|
||||
file_type = Column(String, nullable=False)
|
||||
|
||||
image_exif = Column(PickleType, nullable=False)
|
||||
image_colours = Column(PickleType, nullable=False)
|
||||
|
||||
post_description = Column(String, nullable=False)
|
||||
post_alt = Column(String, nullable=False)
|
||||
|
||||
junction = relationship('group_junction')
|
||||
|
||||
def __init__(self, file_name, description, alt, author_id):
|
||||
self.file_name = file_name
|
||||
self.description = description
|
||||
self.alt = alt
|
||||
self.author_id = author_id
|
||||
self.created_at = datetime.now()
|
||||
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
|
||||
Joins with group_junction
|
||||
|
@ -77,16 +70,10 @@ class groups (base): # pylint: disable=too-few-public-methods, C0103
|
|||
author_id = Column(Integer, ForeignKey('users.id'))
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
junction = relationship('group_junction')
|
||||
|
||||
def __init__(self, name, description, author_id):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.author_id = author_id
|
||||
self.created_at = datetime.now()
|
||||
junction = relationship('GroupJunction', backref='groups')
|
||||
|
||||
|
||||
class group_junction (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
Junction table for posts and groups
|
||||
Joins with posts and groups
|
||||
|
@ -97,12 +84,8 @@ class group_junction (base): # pylint: disable=too-few-public-methods, C0103
|
|||
group_id = Column(Integer, ForeignKey('groups.id'))
|
||||
post_id = Column(Integer, ForeignKey('posts.id'))
|
||||
|
||||
def __init__(self, group_id, post_id):
|
||||
self.group_id = group_id
|
||||
self.post_id = post_id
|
||||
|
||||
|
||||
class sessions (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class Sessions (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
Session table
|
||||
Joins with user
|
||||
|
@ -117,16 +100,8 @@ class sessions (base): # pylint: disable=too-few-public-methods, C0103
|
|||
active = Column(Boolean, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
def __init__(self, user_id, session_uuid, ip_address, user_agent, active): # pylint: disable=too-many-arguments, C0103
|
||||
self.user_id = user_id
|
||||
self.session_uuid = session_uuid
|
||||
self.ip_address = ip_address
|
||||
self.user_agent = user_agent
|
||||
self.active = active
|
||||
self.created_at = datetime.now()
|
||||
|
||||
|
||||
class logs (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class Logs (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
Log table
|
||||
Joins with user
|
||||
|
@ -140,15 +115,8 @@ class logs (base): # pylint: disable=too-few-public-methods, C0103
|
|||
msg = Column(String, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
def __init__(self, user_id, ip_address, code, msg):
|
||||
self.user_id = user_id
|
||||
self.ip_address = ip_address
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
self.created_at = datetime.now()
|
||||
|
||||
|
||||
class bans (base): # pylint: disable=too-few-public-methods, C0103
|
||||
class Bans (base): # pylint: disable=too-few-public-methods, C0103
|
||||
"""
|
||||
Bans table
|
||||
"""
|
||||
|
@ -160,11 +128,5 @@ class bans (base): # pylint: disable=too-few-public-methods, C0103
|
|||
msg = Column(String, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
def __init__(self, ip_address, code, msg):
|
||||
self.ip_address = ip_address
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
self.created_at = datetime.now()
|
||||
|
||||
|
||||
base.metadata.create_all(engine)
|
||||
|
|
|
@ -4,10 +4,9 @@ Parse metadata from images if available
|
|||
otherwise get some basic information from the file
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
|
||||
from PIL import Image
|
||||
from PIL.ExifTags import TAGS, GPSTAGS
|
||||
from PIL.ExifTags import TAGS
|
||||
|
||||
from .helpers import *
|
||||
from .mapping import *
|
||||
|
@ -72,6 +71,7 @@ class Metadata:
|
|||
}
|
||||
elif data in CAMERA_MAPPING:
|
||||
if len(CAMERA_MAPPING[data]) == 2:
|
||||
# Camera - Exif Tag name
|
||||
exif['Camera'][CAMERA_MAPPING[data][0]] = {
|
||||
'raw': encoded_exif[data],
|
||||
'formatted':
|
||||
|
|
|
@ -41,8 +41,6 @@ CAMERA_MAPPING = {
|
|||
'LightSource': ['Light Source', 'light_source'],
|
||||
'SceneCaptureType': ['Scene Capture Type', 'scene_capture_type'],
|
||||
'SceneType': ['Scene Type', 'scene_type'],
|
||||
'Rating': ['Rating', 'rating'],
|
||||
'RatingPercent': ['Rating Percent', 'rating_percent'],
|
||||
}
|
||||
SOFTWARE_MAPPING = {
|
||||
'Software': ['Software'],
|
||||
|
@ -59,4 +57,6 @@ FILE_MAPPING = {
|
|||
'XResolution': ['X-resolution'],
|
||||
'YResolution': ['Y-resolution'],
|
||||
'ResolutionUnit': ['Resolution Units', 'resolution_unit'],
|
||||
'Rating': ['Rating', 'rating'],
|
||||
'RatingPercent': ['Rating Percent', 'rating_percent'],
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ def index():
|
|||
"""
|
||||
Home page of the website, shows the feed of latest images
|
||||
"""
|
||||
images = db_session.query(db.posts).order_by(db.posts.id.desc()).all()
|
||||
|
||||
images = db_session.query(db.Posts.file_name, db.Posts.id, db.Posts.created_at).order_by(db.Posts.id.desc()).all()
|
||||
|
||||
return render_template('index.html',
|
||||
images=images,
|
||||
image_count=len(images),
|
||||
|
@ -35,15 +35,12 @@ def image(image_id):
|
|||
"""
|
||||
Image view, shows the image and its metadata
|
||||
"""
|
||||
img = db_session.query(db.posts).filter_by(id=image_id).first()
|
||||
img = db_session.query(db.Posts).filter_by(id=image_id).first()
|
||||
|
||||
if img is None:
|
||||
abort(404)
|
||||
|
||||
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name)
|
||||
exif = mt.Metadata(img_path).yoink()
|
||||
|
||||
return render_template('image.html', image=img, exif=exif)
|
||||
return render_template('image.html', image=img, exif=img.image_exif)
|
||||
|
||||
@blueprint.route('/group')
|
||||
def groups():
|
||||
|
|
|
@ -20,13 +20,15 @@ function uploadFile(){
|
|||
addNotification("Please select a file to upload", 2);
|
||||
} else {
|
||||
// Make form
|
||||
var formData = new FormData();
|
||||
let formData = new FormData();
|
||||
formData.append("file", $("#file").prop("files")[0]);
|
||||
formData.append("alt", $("#alt").val());
|
||||
formData.append("description", $("#description").val());
|
||||
formData.append("tags", $("#tags").val());
|
||||
formData.append("submit", $("#submit").val());
|
||||
|
||||
//let bar = $('.bar');
|
||||
|
||||
// Upload the information
|
||||
$.ajax({
|
||||
url: '/api/upload',
|
||||
|
@ -34,9 +36,25 @@ function uploadFile(){
|
|||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
beforeSend: function() {
|
||||
//bar.width('0%');
|
||||
var percentVal = 0;
|
||||
console.log("Uploading...");
|
||||
},
|
||||
uploadProgress: function(event, position, total, percentComplete) {
|
||||
//bar.width(percentComplete + '%');
|
||||
percentVal = percentComplete;
|
||||
console.log(percentVal);
|
||||
},
|
||||
complete: function(xhr) {
|
||||
//bar.width('100%');
|
||||
//bar.class += " loading";
|
||||
console.log("Upload complete");
|
||||
},
|
||||
success: function (response) {
|
||||
addNotification("File uploaded successfully!", 1);
|
||||
// popupDissmiss(); // Close popup
|
||||
console.log('File processed successfully');
|
||||
},
|
||||
error: function (response) {
|
||||
switch (response.status) {
|
||||
|
@ -57,6 +75,10 @@ function uploadFile(){
|
|||
addNotification('Error uploading file, blame someone', 2);
|
||||
break;
|
||||
}
|
||||
},
|
||||
always: function (response) {
|
||||
//bar.class += "";
|
||||
console.log("Upload complete");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
</div>
|
||||
|
||||
<div class="image-info__container">
|
||||
{% if image['alt'] != '' %}
|
||||
{% if image['post_alt'] %}
|
||||
<div class="image-info">
|
||||
<span class="image-info__collapse" id="collapse-info">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
||||
|
@ -87,11 +87,11 @@
|
|||
<h2>Alt</h2>
|
||||
</div>
|
||||
<div class="image-info__content">
|
||||
<p>{{ image['alt'] }}</p>
|
||||
<p>{{ image['post_alt'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if image['description'] != '' %}
|
||||
{% if image['post_description'] %}
|
||||
<div class="image-info">
|
||||
<span class="image-info__collapse" id="collapse-info">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
||||
|
@ -105,7 +105,7 @@
|
|||
<h2>Description</h2>
|
||||
</div>
|
||||
<div class="image-info__content">
|
||||
<p>{{ image['description'] }}</p>
|
||||
<p>{{ image['post_description'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in a new issue