You've already forked snikket-web-portal
Password reset link support
This also includes a restructure of the admin API usage because it was restructured upstream :).
This commit is contained in:
@@ -17,6 +17,7 @@ from quart import (
|
|||||||
redirect,
|
redirect,
|
||||||
url_for,
|
url_for,
|
||||||
request,
|
request,
|
||||||
|
abort,
|
||||||
)
|
)
|
||||||
import flask_wtf
|
import flask_wtf
|
||||||
|
|
||||||
@@ -34,6 +35,11 @@ async def index() -> str:
|
|||||||
return await render_template("admin_home.html")
|
return await render_template("admin_home.html")
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetLinkPost(flask_wtf.FlaskForm): # type: ignore
|
||||||
|
action_create = wtforms.StringField()
|
||||||
|
action_revoke = wtforms.StringField()
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/users")
|
@bp.route("/users")
|
||||||
@client.require_admin_session()
|
@client.require_admin_session()
|
||||||
async def users() -> str:
|
async def users() -> str:
|
||||||
@@ -41,9 +47,11 @@ async def users() -> str:
|
|||||||
await client.list_users(),
|
await client.list_users(),
|
||||||
key=lambda x: x.localpart
|
key=lambda x: x.localpart
|
||||||
)
|
)
|
||||||
|
reset_form = PasswordResetLinkPost()
|
||||||
return await render_template(
|
return await render_template(
|
||||||
"admin_users.html",
|
"admin_users.html",
|
||||||
users=users,
|
users=users,
|
||||||
|
reset_form=reset_form,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -86,6 +94,32 @@ async def debug_user(localpart: str) -> typing.Union[str, quart.Response]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/users/password-reset/-", methods=["POST"])
|
||||||
|
@client.require_admin_session()
|
||||||
|
async def create_password_reset_link() -> typing.Union[str, quart.Response]:
|
||||||
|
form = PasswordResetLinkPost()
|
||||||
|
if not form.validate_on_submit():
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
if form.action_create.data:
|
||||||
|
localpart = form.action_create.data
|
||||||
|
target_user_info = await client.get_user_by_localpart(localpart)
|
||||||
|
reset_link = await client.create_password_reset_invite(
|
||||||
|
localpart=localpart,
|
||||||
|
ttl=86400,
|
||||||
|
)
|
||||||
|
elif form.action_revoke.data:
|
||||||
|
await client.delete_invite(form.action_revoke.data)
|
||||||
|
return redirect(url_for(".users"))
|
||||||
|
|
||||||
|
return await render_template(
|
||||||
|
"admin_reset_user_password.html",
|
||||||
|
target_user=target_user_info,
|
||||||
|
reset_link=reset_link,
|
||||||
|
form=form,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InvitesListForm(flask_wtf.FlaskForm): # type:ignore
|
class InvitesListForm(flask_wtf.FlaskForm): # type:ignore
|
||||||
action_revoke = wtforms.StringField()
|
action_revoke = wtforms.StringField()
|
||||||
|
|
||||||
@@ -115,7 +149,7 @@ class InvitePost(flask_wtf.FlaskForm): # type:ignore
|
|||||||
)
|
)
|
||||||
|
|
||||||
reusable = wtforms.BooleanField(
|
reusable = wtforms.BooleanField(
|
||||||
_l("Allow multiple uses"),
|
_l("Invite a group of people"),
|
||||||
)
|
)
|
||||||
|
|
||||||
action_create_invite = wtforms.SubmitField(
|
action_create_invite = wtforms.SubmitField(
|
||||||
@@ -143,7 +177,11 @@ class InvitePost(flask_wtf.FlaskForm): # type:ignore
|
|||||||
@client.require_admin_session()
|
@client.require_admin_session()
|
||||||
async def invitations() -> typing.Union[str, quart.Response]:
|
async def invitations() -> typing.Union[str, quart.Response]:
|
||||||
invites = sorted(
|
invites = sorted(
|
||||||
await client.list_invites(),
|
(
|
||||||
|
invite
|
||||||
|
for invite in await client.list_invites()
|
||||||
|
if not invite.is_reset
|
||||||
|
),
|
||||||
key=lambda x: x.created_at,
|
key=lambda x: x.created_at,
|
||||||
reverse=True,
|
reverse=True,
|
||||||
)
|
)
|
||||||
@@ -190,9 +228,14 @@ async def create_invite() -> typing.Union[str, quart.Response]:
|
|||||||
(c.id_, c.name) for c in circles
|
(c.id_, c.name) for c in circles
|
||||||
]
|
]
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
invite = await client.create_invite(
|
if form.reusable.data:
|
||||||
|
invite = await client.create_group_invite(
|
||||||
|
group_ids=form.circles.data,
|
||||||
|
ttl=form.lifetime.data,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
invite = await client.create_account_invite(
|
||||||
group_ids=form.circles.data,
|
group_ids=form.circles.data,
|
||||||
reusable=form.reusable.data,
|
|
||||||
ttl=form.lifetime.data,
|
ttl=form.lifetime.data,
|
||||||
)
|
)
|
||||||
return redirect(url_for(".edit_invite", id_=invite.id_))
|
return redirect(url_for(".edit_invite", id_=invite.id_))
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class AdminInviteInfo:
|
|||||||
expires: datetime
|
expires: datetime
|
||||||
reusable: bool
|
reusable: bool
|
||||||
group_ids: typing.Collection[str]
|
group_ids: typing.Collection[str]
|
||||||
|
is_reset: bool
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api_response(
|
def from_api_response(
|
||||||
@@ -91,6 +92,7 @@ class AdminInviteInfo:
|
|||||||
landing_page=data.get("landing_page"),
|
landing_page=data.get("landing_page"),
|
||||||
group_ids=data.get("groups", []),
|
group_ids=data.get("groups", []),
|
||||||
reusable=data["reusable"],
|
reusable=data["reusable"],
|
||||||
|
is_reset=data.get("reset", False),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -857,22 +859,63 @@ class ProsodyClient:
|
|||||||
self._raise_error_from_response(resp)
|
self._raise_error_from_response(resp)
|
||||||
|
|
||||||
@autosession
|
@autosession
|
||||||
async def create_invite(
|
async def create_account_invite(
|
||||||
self,
|
self,
|
||||||
group_ids: typing.Collection[str],
|
|
||||||
reusable: bool,
|
|
||||||
ttl: int,
|
|
||||||
*,
|
*,
|
||||||
|
group_ids: typing.Collection[str] = [],
|
||||||
|
restrict_username: typing.Optional[str] = None,
|
||||||
|
ttl: typing.Optional[int] = None,
|
||||||
session: aiohttp.ClientSession,
|
session: aiohttp.ClientSession,
|
||||||
) -> AdminInviteInfo:
|
) -> AdminInviteInfo:
|
||||||
payload = {
|
payload: typing.Dict[str, typing.Any] = {}
|
||||||
"reusable": reusable,
|
payload["groups"] = list(group_ids)
|
||||||
"groups": list(group_ids),
|
if restrict_username is not None:
|
||||||
"ttl": ttl,
|
payload["username"] = restrict_username
|
||||||
}
|
if ttl is not None:
|
||||||
|
payload["ttl"] = ttl
|
||||||
|
|
||||||
async with session.post(
|
async with session.post(
|
||||||
self._admin_v1_endpoint("/invites"),
|
self._admin_v1_endpoint("/invites/account"),
|
||||||
|
json=payload) as resp:
|
||||||
|
self._raise_error_from_response(resp)
|
||||||
|
return AdminInviteInfo.from_api_response(await resp.json())
|
||||||
|
|
||||||
|
@autosession
|
||||||
|
async def create_group_invite(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
group_ids: typing.Collection[str] = [],
|
||||||
|
ttl: typing.Optional[int] = None,
|
||||||
|
session: aiohttp.ClientSession,
|
||||||
|
) -> AdminInviteInfo:
|
||||||
|
payload: typing.Dict[str, typing.Any] = {
|
||||||
|
"groups": list(group_ids),
|
||||||
|
}
|
||||||
|
if ttl is not None:
|
||||||
|
payload["ttl"] = ttl
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
self._admin_v1_endpoint("/invites/group"),
|
||||||
|
json=payload) as resp:
|
||||||
|
self._raise_error_from_response(resp)
|
||||||
|
return AdminInviteInfo.from_api_response(await resp.json())
|
||||||
|
|
||||||
|
@autosession
|
||||||
|
async def create_password_reset_invite(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
localpart: str,
|
||||||
|
ttl: typing.Optional[int] = None,
|
||||||
|
session: aiohttp.ClientSession,
|
||||||
|
) -> AdminInviteInfo:
|
||||||
|
payload: typing.Dict[str, typing.Any] = {
|
||||||
|
"username": localpart,
|
||||||
|
}
|
||||||
|
if ttl is not None:
|
||||||
|
payload["ttl"] = ttl
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
self._admin_v1_endpoint("/invites/reset"),
|
||||||
json=payload) as resp:
|
json=payload) as resp:
|
||||||
self._raise_error_from_response(resp)
|
self._raise_error_from_response(resp)
|
||||||
return AdminInviteInfo.from_api_response(await resp.json())
|
return AdminInviteInfo.from_api_response(await resp.json())
|
||||||
|
|||||||
29
snikket_web/templates/admin_reset_user_password.html
Normal file
29
snikket_web/templates/admin_reset_user_password.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "app.html" %}
|
||||||
|
{% from "library.j2" import showuri, standard_button, custom_form_button %}
|
||||||
|
{% block head_lead %}
|
||||||
|
{{ super() }}
|
||||||
|
{% include "copy-snippet.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% trans %}Password reset{% endtrans %}</h1>
|
||||||
|
<form method="POST">
|
||||||
|
{{- form.csrf_token -}}
|
||||||
|
<div class="form layout-expanded">
|
||||||
|
<h2 class="form-title">{% trans user_name=target_user.localpart %}Password reset link for {{ user_name }}{% endtrans %}</h2>
|
||||||
|
<p class="form-desc">{% trans %}The following link will allow the user to reset their password on their device, once.{% endtrans %}</p>
|
||||||
|
<dd>
|
||||||
|
<dt>{% trans %}Valid until{% endtrans %}</dt>
|
||||||
|
<dd>{{ reset_link.expires | format_date }}</dd>
|
||||||
|
<dt>{% trans %}Link{% endtrans %}</dt>
|
||||||
|
<dd>{% call showuri(reset_link.landing_page) %}{% endcall %}</dd>
|
||||||
|
</dd>
|
||||||
|
<div class="f-bbox">
|
||||||
|
{%- call custom_form_button("remove_link", form.action_revoke.name, reset_link.id_, class="secondary danger") -%}
|
||||||
|
{% trans %}Destroy link{% endtrans %}
|
||||||
|
{%- endcall -%}
|
||||||
|
{%- call standard_button("back", url_for(".users"), class="primary") -%}
|
||||||
|
{% trans %}Back{% endtrans %}
|
||||||
|
{%- endcall -%}
|
||||||
|
</div>
|
||||||
|
</div></form>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
{% extends "admin_app.html" %}
|
{% extends "admin_app.html" %}
|
||||||
{% from "library.j2" import action_button, value_or_hint %}
|
{% from "library.j2" import action_button, value_or_hint, custom_form_button %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans %}Manage users{% endtrans %}</h1>
|
<h1>{% trans %}Manage users{% endtrans %}</h1>
|
||||||
|
<form method="POST" action="{{ url_for(".create_password_reset_link") }}">
|
||||||
|
{{- reset_form.csrf_token -}}
|
||||||
<div class="elevated el-2"><table>
|
<div class="elevated el-2"><table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -19,16 +21,21 @@
|
|||||||
<td>{% call value_or_hint(user.display_name) %}{% endcall %}</td>
|
<td>{% call value_or_hint(user.display_name) %}{% endcall %}</td>
|
||||||
<td class="collapsible">{% call value_or_hint(user.email) %}{% endcall %}</td>
|
<td class="collapsible">{% call value_or_hint(user.email) %}{% endcall %}</td>
|
||||||
<td class="collapsible">{% call value_or_hint(user.phone) %}{% endcall %}</td>
|
<td class="collapsible">{% call value_or_hint(user.phone) %}{% endcall %}</td>
|
||||||
<td>
|
<td class="nowrap">
|
||||||
{%- call action_button("remove", url_for(".delete_user", localpart=user.localpart), class="secondary") -%}
|
{%- call action_button("remove", url_for(".delete_user", localpart=user.localpart), class="secondary") -%}
|
||||||
{% trans user_name=user.localpart %}Delete user {{ user_name }}{% endtrans %}
|
{% trans user_name=user.localpart %}Delete user {{ user_name }}{% endtrans %}
|
||||||
{%- endcall -%}
|
{%- endcall -%}
|
||||||
{%- call action_button("bug_report", url_for(".debug_user", localpart=user.localpart), class="secondary") -%}
|
{%- call action_button("bug_report", url_for(".debug_user", localpart=user.localpart), class="secondary") -%}
|
||||||
{% trans user_name=user.localpart %}Show debug information for {{ user_name }}{% endtrans %}
|
{% trans user_name=user.localpart %}Show debug information for {{ user_name }}{% endtrans %}
|
||||||
{%- endcall -%}
|
{%- endcall -%}
|
||||||
|
{%- call custom_form_button("create_link", reset_form.action_create.name, user.localpart, class="secondary", slim=True) -%}
|
||||||
|
{% trans user_name=user.localpart %}Create password reset link for {{ user_name }}{% endtrans %}
|
||||||
|
{%- endcall -%}
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table></div>
|
</table></div>
|
||||||
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -18,75 +18,75 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.9.0\n"
|
"Generated-By: Babel 2.9.0\n"
|
||||||
|
|
||||||
#: snikket_web/admin.py:52
|
#: snikket_web/admin.py:60
|
||||||
msgid "Delete user permanently"
|
msgid "Delete user permanently"
|
||||||
msgstr "Benutzer endgültig löschen"
|
msgstr "Benutzer endgültig löschen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:95
|
#: snikket_web/admin.py:129
|
||||||
msgid "Invite to circle"
|
msgid "Invite to circle"
|
||||||
msgstr "In Gemeinschaft einladen"
|
msgstr "In Gemeinschaft einladen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:101
|
#: snikket_web/admin.py:135
|
||||||
msgid "At least one circle must be selected"
|
msgid "At least one circle must be selected"
|
||||||
msgstr "Mindestens eine Gemeinschaft muss ausgewählt sein"
|
msgstr "Mindestens eine Gemeinschaft muss ausgewählt sein"
|
||||||
|
|
||||||
#: snikket_web/admin.py:106
|
#: snikket_web/admin.py:140
|
||||||
msgid "Valid for"
|
msgid "Valid for"
|
||||||
msgstr "Gültig für"
|
msgstr "Gültig für"
|
||||||
|
|
||||||
#: snikket_web/admin.py:108
|
#: snikket_web/admin.py:142
|
||||||
msgid "One hour"
|
msgid "One hour"
|
||||||
msgstr "Eine Stunde"
|
msgstr "Eine Stunde"
|
||||||
|
|
||||||
#: snikket_web/admin.py:109
|
#: snikket_web/admin.py:143
|
||||||
msgid "Twelve hours"
|
msgid "Twelve hours"
|
||||||
msgstr "Zwölf Stunden"
|
msgstr "Zwölf Stunden"
|
||||||
|
|
||||||
#: snikket_web/admin.py:110
|
#: snikket_web/admin.py:144
|
||||||
msgid "One day"
|
msgid "One day"
|
||||||
msgstr "Ein Tag"
|
msgstr "Ein Tag"
|
||||||
|
|
||||||
#: snikket_web/admin.py:111
|
#: snikket_web/admin.py:145
|
||||||
msgid "One week"
|
msgid "One week"
|
||||||
msgstr "Eine Woche"
|
msgstr "Eine Woche"
|
||||||
|
|
||||||
#: snikket_web/admin.py:112
|
#: snikket_web/admin.py:146
|
||||||
msgid "Four weeks"
|
msgid "Four weeks"
|
||||||
msgstr "Vier Wochen"
|
msgstr "Vier Wochen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:118
|
#: snikket_web/admin.py:152
|
||||||
msgid "Allow multiple uses"
|
msgid "Allow multiple uses"
|
||||||
msgstr "Mehrfach verwendbar"
|
msgstr "Mehrfach verwendbar"
|
||||||
|
|
||||||
#: snikket_web/admin.py:122
|
#: snikket_web/admin.py:156
|
||||||
msgid "New invitation link"
|
msgid "New invitation link"
|
||||||
msgstr "Neuer Einladungslink"
|
msgstr "Neuer Einladungslink"
|
||||||
|
|
||||||
#: snikket_web/admin.py:180
|
#: snikket_web/admin.py:214
|
||||||
msgid "Revoke"
|
msgid "Revoke"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:231 snikket_web/admin.py:274
|
#: snikket_web/admin.py:265 snikket_web/admin.py:308
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: snikket_web/admin.py:235 snikket_web/templates/admin_circles.html:42
|
#: snikket_web/admin.py:269 snikket_web/templates/admin_circles.html:42
|
||||||
msgid "Create circle"
|
msgid "Create circle"
|
||||||
msgstr "Gemeinschaft gründen"
|
msgstr "Gemeinschaft gründen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:279
|
#: snikket_web/admin.py:313
|
||||||
msgid "Select user"
|
msgid "Select user"
|
||||||
msgstr "Benutzer auswählen"
|
msgstr "Benutzer auswählen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:284 snikket_web/user.py:68
|
#: snikket_web/admin.py:318 snikket_web/user.py:68
|
||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr "Übernehmen"
|
msgstr "Übernehmen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:288
|
#: snikket_web/admin.py:322
|
||||||
msgid "Delete circle permanently"
|
msgid "Delete circle permanently"
|
||||||
msgstr "Gemeinschaft endgültig löschen"
|
msgstr "Gemeinschaft endgültig löschen"
|
||||||
|
|
||||||
#: snikket_web/admin.py:294
|
#: snikket_web/admin.py:328
|
||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Benutzer hinzufügen"
|
msgstr "Benutzer hinzufügen"
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ msgstr "Jeder"
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:12
|
#: snikket_web/templates/admin_delete_user.html:12
|
||||||
#: snikket_web/templates/admin_delete_user.html:16
|
#: snikket_web/templates/admin_delete_user.html:16
|
||||||
#: snikket_web/templates/admin_users.html:9 snikket_web/user.py:55
|
#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:55
|
||||||
msgid "Display name"
|
msgid "Display name"
|
||||||
msgstr "Anzeigename"
|
msgstr "Anzeigename"
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ msgstr "Mitglieder"
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_circles.html:13
|
#: snikket_web/templates/admin_circles.html:13
|
||||||
#: snikket_web/templates/admin_invites.html:24
|
#: snikket_web/templates/admin_invites.html:24
|
||||||
#: snikket_web/templates/admin_users.html:12
|
#: snikket_web/templates/admin_users.html:14
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Aktionen"
|
msgstr "Aktionen"
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ msgid "Copy complete output"
|
|||||||
msgstr "Komplette Ausgabe kopieren"
|
msgstr "Komplette Ausgabe kopieren"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:4
|
#: snikket_web/templates/admin_delete_user.html:4
|
||||||
#: snikket_web/templates/admin_users.html:24
|
#: snikket_web/templates/admin_users.html:26
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Delete user %(user_name)s"
|
msgid "Delete user %(user_name)s"
|
||||||
msgstr "Benutzer %(user_name)s löschen"
|
msgstr "Benutzer %(user_name)s löschen"
|
||||||
@@ -328,12 +328,12 @@ msgid "Are you sure you want to delete the following user?"
|
|||||||
msgstr "Bist du sicher dass du den folgenden Benutzer löschen willst?"
|
msgstr "Bist du sicher dass du den folgenden Benutzer löschen willst?"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:10
|
#: snikket_web/templates/admin_delete_user.html:10
|
||||||
#: snikket_web/templates/admin_users.html:8
|
#: snikket_web/templates/admin_users.html:10
|
||||||
msgid "Login name"
|
msgid "Login name"
|
||||||
msgstr "Anmeldename"
|
msgstr "Anmeldename"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:14
|
#: snikket_web/templates/admin_delete_user.html:14
|
||||||
#: snikket_web/templates/admin_users.html:10
|
#: snikket_web/templates/admin_users.html:12
|
||||||
msgid "Email address"
|
msgid "Email address"
|
||||||
msgstr "E-Mail-Adresse"
|
msgstr "E-Mail-Adresse"
|
||||||
|
|
||||||
@@ -344,6 +344,7 @@ msgstr "Gefahr"
|
|||||||
#: snikket_web/templates/admin_delete_user.html:23
|
#: snikket_web/templates/admin_delete_user.html:23
|
||||||
#: snikket_web/templates/admin_edit_circle.html:15
|
#: snikket_web/templates/admin_edit_circle.html:15
|
||||||
#: snikket_web/templates/admin_edit_invite.html:45
|
#: snikket_web/templates/admin_edit_invite.html:45
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:25
|
||||||
#: snikket_web/templates/user_logout.html:13
|
#: snikket_web/templates/user_logout.html:13
|
||||||
#: snikket_web/templates/user_passwd.html:40
|
#: snikket_web/templates/user_passwd.html:40
|
||||||
#: snikket_web/templates/user_profile.html:25
|
#: snikket_web/templates/user_profile.html:25
|
||||||
@@ -404,10 +405,12 @@ msgstr "Einladung anzeigen"
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_edit_invite.html:13
|
#: snikket_web/templates/admin_edit_invite.html:13
|
||||||
#: snikket_web/templates/admin_invites.html:21
|
#: snikket_web/templates/admin_invites.html:21
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:15
|
||||||
msgid "Valid until"
|
msgid "Valid until"
|
||||||
msgstr "Gültig bis"
|
msgstr "Gültig bis"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_edit_invite.html:15
|
#: snikket_web/templates/admin_edit_invite.html:15
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:17
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Link"
|
msgstr "Link"
|
||||||
|
|
||||||
@@ -462,6 +465,7 @@ msgid "User information"
|
|||||||
msgstr "Benutzerinformationen"
|
msgstr "Benutzerinformationen"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_edit_user.html:25
|
#: snikket_web/templates/admin_edit_user.html:25
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:8
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
msgstr "Passwort zurücksetzen"
|
msgstr "Passwort zurücksetzen"
|
||||||
|
|
||||||
@@ -549,15 +553,37 @@ msgstr "Einladung löschen"
|
|||||||
msgid "Currently, there are no pending invitations."
|
msgid "Currently, there are no pending invitations."
|
||||||
msgstr "Derzeit gibt es keine ausstehenden Einladungen."
|
msgstr "Derzeit gibt es keine ausstehenden Einladungen."
|
||||||
|
|
||||||
#: snikket_web/templates/admin_users.html:11
|
#: snikket_web/templates/admin_reset_user_password.html:12
|
||||||
|
#, python-format
|
||||||
|
msgid "Password reset link for %(user_name)s"
|
||||||
|
msgstr "Link zum Zurücksetzen des Passwortes für %(user_name)s"
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:13
|
||||||
|
msgid ""
|
||||||
|
"The following link will allow the user to reset their password on their "
|
||||||
|
"device, once."
|
||||||
|
msgstr ""
|
||||||
|
"Der folgende Link erlaubt es, das Passwort für das Nutzerkonto einmalig "
|
||||||
|
"zurückzusetzen."
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:22
|
||||||
|
msgid "Destroy link"
|
||||||
|
msgstr "Link zerstören"
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_users.html:13
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr "Telefonnummer"
|
msgstr "Telefonnummer"
|
||||||
|
|
||||||
#: snikket_web/templates/admin_users.html:27
|
#: snikket_web/templates/admin_users.html:29
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Show debug information for %(user_name)s"
|
msgid "Show debug information for %(user_name)s"
|
||||||
msgstr "Debugging-Informationen für %(user_name)s anzeigen"
|
msgstr "Debugging-Informationen für %(user_name)s anzeigen"
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_users.html:32
|
||||||
|
#, python-format
|
||||||
|
msgid "Create password reset link for %(user_name)s"
|
||||||
|
msgstr "Benutzer %(user_name)s löschen"
|
||||||
|
|
||||||
#: snikket_web/templates/app.html:4
|
#: snikket_web/templates/app.html:4
|
||||||
msgid "Snikket Web Portal"
|
msgid "Snikket Web Portal"
|
||||||
msgstr "Snikket Webportal"
|
msgstr "Snikket Webportal"
|
||||||
|
|||||||
@@ -18,75 +18,75 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.9.0\n"
|
"Generated-By: Babel 2.9.0\n"
|
||||||
|
|
||||||
#: snikket_web/admin.py:52
|
#: snikket_web/admin.py:60
|
||||||
msgid "Delete user permanently"
|
msgid "Delete user permanently"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:95
|
#: snikket_web/admin.py:129
|
||||||
msgid "Invite to circle"
|
msgid "Invite to circle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:101
|
#: snikket_web/admin.py:135
|
||||||
msgid "At least one circle must be selected"
|
msgid "At least one circle must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:106
|
#: snikket_web/admin.py:140
|
||||||
msgid "Valid for"
|
msgid "Valid for"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:108
|
#: snikket_web/admin.py:142
|
||||||
msgid "One hour"
|
msgid "One hour"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:109
|
#: snikket_web/admin.py:143
|
||||||
msgid "Twelve hours"
|
msgid "Twelve hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:110
|
#: snikket_web/admin.py:144
|
||||||
msgid "One day"
|
msgid "One day"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:111
|
#: snikket_web/admin.py:145
|
||||||
msgid "One week"
|
msgid "One week"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:112
|
#: snikket_web/admin.py:146
|
||||||
msgid "Four weeks"
|
msgid "Four weeks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:118
|
#: snikket_web/admin.py:152
|
||||||
msgid "Allow multiple uses"
|
msgid "Allow multiple uses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:122
|
#: snikket_web/admin.py:156
|
||||||
msgid "New invitation link"
|
msgid "New invitation link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:180
|
#: snikket_web/admin.py:214
|
||||||
msgid "Revoke"
|
msgid "Revoke"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:231 snikket_web/admin.py:274
|
#: snikket_web/admin.py:265 snikket_web/admin.py:308
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:235 snikket_web/templates/admin_circles.html:42
|
#: snikket_web/admin.py:269 snikket_web/templates/admin_circles.html:42
|
||||||
msgid "Create circle"
|
msgid "Create circle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:279
|
#: snikket_web/admin.py:313
|
||||||
msgid "Select user"
|
msgid "Select user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:284 snikket_web/user.py:68
|
#: snikket_web/admin.py:318 snikket_web/user.py:68
|
||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:288
|
#: snikket_web/admin.py:322
|
||||||
msgid "Delete circle permanently"
|
msgid "Delete circle permanently"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/admin.py:294
|
#: snikket_web/admin.py:328
|
||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:12
|
#: snikket_web/templates/admin_delete_user.html:12
|
||||||
#: snikket_web/templates/admin_delete_user.html:16
|
#: snikket_web/templates/admin_delete_user.html:16
|
||||||
#: snikket_web/templates/admin_users.html:9 snikket_web/user.py:55
|
#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:55
|
||||||
msgid "Display name"
|
msgid "Display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_circles.html:13
|
#: snikket_web/templates/admin_circles.html:13
|
||||||
#: snikket_web/templates/admin_invites.html:24
|
#: snikket_web/templates/admin_invites.html:24
|
||||||
#: snikket_web/templates/admin_users.html:12
|
#: snikket_web/templates/admin_users.html:14
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ msgid "Copy complete output"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:4
|
#: snikket_web/templates/admin_delete_user.html:4
|
||||||
#: snikket_web/templates/admin_users.html:24
|
#: snikket_web/templates/admin_users.html:26
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Delete user %(user_name)s"
|
msgid "Delete user %(user_name)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -313,12 +313,12 @@ msgid "Are you sure you want to delete the following user?"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:10
|
#: snikket_web/templates/admin_delete_user.html:10
|
||||||
#: snikket_web/templates/admin_users.html:8
|
#: snikket_web/templates/admin_users.html:10
|
||||||
msgid "Login name"
|
msgid "Login name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_delete_user.html:14
|
#: snikket_web/templates/admin_delete_user.html:14
|
||||||
#: snikket_web/templates/admin_users.html:10
|
#: snikket_web/templates/admin_users.html:12
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Email address"
|
msgid "Email address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -330,6 +330,7 @@ msgstr ""
|
|||||||
#: snikket_web/templates/admin_delete_user.html:23
|
#: snikket_web/templates/admin_delete_user.html:23
|
||||||
#: snikket_web/templates/admin_edit_circle.html:15
|
#: snikket_web/templates/admin_edit_circle.html:15
|
||||||
#: snikket_web/templates/admin_edit_invite.html:45
|
#: snikket_web/templates/admin_edit_invite.html:45
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:25
|
||||||
#: snikket_web/templates/user_logout.html:13
|
#: snikket_web/templates/user_logout.html:13
|
||||||
#: snikket_web/templates/user_passwd.html:40
|
#: snikket_web/templates/user_passwd.html:40
|
||||||
#: snikket_web/templates/user_profile.html:25
|
#: snikket_web/templates/user_profile.html:25
|
||||||
@@ -388,10 +389,12 @@ msgstr ""
|
|||||||
|
|
||||||
#: snikket_web/templates/admin_edit_invite.html:13
|
#: snikket_web/templates/admin_edit_invite.html:13
|
||||||
#: snikket_web/templates/admin_invites.html:21
|
#: snikket_web/templates/admin_invites.html:21
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:15
|
||||||
msgid "Valid until"
|
msgid "Valid until"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_edit_invite.html:15
|
#: snikket_web/templates/admin_edit_invite.html:15
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:17
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -440,6 +443,7 @@ msgid "User information"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_edit_user.html:25
|
#: snikket_web/templates/admin_edit_user.html:25
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:8
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -523,15 +527,35 @@ msgstr ""
|
|||||||
msgid "Currently, there are no pending invitations."
|
msgid "Currently, there are no pending invitations."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_users.html:11
|
#: snikket_web/templates/admin_reset_user_password.html:12
|
||||||
|
#, fuzzy, python-format
|
||||||
|
msgid "Password reset link for %(user_name)s"
|
||||||
|
msgstr "Welcome home, %(user_name)s."
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:13
|
||||||
|
msgid ""
|
||||||
|
"The following link will allow the user to reset their password on their "
|
||||||
|
"device, once."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_reset_user_password.html:22
|
||||||
|
msgid "Destroy link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_users.html:13
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/admin_users.html:27
|
#: snikket_web/templates/admin_users.html:29
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
msgid "Show debug information for %(user_name)s"
|
msgid "Show debug information for %(user_name)s"
|
||||||
msgstr "Welcome home, %(user_name)s."
|
msgstr "Welcome home, %(user_name)s."
|
||||||
|
|
||||||
|
#: snikket_web/templates/admin_users.html:32
|
||||||
|
#, python-format
|
||||||
|
msgid "Create password reset link for %(user_name)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: snikket_web/templates/app.html:4
|
#: snikket_web/templates/app.html:4
|
||||||
msgid "Snikket Web Portal"
|
msgid "Snikket Web Portal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
Reference in New Issue
Block a user