mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-06-29 03:26:16 +00:00
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:
parent
8c25779882
commit
978086f512
9 changed files with 262 additions and 43 deletions
|
@ -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)
|
||||
|
|
|
@ -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'))
|
||||
|
@ -83,6 +55,7 @@ def upload():
|
|||
|
||||
return 'Gwa Gwa'
|
||||
|
||||
# GET, or in human language, when you visit the page
|
||||
return render_template('upload.html')
|
||||
|
||||
|
||||
|
|
83
gallery/image.py
Normal file
83
gallery/image.py
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -13,15 +13,92 @@
|
|||
onload="imgFade(this)" style="display:none;"
|
||||
/>
|
||||
</div>
|
||||
<div class="image__info">
|
||||
<h2>{{ image['file_name'] }}</h2>
|
||||
<p>{{ image['id'] }}</p>
|
||||
<p>{{ image['author_id'] }}</p>
|
||||
<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>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>
|
||||
{% 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 %}
|
29
gallery/user/themes/default/buttons/img-tool.scss
Normal file
29
gallery/user/themes/default/buttons/img-tool.scss
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
2
setup.py
2
setup.py
|
@ -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=[
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue