From 83bc86846155806c479fdab409d96ef3e6d2f294 Mon Sep 17 00:00:00 2001 From: Matias Silva Date: Wed, 23 Sep 2020 09:45:00 +0100 Subject: [PATCH] Use dynamic image sizes --- lightbluetent/admin.py | 205 ++++++++++++++----- lightbluetent/config.py | 1 + lightbluetent/templates/admin/admin.html | 32 ++- lightbluetent/templates/home/home.html | 4 +- lightbluetent/templates/society/welcome.html | 34 +-- 5 files changed, 194 insertions(+), 82 deletions(-) diff --git a/lightbluetent/admin.py b/lightbluetent/admin.py index 897a2b1..8201721 100644 --- a/lightbluetent/admin.py +++ b/lightbluetent/admin.py @@ -1,7 +1,16 @@ import os import copy -from flask import Blueprint, render_template, request, flash, abort, redirect, url_for, current_app +from flask import ( + Blueprint, + render_template, + request, + flash, + abort, + redirect, + url_for, + current_app, +) from lightbluetent.models import db, User, Society from lightbluetent.home import auth_decorator from lightbluetent.utils import gen_unique_string, match_social, get_social_by_id @@ -12,6 +21,7 @@ bp = Blueprint("admin", __name__, url_prefix="/admin") + def remove_logo(path): images_dir = current_app.config["IMAGES_DIR"] @@ -27,6 +37,7 @@ def remove_logo(path): os.remove(path) current_app.logger.info(f"Deleted logo '{ path }'") + # Delete logo on disk for the society with given uid def delete_society_logo(uid): @@ -44,6 +55,7 @@ def delete_society_logo(uid): db.session.commit() return + # Delete logo on disk for the society with given uid def delete_society_bbb_logo(uid): @@ -67,19 +79,22 @@ def delete_society_bbb_logo(uid): def delete_society_session(uid, session_id): society = Society.query.filter_by(uid=uid).first() sessions = copy.deepcopy(society.sessions) - session_to_delete = next((session for session in sessions if session["id"] == session_id), None) + session_to_delete = next( + (session for session in sessions if session["id"] == session_id), None + ) if session_to_delete is None: return else: - current_app.logger.info(f"For uid='{ society.uid }': deleting session [ day: { session_to_delete['day'] }, start: { session_to_delete['start'] }, end: { session_to_delete['end'] } ]") + current_app.logger.info( + f"For uid='{ society.uid }': deleting session [ day: { session_to_delete['day'] }, start: { session_to_delete['start'] }, end: { session_to_delete['end'] } ]" + ) sessions.remove(session_to_delete) society.sessions = sessions db.session.commit() return - @bp.route("/", methods=("GET", "POST")) @auth_decorator def admin(uid): @@ -108,11 +123,20 @@ def admin(uid): values = {} - for key in ("soc_name", "website", "description", "short_description", - "welcome_text", "logo", "banner_text", - "banner_color", "new_admin_crsid", - "new_session_day", "new_session_start", - "new_session_end"): + for key in ( + "soc_name", + "website", + "description", + "short_description", + "welcome_text", + "logo", + "banner_text", + "banner_color", + "new_admin_crsid", + "new_session_day", + "new_session_start", + "new_session_end", + ): values[key] = request.form.get(key, "").strip() for key in ("mute_on_start", "disable_private_chat"): @@ -141,19 +165,32 @@ def admin(uid): # Delete the old logo if it's not the default delete_society_logo(uid) - static_filename = society.uid + "_" + gen_unique_string() + logo_extension + static_filename = ( + society.uid + "_" + gen_unique_string() + logo_extension + ) path = os.path.join(images_dir, static_filename) - current_app.logger.info(f"For user { crsid }, society uid='{ society.uid }': changing logo...") + current_app.logger.info( + f"For user { crsid }, society uid='{ society.uid }': changing logo..." + ) if not os.path.isdir(images_dir): - current_app.logger.error(f"'{ images_dir }': no such directory.") + current_app.logger.error( + f"'{ images_dir }': no such directory." + ) abort(500) + maxwidth, maxheight = current_app.config["MAX_LOGO_SIZE"] logo_img = Image.open(logo) - logo_resized = logo_img.resize((512, 512)) + ratio = min(maxwidth / logo_img.width, maxheight / logo_img.height) + # possible optimization with reduce here? + logo_resized = logo_img.resize( + (round(logo_img.width * ratio), round(logo_img.height * ratio)) + ) logo_resized.save(path) - current_app.logger.info(f"For uid='{ society.uid }': saved new logo '{ path }'") + current_app.logger.info( + f"For uid='{ society.uid }': saved new logo '{ path }'" + ) society.logo = static_filename db.session.commit() @@ -167,23 +204,33 @@ def admin(uid): # Delete the old logo if it's not the default delete_society_bbb_logo(uid) - static_filename = society.uid + "_bbb_" + gen_unique_string() + bbb_logo_extension + static_filename = ( + society.uid + "_bbb_" + gen_unique_string() + bbb_logo_extension + ) path = os.path.join(images_dir, static_filename) - current_app.logger.info(f"For user { crsid }, society uid='{ society.uid }': changing bbb_logo...") + current_app.logger.info( + f"For user { crsid }, society uid='{ society.uid }': changing bbb_logo..." + ) if not os.path.isdir(images_dir): - current_app.logger.error(f"'{ images_dir }': no such directory.") + current_app.logger.error( + f"'{ images_dir }': no such directory." + ) abort(500) bbb_logo_img = Image.open(bbb_logo) bbb_logo_resized = bbb_logo_img.resize((100, 30)) bbb_logo_resized.save(path) - current_app.logger.info(f"For uid='{ society.uid }': saved new bbb_logo to '{ path }'") + current_app.logger.info( + f"For uid='{ society.uid }': saved new bbb_logo to '{ path }'" + ) society.bbb_logo = static_filename db.session.commit() - current_app.logger.info(f"For uid='{ society.uid }': updated bbb_logo.") + current_app.logger.info( + f"For uid='{ society.uid }': updated bbb_logo." + ) else: errors["bbb_logo"] = "Invalid file." @@ -196,14 +243,18 @@ def admin(uid): # Adding a new admin if values["new_admin_crsid"] != "": - current_app.logger.info(f"For uid='{ society.uid }': { crsid } is adding new admin { values['new_admin_crsid'] }...") + current_app.logger.info( + f"For uid='{ society.uid }': { crsid } is adding new admin { values['new_admin_crsid'] }..." + ) new_admin = User.query.filter_by(crsid=values["new_admin_crsid"]).first() if not new_admin: - errors["new_admin_crsid"] = "That user is not registered yet. Users must register before being added as administrators." + errors[ + "new_admin_crsid" + ] = "That user is not registered yet. Users must register before being added as administrators." is_new_admin = True # Add a new session - if (values["new_session_start"] and values["new_session_end"]): + if values["new_session_start"] and values["new_session_end"]: start_time = [int(nstr) for nstr in values["new_session_start"].split(":")] end_time = [int(nstr) for nstr in values["new_session_end"].split(":")] @@ -213,23 +264,30 @@ def admin(uid): t2 = time(hour=end_time[0], minute=end_time[1]) if t1 > t2: - errors["new_session_start"] = "Unfortunately, time travel is not possible." + errors[ + "new_session_start" + ] = "Unfortunately, time travel is not possible." is_new_session = True - elif (values["new_session_start"]): + elif values["new_session_start"]: errors["new_session_end"] = "No end time specified." - elif (values["new_session_end"]): + elif values["new_session_end"]: errors["new_session_start"] = "No start time specified." if errors: flash("There are errors with the information you provided.") - return render_template("admin/admin.html", - page_title=f"Stall administration for { society.name }", - society=society, crsid=crsid, errors=errors, - sessions_data=sessions_data, - page_parent=url_for("home.home"), has_directory_page=has_directory_page, - **values) + return render_template( + "admin/admin.html", + page_title=f"Stall administration for { society.name }", + society=society, + crsid=crsid, + errors=errors, + sessions_data=sessions_data, + page_parent=url_for("home.home"), + has_directory_page=has_directory_page, + **values, + ) else: society.name = values["soc_name"] society.website = values["website"] @@ -246,15 +304,15 @@ def admin(uid): else: found_social["url"] = value found_social["type"] = match_social(value) - flag_modified(society, 'socials') + flag_modified(society, "socials") else: # create a new social field # and check if its empty if value: social_type = match_social(value) - social_data = {"id": id, "url": value, "type": social_type } + social_data = {"id": id, "url": value, "type": social_type} society.socials.append(social_data) - flag_modified(society, 'socials') + flag_modified(society, "socials") society.description = values["description"] society.short_description = values["short_description"] @@ -268,20 +326,28 @@ def admin(uid): society.admins.append(new_admin) if is_new_session: - society.sessions.append({"id": gen_unique_string(), - "day": values["new_session_day"], - "start": values["new_session_start"], - "end": values["new_session_end"]}) + society.sessions.append( + { + "id": gen_unique_string(), + "day": values["new_session_day"], + "start": values["new_session_start"], + "end": values["new_session_end"], + } + ) # we need this to ensure that sqlalchemy updates the val - flag_modified(society, 'sessions') + flag_modified(society, "sessions") db.session.commit() if is_new_admin: - current_app.logger.info(f"For uid='{ society.uid }': added new admin { new_admin }.") + current_app.logger.info( + f"For uid='{ society.uid }': added new admin { new_admin }." + ) if is_new_session: - current_app.logger.info(f"For uid='{ society.uid }': { crsid } added new session [ day: { values['new_session_day'] }, start: { values['new_session_start'] }, end: { values['new_session_end'] } ]") + current_app.logger.info( + f"For uid='{ society.uid }': { crsid } added new session [ day: { values['new_session_day'] }, start: { values['new_session_start'] }, end: { values['new_session_end'] } ]" + ) flash("Settings saved.") @@ -299,15 +365,21 @@ def admin(uid): "banner_color": society.banner_color, "logo": society.logo, "mute_on_start": society.mute_on_start, - "disable_private_chat": society.disable_private_chat + "disable_private_chat": society.disable_private_chat, } - return render_template("admin/admin.html", - page_title=f"Stall administration for { society.name }", - society=society, crsid=crsid, errors={}, - sessions_data=sessions_data, - page_parent=url_for("home.home"), has_directory_page=has_directory_page, - **values) + return render_template( + "admin/admin.html", + page_title=f"Stall administration for { society.name }", + society=society, + crsid=crsid, + errors={}, + sessions_data=sessions_data, + page_parent=url_for("home.home"), + has_directory_page=has_directory_page, + **values, + ) + @bp.route("//reset_banner") @auth_decorator @@ -333,6 +405,7 @@ def reset_banner(uid): return redirect(url_for("admin.admin", uid=society.uid)) + @bp.route("//delete_logo") @auth_decorator def delete_logo(uid): @@ -348,12 +421,15 @@ def delete_logo(uid): if society not in user.societies: abort(403) - current_app.logger.info(f"User { crsid } deleting logo { society.logo } for uid '{ society.uid }'...") + current_app.logger.info( + f"User { crsid } deleting logo { society.logo } for uid '{ society.uid }'..." + ) delete_society_logo(uid) return redirect(url_for("admin.admin", uid=society.uid)) + @bp.route("//delete_bbb_logo") @auth_decorator def delete_bbb_logo(uid): @@ -369,12 +445,15 @@ def delete_bbb_logo(uid): if society not in user.societies: abort(403) - current_app.logger.info(f"User { crsid } deleting bbb_logo { society.bbb_logo } for uid '{ society.uid }'...") + current_app.logger.info( + f"User { crsid } deleting bbb_logo { society.bbb_logo } for uid '{ society.uid }'..." + ) delete_society_bbb_logo(uid) return redirect(url_for("admin.admin", uid=society.uid)) + @bp.route("//delete_session/") @auth_decorator def delete_session(uid, session_id): @@ -386,7 +465,9 @@ def delete_session(uid, session_id): crsid = auth_decorator.principal - current_app.logger.info(f"User { crsid } deleting session { session_id } for uid '{ society.uid }'...") + current_app.logger.info( + f"User { crsid } deleting session { session_id } for uid '{ society.uid }'..." + ) user = User.query.filter_by(crsid=crsid).first() @@ -397,6 +478,7 @@ def delete_session(uid, session_id): return redirect(url_for("admin.admin", uid=society.uid)) + @bp.route("//delete", methods=("GET", "POST")) @auth_decorator def delete(uid): @@ -421,16 +503,31 @@ def delete(uid): errors["soc_short_name"] = "That is the wrong name." if errors: - return render_template("admin/delete.html", page_title=f"Delete { society.name }", crsid=crsid, society=society, errors=errors) + return render_template( + "admin/delete.html", + page_title=f"Delete { society.name }", + crsid=crsid, + society=society, + errors=errors, + ) else: delete_society_logo(uid) db.session.delete(society) db.session.commit() - current_app.logger.info(f"User { crsid } deleted society with uid='{ society.uid }'") + current_app.logger.info( + f"User { crsid } deleted society with uid='{ society.uid }'" + ) return redirect(url_for("home.home")) else: - return render_template("admin/delete.html", page_title=f"Delete { society.name }", crsid=crsid, society=society, errors={}) + return render_template( + "admin/delete.html", + page_title=f"Delete { society.name }", + crsid=crsid, + society=society, + errors={}, + ) + diff --git a/lightbluetent/config.py b/lightbluetent/config.py index b4ccf2c..3a4290a 100644 --- a/lightbluetent/config.py +++ b/lightbluetent/config.py @@ -23,6 +23,7 @@ class Config(object): DEFAULT_LOGO = "default_logo.png" DEFAULT_BBB_LOGO = "default_bbb_logo.png" + MAX_LOGO_SIZE = (512, 512) LOGO_ALLOWED_EXTENSIONS = {".png", ".jpeg", ".jpg", ".gif"} IMAGES_DIR = "lightbluetent/static/images" diff --git a/lightbluetent/templates/admin/admin.html b/lightbluetent/templates/admin/admin.html index f099f15..7e63cd7 100644 --- a/lightbluetent/templates/admin/admin.html +++ b/lightbluetent/templates/admin/admin.html @@ -43,7 +43,8 @@ {{social_field(n, id=social.id, url=social.url)}} {% endfor %} {{social_field(n)}} - {{ _("Add multiple URLs and emails to spruce up your main page.") }} + {{ _("Add multiple URLs and emails to spruce up your main page.") }} {% else %} {% set social_defaults = ["e.g. https://facebook.com/srcf.net", "e.g. spqr2@srcf.net"] %} @@ -52,7 +53,8 @@ {% for n in range(2) %} {{social_field(n, social_defaults[n])}} {% endfor %} - {{ _("Add multiple URLs and emails to spruce up your main page.") }} + {{ _("Add multiple URLs and emails to spruce up your main page.") }} {% endif %} {% if has_directory_page %} @@ -63,7 +65,8 @@ {%- if errors.short_description is defined %} {{ errors.short_description }} {%- endif %} - {{ _("A short summary of your society. This will appear on the directory page. Maximum 200 characters.") }} + {{ _("A short summary of your society. This will appear on the directory page. Maximum 200 characters.") }} {% endif %}
@@ -73,14 +76,18 @@ {%- if errors.description is defined %} {{ errors.description }} {%- endif %} - {{ _("Write a bit about your society here. What do you do? How often do you meet? How many members do you have?") }} + {{ _("Write a bit about your society here. What do you do? How often do you meet? How many members do you have?") }}
{% set current_logo = "images/{}".format(society.logo) %} - Society logo +
+ Society logo +
@@ -90,7 +97,8 @@ {{ errors.logo }} {%- endif %} Your logo must be a PNG, JPEG or GIF file smaller than 1 MB. - {{ _("This logo will be displayed on your society's welcome page.") }} + {{ _("This logo will be displayed on your society's welcome page.") }} Delete logo
@@ -175,7 +183,7 @@

