Compare commits

...

5 Commits

Author SHA1 Message Date
Jonas Schäfer
b36fc0d5ac Bump hsluv to 5.x
Fixes #134.
2022-05-30 17:38:18 +02:00
Jonas Schäfer
68f72743c5 Bump quart to version 0.17
This is needed because jinja2 had an update which caused the portal to
not work at all:

```
ImportError: cannot import name 'escape' from 'jinja2'
```

Quart needed updating for that.

This update required a lot of typefixes. Apparently, the "canned"
responses (like redirect) are now plain werkzeug responses, while
quart.Response does not inherit from werkzeug.Response (otherwise, we
could've changed the type annotations to werkzeug.Response everywhere,
but that doesn't work because a quart.Response is not a
werkzeug.Response).

P.S.: This time, I *did* check that avatar uploads don't break (see
b007afc).
2022-05-30 17:37:54 +02:00
Daniel Holmgaard
8741efb2c4 Translated using Weblate (Danish)
Currently translated at 100.0% (321 of 321 strings)

Translation: Snikket/Web Portal
Translate-URL: http://i18n.sotecware.net/projects/snikket/web-portal/da/
2022-05-30 14:01:08 +00:00
Daniel Holmgaard
a0e8933b64 Translated using Weblate (Danish)
Currently translated at 95.6% (307 of 321 strings)

Translation: Snikket/Web Portal
Translate-URL: http://i18n.sotecware.net/projects/snikket/web-portal/da/
2022-05-26 23:01:53 +00:00
Zack Zhou
edb3154127 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (321 of 321 strings)

Translation: Snikket/Web Portal
Translate-URL: http://i18n.sotecware.net/projects/snikket/web-portal/zh_Hans/
2022-05-20 00:01:45 +00:00
12 changed files with 146 additions and 125 deletions

View File

@@ -1,7 +1,7 @@
aiohttp~=3.6 aiohttp~=3.6
quart~=0.11,<0.15 quart~=0.17
flask-wtf~=0.14 flask-wtf~=0.14
hsluv~=0.0.2 hsluv~=5.0
flask-babel~=1.0 flask-babel~=1.0
email-validator~=1.1 email-validator~=1.1
environ-config~=20.0 environ-config~=20.0

View File

