From 4f57533d2c28e438e90ac5b78d6ffce116ad2117 Mon Sep 17 00:00:00 2001 From: Aevann Date: Wed, 6 Mar 2024 05:31:45 +0200 Subject: [PATCH] make hole sidebar/banner uploading and deleting not require page reload --- files/assets/js/hole_settings.js | 58 ++++++++++++++++++++++++++ files/routes/holes.py | 64 +++++++++++++++-------------- files/templates/hole/settings.html | 66 +++++++++++++++--------------- 3 files changed, 126 insertions(+), 62 deletions(-) create mode 100644 files/assets/js/hole_settings.js diff --git a/files/assets/js/hole_settings.js b/files/assets/js/hole_settings.js new file mode 100644 index 000000000..87d98c595 --- /dev/null +++ b/files/assets/js/hole_settings.js @@ -0,0 +1,58 @@ +function upload_banner(t, hole_name) { + postToast(t, + `/h/${hole_name}/settings/banners`, + { + "image": t.files[0] + }, + (xhr) => { + const list = document.getElementById('hole-banners') + const url = JSON.parse(xhr.response)['url'] + const html = ` +
+ /h/${hole_name} banner + +
` + + list.insertAdjacentHTML('afterbegin', html); + register_new_elements(list); + + const nobanners = document.getElementById('hole-banner-no-banners') + if (nobanners) nobanners.remove() + } + ); +} + +function upload_sidebar(t, hole_name) { + postToast(t, + `/h/${hole_name}/settings/sidebars`, + { + "image": t.files[0] + }, + (xhr) => { + const list = document.getElementById('hole-sidebars') + const url = JSON.parse(xhr.response)['url'] + const html = ` +
+ /h/${hole_name} sidebar + +
` + + list.insertAdjacentHTML('afterbegin', html); + register_new_elements(list); + + const nosidebars = document.getElementById('hole-sidebar-no-sidebars') + if (nosidebars) nosidebars.remove() + } + ); +} + +function delete_image(t, url) { + postToast(t, url, + { + "url": t.previousElementSibling.src + }, + () => { + t.parentElement.remove(); + } + ); +} diff --git a/files/routes/holes.py b/files/routes/holes.py index 75fa48dad..85094307e 100644 --- a/files/routes/holes.py +++ b/files/routes/holes.py @@ -537,7 +537,7 @@ def get_hole_css(hole): resp.headers.add("Content-Type", "text/css") return resp -@app.post("/h//settings/sidebars/") +@app.post("/h//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) @@ -550,7 +550,7 @@ def upload_hole_sidebar(v, hole): if not v.mods_hole(hole.name): abort(403) if v.shadowbanned: abort(500) - file = request.files["sidebar"] + file = request.files["image"] name = f'/images/{time.time()}'.replace('.','') + '.webp' file.save(name) @@ -568,26 +568,28 @@ def upload_hole_sidebar(v, hole): ) g.db.add(ma) - return redirect(f'/h/{hole}/settings') + return {"message": "Sidebar image uploaded successfully!", "url": sidebarurl} -@app.post("/h//settings/sidebars/delete/") +@app.post("/h//settings/sidebars/delete") @limiter.limit("1/second", deduct_when=lambda response: response.status_code < 400) @limiter.limit("1/second", deduct_when=lambda response: response.status_code < 400, key_func=get_ID) @auth_required -def delete_hole_sidebar(v, hole, index): +def delete_hole_sidebar(v, hole): hole = get_hole(hole) if not v.mods_hole(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] + + sidebar = request.values["url"] + + if sidebar not in hole.sidebarurls: + abort(404, "Sidebar image not found!") + + try: remove_media_using_link(sidebar) + except FileNotFoundError: pass + + hole.sidebarurls.remove(sidebar) g.db.add(hole) ma = HoleAction( @@ -598,7 +600,7 @@ def delete_hole_sidebar(v, hole, index): ) g.db.add(ma) - return {"message": f"Deleted sidebar {index} from /h/{hole} successfully"} + return {"message": "Sidebar image deleted successfully!"} @app.post("/h//settings/sidebars/delete_all") @limiter.limit("1/10 second;30/day", deduct_when=lambda response: response.status_code < 400) @@ -626,7 +628,7 @@ def delete_all_hole_sidebars(v, hole): return {"message": f"Deleted all sidebar images from /h/{hole} successfully"} -@app.post("/h//settings/banners/") +@app.post("/h//settings/banners") @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) @@ -639,7 +641,7 @@ def upload_hole_banner(v, hole): if not v.mods_hole(hole.name): abort(403) if v.shadowbanned: abort(500) - file = request.files["banner"] + file = request.files["image"] name = f'/images/{time.time()}'.replace('.','') + '.webp' file.save(name) @@ -657,37 +659,39 @@ def upload_hole_banner(v, hole): ) g.db.add(ma) - return redirect(f'/h/{hole}/settings') + return {"message": "Banner uploaded successfully!", "url": bannerurl} -@app.post("/h//settings/banners/delete/") +@app.post("/h//settings/banners/delete") @limiter.limit("1/second", deduct_when=lambda response: response.status_code < 400) @limiter.limit("1/second", deduct_when=lambda response: response.status_code < 400, key_func=get_ID) @auth_required -def delete_hole_banner(v, hole, index): +def delete_hole_banner(v, hole): hole = get_hole(hole) if not v.mods_hole(hole.name): abort(403) if not hole.bannerurls: - abort(404, f"Banner not found (/h/{hole.name} has no banners)") - if index < 0 or index >= len(hole.bannerurls): - abort(404, f'Banner not found (banner index {index} is not between 0 and {len(hole.bannerurls)})') - banner = hole.bannerurls[index] - try: - remove_media_using_link(banner) - except FileNotFoundError: - pass - del hole.bannerurls[index] + abort(404, f"Banner not found (/h/{hole.name} has no banner images)") + + banner = request.values["url"] + + if banner not in hole.bannerurls: + abort(404, "Banner not found!") + + try: remove_media_using_link(banner) + except FileNotFoundError: pass + + hole.bannerurls.remove(banner) g.db.add(hole) ma = HoleAction( hole=hole.name, - kind='delete_banner', + kind='delete_banner_image', _note=f'{banner}', user_id=v.id ) g.db.add(ma) - return {"message": f"Deleted banner {index} from /h/{hole} successfully"} + return {"message": "Banner deleted successfully!"} @app.post("/h//settings/banners/delete_all") @limiter.limit("1/10 second;30/day", deduct_when=lambda response: response.status_code < 400) diff --git a/files/templates/hole/settings.html b/files/templates/hole/settings.html index 574cc0d9f..9019f3f15 100644 --- a/files/templates/hole/settings.html +++ b/files/templates/hole/settings.html @@ -99,56 +99,58 @@

Banners

{% if not g.is_tor %}
-
- - -
+ +
All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.
{% endif %} - {% for banner in hole.bannerurls %} -
- /h/{{hole.name}} banner - -
- {% else %} -
- {{macros.ghost_box("No banners uploaded", "", 2, "flex:1")}} -
- {% endfor %} +
+ {% for banner in hole.bannerurls %} +
+ /h/{{hole.name}} banner + +
+ {% else %} +
+ {{macros.ghost_box("No banners uploaded", "", 2, "flex:1")}} +
+ {% endfor %} +

Sidebar Images

{% if not g.is_tor %}
-
- - -
+ +
All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.
{% endif %} - {% for sidebar in hole.sidebarurls %} -
- /h/{{hole.name}} sidebar - -
- {% else %} -
- {{macros.ghost_box("No sidebar images uploaded", "", 2, "flex:1")}} -
- {% endfor %} +
+ {% for sidebar in hole.sidebarurls %} +
+ /h/{{hole.name}} sidebar + +
+ {% else %} +
+ {{macros.ghost_box("No sidebar images uploaded", "", 2, "flex:1")}} +
+ {% endfor %} +
+ + {% endblock %}