- +
@@ -192,7 +200,8 @@ {%- if errors.new_admin_crsid is defined %} {{ errors.new_admin_crsid }} {%- endif %} - {{ _("Enter another user's CRSid to grant them administrative privileges. This will allow them to change anything on this page, including deleting the society. The user should already be registered with us. Once an admin has been added, they cannot be removed.") }} + {{ _("Enter another user's CRSid to grant them administrative privileges. This will allow them to change anything on this page, including deleting the society. The user should already be registered with us. Once an admin has been added, they cannot be removed.") }}

@@ -266,7 +275,8 @@

Day {{n}}

-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/lightbluetent/templates/home/home.html b/lightbluetent/templates/home/home.html index 2ca0084..e06e71a 100644 --- a/lightbluetent/templates/home/home.html +++ b/lightbluetent/templates/home/home.html @@ -13,7 +13,9 @@
{% set current_logo = "images/{}".format(society.logo) %} {% if society.logo != config["DEFAULT_LOGO"] %} - Society logo +
+ Society logo +
{% endif %}
diff --git a/lightbluetent/templates/society/welcome.html b/lightbluetent/templates/society/welcome.html index 9570fe3..45d65e9 100644 --- a/lightbluetent/templates/society/welcome.html +++ b/lightbluetent/templates/society/welcome.html @@ -21,11 +21,11 @@ {% if social.type == "email"%} {{ social.url }} {% else %} - {% if social.url.startswith("https://") or social.url.startswith("http://") %} - {{ social.url}} - {% else %} - {{ social.url}} - {% endif %} + {% if social.url.startswith("https://") or social.url.startswith("http://") %} + {{ social.url}} + {% else %} + {{ social.url}} + {% endif %} {% endif %} {%- endmacro %} @@ -50,20 +50,20 @@

{{ society.name }} {% endif %} {% for social in society.socials %} - {{social_match(social)}} + {{social_match(social)}} {% endfor %}
{% endif %} -
+
{% if has_logo %} -
- Logo +
+ Logo
{% endif %} -
+
{% if society.description %}
{{ _("Society description") }}
@@ -109,19 +109,21 @@
Join the live session
- + {%- if errors.full_name is defined %} {{ errors.full_name }} {%- endif %}
+ {% if not running %}style="pointer-events: none;" {% endif %} value="{{ _('Join session') }}">
-{% endblock %} +{% endblock %} \ No newline at end of file