Added Image deletion

Added buttons for image functions
Moved Image functions to their own file
Added PFP row in users table
Moved Groups back to the root templates folder
This commit is contained in:
Michał Gdula 2023-01-11 10:53:01 +00:00
parent 8c25779882
commit 978086f512
9 changed files with 262 additions and 43 deletions

View file

@ -5,7 +5,7 @@ print("""
| |_| | | | | | |_| | |__| __/ (_| \\__ \\
\\___/|_| |_|_|\\__, |_____\\___|\\__, |___/
|___/ |___/
Created by Fluffy Bean - Version 100123
Created by Fluffy Bean - Version 110123
""")
# Import base packages
@ -98,6 +98,10 @@ def create_app(test_config=None):
app.register_blueprint(gallery.blueprint)
app.add_url_rule('/', endpoint='index')
# Load routes for images
from . import image
app.register_blueprint(image.blueprint)
# Load APIs
from . import api
app.register_blueprint(api.blueprint)

View file

@ -22,41 +22,13 @@ def index():
return render_template('index.html', images=images)
@blueprint.route('/image/<int:id>')
def image(id):
db = get_db()
image = db.execute(
'SELECT * FROM posts'
' WHERE id = ?',
(id,)
).fetchone()
if image is None:
abort(404)
file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name']))
raw_exif = file.getexif()
human_exif = {}
for tag in raw_exif:
name = TAGS.get(tag, tag)
value = raw_exif.get(tag)
if isinstance(value, bytes):
value = value.decode()
human_exif[name] = value
return render_template('image.html', image=image, exif=human_exif)
@blueprint.route('/group')
def groups():
return render_template('groups/group.html', group_id='gwa gwa')
return render_template('group.html', group_id='gwa gwa')
@blueprint.route('/group/<int:id>')
def group(id):
return render_template('groups/group.html', group_id=id)
return render_template('group.html', group_id=id)
@blueprint.route('/upload', methods=('GET', 'POST'))
@ -82,7 +54,8 @@ def upload():
db.commit()
return 'Gwa Gwa'
# GET, or in human language, when you visit the page
return render_template('upload.html')

83
gallery/image.py Normal file
View file

