allow multiple sidebar images in holes

master
Aevann 2023-11-05 00:03:26 +02:00
parent 415b245630
commit 078933f17d
6 changed files with 127 additions and 55 deletions

View File

@ -18,7 +18,7 @@ class Hole(Base):
name = Column(VARCHAR(HOLE_NAME_COLUMN_LENGTH), primary_key=True)
sidebar = Column(VARCHAR(HOLE_SIDEBAR_COLUMN_LENGTH))
sidebar_html = Column(VARCHAR(HOLE_SIDEBAR_HTML_COLUMN_LENGTH))
sidebarurl = Column(VARCHAR(HOLE_SIDEBAR_URL_COLUMN_LENGTH))
sidebarurls = Column(MutableList.as_mutable(ARRAY(VARCHAR(HOLE_BANNER_URL_COLUMN_LENGTH))), default=MutableList([]), nullable=False)
bannerurls = Column(MutableList.as_mutable(ARRAY(VARCHAR(HOLE_BANNER_URL_COLUMN_LENGTH))), default=MutableList([]), nullable=False)
marseyurl = Column(VARCHAR(HOLE_MARSEY_URL_LENGTH))
css = Column(VARCHAR(HOLE_CSS_COLUMN_LENGTH))
@ -38,9 +38,9 @@ class Hole(Base):
@property
@lazy
def sidebar_url(self):
if self.sidebarurl: return self.sidebarurl
return f'{SITE_FULL_IMAGES}/i/{SITE_NAME}/sidebar.webp?x=6'
def random_sidebar(self):
if not self.sidebarurls: return None
return random.choice(self.sidebarurls)
@property
@lazy

View File

@ -511,6 +511,94 @@ def get_hole_css(hole):
resp.headers.add("Content-Type", "text/css")
return resp
@app.post("/h/<hole>/settings/sidebars/")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@limiter.limit("50/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("50/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def upload_hole_sidebar(v, hole):
if g.is_tor: abort(403, "Image uploads are not allowed through Tor")
hole = get_hole(hole)
if not v.mods(hole.name): abort(403)
if v.shadowbanned: abort(500)
file = request.files["sidebar"]
name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name)
sidebarurl = process_image(name, v, resize=1600)
hole.sidebarurls.append(sidebarurl)
g.db.add(hole)
ma = HoleAction(
hole=hole.name,
kind='upload_sidebar',
user_id=v.id
)
g.db.add(ma)
return redirect(f'/h/{hole}/settings')
@app.post("/h/<hole>/settings/sidebars/delete/<int:index>")
@limiter.limit("1/second;30/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("1/second;30/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def delete_hole_sidebar(v, hole, index):
hole = get_hole(hole)
if not v.mods(hole.name): abort(403)
if not hole.sidebarurls:
abort(404, f"Sidebar image not found (/h/{hole.name} has no sidebar images)")
if index < 0 or index >= len(hole.sidebarurls):
abort(404, f'Sidebar image not found (sidebar index {index} is not between 0 and {len(hole.sidebarurls)})')
sidebar = hole.sidebarurls[index]
try:
remove_media_using_link(sidebar)
except FileNotFoundError:
pass
del hole.sidebarurls[index]
g.db.add(hole)
ma = HoleAction(
hole=hole.name,
kind='delete_sidebar',
_note=index,
user_id=v.id
)
g.db.add(ma)
return {"message": f"Deleted sidebar {index} from /h/{hole} successfully"}
@app.post("/h/<hole>/settings/sidebars/delete_all")
@limiter.limit("1/10 second;30/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("1/10 second;30/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def delete_all_hole_sidebars(v, hole):
hole = get_hole(hole)
if not v.mods(hole.name): abort(403)
for sidebar in hole.sidebarurls:
try:
remove_media_using_link(sidebar)
except FileNotFoundError:
pass
hole.sidebarurls = []
g.db.add(hole)
ma = HoleAction(
hole=hole.name,
kind='delete_sidebar',
_note='all',
user_id=v.id
)
g.db.add(ma)
return {"message": f"Deleted all sidebar images from /h/{hole} successfully"}
@app.post("/h/<hole>/settings/banners/")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@ -599,39 +687,6 @@ def delete_all_hole_banners(v, hole):
return {"message": f"Deleted all banners from /h/{hole} successfully"}
@app.post("/h/<hole>/sidebar_image")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@limiter.limit("10/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("10/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def hole_sidebar(v, hole):
if g.is_tor: abort(403, "Image uploads are not allowed through TOR!")
hole = get_hole(hole)
if not v.mods(hole.name): abort(403)
if v.shadowbanned: abort(500)
file = request.files["sidebar"]
name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name)
sidebarurl = process_image(name, v, resize=400)
if sidebarurl:
if hole.sidebarurl:
remove_media_using_link(hole.sidebarurl)
hole.sidebarurl = sidebarurl
g.db.add(hole)
ma = HoleAction(
hole=hole.name,
kind='change_sidebar_image',
user_id=v.id
)
g.db.add(ma)
return redirect(f'/h/{hole}/settings')
@app.post("/h/<hole>/marsey_image")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)

View File

@ -15,7 +15,7 @@
</span>
</div>
<h5 class="mt-5">Marsey</h5>
<h5 class="mt-5 pt-5">Marsey</h5>
<div class="settings-section rounded">
<img loading="lazy" alt="sub marsey picture" src="{{hole.marsey_url}}" style="max-width:100px">
<form class="d-inline-block" action="/h/{{hole}}/marsey_image" method="post" enctype="multipart/form-data">
@ -29,21 +29,35 @@
</div>
</div>
<h5 class=" mt-5">Sidebar Picture</h5>
<div class="settings-section rounded">
<img class="mr-3" loading="lazy" alt="sub sidebar picture" src="{{hole.sidebar_url}}" style="max-width:min(300px,100%)">
<form class="d-inline-block mt-2" action="/h/{{hole}}/sidebar_image" method="post" enctype="multipart/form-data">
<input hidden name="formkey" value="{{v|formkey}}">
<label class="btn btn-secondary text-capitalize mr-2 mb-0">
Upload<input autocomplete="off" type="file" accept="image/*" {% if g.is_tor %}disabled{% endif %} hidden name="sidebar" data-nonce="{{g.nonce}}" onchange_submit>
</label>
</form>
<div class="text-small text-muted mt-3">
All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.
</div>
<h5 class="mt-5 pt-5">Sidebar Images</h5>
<div class="settings-section rounded hole-sidebar-update-section">
{% for sidebar in hole.sidebarurls %}
<section id="hole-sidebar-update-{{loop.index - 1}}" class="mt-5 d-block hole-settings-subsection" style="max-width:min(300px,100%)">
<img class="mr-3" loading="lazy" alt="/h/{{hole.name}} sidebar" src="{{sidebar}}" style="max-height:300px;max-width:100%">
<button class="btn btn-danger hole-sidebar-delete-button mt-2" id="hole-sidebar-delete-{{loop.index}}" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)" data-areyousure="postToastReload(this, '/h/{{hole.name}}/settings/sidebars/delete/{{loop.index - 1}}')">Delete</button>
</section>
{% else %}
<section id="hole-sidebar-no-sidebars" class="d-block hole-settings-subsection" style="max-width:min(300px,100%)">
{{macros.ghost_box("No sidebar images uploaded", "", 2, "flex:1")}}
</section>
{% endfor %}
{% if not g.is_tor %}
<section id="hole-sidebar-upload-new" class="mt-5 hole-settings-subsection">
<form class="d-inline-block" action="/h/{{hole.name}}/settings/sidebars/" method="post" enctype="multipart/form-data">
<input hidden name="formkey" value="{{v|formkey}}">
<label class="btn btn-secondary text-capitalize mr-2 mb-0">
Upload New Sidebar Image<input autocomplete="off" type="file" accept="image/*" hidden name="sidebar" data-nonce="{{g.nonce}}" onchange_submit>
</label>
</form>
<button type="button" class="btn btn-danger hole-sidebar-delete-button" id="hole-sidebar-delete-all" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)" data-areyousure="postToastReload(this, '/h/{{hole.name}}/settings/sidebars/delete_all')">Delete All Sidebar Images</button>
<div class="text-small text-muted mt-3">
All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.
</div>
</section>
{% endif %}
</div>
<h5 class="mt-5">Banners</h5>
<h5 class="mt-5 pt-5">Banners</h5>
<div class="settings-section rounded hole-banner-update-section">
{% for banner in hole.bannerurls %}
<section id="hole-banner-update-{{loop.index - 1}}" class="mt-5 d-block hole-settings-subsection">

