forked from MarseyWorld/MarseyWorld
240 lines
7.5 KiB
Python
240 lines
7.5 KiB
Python
from shutil import copyfile, move
|
|
import imagehash
|
|
|
|
from files.classes.art_submissions import *
|
|
from files.helpers.config.const import *
|
|
from files.helpers.media import *
|
|
from files.helpers.useractions import badge_grant
|
|
from files.routes.wrappers import *
|
|
from files.__main__ import app, limiter
|
|
|
|
@app.get("/submit/sidebar")
|
|
@app.get("/submit/banners")
|
|
@feature_required('ART_SUBMISSIONS')
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
|
@auth_required
|
|
def submit_art(v):
|
|
kind = request.path.split('/')[-1].rstrip('s')
|
|
|
|
entries = g.db.query(ArtSubmission).filter(
|
|
ArtSubmission.kind == kind,
|
|
ArtSubmission.approved == False,
|
|
).order_by(ArtSubmission.id.desc()).all()
|
|
|
|
for entry in entries:
|
|
entry.author = g.db.query(User.username).filter_by(id=entry.author_id).one()[0]
|
|
entry.submitter = g.db.query(User.username).filter_by(id=entry.submitter_id).one()[0]
|
|
|
|
return render_template("submit_art.html", v=v, entries=entries, kind=kind.title())
|
|
|
|
|
|
@app.post("/submit/art")
|
|
@feature_required('ART_SUBMISSIONS')
|
|
@limiter.limit('1/second', scope=rpath)
|
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
|
@limiter.limit("20/day", deduct_when=lambda response: response.status_code < 400)
|
|
@limiter.limit("20/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
|
@auth_required
|
|
def submit_art_post(v):
|
|
if g.is_tor:
|
|
abort(400, "File uploads are not allowed through TOR!")
|
|
|
|
file = request.files["image"]
|
|
if not file or not file.content_type.startswith('image/'):
|
|
abort(400, "You need to submit an image!")
|
|
|
|
kind = request.values.get('kind', '').strip()
|
|
if kind not in {"sidebar", "banner"}:
|
|
abort(400, "Invalid kind!")
|
|
|
|
username = request.values.get('author', '').lower().strip()
|
|
author = get_user(username, v=v)
|
|
|
|
hole = request.values.get('hole', '').lower().strip()
|
|
if hole:
|
|
if not g.db.get(Hole, hole):
|
|
abort(404, "Hole not found!")
|
|
else:
|
|
hole = None
|
|
|
|
entry = ArtSubmission(
|
|
kind=kind,
|
|
author_id=author.id,
|
|
submitter_id=v.id,
|
|
hole=hole,
|
|
)
|
|
g.db.add(entry)
|
|
g.db.flush()
|
|
|
|
highquality = f'/asset_submissions/art/{entry.id}.webp'
|
|
file.save(highquality)
|
|
process_image(highquality, v) #to ensure not malware
|
|
|
|
# #to ensure under 2MB
|
|
temp = f'/asset_submissions/art/{entry.id}-t.webp'
|
|
copyfile(highquality, temp)
|
|
try: process_image(temp, v, resize=entry.resize)
|
|
except:
|
|
os.remove(highquality)
|
|
abort(413, f"Max size for site assets is {MAX_IMAGE_SIZE_BANNER_RESIZED_MB} MB")
|
|
os.remove(temp)
|
|
|
|
if kind == "banner" and v.id != AEVANN_ID:
|
|
with Image.open(highquality) as i:
|
|
if i.width != 2000 or i.height != 200:
|
|
os.remove(highquality)
|
|
abort(400, "Banners must be 2000x200 px")
|
|
|
|
path = f"files/assets/images/{SITE_NAME}/{entry.location_kind}"
|
|
if not entry.hashes:
|
|
for img in os.listdir(path):
|
|
img_path = f'{path}/{img}'
|
|
with Image.open(img_path) as i:
|
|
i_hash = str(imagehash.phash(i))
|
|
if i_hash not in entry.hashes.keys():
|
|
entry.hashes[i_hash] = img_path
|
|
|
|
with Image.open(highquality) as i:
|
|
i_hash = str(imagehash.phash(i))
|
|
if i_hash in entry.hashes.keys():
|
|
os.remove(highquality)
|
|
abort(400, f"Image already exists as a {entry.formatted_kind}!")
|
|
|
|
|
|
return {"message": f"{entry.msg_kind} submitted successfully!"}
|
|
|
|
|
|
@app.post("/admin/approve/art/<int:id>")
|
|
@feature_required('ART_SUBMISSIONS')
|
|
@limiter.limit('1/second', scope=rpath)
|
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
|
@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'])
|
|
def approve_art(v, id):
|
|
comment = request.values.get("comment", "").strip()
|
|
|
|
entry = g.db.get(ArtSubmission, id)
|
|
if not entry:
|
|
abort(404, "Art submission not found!")
|
|
|
|
old = f'/asset_submissions/art/{entry.id}.webp'
|
|
copyfile(old, f"/asset_submissions/art/original/{entry.id}.webp")
|
|
|
|
hole = request.values.get('hole', '').lower().strip()
|
|
if hole:
|
|
hole = g.db.get(Hole, hole)
|
|
if not hole:
|
|
abort(404, "Hole not found!")
|
|
|
|
filename = f'/images/{time.time()}'.replace('.','') + '.webp'
|
|
entry_url = SITE_FULL_IMAGES + filename
|
|
if entry.kind == "sidebar":
|
|
hole.sidebarurls.append(f"{SITE_FULL_IMAGES}{filename}")
|
|
else:
|
|
hole.bannerurls.append(f"{SITE_FULL_IMAGES}{filename}")
|
|
else:
|
|
filename = f"files/assets/images/{SITE_NAME}/{entry.location_kind}/{entry.id}.webp"
|
|
entry_url = f"{SITE_FULL_IMAGES}/i/{SITE_NAME}/{entry.location_kind}/{entry.id}.webp"
|
|
|
|
copyfile(old, filename)
|
|
process_image(filename, v, resize=entry.resize)
|
|
os.remove(old)
|
|
|
|
author = request.values.get('author').strip()
|
|
author = get_user(author)
|
|
entry.author_id = author.id
|
|
g.db.add(entry)
|
|
|
|
pay_reason = f'Reward for making <a href="{entry_url}">{entry.formatted_kind}</a>'
|
|
author.pay_account('coins', 250, pay_reason)
|
|
g.db.add(author)
|
|
|
|
if v.id != author.id:
|
|
msg = f"@{v.username} (a site admin) has approved a {entry.formatted_kind} you made:\n{entry_url}\n\nYou have received 250 coins as a reward!"
|
|
|
|
if comment:
|
|
msg += f"\nComment: `{comment}`"
|
|
|
|
send_repeatable_notification(author.id, msg)
|
|
|
|
if v.id != entry.submitter_id and author.id != entry.submitter_id:
|
|
msg = f"@{v.username} (a site admin) has approved a {entry.formatted_kind} you submitted:\n{entry_url}"
|
|
|
|
if comment:
|
|
msg += f"\nComment: `{comment}`"
|
|
|
|
send_repeatable_notification(entry.submitter_id, msg)
|
|
|
|
|
|
note = entry_url
|
|
if comment:
|
|
note += f' - Comment: "{comment}"'
|
|
|
|
ma = ModAction(
|
|
kind=f"approve_{entry.kind}",
|
|
user_id=v.id,
|
|
target_user_id=entry.author_id,
|
|
_note=note
|
|
)
|
|
g.db.add(ma)
|
|
|
|
entry.approved = True
|
|
|
|
all_by_author = g.db.query(ArtSubmission).filter_by(kind=entry.kind, author_id=author.id, approved=True).count()
|
|
if all_by_author >= 99:
|
|
badge_grant(badge_id=entry.badge_id_100, user=author)
|
|
elif all_by_author >= 9:
|
|
badge_grant(badge_id=entry.badge_id_10, user=author)
|
|
else:
|
|
badge_grant(badge_id=entry.badge_id_1, user=author)
|
|
|
|
return {"message": f"{entry.msg_kind} approved!"}
|
|
|
|
@app.post("/remove/art/<int:id>")
|
|
@feature_required('ART_SUBMISSIONS')
|
|
@limiter.limit('1/second', scope=rpath)
|
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
|
@auth_required
|
|
def remove_art(v, id):
|
|
comment = request.values.get("comment", "").strip()
|
|
|
|
entry = g.db.get(ArtSubmission, id)
|
|
if not entry:
|
|
abort(404, "Art submission not found!")
|
|
|
|
if v.id != entry.submitter_id and v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS']:
|
|
abort(403)
|
|
|
|
if v.id != entry.submitter_id:
|
|
entry_url = f'{SITE_FULL_IMAGES}/asset_submissions/art/{entry.id}.webp'
|
|
msg = f"@{v.username} (a site admin) has rejected a {entry.formatted_kind} you submitted:\n{entry_url}"
|
|
|
|
if comment:
|
|
msg += f"\nComment: `{comment}`"
|
|
|
|
send_repeatable_notification(entry.submitter_id, msg)
|
|
|
|
note = entry_url
|
|
if comment:
|
|
note += f' - Comment: "{comment}"'
|
|
|
|
ma = ModAction(
|
|
kind=f"reject_{entry.kind}",
|
|
user_id=v.id,
|
|
target_user_id=entry.author_id,
|
|
_note=note
|
|
)
|
|
g.db.add(ma)
|
|
|
|
if os.path.isfile(f'/asset_submissions/art/{entry.id}.webp'):
|
|
os.remove(f'/asset_submissions/art/{entry.id}.webp')
|
|
|
|
msg = f"{entry.msg_kind} removed!"
|
|
g.db.delete(entry)
|
|
|
|
return {"message": msg}
|