@ -0,0 +1,83 @@
from flask import Blueprint, flash, g, redirect, render_template, request, url_for, jsonify, current_app
from werkzeug.exceptions import abort
from werkzeug.utils import secure_filename
from gallery.auth import login_required
from gallery.db import get_db
import os
import datetime
from PIL import Image
from PIL.ExifTags import TAGS
dt = datetime.datetime.now()
blueprint = Blueprint('image', __name__, url_prefix='/image')
def get_post(id, check_author=True):
post = get_db().execute(
'SELECT p.author_id FROM posts p JOIN users u ON p.author_id = u.id'
' WHERE p.id = ?',
(id,)
).fetchone()
if post is None:
return False
if check_author and post['author_id'] != g.user['id']:
return False
return post
@blueprint.route('/<int:id>', methods=('GET', 'POST'))
def image(id):
if request.method == 'POST':
image = get_post(id)
action = request.form['action']
if not image:
abort(403)
if action == 'delete':
try:
db = get_db()
db.execute('DELETE FROM posts WHERE id = ?', (id,))
db.commit()
except:
return 'database error'
try:
os.remove(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name']))
except:
return 'os error'
# GET, it should be called Gwa Gwa because it sounds funny
# Get image from database
db = get_db()
image = db.execute(
'SELECT * FROM posts'
' WHERE id = ?',
(id,)
).fetchone()
if image is None:
abort(404)
# Get exif data from image
file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name']))
raw_exif = file.getexif()
human_exif = {}
for tag in raw_exif:
name = TAGS.get(tag, tag)
value = raw_exif.get(tag)
if isinstance(value, bytes):
value = value.decode()
human_exif[name] = value
if len(human_exif) == 0:
human_exif = False
# All in le head
return render_template('image.html', image=image, exif=human_exif)

View file

@ -1,6 +1,7 @@
CREATE TABLE IF NOT EXISTS users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
profile_picture TEXT NOT NULL DEFAULT 'default.png',
email TEXT NOT NULL,
password TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP

View file

@ -13,15 +13,92 @@
onload="imgFade(this)" style="display:none;"
/>
</div>
<div class="img-tools">
<div>
<button class="tool-btn" id="img-download">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" fill="currentColor">
<path d="M8 6.641l1.121-1.12a1 1 0 0 1 1.415 1.413L7.707 9.763a.997.997 0 0 1-1.414 0L3.464 6.934A1 1 0 1 1 4.88 5.52L6 6.641V1a1 1 0 1 1 2 0v5.641zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path>
</svg>
</button>
<button class="tool-btn" id="img-fullscreen">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" fill="currentColor">
<path d="M19 0a1 1 0 0 1 1 1v6a1 1 0 0 1-2 0V3.414L11.414 10 18 16.586V13a1 1 0 0 1 2 0v6a1 1 0 0 1-1 1h-6a1 1 0 0 1 0-2h3.586L10 11.414 3.414 18H7a1 1 0 0 1 0 2H1a1 1 0 0 1-1-1v-6a1 1 0 0 1 2 0v3.586L8.586 10 2 3.414V7a1 1 0 1 1-2 0V1a1 1 0 0 1 1-1h6a1 1 0 1 1 0 2H3.414L10 8.586 16.586 2H13a1 1 0 0 1 0-2h6z"></path>
</svg>
</button>
<button class="tool-btn" id="img-share">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3 -3 24 24" fill="currentColor">
<path d="M3.19 9.345a.97.97 0 0 1 1.37 0 .966.966 0 0 1 0 1.367l-2.055 2.052a1.932 1.932 0 0 0 0 2.735 1.94 1.94 0 0 0 2.74 0l4.794-4.787a.966.966 0 0 0 0-1.367.966.966 0 0 1 0-1.368.97.97 0 0 1 1.37 0 2.898 2.898 0 0 1 0 4.103l-4.795 4.787a3.879 3.879 0 0 1-5.48 0 3.864 3.864 0 0 1 0-5.47L3.19 9.344zm11.62-.69a.97.97 0 0 1-1.37 0 .966.966 0 0 1 0-1.367l2.055-2.052a1.932 1.932 0 0 0 0-2.735 1.94 1.94 0 0 0-2.74 0L7.962 7.288a.966.966 0 0 0 0 1.367.966.966 0 0 1 0 1.368.97.97 0 0 1-1.37 0 2.898 2.898 0 0 1 0-4.103l4.795-4.787a3.879 3.879 0 0 1 5.48 0 3.864 3.864 0 0 1 0 5.47L14.81 8.656z"></path>
</svg>
</button>
</div>
{% if g.user['id'] == image['author_id'] %}
<div>
<button class="tool-btn tool-btn--evil" id="img-delete">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3 -2 24 24" fill="currentColor">
<path d="M6 2V1a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v1h4a2 2 0 0 1 2 2v1a2 2 0 0 1-2 2h-.133l-.68 10.2a3 3 0 0 1-2.993 2.8H5.826a3 3 0 0 1-2.993-2.796L2.137 7H2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h4zm10 2H2v1h14V4zM4.141 7l.687 10.068a1 1 0 0 0 .998.932h6.368a1 1 0 0 0 .998-.934L13.862 7h-9.72zM7 8a1 1 0 0 1 1 1v7a1 1 0 0 1-2 0V9a1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1v7a1 1 0 0 1-2 0V9a1 1 0 0 1 1-1z"></path>
</svg>
</button>
<button class="tool-btn tool-btn--evil" id="img-edit">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2.5 -2.5 24 24" fill="currentColor">
<path d="M12.238 5.472L3.2 14.51l-.591 2.016 1.975-.571 9.068-9.068-1.414-1.415zM13.78 3.93l1.414 1.414 1.318-1.318a.5.5 0 0 0 0-.707l-.708-.707a.5.5 0 0 0-.707 0L13.781 3.93zm3.439-2.732l.707.707a2.5 2.5 0 0 1 0 3.535L5.634 17.733l-4.22 1.22a1 1 0 0 1-1.237-1.241l1.248-4.255 12.26-12.26a2.5 2.5 0 0 1 3.535 0z"></path>
</svg>
</button>
<button class="tool-btn tool-btn--evil" id="img-tags">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 24 24" fill="currentColor">
<path d="M11.586 15.071L13 13.657l1.414 1.414 6.165-6.165 1.09-3.552-2.484-2.483-1.079.336-1.598-1.598L18.591.96a2 2 0 0 1 2.008.496l2.483 2.483a2 2 0 0 1 .498 2L22.345 9.97l-7.93 7.93-2.83-2.828zM14.236.75l2.482 2.483a2 2 0 0 1 .498 2l-1.235 4.028-7.93 7.931-7.78-7.778L8.17 1.516 12.227.254a2 2 0 0 1 2.008.496zM3.1 9.414l4.95 4.95 6.164-6.165 1.09-3.552-2.484-2.483-3.585 1.115L3.1 9.414zm7.424-2.475a1.5 1.5 0 1 1 2.121-2.121 1.5 1.5 0 0 1-2.12 2.121zm6.886 1.022l.782-2.878c.45.152.755.325.917.518a1.5 1.5 0 0 1-.185 2.113c-.29.244-.795.326-1.514.247z"></path>
</svg>
</button>
</div>
{% endif %}
</div>
<div class="image__info">
<h2>{{ image['file_name'] }}</h2>
<h2>Info</h2>
<p>{{ image['file_name'] }}</p>
<p>{{ image['id'] }}</p>
<p>{{ image['author_id'] }}</p>
<p>{{ image['created_at'] }}</p>
<p>{{ image['description'] }}</p>
</div>
<div class="image__info">
{% for tag in exif %}
<p>{{ tag }}: {{ exif[tag] }}</p>
{% endfor %}
</div>
{% if exif is not false %}
<div class="image__info">
<h2>Exif</h2>
{% for tag in exif %}
<p>{{ tag }}: {{ exif[tag] }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<script>
$('#img-download').click(function() {
window.location.href = '/image/{{ image['id'] }}/download';
});
$('#img-fullscreen').click(function() {
});
$('#img-share').click(function() {
navigator.clipboard.writeText(window.location.href);
});
{% if g.user['id'] == image['author_id'] %}
$('#img-delete').click(function() {
$.ajax({
url: '/image/{{ image['id'] }}',
type: 'post',
data: {
action: 'delete'
},
success: function(result) {
window.location.href = '/';
}
});
});
$('#img-edit').click(function() {
window.location.href = '/image/{{ image['id'] }}/edit';
});
$('#img-tags').click(function() {
window.location.href = '/image/{{ image['id'] }}/tags';
});
{% endif %}
</script>
{% endblock %}

View file

@ -0,0 +1,29 @@
.tool-btn {
margin: 0;
padding: 0.5rem;
width: 2.5rem;
height: 2.5rem;
border: none;
background-color: transparent;
color: $white100;
svg {
width: 1.25rem;
height: 1.25rem;
}
&:hover {
cursor: pointer;
color: $green;
}
}
.tool-btn--evil {
color: $red;
&:hover {
color: $white100;
}
}

View file

@ -5,6 +5,7 @@
@import 'ui/nav';
@import 'ui/main';
@import 'buttons/img-tool';
@import 'buttons/btn';
@import 'buttons/up';
@ -28,6 +29,31 @@
z-index: 1;
overflow: unset;
> h1 {
margin: 0 auto;
padding: 0;
font-family: $font-header;
font-size: 5rem;
font-weight: 900;
line-height: 1;
text-align: center;
color: $green;
}
> p {
margin: 0 auto;
padding: 0;
font-family: $font-body;
font-size: 2rem;
font-weight: 600;
line-height: 1;
text-align: center;
color: $white100;
}
/*
h1 {
margin: 0;
padding: 0;
@ -39,6 +65,7 @@
color: $green;
}
*/
}
@keyframes imgLoading {
@ -60,7 +87,7 @@
gap: 0;
h1 {
> h1 {
margin: 0 auto;
padding: 0;
@ -72,7 +99,7 @@
color: $green;
}
p {
> p {
margin: 0 auto;
padding: 0;
@ -231,12 +258,16 @@
padding: 0;
max-width: 100%;
height: 100%;
max-height: 75vh;
background: linear-gradient(-45deg, $black100, $black400 40%, $black100);
background-size: 400% 400%;
border-radius: $rad;
animation: imgLoading 10s ease infinite;
object-fit: contain;
object-position: center;
border-radius: $rad;
}
}
@ -285,3 +316,24 @@
overflow: hidden;
}
}
.img-tools {
width: 100%;
height: 2rem;
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
> div {
margin: 0;
padding: 0;
display: flex;
gap: 0.5rem;
background-color: $black200;
border-radius: $rad;
}
}

View file

@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup(
name='onlylegs',
version='100123',
version='110123',
packages=find_packages(),
include_package_data=True,
install_requires=[