View File

@ -17,7 +17,7 @@
{% block pagetitle %}{{SITE_NAME if not hole else '/h/' ~ hole.name}}{% endblock %}
{% block head_final %}
{% set preview = hole.siderbarurl if hole and hole.sidebarurl else hole.bannerurl %}
{% set preview = hole.random_sidebar if hole and hole.sidebarurls else hole.bannerurl %}
{% if hole %}
<meta property="og:type" content="article">

View File

@ -6,8 +6,8 @@
</h5>
</a>
{% if hole %}
{% set image = hole.sidebar_url %}
{% if hole and hole.sidebarurls %}
{% set image = hole.random_sidebar %}
{% elif IS_EVENT() %}
{% set image = macros.random_image("assets/events/" ~ IS_EVENT() ~ "/images/sidebar") %}
{% else %}
@ -15,7 +15,7 @@
{% endif %}
{% if request.path != '/sidebar' %}
{% if not (hole and hole.sidebarurl) and (IS_FISTMAS() or IS_HOMOWEEN()) %}
{% if not (hole and hole.sidebarurls) and (IS_FISTMAS() or IS_HOMOWEEN()) %}
{% include "events/shared/eye_tracking.html" %}
{% elif v and (v.is_banned or v.chud) %}
<a href="{{SITE_FULL_IMAGES}}/i/{{SITE_NAME}}/sidebar2.webp">

View File

@ -0,0 +1,3 @@
alter table holes add column sidebarurls character varying(60)[] default '{}'::character varying[] not null;
update holes set sidebarurls = array_append(sidebarurls, sidebarurl) WHERE sidebarurl is not null;
alter table holes drop column sidebarurl;