bring back the badge editor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from flask import Blueprint, render_template, request, url_for
|
||||
from ..auth import get_active_user, is_logged_in, hard_login_required
|
||||
from ..models import BookmarkCollections, BookmarkedPosts, BookmarkedThreads, Threads, Posts
|
||||
from ..models import BookmarkCollections, BookmarkedPosts, BookmarkedThreads, Threads, Posts, Badges, BadgeUploads
|
||||
from functools import wraps
|
||||
|
||||
bp = Blueprint('hyperapi', __name__, url_prefix='/hyperapi/')
|
||||
@@ -124,3 +124,12 @@ def bookmark_post():
|
||||
})
|
||||
|
||||
return '', 204
|
||||
|
||||
@bp.get('/badges/editor/')
|
||||
@hard_login_required
|
||||
@user_required
|
||||
def badge_editor():
|
||||
user = get_active_user()
|
||||
badges = Badges.get_for_user(user.id)
|
||||
badge_uploads = BadgeUploads.get_for_user(user.id)
|
||||
return render_template('hyper/badge_editor.html', badges=badges, badge_uploads=badge_uploads)
|
||||
|
||||
@@ -14,7 +14,7 @@ from ..auth import (
|
||||
login_required, revoke_session, get_active_user,
|
||||
parse_display_name, revoke_all_sessions, csrf_verified
|
||||
)
|
||||
from ..models import Users, Posts, Reactions, Threads, Avatars, PostHistory, Mentions, BookmarkCollections, InviteKeys
|
||||
from ..models import Users, Posts, Reactions, Threads, Avatars, PostHistory, Mentions, BookmarkCollections, InviteKeys, Badges, BadgeUploads
|
||||
from ..constants import PermissionLevel, InfoboxKind
|
||||
from ..util import get_form_checkbox, time_now
|
||||
from ..lib.babycode import babycode_to_html
|
||||
@@ -24,6 +24,7 @@ import os
|
||||
import time
|
||||
|
||||
AVATAR_MAX_SIZE = 1000 * 1000 # 1MB
|
||||
BADGE_MAX_SIZE = 1000 * 500 # 500K
|
||||
|
||||
bp = Blueprint('users', __name__, url_prefix='/users/')
|
||||
|
||||
@@ -60,6 +61,22 @@ def validate_and_create_avatar(input_image, filename):
|
||||
except WandException:
|
||||
return False
|
||||
|
||||
def validate_and_create_badge(input_image, filename):
|
||||
try:
|
||||
with Image(blob=input_image) as img:
|
||||
if img.width != 88 or img.height != 31:
|
||||
return False
|
||||
if hasattr(img, 'sequence') and len(img.sequence) > 1:
|
||||
img = Image(image=img.sequence[0])
|
||||
img.strip()
|
||||
|
||||
img.format = 'webp'
|
||||
img.compression_quality = 90
|
||||
img.save(filename=filename)
|
||||
return True
|
||||
except WandException:
|
||||
return False
|
||||
|
||||
def anonymize_user(user_id):
|
||||
deleted_user = Users.find({'username': 'deleteduser'})
|
||||
|
||||
@@ -282,6 +299,7 @@ def posts(username):
|
||||
'users/posts.html', posts=posts,
|
||||
page=page, page_count=page_count,
|
||||
target_user=target_user,
|
||||
Reactions=Reactions,
|
||||
)
|
||||
|
||||
@bp.get('/<username>/threads/')
|
||||
@@ -305,6 +323,7 @@ def threads(username):
|
||||
'users/threads.html', threads=threads,
|
||||
page=page, page_count=page_count,
|
||||
target_user=target_user,
|
||||
Reactions=Reactions,
|
||||
)
|
||||
|
||||
@bp.get('/<username>/comments/')
|
||||
@@ -611,3 +630,107 @@ def revoke_invite_key(username):
|
||||
|
||||
invite.delete()
|
||||
return redirect(url_for('.settings', username=username, _anchor='invite'))
|
||||
|
||||
@bp.post('/<username>/settings/badges/')
|
||||
@login_required
|
||||
@redirect_to_own
|
||||
def save_badges(username):
|
||||
user = get_active_user()
|
||||
if user.is_guest():
|
||||
abort(403)
|
||||
|
||||
ids = request.form.getlist('id[]', type=int)
|
||||
badge_choices = request.form.getlist('badge_choice[]')
|
||||
files = request.files.getlist('badge_file[]')
|
||||
labels = request.form.getlist('label[]')
|
||||
links = request.form.getlist('link[]')
|
||||
|
||||
existing_badges = {badge.id: badge for badge in Badges.findall({'user_id': user.id})}
|
||||
|
||||
if not (len(ids) == len(badge_choices) == len(files) == len(labels) == len(links)):
|
||||
abort(400)
|
||||
|
||||
rejected_badges = []
|
||||
# print(ids)
|
||||
|
||||
# print(db.query(f'SELECT id FROM badges WHERE id NOT IN {db.binding_list(len(ids))}', *ids))
|
||||
deleted_badges = Badges.findall([
|
||||
('id', 'NOT IN', ids),
|
||||
('user_id', '=', user.id),
|
||||
])
|
||||
print(list(map(lambda x: x.id, deleted_badges)))
|
||||
|
||||
with db.transaction():
|
||||
for b in deleted_badges:
|
||||
b.delete()
|
||||
|
||||
for i, id in enumerate(ids):
|
||||
badge_upload_id = badge_choices[i]
|
||||
label = labels[i]
|
||||
link = links[i]
|
||||
pending_badge = {
|
||||
'label': label,
|
||||
'link': link,
|
||||
'sort_order': i,
|
||||
}
|
||||
if badge_upload_id == 'custom':
|
||||
file = files[i]
|
||||
if not file:
|
||||
rejected_badges.append(file.filename)
|
||||
continue
|
||||
file.seek(0, os.SEEK_END)
|
||||
file_size = file.tell()
|
||||
file.seek(0, os.SEEK_SET)
|
||||
|
||||
if file_size > BADGE_MAX_SIZE:
|
||||
rejected_badges.append(file.filename)
|
||||
continue
|
||||
|
||||
file_bytes = file.read()
|
||||
now = time_now()
|
||||
filename = f'u{user.id}d{now}s{i}.webp'
|
||||
output_path = os.path.join(current_app.config['BADGES_UPLOAD_PATH'], filename)
|
||||
proxied_filename = f'/static/badges/user/{filename}'
|
||||
res = validate_and_create_badge(file_bytes, output_path)
|
||||
if not res:
|
||||
rejected_badges.append(file.filename)
|
||||
continue
|
||||
|
||||
bu = BadgeUploads.create({
|
||||
'user_id': user.id,
|
||||
'uploaded_at': now,
|
||||
'file_path': proxied_filename,
|
||||
'original_filename': file.filename
|
||||
})
|
||||
else:
|
||||
bu = BadgeUploads.find({'id': badge_upload_id})
|
||||
if not bu:
|
||||
continue
|
||||
|
||||
pending_badge['upload'] = bu.id
|
||||
|
||||
if id == -1:
|
||||
pending_badge['user_id'] = user.id
|
||||
badge = Badges.create(pending_badge)
|
||||
else:
|
||||
badge = Badges.find({'id': id})
|
||||
if badge.user_id != user.id:
|
||||
continue
|
||||
if not badge:
|
||||
continue
|
||||
badge.update(pending_badge)
|
||||
|
||||
for stale_upload in BadgeUploads.get_unused_for_user(user.id):
|
||||
filename = os.path.join(current_app.config['BADGES_UPLOAD_PATH'], os.path.basename(stale_upload.file_path))
|
||||
os.remove(filename)
|
||||
stale_upload.delete()
|
||||
|
||||
message = 'Badges updated.'
|
||||
icon = InfoboxKind.INFO
|
||||
if rejected_badges:
|
||||
message += f';Some of your badges were incorrect and were not uploaded: {", ".join(rejected_badges)}.'
|
||||
icon = InfoboxKind.WARN
|
||||
|
||||
flash(message, icon)
|
||||
|
||||
return redirect(url_for('.settings', username=username))
|
||||
|
||||
Reference in New Issue
Block a user