diff --git a/snikket_web/__init__.py b/snikket_web/__init__.py
index 88860ba..b3c5015 100644
--- a/snikket_web/__init__.py
+++ b/snikket_web/__init__.py
@@ -155,6 +155,11 @@ class AppConfig:
"sv",
], converter=autosplit)
apple_store_url = environ.var("")
+ # Default limit of 1 MiB is what was discovered to be the effective limit
+ # in #67, hence we set that here for now.
+ # Future versions may change this default, and the standard deployment
+ # tools may also very well override it.
+ max_avatar_size = environ.var(1024*1024, converter=int)
_UPPER_CASE = "".join(map(chr, range(ord("A"), ord("Z")+1)))
@@ -185,6 +190,7 @@ def create_app() -> quart.Quart:
app.config["SITE_NAME"] = config.site_name or config.domain
app.config["AVATAR_CACHE_TTL"] = config.avatar_cache_ttl
app.config["APPLE_STORE_URL"] = config.apple_store_url
+ app.config["MAX_AVATAR_SIZE"] = config.max_avatar_size
app.context_processor(proc)
app.register_error_handler(
diff --git a/snikket_web/templates/unauth.html b/snikket_web/templates/unauth.html
index 897035c..10fdff3 100644
--- a/snikket_web/templates/unauth.html
+++ b/snikket_web/templates/unauth.html
@@ -9,7 +9,7 @@
{#- -#}
-
+
{%- for category, message in get_flashed_messages(True) -%}
{% if category == "success" %}
diff --git a/snikket_web/templates/user_profile.html b/snikket_web/templates/user_profile.html
index e7ce934..f420801 100644
--- a/snikket_web/templates/user_profile.html
+++ b/snikket_web/templates/user_profile.html
@@ -1,10 +1,11 @@
{% extends "app.html" %}
-{% from "library.j2" import standard_button, form_button, avatar with context %}
+{% from "library.j2" import standard_button, form_button, render_errors, avatar with context %}
{% block content %}
{% trans %}Update your profile{% endtrans %}
+
{% endblock %}
diff --git a/snikket_web/translations/messages.pot b/snikket_web/translations/messages.pot
index 493dfe9..efa8aa1 100644
--- a/snikket_web/translations/messages.pot
+++ b/snikket_web/translations/messages.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2021-02-23 07:55+0100\n"
+"POT-Creation-Date: 2021-03-20 12:56+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME
\n"
"Language-Team: LANGUAGE \n"
@@ -149,39 +149,39 @@ msgstr ""
msgid "Main"
msgstr ""
-#: snikket_web/invite.py:104
+#: snikket_web/invite.py:106
msgid "Username"
msgstr ""
-#: snikket_web/invite.py:108 snikket_web/invite.py:175 snikket_web/main.py:42
+#: snikket_web/invite.py:110 snikket_web/invite.py:177 snikket_web/main.py:42
msgid "Password"
msgstr ""
-#: snikket_web/invite.py:112 snikket_web/invite.py:179
+#: snikket_web/invite.py:114 snikket_web/invite.py:181
msgid "Confirm password"
msgstr ""
-#: snikket_web/invite.py:116 snikket_web/invite.py:183
+#: snikket_web/invite.py:118 snikket_web/invite.py:185
msgid "The passwords must match"
msgstr ""
-#: snikket_web/invite.py:121
+#: snikket_web/invite.py:123
msgid "Create account"
msgstr ""
-#: snikket_web/invite.py:148
+#: snikket_web/invite.py:150
msgid "That username is already taken"
msgstr ""
-#: snikket_web/invite.py:152 snikket_web/invite.py:216
+#: snikket_web/invite.py:154 snikket_web/invite.py:218
msgid "Registration was declined for unknown reasons"
msgstr ""
-#: snikket_web/invite.py:156
+#: snikket_web/invite.py:158
msgid "The username is not valid"
msgstr ""
-#: snikket_web/invite.py:188 snikket_web/templates/user_home.html:32
+#: snikket_web/invite.py:190 snikket_web/templates/user_home.html:32
#: snikket_web/templates/user_passwd.html:29
msgid "Change password"
msgstr ""
@@ -202,67 +202,77 @@ msgstr ""
msgid "Login successful!"
msgstr ""
-#: snikket_web/user.py:28
+#: snikket_web/user.py:29
msgid "Current password"
msgstr ""
-#: snikket_web/user.py:33
+#: snikket_web/user.py:34
msgid "New password"
msgstr ""
-#: snikket_web/user.py:38
+#: snikket_web/user.py:39
msgid "Confirm new password"
msgstr ""
-#: snikket_web/user.py:42
+#: snikket_web/user.py:43
msgid "The new passwords must match"
msgstr ""
-#: snikket_web/user.py:49
+#: snikket_web/user.py:50
msgid "Sign out"
msgstr ""
-#: snikket_web/user.py:54
+#: snikket_web/user.py:55
msgid "Nobody"
msgstr ""
-#: snikket_web/user.py:55
+#: snikket_web/user.py:56
msgid "Friends only"
msgstr ""
-#: snikket_web/user.py:56
+#: snikket_web/user.py:57
msgid "Everyone"
msgstr ""
#: snikket_web/templates/admin_delete_user.html:12
-#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:62
+#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:63
msgid "Display name"
msgstr ""
-#: snikket_web/user.py:66
+#: snikket_web/user.py:67
msgid "Avatar"
msgstr ""
-#: snikket_web/user.py:70
+#: snikket_web/user.py:71
msgid "Profile visibility"
msgstr ""
-#: snikket_web/user.py:75
+#: snikket_web/user.py:76
msgid "Update profile"
msgstr ""
-#: snikket_web/user.py:100
+#: snikket_web/user.py:101
msgid "Incorrect password"
msgstr ""
-#: snikket_web/user.py:104
+#: snikket_web/user.py:105
msgid "Password changed"
msgstr ""
-#: snikket_web/user.py:146
+#: snikket_web/user.py:113
+msgid ""
+"The chosen avatar is too big. To be able to upload larger avatars, please"
+" use the app"
+msgstr ""
+
+#: snikket_web/user.py:161
msgid "Profile updated"
msgstr ""
+#: snikket_web/templates/unauth.html:18 snikket_web/user.py:169
+msgid "Error"
+msgstr ""
+
#: snikket_web/templates/_footer.html:4
#, python-format
msgid "A Snikket service"
@@ -480,7 +490,7 @@ msgstr ""
#: snikket_web/templates/admin_reset_user_password.html:25
#: snikket_web/templates/user_logout.html:10
#: snikket_web/templates/user_passwd.html:27
-#: snikket_web/templates/user_profile.html:28
+#: snikket_web/templates/user_profile.html:32
msgid "Back"
msgstr ""
@@ -1068,10 +1078,6 @@ msgstr ""
msgid "Operation successful"
msgstr ""
-#: snikket_web/templates/unauth.html:18
-msgid "Error"
-msgstr ""
-
#: snikket_web/templates/user_home.html:9
msgid "Welcome!"
msgstr ""
@@ -1140,11 +1146,11 @@ msgstr ""
msgid "Profile"
msgstr ""
-#: snikket_web/templates/user_profile.html:19
+#: snikket_web/templates/user_profile.html:23
msgid "Visibility"
msgstr ""
-#: snikket_web/templates/user_profile.html:20
+#: snikket_web/templates/user_profile.html:24
msgid ""
"This section allows you to control who can see your profile information, "
"like avatar and nickname."
diff --git a/snikket_web/user.py b/snikket_web/user.py
index 982ad7a..3f14ce6 100644
--- a/snikket_web/user.py
+++ b/snikket_web/user.py
@@ -9,6 +9,7 @@ from quart import (
redirect,
url_for,
flash,
+ current_app,
)
import quart.exceptions
@@ -109,9 +110,17 @@ async def change_pw() -> typing.Union[str, quart.Response]:
return await render_template("user_passwd.html", form=form)
+EAVATARTOOBIG = _l(
+ "The chosen avatar is too big. To be able to upload larger "
+ "avatars, please use the app"
+)
+
+
@bp.route("/profile", methods=["GET", "POST"])
@client.require_session()
async def profile() -> typing.Union[str, quart.Response]:
+ max_avatar_size = current_app.config["MAX_AVATAR_SIZE"]
+
form = ProfileForm()
if request.method != "POST":
user_info = await client.get_user_info()
@@ -125,30 +134,40 @@ async def profile() -> typing.Union[str, quart.Response]:
if form.validate_on_submit():
user_info = await client.get_user_info()
+ ok = True
file_info = (await request.files).get(form.avatar.name)
if file_info is not None:
mimetype = file_info.mimetype
data = file_info.stream.read()
- if len(data) > 0:
+ if len(data) > max_avatar_size:
+ print(len(data), max_avatar_size)
+ form.avatar.errors.append(EAVATARTOOBIG)
+ ok = False
+ elif len(data) > 0:
await client.set_user_avatar(data, mimetype)
- if user_info.get("nickname") != form.nickname.data:
- await client.set_user_nickname(form.nickname.data)
+ if ok:
+ if user_info.get("nickname") != form.nickname.data:
+ await client.set_user_nickname(form.nickname.data)
- access_model = form.profile_access_model.data
- await asyncio.gather(
- client.set_avatar_access_model(access_model),
- client.set_vcard_access_model(access_model),
- client.set_nickname_access_model(access_model),
- )
+ access_model = form.profile_access_model.data
+ await asyncio.gather(
+ client.set_avatar_access_model(access_model),
+ client.set_vcard_access_model(access_model),
+ client.set_nickname_access_model(access_model),
+ )
- await flash(
- _("Profile updated"),
- "success",
- )
- return redirect(url_for(".profile"))
+ await flash(
+ _("Profile updated"),
+ "success",
+ )
+ return redirect(url_for(".profile"))
- return await render_template("user_profile.html", form=form)
+ return await render_template("user_profile.html",
+ form=form,
+ max_avatar_size=max_avatar_size,
+ avatar_too_big_warning_header=_l("Error"),
+ avatar_too_big_warning=EAVATARTOOBIG)
@bp.route("/logout", methods=["GET", "POST"])