forked from rDrama/rDrama
allow multiple sidebar images in holes
parent
415b245630
commit
078933f17d
|
@ -18,7 +18,7 @@ class Hole(Base):
|
||||||
name = Column(VARCHAR(HOLE_NAME_COLUMN_LENGTH), primary_key=True)
|
name = Column(VARCHAR(HOLE_NAME_COLUMN_LENGTH), primary_key=True)
|
||||||
sidebar = Column(VARCHAR(HOLE_SIDEBAR_COLUMN_LENGTH))
|
sidebar = Column(VARCHAR(HOLE_SIDEBAR_COLUMN_LENGTH))
|
||||||
sidebar_html = Column(VARCHAR(HOLE_SIDEBAR_HTML_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)
|
bannerurls = Column(MutableList.as_mutable(ARRAY(VARCHAR(HOLE_BANNER_URL_COLUMN_LENGTH))), default=MutableList([]), nullable=False)
|
||||||
marseyurl = Column(VARCHAR(HOLE_MARSEY_URL_LENGTH))
|
marseyurl = Column(VARCHAR(HOLE_MARSEY_URL_LENGTH))
|
||||||
css = Column(VARCHAR(HOLE_CSS_COLUMN_LENGTH))
|
css = Column(VARCHAR(HOLE_CSS_COLUMN_LENGTH))
|
||||||
|
@ -38,9 +38,9 @@ class Hole(Base):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def sidebar_url(self):
|
def random_sidebar(self):
|
||||||
if self.sidebarurl: return self.sidebarurl
|
if not self.sidebarurls: return None
|
||||||
return f'{SITE_FULL_IMAGES}/i/{SITE_NAME}/sidebar.webp?x=6'
|
return random.choice(self.sidebarurls)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
|
|
|
@ -511,6 +511,94 @@ def get_hole_css(hole):
|
||||||
resp.headers.add("Content-Type", "text/css")
|
resp.headers.add("Content-Type", "text/css")
|
||||||
return resp
|
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/")
|
@app.post("/h/<hole>/settings/banners/")
|
||||||
@limiter.limit('1/second', scope=rpath)
|
@limiter.limit('1/second', scope=rpath)
|
||||||
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
@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"}
|
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")
|
@app.post("/h/<hole>/marsey_image")
|
||||||
@limiter.limit('1/second', scope=rpath)
|
@limiter.limit('1/second', scope=rpath)
|
||||||
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class="mt-5">Marsey</h5>
|
<h5 class="mt-5 pt-5">Marsey</h5>
|
||||||
<div class="settings-section rounded">
|
<div class="settings-section rounded">
|
||||||
<img loading="lazy" alt="sub marsey picture" src="{{hole.marsey_url}}" style="max-width:100px">
|
<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">
|
<form class="d-inline-block" action="/h/{{hole}}/marsey_image" method="post" enctype="multipart/form-data">
|
||||||
|
@ -29,21 +29,35 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class=" mt-5">Sidebar Picture</h5>
|
<h5 class="mt-5 pt-5">Sidebar Images</h5>
|
||||||
<div class="settings-section rounded">
|
<div class="settings-section rounded hole-sidebar-update-section">
|
||||||
<img class="mr-3" loading="lazy" alt="sub sidebar picture" src="{{hole.sidebar_url}}" style="max-width:min(300px,100%)">
|
{% for sidebar in hole.sidebarurls %}
|
||||||
<form class="d-inline-block mt-2" action="/h/{{hole}}/sidebar_image" method="post" enctype="multipart/form-data">
|
<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}}">
|
<input hidden name="formkey" value="{{v|formkey}}">
|
||||||
<label class="btn btn-secondary text-capitalize mr-2 mb-0">
|
<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>
|
Upload New Sidebar Image<input autocomplete="off" type="file" accept="image/*" hidden name="sidebar" data-nonce="{{g.nonce}}" onchange_submit>
|
||||||
</label>
|
</label>
|
||||||
</form>
|
</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">
|
<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.
|
All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class="mt-5">Banners</h5>
|
<h5 class="mt-5 pt-5">Banners</h5>
|
||||||
<div class="settings-section rounded hole-banner-update-section">
|
<div class="settings-section rounded hole-banner-update-section">
|
||||||
{% for banner in hole.bannerurls %}
|
{% for banner in hole.bannerurls %}
|
||||||
<section id="hole-banner-update-{{loop.index - 1}}" class="mt-5 d-block hole-settings-subsection">
|
<section id="hole-banner-update-{{loop.index - 1}}" class="mt-5 d-block hole-settings-subsection">
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
{% block pagetitle %}{{SITE_NAME if not hole else '/h/' ~ hole.name}}{% endblock %}
|
{% block pagetitle %}{{SITE_NAME if not hole else '/h/' ~ hole.name}}{% endblock %}
|
||||||
|
|
||||||
{% block head_final %}
|
{% 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 %}
|
{% if hole %}
|
||||||
<meta property="og:type" content="article">
|
<meta property="og:type" content="article">
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
</h5>
|
</h5>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% if hole %}
|
{% if hole and hole.sidebarurls %}
|
||||||
{% set image = hole.sidebar_url %}
|
{% set image = hole.random_sidebar %}
|
||||||
{% elif IS_EVENT() %}
|
{% elif IS_EVENT() %}
|
||||||
{% set image = macros.random_image("assets/events/" ~ IS_EVENT() ~ "/images/sidebar") %}
|
{% set image = macros.random_image("assets/events/" ~ IS_EVENT() ~ "/images/sidebar") %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if request.path != '/sidebar' %}
|
{% 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" %}
|
{% include "events/shared/eye_tracking.html" %}
|
||||||
{% elif v and (v.is_banned or v.chud) %}
|
{% elif v and (v.is_banned or v.chud) %}
|
||||||
<a href="{{SITE_FULL_IMAGES}}/i/{{SITE_NAME}}/sidebar2.webp">
|
<a href="{{SITE_FULL_IMAGES}}/i/{{SITE_NAME}}/sidebar2.webp">
|
||||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue