Use standard error rendering for the login form

This provides a consistent UX.
This commit is contained in:
Jonas Schäfer
2021-03-20 13:05:14 +01:00
parent b822000f2e
commit ad229d6700
7 changed files with 96 additions and 97 deletions

View File

@@ -19,12 +19,11 @@ from quart import (
abort,
flash,
)
import flask_wtf
from flask_babel import lazy_gettext as _l, _
from . import prosodyclient
from .infra import client, circle_name
from .infra import client, circle_name, BaseForm
bp = Blueprint("admin", __name__, url_prefix="/admin")
@@ -35,7 +34,7 @@ async def index() -> str:
return await render_template("admin_home.html")
class PasswordResetLinkPost(flask_wtf.FlaskForm): # type: ignore
class PasswordResetLinkPost(BaseForm):
action_create = wtforms.StringField()
action_revoke = wtforms.StringField()
@@ -55,7 +54,7 @@ async def users() -> str:
)
class DeleteUserForm(flask_wtf.FlaskForm): # type:ignore
class DeleteUserForm(BaseForm):
action_delete = wtforms.SubmitField(
_l("Delete user permanently")
)
@@ -132,11 +131,11 @@ async def create_password_reset_link() -> typing.Union[str, quart.Response]:
)
class InvitesListForm(flask_wtf.FlaskForm): # type:ignore
class InvitesListForm(BaseForm):
action_revoke = wtforms.StringField()
class InvitePost(flask_wtf.FlaskForm): # type:ignore
class InvitePost(BaseForm):
circles = wtforms.SelectMultipleField(
_l("Invite to circle"),
# NOTE: This is for when/if we ever support multi-group invites.
@@ -230,7 +229,7 @@ async def invitations() -> typing.Union[str, quart.Response]:
)
class InviteForm(flask_wtf.FlaskForm): # type:ignore
class InviteForm(BaseForm):
action_revoke = wtforms.SubmitField(
_l("Revoke")
)
@@ -302,7 +301,7 @@ async def edit_invite(id_: str) -> typing.Union[str, quart.Response]:
)
class CirclePost(flask_wtf.FlaskForm): # type:ignore
class CirclePost(BaseForm):
name = wtforms.StringField(
_l("Name"),
validators=[wtforms.validators.InputRequired()],
@@ -350,7 +349,7 @@ async def create_circle() -> typing.Union[str, quart.Response]:
)
class EditCircleForm(flask_wtf.FlaskForm): # type:ignore
class EditCircleForm(BaseForm):
name = wtforms.StringField(
_l("Name"),
validators=[wtforms.validators.InputRequired()],

View File

@@ -10,6 +10,7 @@ from quart import (
)
import flask_babel
import flask_wtf
from flask_babel import _
from . import prosodyclient
@@ -55,3 +56,14 @@ def generate_error_id() -> str:
return base64.b32encode(secrets.token_bytes(8)).decode(
"ascii"
).rstrip("=")
class BaseForm(flask_wtf.FlaskForm): # type:ignore
def __init__(self, *args: typing.Any, **kwargs: typing.Any):
meta = kwargs["meta"] = dict(kwargs.get("meta", {}))
if "locales" not in meta:
locale = flask_babel.get_locale()
if locale:
meta["locales"] = [str(locale)]
super().__init__(*args, **kwargs)

View File

@@ -16,10 +16,9 @@ from quart import (
import wtforms
import flask_wtf
from flask_babel import lazy_gettext as _l
from .infra import client, selected_locale
from .infra import client, selected_locale, BaseForm
bp = Blueprint("invite", __name__)
@@ -102,7 +101,7 @@ async def view(id_: str) -> typing.Union[quart.Response,
)
class RegisterForm(flask_wtf.FlaskForm): # type:ignore
class RegisterForm(BaseForm):
localpart = wtforms.StringField(
_l("Username"),
)
@@ -173,7 +172,7 @@ async def register(id_: str) -> typing.Union[str, quart.Response]:
)
class ResetForm(flask_wtf.FlaskForm): # type:ignore
class ResetForm(BaseForm):
password = wtforms.PasswordField(
_l("Password"),
)

View File

@@ -22,17 +22,16 @@ import babel
import wtforms
import flask_wtf
from flask_babel import lazy_gettext as _l, _
from . import xmpputil, _version
from .infra import client
from .infra import client, BaseForm
bp = quart.Blueprint("main", __name__)
class LoginForm(flask_wtf.FlaskForm): # type:ignore
class LoginForm(BaseForm):
address = wtforms.TextField(
_l("Address"),
validators=[wtforms.validators.InputRequired()],

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% from "library.j2" import box, form_button %}
{% from "library.j2" import box, form_button, render_errors %}
{% set body_id = "login" %}
{% block head_lead %}
<title>{{ _("Snikket Login") }}</title>
@@ -14,11 +14,7 @@
<p class="form-desc">{{ _("Enter your Snikket address and password to manage your account.") }}</p>
<form method="POST" action="{{ url_for('.login') }}" name="login" id="login-form" onsubmit="return domainCheck();" data-addressid="{{ form.address.id }}" data-domain="{{ config["SNIKKET_DOMAIN"] }}">
{{ form.csrf_token }}
{% if form.errors %}
{% call box("alert", _("Login failed")) %}
<p>{{ form.errors.values() | flatten | join(", ")}}</p>
{% endcall %}
{% endif %}
{% call render_errors(form) %}{% endcall %}
<div class="box alert" role="alert" style="display: none;" id="id-warning">
<header>{% trans %}Incorrect address{% endtrans %}</header>
<p>{% trans snikket_domain=config["SNIKKET_DOMAIN"] %}This Snikket service only hosts addresses ending in <em>@{{ snikket_domain }}</em>. Your password was not sent.{% endtrans %}</p>

View File

@@ -17,259 +17,259 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.0\n"
#: snikket_web/admin.py:60
#: snikket_web/admin.py:59
msgid "Delete user permanently"
msgstr ""
#: snikket_web/admin.py:73
#: snikket_web/admin.py:72
msgid "User deleted"
msgstr ""
#: snikket_web/admin.py:116
#: snikket_web/admin.py:115
msgid "Password reset link created"
msgstr ""
#: snikket_web/admin.py:122
#: snikket_web/admin.py:121
msgid "Password reset link deleted"
msgstr ""
#: snikket_web/admin.py:141
#: snikket_web/admin.py:140
msgid "Invite to circle"
msgstr ""
#: snikket_web/admin.py:147
#: snikket_web/admin.py:146
msgid "At least one circle must be selected"
msgstr ""
#: snikket_web/admin.py:152
#: snikket_web/admin.py:151
msgid "Valid for"
msgstr ""
#: snikket_web/admin.py:154
#: snikket_web/admin.py:153
msgid "One hour"
msgstr ""
#: snikket_web/admin.py:155
#: snikket_web/admin.py:154
msgid "Twelve hours"
msgstr ""
#: snikket_web/admin.py:156
#: snikket_web/admin.py:155
msgid "One day"
msgstr ""
#: snikket_web/admin.py:157
#: snikket_web/admin.py:156
msgid "One week"
msgstr ""
#: snikket_web/admin.py:158
#: snikket_web/admin.py:157
msgid "Four weeks"
msgstr ""
#: snikket_web/admin.py:164 snikket_web/templates/admin_edit_invite.html:17
#: snikket_web/admin.py:163 snikket_web/templates/admin_edit_invite.html:17
msgid "Invitation type"
msgstr ""
#: snikket_web/admin.py:166 snikket_web/templates/library.j2:116
#: snikket_web/admin.py:165 snikket_web/templates/library.j2:116
msgid "Individual"
msgstr ""
#: snikket_web/admin.py:167 snikket_web/templates/library.j2:114
#: snikket_web/admin.py:166 snikket_web/templates/library.j2:114
msgid "Group"
msgstr ""
#: snikket_web/admin.py:173
#: snikket_web/admin.py:172
msgid "New invitation link"
msgstr ""
#: snikket_web/admin.py:235
#: snikket_web/admin.py:234
msgid "Revoke"
msgstr ""
#: snikket_web/admin.py:259
#: snikket_web/admin.py:258
msgid "Invitation created"
msgstr ""
#: snikket_web/admin.py:275
#: snikket_web/admin.py:274
msgid "No such invitation exists"
msgstr ""
#: snikket_web/admin.py:290
#: snikket_web/admin.py:289
msgid "Invitation revoked"
msgstr ""
#: snikket_web/admin.py:307 snikket_web/admin.py:355
#: snikket_web/admin.py:306 snikket_web/admin.py:354
msgid "Name"
msgstr ""
#: snikket_web/admin.py:312 snikket_web/templates/admin_circles.html:47
#: snikket_web/admin.py:311 snikket_web/templates/admin_circles.html:47
msgid "Create circle"
msgstr ""
#: snikket_web/admin.py:342
#: snikket_web/admin.py:341
msgid "Circle created"
msgstr ""
#: snikket_web/admin.py:360
#: snikket_web/admin.py:359
msgid "Select user"
msgstr ""
#: snikket_web/admin.py:365
#: snikket_web/admin.py:364
msgid "Update circle"
msgstr ""
#: snikket_web/admin.py:369
#: snikket_web/admin.py:368
msgid "Delete circle permanently"
msgstr ""
#: snikket_web/admin.py:375
#: snikket_web/admin.py:374
msgid "Add user"
msgstr ""
#: snikket_web/admin.py:391
#: snikket_web/admin.py:390
msgid "No such circle exists"
msgstr ""
#: snikket_web/admin.py:428
#: snikket_web/admin.py:427
msgid "Circle data updated"
msgstr ""
#: snikket_web/admin.py:434
#: snikket_web/admin.py:433
msgid "Circle deleted"
msgstr ""
#: snikket_web/admin.py:445
#: snikket_web/admin.py:444
msgid "User added to circle"
msgstr ""
#: snikket_web/admin.py:454
#: snikket_web/admin.py:453
msgid "User removed from circle"
msgstr ""
#: snikket_web/infra.py:40
#: snikket_web/infra.py:41
msgid "Main"
msgstr ""
#: snikket_web/invite.py:107
#: snikket_web/invite.py:106
msgid "Username"
msgstr ""
#: snikket_web/invite.py:111 snikket_web/invite.py:178 snikket_web/main.py:42
#: snikket_web/invite.py:110 snikket_web/invite.py:177 snikket_web/main.py:41
msgid "Password"
msgstr ""
#: snikket_web/invite.py:115 snikket_web/invite.py:182
#: snikket_web/invite.py:114 snikket_web/invite.py:181
msgid "Confirm password"
msgstr ""
#: snikket_web/invite.py:119 snikket_web/invite.py:186
#: snikket_web/invite.py:118 snikket_web/invite.py:185
msgid "The passwords must match"
msgstr ""
#: snikket_web/invite.py:124
#: snikket_web/invite.py:123
msgid "Create account"
msgstr ""
#: snikket_web/invite.py:151
#: snikket_web/invite.py:150
msgid "That username is already taken."
msgstr ""
#: snikket_web/invite.py:155 snikket_web/invite.py:219
#: snikket_web/invite.py:154 snikket_web/invite.py:218
msgid "Registration was declined for unknown reasons."
msgstr ""
#: snikket_web/invite.py:159
#: snikket_web/invite.py:158
msgid "The username is not valid."
msgstr ""
#: snikket_web/invite.py:191 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 ""
#: snikket_web/main.py:37
#: snikket_web/main.py:36
msgid "Address"
msgstr ""
#: snikket_web/main.py:47
#: snikket_web/main.py:46
msgid "Sign in"
msgstr ""
#: snikket_web/main.py:56
#: snikket_web/main.py:55
msgid "Invalid username or password."
msgstr ""
#: snikket_web/main.py:84
#: snikket_web/main.py:83
msgid "Login successful!"
msgstr ""
#: snikket_web/user.py:29
#: snikket_web/user.py:27
msgid "Current password"
msgstr ""
#: snikket_web/user.py:34
#: snikket_web/user.py:32
msgid "New password"
msgstr ""
#: snikket_web/user.py:39
#: snikket_web/user.py:37
msgid "Confirm new password"
msgstr ""
#: snikket_web/user.py:43
#: snikket_web/user.py:41
msgid "The new passwords must match"
msgstr ""
#: snikket_web/user.py:50
#: snikket_web/user.py:48
msgid "Sign out"
msgstr ""
#: snikket_web/user.py:55
#: snikket_web/user.py:53
msgid "Nobody"
msgstr ""
#: snikket_web/user.py:56
#: snikket_web/user.py:54
msgid "Friends only"
msgstr ""
#: snikket_web/user.py:57
#: snikket_web/user.py:55
msgid "Everyone"
msgstr ""
#: snikket_web/templates/admin_delete_user.html:12
#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:63
#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:61
msgid "Display name"
msgstr ""
#: snikket_web/user.py:67
#: snikket_web/user.py:65
msgid "Avatar"
msgstr ""
#: snikket_web/user.py:71
#: snikket_web/user.py:69
msgid "Profile visibility"
msgstr ""
#: snikket_web/user.py:76
#: snikket_web/user.py:74
msgid "Update profile"
msgstr ""
#: snikket_web/user.py:101
#: snikket_web/user.py:99
msgid "Incorrect password."
msgstr ""
#: snikket_web/user.py:105
#: snikket_web/user.py:103
msgid "Password changed"
msgstr ""
#: snikket_web/user.py:113
#: snikket_web/user.py:111
msgid ""
"The chosen avatar is too big. To be able to upload larger avatars, please"
" use the app."
msgstr ""
#: snikket_web/user.py:161
#: snikket_web/user.py:159
msgid "Profile updated"
msgstr ""
#: snikket_web/templates/unauth.html:18 snikket_web/user.py:169
#: snikket_web/templates/unauth.html:18 snikket_web/user.py:167
msgid "Error"
msgstr ""
@@ -1106,15 +1106,11 @@ msgstr ""
msgid "Enter your Snikket address and password to manage your account."
msgstr ""
#: snikket_web/templates/login.html:18
msgid "Login failed"
msgstr ""
#: snikket_web/templates/login.html:23
#: snikket_web/templates/login.html:19
msgid "Incorrect address"
msgstr ""
#: snikket_web/templates/login.html:24
#: snikket_web/templates/login.html:20
#, python-format
msgid ""
"This Snikket service only hosts addresses ending in "

View File

@@ -15,16 +15,14 @@ import quart.exceptions
import wtforms
import flask_wtf
from flask_babel import lazy_gettext as _l, _
from .infra import client
from .infra import client, BaseForm
bp = Blueprint('user', __name__)
class ChangePasswordForm(flask_wtf.FlaskForm): # type:ignore
class ChangePasswordForm(BaseForm):
current_password = wtforms.PasswordField(
_l("Current password"),
validators=[wtforms.validators.InputRequired()]
@@ -45,7 +43,7 @@ class ChangePasswordForm(flask_wtf.FlaskForm): # type:ignore
)
class LogoutForm(flask_wtf.FlaskForm): # type:ignore
class LogoutForm(BaseForm):
action_signout = wtforms.SubmitField(
_l("Sign out"),
)
@@ -58,7 +56,7 @@ _ACCESS_MODEL_CHOICES = [
]
class ProfileForm(flask_wtf.FlaskForm): # type:ignore
class ProfileForm(BaseForm):
nickname = wtforms.TextField(
_l("Display name"),
)