@@ -18,6 +18,8 @@ from quart import (
jsonify, jsonify,
) )
import werkzeug.exceptions
import environ import environ
from . import colour, infra from . import colour, infra
@@ -40,7 +42,7 @@ async def proc() -> typing.Dict[str, typing.Any]:
try: try:
user_info = await infra.client.get_user_info() user_info = await infra.client.get_user_info()
except (aiohttp.ClientError, quart.exceptions.HTTPException): except (aiohttp.ClientError, werkzeug.exceptions.HTTPException):
user_info = {} user_info = {}
return { return {
@@ -105,16 +107,16 @@ async def backend_error_handler(exc: Exception) -> quart.Response:
async def generic_http_error( async def generic_http_error(
exc: quart.exceptions.HTTPException, exc: werkzeug.exceptions.HTTPException,
) -> quart.Response: ) -> quart.Response:
return quart.Response( return quart.Response(
await render_template( await render_template(
"generic_http_error.html", "generic_http_error.html",
status=exc.status_code, status=exc.code,
description=exc.description, description=exc.description,
name=exc.name, name=exc.name,
), ),
status=exc.status_code, status=exc.code,
) )
@@ -200,19 +202,19 @@ def create_app() -> quart.Quart:
app.context_processor(proc) app.context_processor(proc)
app.register_error_handler( app.register_error_handler(
aiohttp.ClientConnectorError, aiohttp.ClientConnectorError,
backend_error_handler, # type:ignore backend_error_handler,
) )
app.register_error_handler( app.register_error_handler(
quart.exceptions.HTTPException, werkzeug.exceptions.HTTPException,
generic_http_error, # type:ignore generic_http_error, # type:ignore
) )
app.register_error_handler( app.register_error_handler(
Exception, Exception,
generic_error_handler, # type:ignore generic_error_handler,
) )
@app.route("/") @app.route("/")
async def index() -> quart.Response: async def index() -> werkzeug.Response:
if infra.client.has_session: if infra.client.has_session:
return redirect(url_for('user.index')) return redirect(url_for('user.index'))

View File

@@ -7,6 +7,8 @@ from datetime import datetime
import aiohttp import aiohttp
import werkzeug.exceptions
import quart.flask_patch import quart.flask_patch
import wtforms import wtforms
@@ -92,7 +94,7 @@ class EditUserForm(BaseForm):
@bp.route("/user/<localpart>/", methods=["GET", "POST"]) @bp.route("/user/<localpart>/", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def edit_user(localpart: str) -> typing.Union[quart.Response, str]: async def edit_user(localpart: str) -> typing.Union[werkzeug.Response, str]:
target_user_info = await client.get_user_by_localpart(localpart) target_user_info = await client.get_user_by_localpart(localpart)
form = EditUserForm() form = EditUserForm()
@@ -147,7 +149,7 @@ class DeleteUserForm(BaseForm):
@bp.route("/user/<localpart>/delete", methods=["GET", "POST"]) @bp.route("/user/<localpart>/delete", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def delete_user(localpart: str) -> typing.Union[str, quart.Response]: async def delete_user(localpart: str) -> typing.Union[str, werkzeug.Response]:
target_user_info = await client.get_user_by_localpart(localpart) target_user_info = await client.get_user_by_localpart(localpart)
form = DeleteUserForm() form = DeleteUserForm()
if form.validate_on_submit(): if form.validate_on_submit():
@@ -186,7 +188,7 @@ async def debug_user(localpart: str) -> typing.Union[str, quart.Response]:
@client.require_admin_session() @client.require_admin_session()
async def user_password_reset_link( async def user_password_reset_link(
id_: str, id_: str,
) -> typing.Union[str, quart.Response]: ) -> typing.Union[str, werkzeug.Response]:
invite_info = await client.get_invite_by_id( invite_info = await client.get_invite_by_id(
id_, id_,
) )
@@ -278,7 +280,7 @@ class InvitePost(BaseForm):
@bp.route("/invitations", methods=["GET", "POST"]) @bp.route("/invitations", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def invitations() -> typing.Union[str, quart.Response]: async def invitations() -> typing.Union[str, werkzeug.Response]:
invites = sorted( invites = sorted(
( (
invite invite
@@ -324,7 +326,7 @@ class InviteForm(BaseForm):
@bp.route("/invitation/-/new", methods=["POST"]) @bp.route("/invitation/-/new", methods=["POST"])
@client.require_admin_session() @client.require_admin_session()
async def create_invite() -> typing.Union[str, quart.Response]: async def create_invite() -> typing.Union[str, werkzeug.Response]:
form = InvitePost() form = InvitePost()
circles = await client.list_groups() circles = await client.list_groups()
form.circles.choices = [ form.circles.choices = [
@@ -352,7 +354,7 @@ async def create_invite() -> typing.Union[str, quart.Response]:
@bp.route("/invitation/<id_>", methods=["GET", "POST"]) @bp.route("/invitation/<id_>", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def edit_invite(id_: str) -> typing.Union[str, quart.Response]: async def edit_invite(id_: str) -> typing.Union[str, werkzeug.Response]:
try: try:
invite_info = await client.get_invite_by_id(id_) invite_info = await client.get_invite_by_id(id_)
except aiohttp.ClientResponseError as exc: except aiohttp.ClientResponseError as exc:
@@ -418,7 +420,7 @@ async def circles() -> str:
@bp.route("/circle/-/new", methods=["POST"]) @bp.route("/circle/-/new", methods=["POST"])
@client.require_admin_session() @client.require_admin_session()
async def create_circle() -> typing.Union[str, quart.Response]: async def create_circle() -> typing.Union[str, werkzeug.Response]:
create_form = CirclePost() create_form = CirclePost()
if create_form.validate_on_submit(): if create_form.validate_on_submit():
circle = await client.create_group( circle = await client.create_group(
@@ -464,7 +466,7 @@ class EditCircleForm(BaseForm):
@bp.route("/circle/<id_>", methods=["GET", "POST"]) @bp.route("/circle/<id_>", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def edit_circle(id_: str) -> typing.Union[str, quart.Response]: async def edit_circle(id_: str) -> typing.Union[str, werkzeug.Response]:
async with client.authenticated_session() as session: async with client.authenticated_session() as session:
try: try:
circle = await client.get_group_by_id( circle = await client.get_group_by_id(
@@ -626,7 +628,7 @@ class AnnouncementForm(BaseForm):
@bp.route("/system/", methods=["GET", "POST"]) @bp.route("/system/", methods=["GET", "POST"])
@client.require_admin_session() @client.require_admin_session()
async def system() -> typing.Union[str, quart.Response]: async def system() -> typing.Union[str, werkzeug.Response]:
form = AnnouncementForm() form = AnnouncementForm()
if form.validate_on_submit(): if form.validate_on_submit():
@@ -657,7 +659,7 @@ async def system() -> typing.Union[str, quart.Response]:
now = time.time() now = time.time()
try: try:
prosody_metrics = await client.get_system_metrics() prosody_metrics = await client.get_system_metrics()
except quart.exceptions.NotFound: except werkzeug.exceptions.NotFound:
# server does not offer the endpoint for whatever reason -- ignore # server does not offer the endpoint for whatever reason -- ignore
prosody_metrics = {} prosody_metrics = {}

View File

@@ -15,6 +15,8 @@ from quart import (
session as http_session, session as http_session,
) )
import werkzeug
import wtforms import wtforms
from flask_babel import lazy_gettext as _l, gettext from flask_babel import lazy_gettext as _l, gettext
@@ -46,14 +48,14 @@ def apple_store_badge() -> str:
@bp.context_processor @bp.context_processor
def context() -> typing.Mapping[str, typing.Any]: def context() -> typing.Dict[str, typing.Any]:
return { return {
"apple_store_badge": apple_store_badge, "apple_store_badge": apple_store_badge,
} }
@bp.route("/<id_>") @bp.route("/<id_>")
async def view_old(id_: str) -> quart.Response: async def view_old(id_: str) -> werkzeug.Response:
return redirect(url_for(".view", id_=id_)) return redirect(url_for(".view", id_=id_))
@@ -131,7 +133,7 @@ class RegisterForm(BaseForm):
@bp.route("/<id_>/register", methods=["GET", "POST"]) @bp.route("/<id_>/register", methods=["GET", "POST"])
async def register(id_: str) -> typing.Union[str, quart.Response]: async def register(id_: str) -> typing.Union[str, werkzeug.Response]:
try: try:
invite = await client.get_public_invite_by_id(id_) invite = await client.get_public_invite_by_id(id_)
except aiohttp.ClientResponseError as exc: except aiohttp.ClientResponseError as exc:
@@ -199,7 +201,7 @@ class ResetForm(BaseForm):
@bp.route("/<id_>/reset", methods=["GET", "POST"]) @bp.route("/<id_>/reset", methods=["GET", "POST"])
async def reset(id_: str) -> typing.Union[str, quart.Response]: async def reset(id_: str) -> typing.Union[str, werkzeug.Response]:
try: try:
invite = await client.get_public_invite_by_id(id_) invite = await client.get_public_invite_by_id(id_)
except aiohttp.ClientResponseError as exc: except aiohttp.ClientResponseError as exc:
@@ -300,5 +302,5 @@ async def reset_success() -> str:
@bp.route("/-") @bp.route("/-")
async def index() -> quart.Response: async def index() -> werkzeug.Response:
return redirect(url_for("index")) return redirect(url_for("index"))

View File

@@ -18,6 +18,8 @@ from quart import (
flash, flash,
) )
import werkzeug.exceptions
import babel import babel
import wtforms import wtforms
@@ -48,7 +50,7 @@ class LoginForm(BaseForm):
@bp.route("/-") @bp.route("/-")
async def index() -> quart.Response: async def index() -> werkzeug.Response:
return redirect(url_for("index")) return redirect(url_for("index"))
@@ -56,7 +58,7 @@ ERR_CREDENTIALS_INVALID = _l("Invalid username or password.")
@bp.route("/login", methods=["GET", "POST"]) @bp.route("/login", methods=["GET", "POST"])
async def login() -> typing.Union[str, quart.Response]: async def login() -> typing.Union[str, werkzeug.Response]:
if client.has_session and (await client.test_session()): if client.has_session and (await client.test_session()):
return redirect(url_for('user.index')) return redirect(url_for('user.index'))
@@ -76,7 +78,7 @@ async def login() -> typing.Union[str, quart.Response]:
password = form.password.data password = form.password.data
try: try:
await client.login(jid, password) await client.login(jid, password)
except quart.exceptions.Unauthorized: except werkzeug.exceptions.Unauthorized:
form.password.errors.append(ERR_CREDENTIALS_INVALID) form.password.errors.append(ERR_CREDENTIALS_INVALID)
else: else:
await flash( await flash(
@@ -95,14 +97,13 @@ async def about() -> str:
if current_app.debug or client.is_admin_session: if current_app.debug or client.is_admin_session:
version = _version.version version = _version.version
extra_versions["Quart"] = quart.__version__
extra_versions["aiohttp"] = aiohttp.__version__ extra_versions["aiohttp"] = aiohttp.__version__
extra_versions["babel"] = babel.__version__ extra_versions["babel"] = babel.__version__
extra_versions["wtforms"] = wtforms.__version__ extra_versions["wtforms"] = wtforms.__version__
extra_versions["flask-wtf"] = flask_wtf.__version__ extra_versions["flask-wtf"] = flask_wtf.__version__
try: try:
extra_versions["Prosody"] = await client.get_server_version() extra_versions["Prosody"] = await client.get_server_version()
except quart.exceptions.Unauthorized: except werkzeug.exceptions.Unauthorized:
extra_versions["Prosody"] = "unknown" extra_versions["Prosody"] = "unknown"
return await render_template( return await render_template(

View File

@@ -19,7 +19,9 @@ from quart import (
current_app, _app_ctx_stack, session as http_session, abort, redirect, current_app, _app_ctx_stack, session as http_session, abort, redirect,
url_for, url_for,
) )
import quart.exceptions import quart
import werkzeug.exceptions
from . import xmpputil from . import xmpputil
from .xmpputil import split_jid from .xmpputil import split_jid
@@ -386,16 +388,16 @@ class ProsodyClient:
) -> typing.Callable[ ) -> typing.Callable[
[typing.Callable[..., typing.Awaitable[T]]], [typing.Callable[..., typing.Awaitable[T]]],
typing.Callable[..., typing.Awaitable[ typing.Callable[..., typing.Awaitable[
typing.Union[T, quart.Response]]]]: typing.Union[T, quart.Response, werkzeug.Response]]]]:
def decorator( def decorator(
f: typing.Callable[..., typing.Awaitable[T]], f: typing.Callable[..., typing.Awaitable[T]],
) -> typing.Callable[..., typing.Awaitable[ ) -> typing.Callable[..., typing.Awaitable[
typing.Union[T, quart.Response]]]: typing.Union[T, quart.Response, werkzeug.Response]]]:
@functools.wraps(f) @functools.wraps(f)
async def wrapped( async def wrapped(
*args: typing.Any, *args: typing.Any,
**kwargs: typing.Any, **kwargs: typing.Any,
) -> typing.Union[T, quart.Response]: ) -> typing.Union[T, quart.Response, werkzeug.Response]:
if not self.has_session or not (await self.test_session()): if not self.has_session or not (await self.test_session()):
redirect_to_value = redirect_to redirect_to_value = redirect_to
if redirect_to_value is not False: if redirect_to_value is not False:
@@ -415,17 +417,17 @@ class ProsodyClient:
) -> typing.Callable[ ) -> typing.Callable[
[typing.Callable[..., typing.Awaitable[T]]], [typing.Callable[..., typing.Awaitable[T]]],
typing.Callable[..., typing.Awaitable[ typing.Callable[..., typing.Awaitable[
typing.Union[T, quart.Response]]]]: typing.Union[T, quart.Response, werkzeug.Response]]]]:
def decorator( def decorator(
f: typing.Callable[..., typing.Awaitable[T]], f: typing.Callable[..., typing.Awaitable[T]],
) -> typing.Callable[..., typing.Awaitable[ ) -> typing.Callable[..., typing.Awaitable[
typing.Union[T, quart.Response]]]: typing.Union[T, quart.Response, werkzeug.Response]]]:
@functools.wraps(f) @functools.wraps(f)
@self.require_session(redirect_to=redirect_to) @self.require_session(redirect_to=redirect_to)
async def wrapped( async def wrapped(
*args: typing.Any, *args: typing.Any,
**kwargs: typing.Any, **kwargs: typing.Any,
) -> typing.Union[T, quart.Response]: ) -> typing.Union[T, quart.Response, werkzeug.Response]:
if not self.is_admin_session: if not self.is_admin_session:
raise abort(403, "This is not for you.") raise abort(403, "This is not for you.")
@@ -492,7 +494,7 @@ class ProsodyClient:
session=session, session=session,
) )
avatar_hash = avatar_info["sha1"] avatar_hash = avatar_info["sha1"]
except quart.exceptions.HTTPException: except werkzeug.exceptions.HTTPException:
avatar_hash = None avatar_hash = None
return { return {
@@ -644,7 +646,7 @@ class ProsodyClient:
new_access_model, new_access_model,
) )
)) ))
except quart.exceptions.NotFound: except werkzeug.exceptions.NotFound:
if ignore_not_found: if ignore_not_found:
return return
raise raise
@@ -774,7 +776,7 @@ class ProsodyClient:
session: aiohttp.ClientSession, session: aiohttp.ClientSession,
) -> str: ) -> str:
access_models = filter( access_models = filter(
lambda x: not isinstance(x, quart.exceptions.NotFound), lambda x: not isinstance(x, werkzeug.exceptions.NotFound),
await asyncio.gather( await asyncio.gather(
self.get_avatar_access_model(session=session), self.get_avatar_access_model(session=session),
self.get_nickname_access_model(session=session), self.get_nickname_access_model(session=session),

View File

@@ -6,18 +6,18 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: translations@snikket.org\n"
"POT-Creation-Date: 2022-01-17 17:27+0100\n" "POT-Creation-Date: 2022-01-17 17:27+0100\n"
"PO-Revision-Date: 2021-04-02 19:01+0000\n" "PO-Revision-Date: 2022-05-30 14:01+0000\n"
"Last-Translator: Daniel Holmgaard <annoncer@protonmail.com>\n" "Last-Translator: Daniel Holmgaard <fovatis@tutanota.com>\n"
"Language-Team: Danish <https://i18n.sotecware.net/projects/snikket/web-" "Language-Team: Danish <http://i18n.sotecware.net/projects/snikket/web-portal/"
"portal/da/>\n" "da/>\n"
"Language: da\n" "Language: da\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.5.1\n" "X-Generator: Weblate 4.8.1\n"
"Generated-By: Babel 2.9.0\n" "Generated-By: Babel 2.9.0\n"
#: snikket_web/admin.py:68 snikket_web/templates/admin_delete_user.html:10 #: snikket_web/admin.py:68 snikket_web/templates/admin_delete_user.html:10
@@ -194,23 +194,23 @@ msgstr "Bruger fjernet fra cirkel"
#: snikket_web/admin.py:609 #: snikket_web/admin.py:609
msgid "Message contents" msgid "Message contents"
msgstr "" msgstr "Meddelelsens indhold"
#: snikket_web/admin.py:615 #: snikket_web/admin.py:615
msgid "Only send to online users" msgid "Only send to online users"
msgstr "" msgstr "Send kun til online brugere"
#: snikket_web/admin.py:619 #: snikket_web/admin.py:619
msgid "Post to all users" msgid "Post to all users"
msgstr "" msgstr "Send til alle brugere"
#: snikket_web/admin.py:623 #: snikket_web/admin.py:623
msgid "Send preview to yourself" msgid "Send preview to yourself"
msgstr "" msgstr "Send forhåndsvisning til dig selv"
#: snikket_web/admin.py:645 #: snikket_web/admin.py:645
msgid "Announcement sent!" msgid "Announcement sent!"
msgstr "" msgstr "Bekendgørelse sendt!"
#: snikket_web/infra.py:51 #: snikket_web/infra.py:51
msgid "Main" msgid "Main"
@@ -221,6 +221,8 @@ msgid ""
"The account data you tried to import is too large to upload. Please contact " "The account data you tried to import is too large to upload. Please contact "
"your Snikket operator." "your Snikket operator."
msgstr "" msgstr ""
"De kontodata, du forsøgte at importere, er for store til at uploade. Kontakt "
"din Snikket-operatør."
#: snikket_web/invite.py:112 #: snikket_web/invite.py:112
msgid "Username" msgid "Username"
@@ -261,11 +263,11 @@ msgstr "Ændr adgangskode"
#: snikket_web/invite.py:244 #: snikket_web/invite.py:244
msgid "Account data file" msgid "Account data file"
msgstr "" msgstr "Kontodatafil"
#: snikket_web/invite.py:248 #: snikket_web/invite.py:248
msgid "Import data" msgid "Import data"
msgstr "" msgstr "Importer data"
#: snikket_web/invite.py:269 #: snikket_web/invite.py:269
#, python-format #, python-format
@@ -273,6 +275,8 @@ msgid ""
"The account data you tried to import is in an unknown format. Please upload " "The account data you tried to import is in an unknown format. Please upload "
"an XML file in XEP-0227 format (provided format: %(mimetype)s)." "an XML file in XEP-0227 format (provided format: %(mimetype)s)."
msgstr "" msgstr ""
"De kontodata, du forsøgte at importere, er i et ukendt format. Upload en XML-"
"fil i XEP-0227-format (forudsat format: %(mimetype)s)."
#: snikket_web/invite.py:289 snikket_web/templates/unauth.html:18 #: snikket_web/invite.py:289 snikket_web/templates/unauth.html:18
#: snikket_web/user.py:178 #: snikket_web/user.py:178
@@ -341,11 +345,11 @@ msgstr "Opdater profil"
#: snikket_web/user.py:82 #: snikket_web/user.py:82
msgid "Account data" msgid "Account data"
msgstr "" msgstr "Kontodata"
#: snikket_web/user.py:86 #: snikket_web/user.py:86
msgid "Upload" msgid "Upload"
msgstr "" msgstr "Upload"
#: snikket_web/user.py:111 #: snikket_web/user.py:111
msgid "Incorrect password." msgid "Incorrect password."
@@ -369,11 +373,11 @@ msgstr "Profil opdateret"
#: snikket_web/user.py:184 #: snikket_web/user.py:184
msgid "Export" msgid "Export"
msgstr "" msgstr "Exporter"
#: snikket_web/user.py:202 #: snikket_web/user.py:202
msgid "You currently have no account data to export." msgid "You currently have no account data to export."
msgstr "" msgstr "Du har i øjeblikket ingen kontodata at eksportere."
#: snikket_web/templates/_footer.html:4 #: snikket_web/templates/_footer.html:4
#, python-format #, python-format
@@ -662,7 +666,7 @@ msgstr "Cirkel medlemmer"
#: snikket_web/templates/admin_edit_circle.html:71 #: snikket_web/templates/admin_edit_circle.html:71
msgid "The user has been deleted from the server." msgid "The user has been deleted from the server."
msgstr "" msgstr "Brugeren er blevet slettet fra serveren."
#: snikket_web/templates/admin_edit_circle.html:71 #: snikket_web/templates/admin_edit_circle.html:71
#: snikket_web/templates/library.j2:108 #: snikket_web/templates/library.j2:108
@@ -876,22 +880,20 @@ msgstr "Håndter invitationer"
#: snikket_web/templates/admin_home.html:35 #: snikket_web/templates/admin_home.html:35
msgid "System health" msgid "System health"
msgstr "" msgstr "Systemets sundhed"
#: snikket_web/templates/admin_home.html:38 #: snikket_web/templates/admin_home.html:38
msgid "View the server status or send a broadcast message to all users." msgid "View the server status or send a broadcast message to all users."
msgstr "" msgstr "Vis serverstatus, eller send en udsendelsesmeddelelse til alle brugere."
#: snikket_web/templates/admin_home.html:40 #: snikket_web/templates/admin_home.html:40
msgid "Send a broadcast message to all users." msgid "Send a broadcast message to all users."
msgstr "" msgstr "Send en udsendelsesmeddelelse til alle brugere."
#: snikket_web/templates/admin_home.html:43 #: snikket_web/templates/admin_home.html:43
#: snikket_web/templates/admin_system.html:4 #: snikket_web/templates/admin_system.html:4
#, fuzzy
#| msgid "Manage users"
msgid "Manage system" msgid "Manage system"
msgstr "Håndter brugere" msgstr "Håndter system"
#: snikket_web/templates/admin_home.html:48 #: snikket_web/templates/admin_home.html:48
msgid "Go back to your user's web portal page." msgid "Go back to your user's web portal page."
@@ -952,11 +954,11 @@ msgstr "Ødelæg link"
#: snikket_web/templates/admin_system.html:6 #: snikket_web/templates/admin_system.html:6
msgid "Overall system status" msgid "Overall system status"
msgstr "" msgstr "Samlet systemstatus"
#: snikket_web/templates/admin_system.html:9 #: snikket_web/templates/admin_system.html:9
msgid "System load (5 minute average)" msgid "System load (5 minute average)"
msgstr "" msgstr "Systembelastning (5 minutters gennemsnit)"
#: snikket_web/templates/admin_system.html:14 #: snikket_web/templates/admin_system.html:14
#: snikket_web/templates/admin_system.html:22 #: snikket_web/templates/admin_system.html:22
@@ -967,11 +969,11 @@ msgstr ""
#: snikket_web/templates/admin_system.html:76 #: snikket_web/templates/admin_system.html:76
#: snikket_web/templates/admin_system.html:84 #: snikket_web/templates/admin_system.html:84
msgid "unknown" msgid "unknown"
msgstr "" msgstr "ukendt"
#: snikket_web/templates/admin_system.html:17 #: snikket_web/templates/admin_system.html:17
msgid "Memory use" msgid "Memory use"
msgstr "" msgstr "Forbrug af hukommelse"
#: snikket_web/templates/admin_system.html:20 #: snikket_web/templates/admin_system.html:20
#, python-format #, python-format
@@ -979,54 +981,56 @@ msgid ""
"%(percentage_global)s of %(mem_available)s. Of that, Snikket uses " "%(percentage_global)s of %(mem_available)s. Of that, Snikket uses "
"%(percentage_snikket)s." "%(percentage_snikket)s."
msgstr "" msgstr ""
"%(percentage_global)s af %(mem_available)s. Der af bruger Snikket "
"%(percentage_snikket)s."
#: snikket_web/templates/admin_system.html:27 #: snikket_web/templates/admin_system.html:27
msgid "Web portal status" msgid "Web portal status"
msgstr "" msgstr "Webportalens status"
#: snikket_web/templates/admin_system.html:30 #: snikket_web/templates/admin_system.html:30
#: snikket_web/templates/admin_system.html:53 #: snikket_web/templates/admin_system.html:53
msgid "Version" msgid "Version"
msgstr "" msgstr "Version"
#: snikket_web/templates/admin_system.html:31 #: snikket_web/templates/admin_system.html:31
#: snikket_web/templates/admin_system.html:54 #: snikket_web/templates/admin_system.html:54
msgid "View all versions" msgid "View all versions"
msgstr "" msgstr "Vis alle versioner"
#: snikket_web/templates/admin_system.html:32 #: snikket_web/templates/admin_system.html:32
#: snikket_web/templates/admin_system.html:55 #: snikket_web/templates/admin_system.html:55
msgid "Average CPU use" msgid "Average CPU use"
msgstr "" msgstr "Gennemsnitlig CPU-forbrug"
#: snikket_web/templates/admin_system.html:40 #: snikket_web/templates/admin_system.html:40
#: snikket_web/templates/admin_system.html:63 #: snikket_web/templates/admin_system.html:63
msgid "Current memory use" msgid "Current memory use"
msgstr "" msgstr "Nuværende hukommelsesbrug"
#: snikket_web/templates/admin_system.html:50 #: snikket_web/templates/admin_system.html:50
#, fuzzy
#| msgid "Snikket Web Portal"
msgid "Snikket server status" msgid "Snikket server status"
msgstr "Snikket Webportal" msgstr "Snikket server status"
#: snikket_web/templates/admin_system.html:71 #: snikket_web/templates/admin_system.html:71
msgid "Storage used by shared files" msgid "Storage used by shared files"
msgstr "" msgstr "Lagerplads, der bruges af delte filer"
#: snikket_web/templates/admin_system.html:79 #: snikket_web/templates/admin_system.html:79
msgid "Connected devices" msgid "Connected devices"
msgstr "" msgstr "Forbundet enheder"
#: snikket_web/templates/admin_system.html:90 #: snikket_web/templates/admin_system.html:90
msgid "Broadcast message" msgid "Broadcast message"
msgstr "" msgstr "Send besked"
#: snikket_web/templates/admin_system.html:92 #: snikket_web/templates/admin_system.html:92
msgid "" msgid ""
"This form allows you to send a message to all users currently online on your " "This form allows you to send a message to all users currently online on your "
"Snikket server. Use it wisely." "Snikket server. Use it wisely."
msgstr "" msgstr ""
"Denne formular giver dig mulighed for at sende en besked til alle brugere, "
"der i øjeblikket er online på din Snikket-server. Brug den med omtanke."
#: snikket_web/templates/admin_users.html:19 #: snikket_web/templates/admin_users.html:19
msgid "The user is an administrator." msgid "The user is an administrator."
@@ -1300,22 +1304,20 @@ msgid ""
"You can now safely close this page, or log in to the web portal to <a href=" "You can now safely close this page, or log in to the web portal to <a href="
"\"%(login_url)s\">manage your account</a>." "\"%(login_url)s\">manage your account</a>."
msgstr "" msgstr ""
"Du kan nu trygt lukke denne side eller logge ind på webportalen for at <a "
"href=\"%(login_url)s\">administrere din konto</a>."
#: snikket_web/templates/invite_success.html:21 #: snikket_web/templates/invite_success.html:21
#, fuzzy
#| msgid "Operation successful"
msgid "Import successful" msgid "Import successful"
msgstr "Operation lykkes" msgstr "Importering lykkes"
#: snikket_web/templates/invite_success.html:22 #: snikket_web/templates/invite_success.html:22
msgid "Congratulations! Your account data has been successfully imported." msgid "Congratulations! Your account data has been successfully imported."
msgstr "" msgstr "Tillykke! Dine kontodata er blevet importeret."
#: snikket_web/templates/invite_success.html:26 #: snikket_web/templates/invite_success.html:26
#, fuzzy
#| msgid "Using the Snikket app"
msgid "Moving to Snikket?" msgid "Moving to Snikket?"
msgstr "Bruger Snikket appen" msgstr "Flytte til Snikket?"
#: snikket_web/templates/invite_success.html:27 #: snikket_web/templates/invite_success.html:27
msgid "" msgid ""
@@ -1324,10 +1326,14 @@ msgid ""
"information, etc.) from your previous account. When you have exported the " "information, etc.) from your previous account. When you have exported the "
"data from your previous account, upload it using the form below." "data from your previous account, upload it using the form below."
msgstr "" msgstr ""
"Hvis du flytter fra en anden Snikket-platform eller en anden XMPP-kompatibel "
"tjeneste, kan du eventuelt importere dataene (kontakter, profiloplysninger "
"osv.) fra din tidligere konto. Når du har eksporteret dataene fra din "
"tidligere konto, skal du uploade dem ved hjælp af nedenstående formular."
#: snikket_web/templates/invite_success.html:30 #: snikket_web/templates/invite_success.html:30
msgid "Upload account data" msgid "Upload account data"
msgstr "" msgstr "Upload kontodata"
#: snikket_web/templates/invite_view.html:6 #: snikket_web/templates/invite_view.html:6
#, python-format #, python-format
@@ -1558,10 +1564,8 @@ msgstr "Rediger profil"
#: snikket_web/templates/user_home.html:33 #: snikket_web/templates/user_home.html:33
#: snikket_web/templates/user_manage_data.html:4 #: snikket_web/templates/user_manage_data.html:4
#, fuzzy
#| msgid "Manage users"
msgid "Manage your data" msgid "Manage your data"
msgstr "Håndter brugere" msgstr "Håndter dine data"
#: snikket_web/templates/user_home.html:39 #: snikket_web/templates/user_home.html:39
msgid "Your Snikket" msgid "Your Snikket"
@@ -1588,16 +1592,16 @@ msgstr ""
"af de forbundne enheder." "af de forbundne enheder."
#: snikket_web/templates/user_manage_data.html:8 #: snikket_web/templates/user_manage_data.html:8
#, fuzzy
#| msgid "Your account"
msgid "Export account" msgid "Export account"
msgstr "Din konto" msgstr "Eksporter konto"
#: snikket_web/templates/user_manage_data.html:9 #: snikket_web/templates/user_manage_data.html:9
msgid "" msgid ""
"Download your account data as a file for backup purposes or to move your " "Download your account data as a file for backup purposes or to move your "
"account to another service." "account to another service."
msgstr "" msgstr ""
"Download dine kontodata som en fil til sikkerhedskopieringsformål eller for "
"at flytte din konto til en anden tjeneste."
#: snikket_web/templates/user_passwd.html:5 #: snikket_web/templates/user_passwd.html:5
msgid "Change your password" msgid "Change your password"

View File

@@ -6,18 +6,19 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: translations@snikket.org\n"
"POT-Creation-Date: 2022-01-17 17:27+0100\n" "POT-Creation-Date: 2022-01-17 17:27+0100\n"
"PO-Revision-Date: 2022-05-14 14:42+0800\n" "PO-Revision-Date: 2022-05-20 00:01+0000\n"
"Last-Translator: Raka <me@bihu.im>\n" "Last-Translator: Zack Zhou <lnx@outlook.com>\n"
"Language-Team: zh_Hans_CN <LL@li.org>\n" "Language-Team: Chinese (Simplified) <http://i18n.sotecware.net/projects/"
"Language: zh_CN\n" "snikket/web-portal/zh_Hans/>\n"
"Language: zh_Hans_CN\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n" "Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.8.1\n"
"Generated-By: Babel 2.10.1\n" "Generated-By: Babel 2.10.1\n"
"X-Generator: Poedit 3.0.1\n"
#: snikket_web/admin.py:68 snikket_web/templates/admin_delete_user.html:10 #: snikket_web/admin.py:68 snikket_web/templates/admin_delete_user.html:10
#: snikket_web/templates/admin_edit_circle.html:59 #: snikket_web/templates/admin_edit_circle.html:59
@@ -371,7 +372,7 @@ msgstr "导出"
#: snikket_web/user.py:202 #: snikket_web/user.py:202
msgid "You currently have no account data to export." msgid "You currently have no account data to export."
msgstr "目前没有需要导出的数据" msgstr "目前没有需要导出的数据"
#: snikket_web/templates/_footer.html:4 #: snikket_web/templates/_footer.html:4
#, python-format #, python-format
@@ -415,13 +416,15 @@ msgid ""
"\"%(agpl_url)s\">Affero GNU General Public License, version 3.0 or later</a>. " "\"%(agpl_url)s\">Affero GNU General Public License, version 3.0 or later</a>. "
"The full terms of the license can be reviewed using the aforementioned link." "The full terms of the license can be reviewed using the aforementioned link."
msgstr "" msgstr ""
"此Web门户软件许可遵循 <a href=\"%(agpl_url)s\">GNU Affero通用公共许可证版本3."
"0及之后版本</a>中的条款。此许可证的完整条款请使用前文中的链接查看。"
#: snikket_web/templates/about.html:15 #: snikket_web/templates/about.html:15
#, python-format #, python-format
msgid "" msgid ""
"The source code of the web portal can be downloaded and viewed in <a href=" "The source code of the web portal can be downloaded and viewed in <a href="
"\"%(source_url)s\">its GitHub repository</a>." "\"%(source_url)s\">its GitHub repository</a>."
msgstr "" msgstr "此Web门户的源代码可在<a href=\"%(source_url)s\">其GitHub repository</a>查看并下载。"
#: snikket_web/templates/about.html:16 #: snikket_web/templates/about.html:16
#, python-format #, python-format
@@ -430,6 +433,8 @@ msgid ""
"Material Icons</a>, made available by Google under the terms of the <a href=" "Material Icons</a>, made available by Google under the terms of the <a href="
"\"%(apache20_url)s\">Apache 2.0 License</a>." "\"%(apache20_url)s\">Apache 2.0 License</a>."
msgstr "" msgstr ""
"Web门户中使用的图标为<a href=\"%(source_url)s\">Googles Material Icons</a>"
"由Google制作分发并遵循<a href=\"%(apache20_url)s\">Apache 2.0 许可证</a>中的条款。"
#: snikket_web/templates/about.html:17 #: snikket_web/templates/about.html:17
msgid "Trademarks" msgid "Trademarks"
@@ -442,6 +447,8 @@ msgid ""
"Company. For more information about the trademarks, visit the <a href=" "Company. For more information about the trademarks, visit the <a href="
"\"%(trademarks_url)s\">Snikket Trademarks information page</a>." "\"%(trademarks_url)s\">Snikket Trademarks information page</a>."
msgstr "" msgstr ""
"“Snikket”和鹦鹉logo是Snikket Community Interest Company的商标。关于商标的更多信息请访问<a href="
"\"%(trademarks_url)s\">Snikket商标信息页面</a>。"
#: snikket_web/templates/about.html:19 #: snikket_web/templates/about.html:19
msgid "Software Versions" msgid "Software Versions"
@@ -544,12 +551,11 @@ msgstr "警告"
#: snikket_web/templates/admin_debug_user.html:12 #: snikket_web/templates/admin_debug_user.html:12
msgid "The below dump may contain sensitive information." msgid "The below dump may contain sensitive information."
msgstr "Dump可能包括敏感信息" msgstr "调试信息中可能包括敏感信息"
#: snikket_web/templates/admin_debug_user.html:15 #: snikket_web/templates/admin_debug_user.html:15
#, fuzzy
msgid "Raw debug dump" msgid "Raw debug dump"
msgstr "Debug信息" msgstr "原始调试信息"
#: snikket_web/templates/admin_debug_user.html:17 #: snikket_web/templates/admin_debug_user.html:17
msgid "Copy complete output" msgid "Copy complete output"
@@ -596,7 +602,7 @@ msgstr "这是你的主圈子"
#: snikket_web/templates/admin_edit_circle.html:15 #: snikket_web/templates/admin_edit_circle.html:15
msgid "This circle is managed automatically and cannot be removed or renamed." msgid "This circle is managed automatically and cannot be removed or renamed."
msgstr "此圈子由系统自动生成,无法被修改或删除" msgstr "此圈子由系统自动生成,无法被修改或删除"
#: snikket_web/templates/admin_edit_circle.html:17 #: snikket_web/templates/admin_edit_circle.html:17
#: snikket_web/templates/admin_edit_circle.html:33 #: snikket_web/templates/admin_edit_circle.html:33
@@ -636,7 +642,7 @@ msgstr "圈子成员"
#: snikket_web/templates/admin_edit_circle.html:71 #: snikket_web/templates/admin_edit_circle.html:71
msgid "The user has been deleted from the server." msgid "The user has been deleted from the server."
msgstr "用户已从实例删除" msgstr "用户已从实例删除"
#: snikket_web/templates/admin_edit_circle.html:71 #: snikket_web/templates/admin_edit_circle.html:71
#: snikket_web/templates/library.j2:108 #: snikket_web/templates/library.j2:108
@@ -698,7 +704,7 @@ msgstr "圈子"
#: snikket_web/templates/admin_edit_invite.html:35 #: snikket_web/templates/admin_edit_invite.html:35
msgid "The user will not be added to any circle and will have no contacts." msgid "The user will not be added to any circle and will have no contacts."
msgstr "此用户将不会有圈子和联系人" msgstr "此用户将不会有任何圈子和联系人"
#: snikket_web/templates/admin_edit_invite.html:40 #: snikket_web/templates/admin_edit_invite.html:40
msgid "Contact" msgid "Contact"
@@ -744,7 +750,7 @@ msgstr "编辑用户"
#: snikket_web/templates/admin_edit_user.html:26 #: snikket_web/templates/admin_edit_user.html:26
msgid "The login name cannot be changed." msgid "The login name cannot be changed."
msgstr "账号无法修改" msgstr "登录账号无法修改"
#: snikket_web/templates/admin_edit_user.html:33 #: snikket_web/templates/admin_edit_user.html:33
msgid "" msgid ""
@@ -755,7 +761,7 @@ msgstr "权限级别控制此Sknikket实例的用户能发起交流的范围。"
#: snikket_web/templates/admin_edit_user.html:40 #: snikket_web/templates/admin_edit_user.html:40
#, python-format #, python-format
msgid "<strong>%(title)s%(icon)s</strong><p>%(description)s</p>" msgid "<strong>%(title)s%(icon)s</strong><p>%(description)s</p>"
msgstr "" msgstr "<strong>%(title)s%(icon)s</strong><p>%(description)s</p>"
#: snikket_web/templates/admin_edit_user.html:50 #: snikket_web/templates/admin_edit_user.html:50
msgid "Return to user list" msgid "Return to user list"
@@ -807,7 +813,7 @@ msgstr "用户"
#: snikket_web/templates/admin_home.html:11 #: snikket_web/templates/admin_home.html:11
msgid "Create password reset links or delete users." msgid "Create password reset links or delete users."
msgstr "创建密码重置链接或删除用户" msgstr "创建密码重置链接或删除用户"
#: snikket_web/templates/admin_home.html:15 #: snikket_web/templates/admin_home.html:15
#: snikket_web/templates/admin_users.html:4 #: snikket_web/templates/admin_users.html:4
@@ -837,7 +843,7 @@ msgstr "系统健康状况"
#: snikket_web/templates/admin_home.html:38 #: snikket_web/templates/admin_home.html:38
msgid "View the server status or send a broadcast message to all users." msgid "View the server status or send a broadcast message to all users."
msgstr "查看服务器状态或向所有用户发布广播消息" msgstr "查看服务器状态或向所有用户发布广播消息"
#: snikket_web/templates/admin_home.html:40 #: snikket_web/templates/admin_home.html:40
msgid "Send a broadcast message to all users." msgid "Send a broadcast message to all users."
@@ -850,7 +856,7 @@ msgstr "系统管理"
#: snikket_web/templates/admin_home.html:48 #: snikket_web/templates/admin_home.html:48
msgid "Go back to your user's web portal page." msgid "Go back to your user's web portal page."
msgstr "返回用户门户页面" msgstr "返回用户门户页面"
#: snikket_web/templates/admin_home.html:50 #: snikket_web/templates/admin_home.html:50
msgid "Exit admin panel" msgid "Exit admin panel"
@@ -882,7 +888,7 @@ msgstr "删除邀请"
#: snikket_web/templates/admin_invites.html:57 #: snikket_web/templates/admin_invites.html:57
msgid "Currently, there are no pending invitations." msgid "Currently, there are no pending invitations."
msgstr "当前没有待定邀请" msgstr "当前没有待定邀请"
#: snikket_web/templates/admin_reset_user_password.html:8 #: snikket_web/templates/admin_reset_user_password.html:8
msgid "Password reset" msgid "Password reset"
@@ -987,7 +993,7 @@ msgstr "此用户是管理员。"
#: snikket_web/templates/admin_users.html:19 #: snikket_web/templates/admin_users.html:19
msgid " (Administrator)" msgid " (Administrator)"
msgstr "(管理员)" msgstr " (管理员)"
#: snikket_web/templates/admin_users.html:22 #: snikket_web/templates/admin_users.html:22
msgid "The user is restricted." msgid "The user is restricted."
@@ -995,7 +1001,7 @@ msgstr "此用户受到限制。"
#: snikket_web/templates/admin_users.html:22 #: snikket_web/templates/admin_users.html:22
msgid " (Restricted)" msgid " (Restricted)"
msgstr "(受限)" msgstr " (受限)"
#: snikket_web/templates/app.html:4 #: snikket_web/templates/app.html:4
msgid "Snikket Web Portal" msgid "Snikket Web Portal"
@@ -1040,7 +1046,7 @@ msgstr "邀请到 %(site_name)s"
#: snikket_web/templates/invite_view.html:14 #: snikket_web/templates/invite_view.html:14
#, python-format #, python-format
msgid "Powered by <img src=\"%(logo_url)s\" alt=\"Snikket\">" msgid "Powered by <img src=\"%(logo_url)s\" alt=\"Snikket\">"
msgstr "" msgstr "由<img alt=\"Snikket\" src=\"%(logo_url)s\">强力驱动"
#: snikket_web/templates/invite_invalid.html:8 #: snikket_web/templates/invite_invalid.html:8
msgid "Invite expired" msgid "Invite expired"
@@ -1131,7 +1137,7 @@ msgstr "在线重置密码"
msgid "" msgid ""
"To reset your password online, fill out the fields below and confirm using the " "To reset your password online, fill out the fields below and confirm using the "
"button." "button."
msgstr "填写信息并提交来重置密码" msgstr "填写信息并使用下面的按钮提交来在线重置密码"
#: snikket_web/templates/invite_reset_success.html:5 #: snikket_web/templates/invite_reset_success.html:5
msgid "Password reset successful | Snikket" msgid "Password reset successful | Snikket"
@@ -1300,6 +1306,8 @@ msgid ""
"Install the Snikket App on your Android device (<a href=\"%(ios_info_url)s\" " "Install the Snikket App on your Android device (<a href=\"%(ios_info_url)s\" "
"rel=\"noopener noreferrer\" target=\"_blank\">iOS coming soon!</a>)." "rel=\"noopener noreferrer\" target=\"_blank\">iOS coming soon!</a>)."
msgstr "" msgstr ""
"在你的Android设备上安装Snikket App<a href=\"%(ios_info_url)s\" rel=\"noopener "
"noreferrer\" target=\"_blank\">iOS 版本即将到来!</a>)。"
#: snikket_web/templates/invite_view.html:28 #: snikket_web/templates/invite_view.html:28
msgid "Get it on Google Play" msgid "Get it on Google Play"

View File

@@ -13,7 +13,7 @@ from quart import (
flash, flash,
current_app, current_app,
) )
import quart.exceptions import werkzeug.exceptions
import wtforms import wtforms
@@ -96,7 +96,7 @@ async def index() -> str:
@bp.route('/passwd', methods=["GET", "POST"]) @bp.route('/passwd', methods=["GET", "POST"])
@client.require_session() @client.require_session()
async def change_pw() -> typing.Union[str, quart.Response]: async def change_pw() -> typing.Union[str, werkzeug.Response]:
form = ChangePasswordForm() form = ChangePasswordForm()
if form.validate_on_submit(): if form.validate_on_submit():
try: try:
@@ -104,8 +104,8 @@ async def change_pw() -> typing.Union[str, quart.Response]:
form.current_password.data, form.current_password.data,
form.new_password.data, form.new_password.data,
) )
except (quart.exceptions.Unauthorized, except (werkzeug.exceptions.Unauthorized,
quart.exceptions.Forbidden): werkzeug.exceptions.Forbidden):
# server refused current password, set an appropriate error # server refused current password, set an appropriate error
form.current_password.errors.append( form.current_password.errors.append(
_("Incorrect password."), _("Incorrect password."),
@@ -128,7 +128,7 @@ EAVATARTOOBIG = _l(
@bp.route("/profile", methods=["GET", "POST"]) @bp.route("/profile", methods=["GET", "POST"])
@client.require_session() @client.require_session()
async def profile() -> typing.Union[str, quart.Response]: async def profile() -> typing.Union[str, werkzeug.Response]:
max_avatar_size = current_app.config["MAX_AVATAR_SIZE"] max_avatar_size = current_app.config["MAX_AVATAR_SIZE"]
form = ProfileForm() form = ProfileForm()
@@ -221,7 +221,7 @@ async def manage_data() -> typing.Union[str, quart.Response]:
@bp.route("/logout", methods=["GET", "POST"]) @bp.route("/logout", methods=["GET", "POST"])
@client.require_session() @client.require_session()
async def logout() -> typing.Union[quart.Response, str]: async def logout() -> typing.Union[werkzeug.Response, str]:
form = LogoutForm() form = LogoutForm()
if form.validate_on_submit(): if form.validate_on_submit():
await client.logout() await client.logout()

View File

@@ -4,7 +4,7 @@ import typing
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from quart import abort from quart import abort
import quart.exceptions import werkzeug.exceptions
TAG_XMPP_ERROR = "error" TAG_XMPP_ERROR = "error"
@@ -239,7 +239,7 @@ def extract_pubsub_item_get_reply(
) -> typing.Optional[ET.Element]: ) -> typing.Optional[ET.Element]:
try: try:
pubsub = extract_iq_reply(iq_tree, TAG_PUBSUB) pubsub = extract_iq_reply(iq_tree, TAG_PUBSUB)
except quart.exceptions.NotFound: except werkzeug.exceptions.NotFound:
return None return None
if pubsub is None: if pubsub is None: