You've already forked snikket-web-portal
Compare commits
25 Commits
stable/0.1
...
enable-ita
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4de4509fc9 | ||
|
|
93e3b325b1 | ||
|
|
ceecfc861c | ||
|
|
2467e73781 | ||
|
|
2f34d39a09 | ||
|
|
de8589923b | ||
|
|
db3a1ac22f | ||
|
|
b48d130659 | ||
|
|
1aed573eb2 | ||
|
|
d4707196ec | ||
|
|
8a8d4c54bd | ||
|
|
ab534e3a59 | ||
|
|
4c128f1af2 | ||
|
|
8b551a8946 | ||
|
|
182d2301be | ||
|
|
6dba5e3a65 | ||
|
|
713da89445 | ||
|
|
9876e42fb7 | ||
|
|
8b66c5a063 | ||
|
|
ddf9f89d77 | ||
|
|
53e023f9ae | ||
|
|
e4d339627e | ||
|
|
cd3026911b | ||
|
|
d7da16f780 | ||
|
|
8ed0fbec25 |
@@ -2,4 +2,7 @@
|
||||
|
||||
export SNIKKET_WEB_DOMAIN="$SNIKKET_DOMAIN"
|
||||
|
||||
exec hypercorn -b "127.0.0.1:5765" 'snikket_web:create_app()'
|
||||
export SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_INTERFACE="${SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_INTERFACE-127.0.0.1}"
|
||||
export SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_PORT="${SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_PORT-5765}"
|
||||
|
||||
exec hypercorn -b "${SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_INTERFACE}:${SNIKKET_TWEAK_PORTAL_INTERNAL_HTTP_PORT}" 'snikket_web:create_app()'
|
||||
|
||||
@@ -149,6 +149,7 @@ class AppConfig:
|
||||
"en",
|
||||
"fr",
|
||||
"id",
|
||||
"it",
|
||||
"pl",
|
||||
], converter=autosplit)
|
||||
apple_store_url = environ.var("")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version_info = (0, 1, 1, "a0")
|
||||
version_info = (0, 1, 2, "a0")
|
||||
version = (
|
||||
".".join(map(str, version_info[:3])) +
|
||||
(f"-{version_info[3]}" if version_info[3] else "")
|
||||
|
||||
@@ -17,10 +17,11 @@ from quart import (
|
||||
url_for,
|
||||
request,
|
||||
abort,
|
||||
flash,
|
||||
)
|
||||
import flask_wtf
|
||||
|
||||
from flask_babel import lazy_gettext as _l
|
||||
from flask_babel import lazy_gettext as _l, _
|
||||
|
||||
from . import prosodyclient
|
||||
from .infra import client, circle_name
|
||||
@@ -68,6 +69,10 @@ async def delete_user(localpart: str) -> typing.Union[str, quart.Response]:
|
||||
if form.validate_on_submit():
|
||||
if form.action_delete.data:
|
||||
await client.delete_user_by_localpart(localpart)
|
||||
await flash(
|
||||
_("User deleted"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".users"))
|
||||
|
||||
return await render_template(
|
||||
@@ -107,8 +112,16 @@ async def create_password_reset_link() -> typing.Union[str, quart.Response]:
|
||||
localpart=localpart,
|
||||
ttl=86400,
|
||||
)
|
||||
await flash(
|
||||
_("Password reset link created"),
|
||||
"success",
|
||||
)
|
||||
elif form.action_revoke.data:
|
||||
await client.delete_invite(form.action_revoke.data)
|
||||
await flash(
|
||||
_("Password reset link deleted"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".users"))
|
||||
|
||||
return await render_template(
|
||||
@@ -242,6 +255,10 @@ async def create_invite() -> typing.Union[str, quart.Response]:
|
||||
group_ids=form.circles.data,
|
||||
ttl=form.lifetime.data,
|
||||
)
|
||||
await flash(
|
||||
_("Invitation created"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".edit_invite", id_=invite.id_))
|
||||
return await render_template("admin_create_invite.html",
|
||||
invite_form=form)
|
||||
@@ -254,7 +271,11 @@ async def edit_invite(id_: str) -> typing.Union[str, quart.Response]:
|
||||
invite_info = await client.get_invite_by_id(id_)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 404:
|
||||
abort(404)
|
||||
await flash(
|
||||
_("No such invitation exists"),
|
||||
"alert",
|
||||
)
|
||||
return redirect(url_for(".invitations"))
|
||||
circles = await client.list_groups()
|
||||
circle_map = {
|
||||
circle.id_: circle
|
||||
@@ -265,6 +286,10 @@ async def edit_invite(id_: str) -> typing.Union[str, quart.Response]:
|
||||
if form.validate_on_submit():
|
||||
if form.action_revoke.data:
|
||||
await client.delete_invite(id_)
|
||||
await flash(
|
||||
_("Invitation revoked"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".invitations"))
|
||||
return redirect(url_for(".edit_invite", id_=id_))
|
||||
|
||||
@@ -313,6 +338,10 @@ async def create_circle() -> typing.Union[str, quart.Response]:
|
||||
circle = await client.create_group(
|
||||
name=create_form.name.data,
|
||||
)
|
||||
await flash(
|
||||
_("Circle created"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".edit_circle", id_=circle.id_))
|
||||
|
||||
return await render_template(
|
||||
@@ -358,6 +387,10 @@ async def edit_circle(id_: str) -> typing.Union[str, quart.Response]:
|
||||
)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 404:
|
||||
await flash(
|
||||
_("No such circle exists"),
|
||||
"alert",
|
||||
)
|
||||
return redirect(url_for(".circles"))
|
||||
raise
|
||||
|
||||
@@ -391,21 +424,36 @@ async def edit_circle(id_: str) -> typing.Union[str, quart.Response]:
|
||||
id_,
|
||||
new_name=form.name.data,
|
||||
)
|
||||
await flash(
|
||||
_("Circle data updated"),
|
||||
"success",
|
||||
)
|
||||
elif form.action_delete.data:
|
||||
await client.delete_group(id_)
|
||||
await flash(
|
||||
_("Circle deleted"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".circles"))
|
||||
elif form.action_add_user.data:
|
||||
if form.user_to_add.data in valid_users:
|
||||
print("is valid")
|
||||
await client.add_group_member(
|
||||
id_,
|
||||
form.user_to_add.data,
|
||||
)
|
||||
await flash(
|
||||
_("User added to circle"),
|
||||
"success",
|
||||
)
|
||||
elif form.action_remove_user.data:
|
||||
await client.remove_group_member(
|
||||
id_,
|
||||
form.action_remove_user.data,
|
||||
)
|
||||
await flash(
|
||||
_("User removed from circle"),
|
||||
"success",
|
||||
)
|
||||
|
||||
return redirect(url_for(".edit_circle", id_=id_))
|
||||
else:
|
||||
|
||||
@@ -48,8 +48,12 @@ def context() -> typing.Mapping[str, typing.Any]:
|
||||
|
||||
|
||||
@bp.route("/<id_>")
|
||||
async def view_old(id_: str) -> quart.Response:
|
||||
return redirect(url_for(".view", id_=id_))
|
||||
|
||||
|
||||
@bp.route("/<id_>/")
|
||||
async def view(id_: str) -> str:
|
||||
async def view(id_: str) -> typing.Union[quart.Response, str]:
|
||||
try:
|
||||
invite = await client.get_public_invite_by_id(id_)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
@@ -80,13 +84,19 @@ async def view(id_: str) -> str:
|
||||
)
|
||||
apple_store_url = current_app.config["APPLE_STORE_URL"]
|
||||
|
||||
return await render_template(
|
||||
body = await render_template(
|
||||
"invite_view.html",
|
||||
invite=invite,
|
||||
play_store_url=play_store_url,
|
||||
apple_store_url=apple_store_url,
|
||||
invite_id=id_,
|
||||
)
|
||||
return quart.Response(
|
||||
body,
|
||||
headers={
|
||||
"Link": "<{}> rel=\"alternate\"".format(invite.xmpp_uri),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class RegisterForm(flask_wtf.FlaskForm): # type:ignore
|
||||
|
||||
@@ -15,6 +15,7 @@ from quart import (
|
||||
render_template,
|
||||
request,
|
||||
Response,
|
||||
flash,
|
||||
)
|
||||
|
||||
import babel
|
||||
@@ -52,6 +53,9 @@ async def index() -> quart.Response:
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
ERR_CREDENTIALS_INVALID = _l("Invalid username or password.")
|
||||
|
||||
|
||||
@bp.route("/login", methods=["GET", "POST"])
|
||||
async def login() -> typing.Union[str, quart.Response]:
|
||||
if client.has_session and (await client.test_session()):
|
||||
@@ -63,16 +67,24 @@ async def login() -> typing.Union[str, quart.Response]:
|
||||
localpart, domain, resource = xmpputil.split_jid(jid)
|
||||
if not localpart:
|
||||
localpart, domain = domain, current_app.config["SNIKKET_DOMAIN"]
|
||||
jid = "{}@{}".format(localpart, domain)
|
||||
password = form.password.data
|
||||
try:
|
||||
await client.login(jid, password)
|
||||
except quart.exceptions.Unauthorized:
|
||||
form.password.errors.append(
|
||||
_("Invalid username or password.")
|
||||
)
|
||||
if domain != current_app.config["SNIKKET_DOMAIN"]:
|
||||
# (a) prosody throws a 400 at us and I prefer to catch that here
|
||||
# and (b) I don’t want to pass on this obviously not-for-here
|
||||
# password further than necessary.
|
||||
form.password.errors.append(ERR_CREDENTIALS_INVALID)
|
||||
else:
|
||||
return redirect(url_for('user.index'))
|
||||
jid = "{}@{}".format(localpart, domain)
|
||||
password = form.password.data
|
||||
try:
|
||||
await client.login(jid, password)
|
||||
except quart.exceptions.Unauthorized:
|
||||
form.password.errors.append(ERR_CREDENTIALS_INVALID)
|
||||
else:
|
||||
await flash(
|
||||
_("Login successful!"),
|
||||
"success"
|
||||
)
|
||||
return redirect(url_for('user.index'))
|
||||
|
||||
return await render_template("login.html", form=form)
|
||||
|
||||
|
||||
@@ -252,3 +252,4 @@ $h-sizes: [200.0%, 174.11011266%, 151.57165665%, 131.95079108%, 114.8698355%, 10
|
||||
$h-small-sizes: [150.0%, 138.31618672%, 127.54245006%, 117.60790225%, 108.44717712%, 100.0%];
|
||||
$small-screen-threshold: 40rem;
|
||||
$medium-screen-threshold: 60rem;
|
||||
$large-screen-threshold: 80rem;
|
||||
|
||||
@@ -33,13 +33,35 @@ body {
|
||||
|
||||
main {
|
||||
padding: $w-l1;
|
||||
margin-left: auto;
|
||||
max-width: 60rem;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#mwrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
> .filler, > .flashbox {
|
||||
flex: 1 1 1rem;
|
||||
}
|
||||
|
||||
> main {
|
||||
flex: 0 1 60rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $large-screen-threshold) {
|
||||
#mwrap {
|
||||
display: block;
|
||||
|
||||
> main {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flashbox > div.box > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* top bar */
|
||||
@@ -995,6 +1017,23 @@ div.profile-card {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input[type="submit"], button, .button {
|
||||
&.slimmify {
|
||||
> svg.icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
> span {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
top: -100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clipboard button */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "library.j2" import standard_button %}
|
||||
{% block head_lead %}
|
||||
<title>About Snikket</title>
|
||||
<title>{% trans %}About Snikket{% endtrans %}</title>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<main>
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
{% endblock %}
|
||||
{% block topbar_right %}
|
||||
{{- super() -}}
|
||||
{% call standard_button("logout", url_for("user.logout"), class="tertiary") %}{% trans %}Log out{% endtrans %}{% endcall %}
|
||||
{% call standard_button("logout", url_for("user.logout"), class="tertiary slimmify") %}{% trans %}Log out{% endtrans %}{% endcall %}
|
||||
{%- endblock %}
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for("static", filename="css/invite.css") }}">
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div id="mwrap"><main>{% block content %}{% endblock %}</main></div>
|
||||
<div id="mwrap"><div class="filler"></div><main>{% block content %}{% endblock %}</main><div class="filler"></div></div>
|
||||
{%- include "_footer.html" -%}
|
||||
{% endblock %}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<title>{% trans site_name=config["SITE_NAME"] %}Invite to {{ site_name }} | Snikket{% endtrans %}</title>
|
||||
<script async type="text/javascript" src="{{ url_for("static", filename="js/invite-magic.js") }}"></script>
|
||||
<script async type="text/javascript" src="{{ url_for("static", filename="js/qrcode.min.js") }}"></script>
|
||||
<link rel="alternate" href="{{ invite.xmpp_uri }}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="elevated box el-3">
|
||||
@@ -30,7 +31,7 @@
|
||||
{%- endif -%}
|
||||
</ul>
|
||||
{%- call standard_button("qrcode", "#qr-modal", class="primary", onclick="open_modal(this); return false;") -%}
|
||||
{% trans %}Not on mobile?{% endtrans %}
|
||||
{% trans %}Send to mobile device{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</div>
|
||||
<p>{% trans %}After installation the app should automatically open and prompt you to create an account. If not, simply click the button below.{% endtrans %}</p>
|
||||
|
||||
@@ -9,16 +9,20 @@
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div id="mwrap"><main><div class="form layout-expanded">
|
||||
<div id="mwrap"><div class="filler"></div><main><div class="form layout-expanded">
|
||||
<h1 class="form-title">{{ config["SITE_NAME"] }}</h1>
|
||||
<p class="form-desc">{{ _("Enter your Snikket address and password to manage your account.") }}</p>
|
||||
<form method="POST" action="{{ url_for('.login') }}" name="login">
|
||||
<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 %}
|
||||
<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>
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.address.label(class="a11y-only") }}
|
||||
{{ form.address(placeholder=form.address.label.text) }}
|
||||
@@ -31,6 +35,22 @@
|
||||
{%- call form_button("login", form.action_signin, class="primary") -%}{% endcall -%}
|
||||
</div>
|
||||
</from>
|
||||
</div></main></div>
|
||||
<script type="text/javascript">
|
||||
var domainCheck = function() {
|
||||
var form = document.getElementById("login-form");
|
||||
var addressId = form.dataset.addressid;
|
||||
var addressField = document.getElementById(addressId);
|
||||
var domain = form.dataset.domain;
|
||||
var address = addressField.value;
|
||||
var errorBox = document.getElementById("id-warning");
|
||||
if (address.includes("@") && !address.endsWith(domain)) {
|
||||
errorBox.style.display = "block";
|
||||
return false;
|
||||
}
|
||||
errorBox.style.display = "none";
|
||||
return true;
|
||||
};
|
||||
</script>
|
||||
</div></main><div class="filler"></div></div>
|
||||
{%- include "_footer.html" -%}
|
||||
{% endblock %}
|
||||
|
||||
@@ -7,6 +7,25 @@
|
||||
<div class="filler"></div>
|
||||
{% block topbar_right %}{% endblock %}
|
||||
</div>
|
||||
<div id="mwrap"><main>{% block content %}{% endblock %}</main></div>
|
||||
<div id="mwrap">
|
||||
{#- -#}
|
||||
<div class="flashbox">
|
||||
{%- for category, message in get_flashed_messages(True) -%}
|
||||
<div class="box {{ category }} el-5" role="alert">
|
||||
{% if category == "success" %}
|
||||
<header>{% trans %}Operation successful{% endtrans %}</header>
|
||||
{% elif category == "alert" %}
|
||||
<header>{% trans %}Error{% endtrans %}</header>
|
||||
{% endif %}
|
||||
<p>{{ message }}</p>
|
||||
</div>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{#- -#}
|
||||
<main>{% block content %}{% endblock %}</main>
|
||||
{#- -#}
|
||||
<div class="filler"></div>
|
||||
{#- -#}
|
||||
</div>
|
||||
{%- include "_footer.html" -%}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{% extends "app.html" %}
|
||||
{% from "library.j2" import standard_button, form_button %}
|
||||
{% block head_lead %}
|
||||
<title>Snikket Web Portal</title>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="form layout-expanded"><form method="POST">
|
||||
<h2 class="form-title">{% trans %}Sign out of the Snikket Web Portal{% endtrans %}</h2>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{% extends "app.html" %}
|
||||
{% from "library.j2" import standard_button, custom_form_button, render_errors %}
|
||||
{% block head_lead %}
|
||||
<title>Snikket Web Portal</title>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="form layout-expanded"><form method="POST">
|
||||
<h1 class="form-title">{% trans %}Change your password{% endtrans %}</h1>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{% extends "app.html" %}
|
||||
{% from "library.j2" import standard_button, form_button, avatar with context %}
|
||||
{% block head_lead %}
|
||||
<title>Snikket Web Portal</title>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Update your profile{% endtrans %}</h1>
|
||||
<div class="form layout-expanded"><form method="POST" enctype="multipart/form-data">
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: SnikketWeb 0.1.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-01-30 12:45+0100\n"
|
||||
"PO-Revision-Date: 2021-01-31 12:54+0000\n"
|
||||
"PO-Revision-Date: 2021-02-10 17:01+0000\n"
|
||||
"Last-Translator: Jonas Schäfer <jonas@zombofant.net>\n"
|
||||
"Language-Team: German <https://i18n.sotecware.net/projects/snikket/"
|
||||
"web-portal/de/>\n"
|
||||
@@ -353,7 +353,7 @@ msgstr "Neue Gemeinschaft"
|
||||
|
||||
#: snikket_web/templates/admin_create_invite.html:3
|
||||
msgid "Create invitation"
|
||||
msgstr "Gemeinschaft gründen"
|
||||
msgstr "Einladung erzeugen"
|
||||
|
||||
#: snikket_web/templates/admin_create_invite_form.html:5
|
||||
msgid "Create new invitation"
|
||||
@@ -653,7 +653,7 @@ msgstr "Debugging-Informationen für %(user_name)s anzeigen"
|
||||
#: snikket_web/templates/admin_users.html:28
|
||||
#, python-format
|
||||
msgid "Create password reset link for %(user_name)s"
|
||||
msgstr "Benutzer %(user_name)s löschen"
|
||||
msgstr "Link zum Zurücksetzen des Passwortes von %(user_name)s erzeugen"
|
||||
|
||||
#: snikket_web/templates/app.html:4
|
||||
msgid "Snikket Web Portal"
|
||||
|
||||
1072
snikket_web/translations/es_MX/LC_MESSAGES/messages.po
Normal file
1072
snikket_web/translations/es_MX/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-01-30 12:45+0100\n"
|
||||
"PO-Revision-Date: 2021-02-02 21:01+0000\n"
|
||||
"PO-Revision-Date: 2021-02-16 12:02+0000\n"
|
||||
"Last-Translator: Link Mauve <linkmauve@linkmauve.fr>\n"
|
||||
"Language-Team: French <https://i18n.sotecware.net/projects/snikket/"
|
||||
"web-portal/fr/>\n"
|
||||
@@ -46,7 +46,7 @@ msgstr "Douze heures"
|
||||
|
||||
#: snikket_web/admin.py:144
|
||||
msgid "One day"
|
||||
msgstr "Un jour"
|
||||
msgstr "Une journée"
|
||||
|
||||
#: snikket_web/admin.py:145
|
||||
msgid "One week"
|
||||
@@ -382,11 +382,11 @@ msgstr "Le contenu ci-dessous peut contenir des informations sensibles."
|
||||
|
||||
#: snikket_web/templates/admin_debug_user.html:15
|
||||
msgid "Raw debug dump"
|
||||
msgstr "Journal de débogage brute"
|
||||
msgstr "Journal de débogage brut"
|
||||
|
||||
#: snikket_web/templates/admin_debug_user.html:17
|
||||
msgid "Copy complete output"
|
||||
msgstr "Copier le journal complet"
|
||||
msgstr "Copier le journal entier"
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:4
|
||||
#: snikket_web/templates/admin_users.html:22
|
||||
@@ -686,7 +686,7 @@ msgstr "Le portail web a rencontré une erreur interne."
|
||||
#: snikket_web/templates/invite_view.html:12
|
||||
#, python-format
|
||||
msgid "Invite to %(site_name)s"
|
||||
msgstr "Inviter à %(site_name)s"
|
||||
msgstr "Invitation à %(site_name)s"
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:6
|
||||
#: snikket_web/templates/invite_register.html:10
|
||||
@@ -762,9 +762,8 @@ msgid ""
|
||||
"If you plan to use a legacy XMPP client, you can register an account online "
|
||||
"and enter your credentials into any XMPP-compatible software."
|
||||
msgstr ""
|
||||
"Si vous prévoyez d’utiliser un ancien client XMPP, vous pouvez ouvrir un "
|
||||
"compte en ligne et saisir vos indentifiants dans tout logiciel compatible "
|
||||
"XMPP."
|
||||
"Si vous prévoyez d’utiliser un client XMPP, vous pouvez ouvrir un compte en "
|
||||
"ligne et saisir vos indentifiants dans tout logiciel compatible XMPP."
|
||||
|
||||
#: snikket_web/templates/invite_register.html:27
|
||||
msgid ""
|
||||
@@ -907,13 +906,13 @@ msgid ""
|
||||
"You can now set up your legacy XMPP client with the above address and the "
|
||||
"password you chose during registration."
|
||||
msgstr ""
|
||||
"Vous pouvez maintenant configurer votre ancien client XMPP avec l’adresse ci-"
|
||||
"dessus et le mot de passe que vous avez choisi lors de l’enregistrement."
|
||||
"Vous pouvez maintenant configurer votre client XMPP avec l’adresse ci-dessus "
|
||||
"et le mot de passe que vous avez choisi lors de l’enregistrement."
|
||||
|
||||
#: snikket_web/templates/invite_view.html:6
|
||||
#, python-format
|
||||
msgid "Invite to %(site_name)s | Snikket"
|
||||
msgstr "Inviter à %(site_name)s | Snikket"
|
||||
msgstr "Invitation à %(site_name)s | Snikket"
|
||||
|
||||
#: snikket_web/templates/invite_view.html:15
|
||||
#, python-format
|
||||
@@ -921,9 +920,9 @@ msgid ""
|
||||
"You have been invited to chat with %(inviter_name)s using Snikket, a secure, "
|
||||
"privacy-friendly chat app on %(site_name)s."
|
||||
msgstr ""
|
||||
"Vous avez été invité à converser avec %(inviter_name)s en utilisant Snikket, "
|
||||
"une application de messagerie sécurisée et respectueuse de la vie privée sur "
|
||||
"%(site_name)s."
|
||||
"Vous avez été invité(e) à converser avec %(inviter_name)s en utilisant "
|
||||
"Snikket, une application de messagerie sécurisée et respectueuse de la vie "
|
||||
"privée sur %(site_name)s."
|
||||
|
||||
#: snikket_web/templates/invite_view.html:17
|
||||
#, python-format
|
||||
@@ -1048,7 +1047,7 @@ msgstr "Peut être utilisée pour créer un seul compte sur ce service Snikket."
|
||||
|
||||
#: snikket_web/templates/login.html:5
|
||||
msgid "Snikket Login"
|
||||
msgstr "Identifiant Snikket"
|
||||
msgstr "Connexion à Snikket"
|
||||
|
||||
#: snikket_web/templates/login.html:14
|
||||
msgid "Enter your Snikket address and password to manage your account."
|
||||
@@ -1065,7 +1064,7 @@ msgstr "Bienvenue !"
|
||||
#: snikket_web/templates/user_home.html:10
|
||||
#, python-format
|
||||
msgid "Welcome home, %(user_name)s."
|
||||
msgstr "Bienvenue à la maison, %(user_name)s."
|
||||
msgstr "Bienvenue chez vous, %(user_name)s."
|
||||
|
||||
#: snikket_web/templates/user_home.html:14
|
||||
msgid "Your account"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-01-30 12:45+0100\n"
|
||||
"PO-Revision-Date: 2021-01-31 12:54+0000\n"
|
||||
"PO-Revision-Date: 2021-02-18 20:01+0000\n"
|
||||
"Last-Translator: misiek <migelazur@mailbox.org>\n"
|
||||
"Language-Team: Polish <https://i18n.sotecware.net/projects/snikket/"
|
||||
"web-portal/pl/>\n"
|
||||
@@ -268,8 +268,8 @@ msgid ""
|
||||
"\"%(apache20_url)s\">Apache 2.0 License</a>."
|
||||
msgstr ""
|
||||
"Ikony wykorzystane w portalu to <a href=\"%(source_url)s\">Google’s Material "
|
||||
"Icons</a>, udostępnione przez Google na warunkach licencji<a href="
|
||||
"\"%(apache20_url)s\">Apache 2.0</a>."
|
||||
"Icons</a>, udostępnione przez Google na warunkach licencji <a href=\""
|
||||
"%(apache20_url)s\">Apache 2.0</a>."
|
||||
|
||||
#: snikket_web/templates/about.html:17
|
||||
msgid "Software Versions"
|
||||
@@ -690,7 +690,7 @@ msgstr "Portal internetowy napotkał błąd wewnętrzny."
|
||||
#: snikket_web/templates/invite_view.html:12
|
||||
#, python-format
|
||||
msgid "Invite to %(site_name)s"
|
||||
msgstr "Zaproś na %(site_name)s"
|
||||
msgstr "Zaproszenie na %(site_name)s"
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:6
|
||||
#: snikket_web/templates/invite_register.html:10
|
||||
@@ -930,7 +930,7 @@ msgid ""
|
||||
"You have been invited to chat on %(site_name)s using Snikket, a secure, "
|
||||
"privacy-friendly chat app."
|
||||
msgstr ""
|
||||
"Zostałeś zaproszony do czatu na %(site_name)s za pomocą Snikket - "
|
||||
"Zostałeś zaproszony do czatowania na %(site_name)s za pomocą Snikket - "
|
||||
"bezpiecznej i przyjaznej dla prywatności aplikacji do rozmów."
|
||||
|
||||
#: snikket_web/templates/invite_view.html:19
|
||||
@@ -1040,13 +1040,13 @@ msgstr "usunięty"
|
||||
#: snikket_web/templates/library.j2:122
|
||||
msgid "Can be used multiple times to create accounts on this Snikket service."
|
||||
msgstr ""
|
||||
"Może być wykorzystywany wielokrotnie, by utworzyć konto na tym serwerze "
|
||||
"Może być wykorzystywane wielokrotnie, by utworzyć konto na tym serwerze "
|
||||
"Snikket."
|
||||
|
||||
#: snikket_web/templates/library.j2:124
|
||||
msgid "Can be used once to create an account on this Snikket service."
|
||||
msgstr ""
|
||||
"Może być wykorzystany jeden raz, by utworzyć konto na tym serwerze Snikket."
|
||||
"Może być wykorzystane jeden raz, by utworzyć konto na tym serwerze Snikket."
|
||||
|
||||
#: snikket_web/templates/login.html:5
|
||||
msgid "Snikket Login"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-01-30 12:45+0100\n"
|
||||
"PO-Revision-Date: 2021-02-02 21:01+0000\n"
|
||||
"Last-Translator: GodGoldfish <mathis.useless@protonmail.com>\n"
|
||||
"PO-Revision-Date: 2021-02-04 19:02+0000\n"
|
||||
"Last-Translator: GodGoldfish <godgoldfish@pm.me>\n"
|
||||
"Language-Team: Russian <https://i18n.sotecware.net/projects/snikket/"
|
||||
"web-portal/ru/>\n"
|
||||
"Language: ru\n"
|
||||
@@ -130,12 +130,10 @@ msgid "That username is already taken"
|
||||
msgstr "Это имя пользователя уже используется"
|
||||
|
||||
#: snikket_web/invite.py:141 snikket_web/invite.py:205
|
||||
#, fuzzy
|
||||
msgid "Registration was declined for unknown reasons"
|
||||
msgstr "В регистрации отказано по неизвестным причинам"
|
||||
msgstr "Регистрация была отклонена по неизвестным причинам"
|
||||
|
||||
#: snikket_web/invite.py:145
|
||||
#, fuzzy
|
||||
msgid "The username is not valid"
|
||||
msgstr "Имя пользователя недействительно"
|
||||
|
||||
@@ -153,7 +151,6 @@ msgid "Sign in"
|
||||
msgstr "Войти"
|
||||
|
||||
#: snikket_web/main.py:72
|
||||
#, fuzzy
|
||||
msgid "Invalid username or password."
|
||||
msgstr "Неверное имя пользователя или пароль."
|
||||
|
||||
@@ -392,14 +389,12 @@ msgstr ""
|
||||
"Приведенное ниже содержание может содержать конфиденциальную информацию."
|
||||
|
||||
#: snikket_web/templates/admin_debug_user.html:15
|
||||
#, fuzzy
|
||||
msgid "Raw debug dump"
|
||||
msgstr "Сырой журнал отладки"
|
||||
msgstr "Исходная отладка переполнения"
|
||||
|
||||
#: snikket_web/templates/admin_debug_user.html:17
|
||||
#, fuzzy
|
||||
msgid "Copy complete output"
|
||||
msgstr "Скопируйте полный журнал"
|
||||
msgstr "Копировать полный вывод"
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:4
|
||||
#: snikket_web/templates/admin_users.html:22
|
||||
@@ -412,13 +407,11 @@ msgid "Delete user"
|
||||
msgstr "Удалить пользователя"
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:8
|
||||
#, fuzzy
|
||||
msgid "Are you sure you want to delete the following user?"
|
||||
msgstr "Вы уверены, что хотите удалить следующего пользователя?"
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:10
|
||||
#: snikket_web/templates/admin_users.html:10
|
||||
#, fuzzy
|
||||
msgid "Login name"
|
||||
msgstr "Логин"
|
||||
|
||||
@@ -447,9 +440,8 @@ msgid "Back"
|
||||
msgstr "Вернуть"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:14
|
||||
#, fuzzy
|
||||
msgid "This is your main circle"
|
||||
msgstr "Это твой главный круг"
|
||||
msgstr "Это ваш основной круг"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:15
|
||||
#, fuzzy
|
||||
@@ -459,27 +451,23 @@ msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:17
|
||||
#: snikket_web/templates/admin_edit_circle.html:33
|
||||
#, fuzzy
|
||||
msgid "Group chat address"
|
||||
msgstr "Адрес групповой беседы"
|
||||
msgstr "Адрес группового чата"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:20
|
||||
#: snikket_web/templates/admin_edit_circle.html:36
|
||||
#: snikket_web/templates/invite_success.html:15
|
||||
#: snikket_web/templates/user_home.html:21
|
||||
#, fuzzy
|
||||
msgid "Copy address"
|
||||
msgstr "Скопируйте адрес"
|
||||
msgstr "Копировать адрес"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:26
|
||||
#, fuzzy
|
||||
msgid "Circle information"
|
||||
msgstr "Информация о круге"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:39
|
||||
#, fuzzy
|
||||
msgid "This circle has no group chat associated."
|
||||
msgstr "У этого круга нет группового разговора."
|
||||
msgstr "С этим кругом не связан ни один групповой чат."
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:48
|
||||
msgid "Delete circle"
|
||||
@@ -491,49 +479,41 @@ msgid "Deleting a circle does not delete any users in the circle."
|
||||
msgstr "Удаление круга не приводит к удалению пользователей из круга."
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:55
|
||||
#, fuzzy
|
||||
msgid "Circle members"
|
||||
msgstr "Члены Круга"
|
||||
msgstr "Участники круга"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:70
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "Remove user %(username)s from circle"
|
||||
msgstr "Удалить пользователя %(username)s из круга"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:78
|
||||
#, fuzzy
|
||||
msgid "This circle currently has no members."
|
||||
msgstr "У этого круга пока нет членов."
|
||||
msgstr "У этого круга пока нет участников."
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:80
|
||||
#, fuzzy
|
||||
msgid "Invite more members"
|
||||
msgstr "Приглашать других членов"
|
||||
msgstr "Пригласить других участников"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:83
|
||||
#, fuzzy
|
||||
msgid "Add existing user"
|
||||
msgstr "Добавить существующего пользователя"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:94
|
||||
#, fuzzy
|
||||
msgid "All users added"
|
||||
msgstr "Все пользователи добавлены"
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:95
|
||||
#, fuzzy
|
||||
msgid "All users on this service are already in this circle."
|
||||
msgstr "Все пользователи этого сервиса уже находятся в этом кругу."
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:8
|
||||
#, fuzzy
|
||||
msgid "View invitation"
|
||||
msgstr "Информация о приглашении"
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:13
|
||||
#: snikket_web/templates/admin_invites.html:21
|
||||
#: snikket_web/templates/admin_reset_user_password.html:15
|
||||
#, fuzzy
|
||||
msgid "Valid until"
|
||||
msgstr "Действительно до"
|
||||
|
||||
@@ -571,7 +551,7 @@ msgid "Contact"
|
||||
msgstr "Контакт"
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:41
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "The user will get added as contact of %(peer_jid)s."
|
||||
msgstr "Пользователь будет добавлен как контакт %(peer_jid)s."
|
||||
|
||||
@@ -580,9 +560,8 @@ msgid "Created"
|
||||
msgstr "Создано"
|
||||
|
||||
#: snikket_web/templates/admin_home.html:4
|
||||
#, fuzzy
|
||||
msgid "Welcome to the admin panel!"
|
||||
msgstr "Добро пожаловать в панель администрирования!"
|
||||
msgstr "Добро пожаловать в административную панель!"
|
||||
|
||||
#: snikket_web/templates/admin_home.html:5
|
||||
#, python-format
|
||||
@@ -594,18 +573,15 @@ msgid "Users"
|
||||
msgstr "Пользователи"
|
||||
|
||||
#: snikket_web/templates/admin_home.html:11
|
||||
#, fuzzy
|
||||
msgid "Create password reset links or delete users."
|
||||
msgstr "Создайте ссылки для сброса пароля или удалите пользователей."
|
||||
|
||||
#: snikket_web/templates/admin_home.html:15
|
||||
#: snikket_web/templates/admin_users.html:4
|
||||
#, fuzzy
|
||||
msgid "Manage users"
|
||||
msgstr "Управление пользователями"
|
||||
msgstr "Управлять пользователями"
|
||||
|
||||
#: snikket_web/templates/admin_home.html:21
|
||||
#, fuzzy
|
||||
msgid "Create and manage social circles represented on your service."
|
||||
msgstr ""
|
||||
"Создавайте и управляйте социальными кругами, представленными на вашем "
|
||||
@@ -616,7 +592,6 @@ msgid "Invitations"
|
||||
msgstr "Приглашения"
|
||||
|
||||
#: snikket_web/templates/admin_home.html:29
|
||||
#, fuzzy
|
||||
msgid "Create, revoke or copy invitations."
|
||||
msgstr "Создавайте, отзывайте или копируйте приглашения."
|
||||
|
||||
|
||||
@@ -2,7 +2,14 @@ import asyncio
|
||||
import typing
|
||||
|
||||
import quart.flask_patch
|
||||
from quart import Blueprint, render_template, request, redirect, url_for
|
||||
from quart import (
|
||||
Blueprint,
|
||||
render_template,
|
||||
request,
|
||||
redirect,
|
||||
url_for,
|
||||
flash,
|
||||
)
|
||||
import quart.exceptions
|
||||
|
||||
import wtforms
|
||||
@@ -93,6 +100,10 @@ async def change_pw() -> typing.Union[str, quart.Response]:
|
||||
_("Incorrect password"),
|
||||
)
|
||||
else:
|
||||
await flash(
|
||||
_("Password changed"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for("user.change_pw"))
|
||||
|
||||
return await render_template("user_passwd.html", form=form)
|
||||
@@ -131,6 +142,10 @@ async def profile() -> typing.Union[str, quart.Response]:
|
||||
client.set_nickname_access_model(access_model),
|
||||
)
|
||||
|
||||
await flash(
|
||||
_("Profile updated"),
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for(".profile"))
|
||||
|
||||
return await render_template("user_profile.html", form=form)
|
||||
@@ -142,6 +157,12 @@ async def logout() -> typing.Union[quart.Response, str]:
|
||||
form = LogoutForm()
|
||||
if form.validate_on_submit():
|
||||
await client.logout()
|
||||
# No flashing here because we don’t collect flashes in the login page
|
||||
# and it’d be weird.
|
||||
# await flash(
|
||||
# _("Logged out"),
|
||||
# "success",
|
||||
# )
|
||||
return redirect(url_for("main.index"))
|
||||
|
||||
return await render_template("user_logout.html", form=form)
|
||||
|
||||
Reference in New Issue
Block a user