Compare commits

..

5 Commits

Author SHA1 Message Date
Matthew Wild
2ff47c486a Update translation strings 2024-04-30 10:52:52 +01:00
Matthew Wild
338ee0b278 Add 'share' button for browsers supporting Web Share API 2024-04-30 10:48:51 +01:00
Matthew Wild
64c6548a48 Support for optional text notes on invitations 2024-04-29 18:39:06 +01:00
Matthew Wild
8c824149cc Fixes for invitation display
- Reorder columns, from generic to specific
- Fix empty tooltip on invitation types caused by incorrect macro usage
2024-04-29 18:19:07 +01:00
Matthew Wild
607863cfc4 Remove duplicate template macro 2024-04-29 18:00:22 +01:00
14 changed files with 200 additions and 89 deletions

View File

@@ -213,7 +213,6 @@ def create_app() -> quart.Quart:
app.config["ABUSE_EMAIL"] = config.abuse_email app.config["ABUSE_EMAIL"] = config.abuse_email
app.config["SECURITY_EMAIL"] = config.security_email app.config["SECURITY_EMAIL"] = config.security_email
app.config["SESSION_COOKIE_SECURE"] = True app.config["SESSION_COOKIE_SECURE"] = True
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
app.context_processor(proc) app.context_processor(proc)
app.register_error_handler( app.register_error_handler(

View File

@@ -301,6 +301,10 @@ class InvitePost(BaseForm):
default="prosody:registered", default="prosody:registered",
) )
note = wtforms.StringField(
_l("Comment (optional)"),
)
action_create_invite = wtforms.SubmitField( action_create_invite = wtforms.SubmitField(
_l("New invitation link") _l("New invitation link")
) )
@@ -382,12 +386,14 @@ async def create_invite() -> typing.Union[str, werkzeug.Response]:
group_ids=form.circles.data, group_ids=form.circles.data,
role_names=[form.role.data], role_names=[form.role.data],
ttl=form.lifetime.data, ttl=form.lifetime.data,
note=form.note.data,
) )
else: else:
invite = await client.create_account_invite( invite = await client.create_account_invite(
group_ids=form.circles.data, group_ids=form.circles.data,
role_names=[form.role.data], role_names=[form.role.data],
ttl=form.lifetime.data, ttl=form.lifetime.data,
note=form.note.data,
) )
await flash( await flash(
_("Invitation created"), _("Invitation created"),

View File

@@ -162,6 +162,7 @@ class AdminInviteInfo:
group_ids: typing.Collection[str] group_ids: typing.Collection[str]
role_names: typing.Collection[str] role_names: typing.Collection[str]
is_reset: bool is_reset: bool
note: typing.Optional[str]
@classmethod @classmethod
def from_api_response( def from_api_response(
@@ -181,6 +182,7 @@ class AdminInviteInfo:
role_names=data.get("roles", []), role_names=data.get("roles", []),
reusable=data["reusable"], reusable=data["reusable"],
is_reset=data.get("reset", False), is_reset=data.get("reset", False),
note=data.get("note"),
) )
@@ -1091,6 +1093,7 @@ class ProsodyClient:
role_names: typing.Collection[str] = [], role_names: typing.Collection[str] = [],
restrict_username: typing.Optional[str] = None, restrict_username: typing.Optional[str] = None,
ttl: typing.Optional[int] = None, ttl: typing.Optional[int] = None,
note: typing.Optional[str] = None,
session: aiohttp.ClientSession, session: aiohttp.ClientSession,
) -> AdminInviteInfo: ) -> AdminInviteInfo:
payload: typing.Dict[str, typing.Any] = {} payload: typing.Dict[str, typing.Any] = {}
@@ -1100,6 +1103,8 @@ class ProsodyClient:
payload["username"] = restrict_username payload["username"] = restrict_username
if ttl is not None: if ttl is not None:
payload["ttl"] = ttl payload["ttl"] = ttl
if note is not None:
payload["note"] = note
async with session.post( async with session.post(
self._admin_v1_endpoint("/invites/account"), self._admin_v1_endpoint("/invites/account"),
@@ -1114,6 +1119,7 @@ class ProsodyClient:
group_ids: typing.Collection[str] = [], group_ids: typing.Collection[str] = [],
role_names: typing.Collection[str] = [], role_names: typing.Collection[str] = [],
ttl: typing.Optional[int] = None, ttl: typing.Optional[int] = None,
note: typing.Optional[str] = None,
session: aiohttp.ClientSession, session: aiohttp.ClientSession,
) -> AdminInviteInfo: ) -> AdminInviteInfo:
payload: typing.Dict[str, typing.Any] = { payload: typing.Dict[str, typing.Any] = {
@@ -1122,6 +1128,8 @@ class ProsodyClient:
} }
if ttl is not None: if ttl is not None:
payload["ttl"] = ttl payload["ttl"] = ttl
if note is not None:
payload["note"] = note
async with session.post( async with session.post(
self._admin_v1_endpoint("/invites/group"), self._admin_v1_endpoint("/invites/group"),

View File

@@ -992,19 +992,18 @@ div.profile-card {
} }
} }
/* clipboard button */ /* clipboard and share buttons */
.copy-to-clipboard { .copy-to-clipboard, .share-button {
cursor: pointer; cursor: pointer;
font-style: normal; font-style: normal;
text-decoration: none; text-decoration: none;
} }
body.no-copy .copy-to-clipboard { body.no-copy .copy-to-clipboard, body.no-share .share-button {
display: none !important; display: none !important;
} }
/* magic */ /* magic */
pre.guru-meditation { pre.guru-meditation {

View File

@@ -193,4 +193,9 @@ licensed under the terms of the Apache 2.0 License -->
<g><rect fill="none" height="24" width="24" /><rect fill="none" height="24" width="24" /></g> <g><rect fill="none" height="24" width="24" /><rect fill="none" height="24" width="24" /></g>
<g><g><path d="M21,8c-1.45,0-2.26,1.44-1.93,2.51l-3.55,3.56c-0.3-0.09-0.74-0.09-1.04,0l-2.55-2.55C12.27,10.45,11.46,9,10,9 c-1.45,0-2.27,1.44-1.93,2.52l-4.56,4.55C2.44,15.74,1,16.55,1,18c0,1.1,0.9,2,2,2c1.45,0,2.26-1.44,1.93-2.51l4.55-4.56 c0.3,0.09,0.74,0.09,1.04,0l2.55,2.55C12.73,16.55,13.54,18,15,18c1.45,0,2.27-1.44,1.93-2.52l3.56-3.55 C21.56,12.26,23,11.45,23,10C23,8.9,22.1,8,21,8z" /><polygon points="15,9 15.94,6.93 18,6 15.94,5.07 15,3 14.08,5.07 12,6 14.08,6.93" /><polygon points="3.5,11 4,9 6,8.5 4,8 3.5,6 3,8 1,8.5 3,9" /></g></g> <g><g><path d="M21,8c-1.45,0-2.26,1.44-1.93,2.51l-3.55,3.56c-0.3-0.09-0.74-0.09-1.04,0l-2.55-2.55C12.27,10.45,11.46,9,10,9 c-1.45,0-2.27,1.44-1.93,2.52l-4.56,4.55C2.44,15.74,1,16.55,1,18c0,1.1,0.9,2,2,2c1.45,0,2.26-1.44,1.93-2.51l4.55-4.56 c0.3,0.09,0.74,0.09,1.04,0l2.55,2.55C12.73,16.55,13.54,18,15,18c1.45,0,2.27-1.44,1.93-2.52l3.56-3.55 C21.56,12.26,23,11.45,23,10C23,8.9,22.1,8,21,8z" /><polygon points="15,9 15.94,6.93 18,6 15.94,5.07 15,3 14.08,5.07 12,6 14.08,6.93" /><polygon points="3.5,11 4,9 6,8.5 4,8 3.5,6 3,8 1,8.5 3,9" /></g></g>
</symbol> </symbol>
<!-- from: social/share/materialiconsround/24px.svg -->
<symbol id="icon-share" viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z" />
</symbol>
</defs></svg> </defs></svg>

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -66,6 +66,12 @@
{%- call render_errors(invite_form.circles) -%}{%- endcall -%} {%- call render_errors(invite_form.circles) -%}{%- endcall -%}
</div> </div>
<!-- Comment -->
<div class="f-ebox">
{{ invite_form.note.label }}
{{ invite_form.note }}
</div>
<div class="f-bbox"> <div class="f-bbox">
{%- call form_button("create_link", invite_form.action_create_invite, class="primary") %}{% endcall -%} {%- call form_button("create_link", invite_form.action_create_invite, class="primary") %}{% endcall -%}
</div> </div>

View File

@@ -1,5 +1,5 @@
{% extends "admin_app.html" %} {% extends "admin_app.html" %}
{% from "library.j2" import showuri, form_button, standard_button, extract_circle_name, invite_type_description %} {% from "library.j2" import showuri, form_button, standard_button, extract_circle_name, invite_type_name, invite_type_description %}
{% block head_lead %} {% block head_lead %}
{{ super() }} {{ super() }}
{% include "copy-snippet.html" %} {% include "copy-snippet.html" %}
@@ -13,9 +13,10 @@
<dt>{% trans %}Valid until{% endtrans %}</dt> <dt>{% trans %}Valid until{% endtrans %}</dt>
<dd>{{ invite.expires | format_date }}</dd> <dd>{{ invite.expires | format_date }}</dd>
<dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt> <dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt>
<dd>{% call showuri(invite.landing_page, id_="link-field") %}{% endcall %}</dd> <dd>{% call showuri(invite.landing_page, id_="link-field") %}{% trans %}Invitation to Snikket{% endtrans %}{% endcall %}</dd>
<dt>{% trans %}Invitation type{% endtrans %}</dt> <dt>{% trans %}Invitation type{% endtrans %}</dt>
<dd>{% call invite_type_description(invite) %}{% endcall %}</dd> {% set invite_type = invite.reusable and "group" or "account" %}
<dd><span class="with-tooltip above" data-tooltip="{% call invite_type_description(invite_type) %}{% endcall %}">{% call invite_type_name(invite_type) %}{% endcall %}</span></dd>
{%- set ngroups = invite.group_ids | length -%} {%- set ngroups = invite.group_ids | length -%}
{%- if ngroups > 1 -%} {%- if ngroups > 1 -%}
{#- not supported via the web UI, but we should still display it properly -#} {#- not supported via the web UI, but we should still display it properly -#}

View File

@@ -1,5 +1,5 @@
{% extends "admin_app.html" %} {% extends "admin_app.html" %}
{% from "library.j2" import action_button, icon, clipboard_button, form_button, custom_form_button, extract_circle_name, invite_type_name, invite_type_description %} {% from "library.j2" import action_button, icon, clipboard_button, share_button, form_button, custom_form_button, extract_circle_name, invite_type_name, invite_type_description %}
{% block head_lead %} {% block head_lead %}
{{ super() }} {{ super() }}
{% include "copy-snippet.html" %} {% include "copy-snippet.html" %}
@@ -18,17 +18,18 @@
<col/> <col/>
<thead> <thead>
<tr> <tr>
<th>{% trans %}Expires{% endtrans %}</th>
<th class="collapsible">{% trans %}Type{% endtrans %}</th> <th class="collapsible">{% trans %}Type{% endtrans %}</th>
<th class="collapsible">{% trans %}Circle{% endtrans %}</th> <th class="collapsible">{% trans %}Circle{% endtrans %}</th>
<th>{% trans %}Expires{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th>
<th>{% trans %}Actions{% endtrans %}</th> <th>{% trans %}Actions{% endtrans %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for invite in invites %} {% for invite in invites %}
{% set invite_type = invite.reusable and "group" or "account" %}
<tr> <tr>
<td>{{ (invite.expires - now) | format_timedelta(add_direction=True) }}</td> <td class="collapsible"><span class="with-tooltip above" data-tooltip="{% call invite_type_description(invite_type) %}{% endcall %}">{% call invite_type_name(invite_type) %}{% endcall %}</span></td>
<td class="collapsible"><span class="with-tooltip above" data-tooltip="{% call invite_type_description(invite) %}{% endcall %}">{% call invite_type_name(invite) %}{% endcall %}</span></td>
<td class="collapsible"> <td class="collapsible">
{#- -#} {#- -#}
<ul class="inline"> <ul class="inline">
@@ -38,6 +39,8 @@
</ul> </ul>
{#- -#} {#- -#}
</td> </td>
<td>{{ (invite.expires - now) | format_timedelta(add_direction=True) }}</td>
<td>{% if invite.note is not none %}{{ invite.note }}{% endif %}</td>
<td class="nowrap"> <td class="nowrap">
{%- call action_button("more", url_for(".edit_invite", id_=invite.id_), class="secondary") -%} {%- call action_button("more", url_for(".edit_invite", id_=invite.id_), class="secondary") -%}
{% trans %}Show invite details{% endtrans %} {% trans %}Show invite details{% endtrans %}
@@ -45,6 +48,9 @@
{%- call clipboard_button(invite.landing_page, class="primary") -%} {%- call clipboard_button(invite.landing_page, class="primary") -%}
{% trans %}Copy invite link to clipboard{% endtrans %} {% trans %}Copy invite link to clipboard{% endtrans %}
{%- endcall -%} {%- endcall -%}
{%- call share_button("Invitation to Snikket", invite.landing_page, class="primary") -%}
{% trans %}Share invitation link{% endtrans %}
{%- endcall -%}
{%- call custom_form_button("remove_link", form.action_revoke.name, invite.id_, class="secondary danger", slim=True) -%} {%- call custom_form_button("remove_link", form.action_revoke.name, invite.id_, class="secondary danger", slim=True) -%}
{% trans %}Delete invitation{% endtrans %} {% trans %}Delete invitation{% endtrans %}
{%- endcall -%} {%- endcall -%}

View File

@@ -15,7 +15,7 @@
<dt>{% trans %}Valid until{% endtrans %}</dt> <dt>{% trans %}Valid until{% endtrans %}</dt>
<dd>{{ reset_link.expires | format_date }}</dd> <dd>{{ reset_link.expires | format_date }}</dd>
<dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt> <dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt>
<dd>{% call showuri(reset_link.landing_page, id_="link-field") %}{% endcall %}</dd> <dd>{% call showuri(reset_link.landing_page, id_="link-field") %}Reset your Snikket password{% endcall %}</dd>
</dd> </dd>
<div class="f-bbox"> <div class="f-bbox">
{%- call custom_form_button("remove_link", form.action_revoke.name, reset_link.id_, class="secondary danger") -%} {%- call custom_form_button("remove_link", form.action_revoke.name, reset_link.id_, class="secondary danger") -%}

View File

@@ -16,5 +16,5 @@
<meta name="msapplication-TileColor" content="#fbd308"> <meta name="msapplication-TileColor" content="#fbd308">
<meta name="theme-color" content="#fbd308"> <meta name="theme-color" content="#fbd308">
</head> </head>
<body{% if body_id | default(False) %} id="{{ body_id }}"{% endif %} class="{% if is_in_debug_mode %}debug{% endif %}{% if body_class | default(False) %} {{ body_class }}{% endif %}"{% if onload | default(False) %} onload="{{ onload }}"{% endif %}>{% block body %}{% endblock %}</body> <body{% if body_id | default(False) %} id="{{ body_id }}"{% endif %} class="{% if is_in_debug_mode %}debug{% endif %}{% if body_class | default(False) %} {{ body_class }}{% endif %} no-copy no-share"{% if onload | default(False) %} onload="{{ onload }}"{% endif %}>{% block body %}{% endblock %}</body>
</html> </html>

View File

@@ -115,8 +115,63 @@ var copy_to_clipboard_btn = function(el) {
}); });
}; };
var copy_to_clipboard_btn = function(el) {
var text = el.dataset.cliptext;
if (!text) {
console.error('copy_to_clipboard used on element without text to copy');
}
copyTextToClipboard(text, el, function(success) {
var existing_result_el = document.getElementById("clipboard-result");
if (existing_result_el !== null) {
existing_result_el.parentNode.removeChild(existing_result_el);
}
var icon = "done";
if (!success) {
icon = "cancel";
}
var icon_bak = get_current_icon(el.firstChild);
change_icon(el.firstChild, icon);
setTimeout(function() {
change_icon(el.firstChild, icon_bak);
el.blur();
}, 1500);
});
};
var share_url_btn = function(el) {
let data = {
"title": el.dataset.shareTitle,
"url": el.dataset.shareUrl,
}
let icon_bak = get_current_icon(el.firstChild);
new Promise(function (resolve, reject) {
if(!navigator.canShare || !navigator.canShare(data)) {
return reject();
}
return resolve(navigator.share(data));
}).then(function () {
// Success
change_icon(el.firstChild, "done");
}, function () {
// Failure
change_icon(el.firstChild, "cancel");
}).finally(function () {
// Either way, clear status icon after 1.5s
setTimeout(function() {
change_icon(el.firstChild, icon_bak);
el.blur();
}, 1500);
});
}
window.addEventListener('load', function() { window.addEventListener('load', function() {
document.body.classList.remove("no-copy"); document.body.classList.remove("no-copy");
if(navigator.share) {
document.body.classList.remove("no-share");
}
}); });
</script> </script>

View File

@@ -38,7 +38,10 @@
<em>—</em> <em>—</em>
{%- else -%} {%- else -%}
<div><input type="text" {% if id_ %}id="{{ id_ }}" {% endif %}readonly="readonly" value="{{ uri }}"></div> <div><input type="text" {% if id_ %}id="{{ id_ }}" {% endif %}readonly="readonly" value="{{ uri }}"></div>
<div>{% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %}</div> <div>
{% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %}
{% call share_button(caller() if caller is not none else None, uri, show_label=True) %}{% trans %}Share{% endtrans %}{% endcall %}
</div>
{%- endif -%} {%- endif -%}
{% endmacro %} {% endmacro %}
@@ -82,7 +85,7 @@
{% macro clipboard_button(data, show_label=False, caller=None, class=None) -%} {% macro clipboard_button(data, show_label=False, caller=None, class=None) -%}
{%- set label = caller() -%} {%- set label = caller() -%}
<a class="button{% if class %} {{ class }}{% endif %}" <a class="button copy-to-clipboard{% if class %} {{ class }}{% endif %}"
href="#" href="#"
{% if not show_label %} {% if not show_label %}
aria-label="{{ label }}" aria-label="{{ label }}"
@@ -97,6 +100,24 @@
</a> </a>
{%- endmacro %} {%- endmacro %}
{% macro share_button(title, url, show_label=False, caller=None, class=None) -%}
{%- set label = caller() -%}
<a class="button share-button{% if class %} {{ class }}{% endif %}"
href="#"
{% if not show_label %}
aria-label="{{ label }}"
title="{{ label }}"
{% endif %}
data-share-title="{{ title }}"
data-share-url="{{ url }}"
onclick="share_url_btn(this); return false;">
{%- call icon("share") %}{% endcall -%}
{%- if show_label %}
<span>{{ label }}</span>
{% endif -%}
</a>
{%- endmacro %}
{% macro render_errors(field, caller=None) -%} {% macro render_errors(field, caller=None) -%}
{%- set error_list = field.errors if field.errors is not mapping else (field.errors.values() | flatten | list) -%} {%- set error_list = field.errors if field.errors is not mapping else (field.errors.values() | flatten | list) -%}
{%- if error_list -%} {%- if error_list -%}
@@ -132,19 +153,11 @@
{%- endif -%} {%- endif -%}
{% endmacro %} {% endmacro %}
{%- macro invite_type_name(invite_info, caller=None) -%} {%- macro invite_type_name(invite_type, caller=None) -%}
{%- if invite_info.reusable -%} {%- if invite_type == "account" -%}
{% trans %}Group{% endtrans %}
{%- else -%}
{% trans %}Individual{% endtrans %} {% trans %}Individual{% endtrans %}
{%- endif -%}
{%- endmacro -%}
{%- macro invite_type_description(invite_info, caller=None) -%}
{%- if invite_info.reusable -%}
{% trans %}Can be used multiple times to create accounts on this Snikket service.{% endtrans %}
{%- else -%} {%- else -%}
{% trans %}Can be used once to create an account on this Snikket service.{% endtrans %} {% trans %}Group{% endtrans %}
{%- endif -%} {%- endif -%}
{%- endmacro -%} {%- endmacro -%}

View File

@@ -8,7 +8,7 @@ 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: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-04-27 14:22+0200\n" "POT-Creation-Date: 2024-04-30 10:52+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -136,117 +136,121 @@ msgstr ""
msgid "Invitation type" msgid "Invitation type"
msgstr "" msgstr ""
#: snikket_web/admin.py:288 snikket_web/templates/library.j2:139 #: snikket_web/admin.py:288 snikket_web/templates/library.j2:158
msgid "Individual" msgid "Individual"
msgstr "" msgstr ""
#: snikket_web/admin.py:289 snikket_web/templates/library.j2:137 #: snikket_web/admin.py:289 snikket_web/templates/library.j2:160
msgid "Group" msgid "Group"
msgstr "" msgstr ""
#: snikket_web/admin.py:305 #: snikket_web/admin.py:305
msgid "Comment (optional)"
msgstr ""
#: snikket_web/admin.py:309
msgid "New invitation link" msgid "New invitation link"
msgstr "" msgstr ""
#: snikket_web/admin.py:367 #: snikket_web/admin.py:371
msgid "Revoke" msgid "Revoke"
msgstr "" msgstr ""
#: snikket_web/admin.py:393 #: snikket_web/admin.py:399
msgid "Invitation created" msgid "Invitation created"
msgstr "" msgstr ""
#: snikket_web/admin.py:409 #: snikket_web/admin.py:415
msgid "No such invitation exists" msgid "No such invitation exists"
msgstr "" msgstr ""
#: snikket_web/admin.py:424 #: snikket_web/admin.py:430
msgid "Invitation revoked" msgid "Invitation revoked"
msgstr "" msgstr ""
#: snikket_web/admin.py:441 snikket_web/admin.py:489 #: snikket_web/admin.py:447 snikket_web/admin.py:495
#: snikket_web/templates/admin_delete_circle.html:10 #: snikket_web/templates/admin_delete_circle.html:10
#: snikket_web/templates/admin_edit_circle.html:44 #: snikket_web/templates/admin_edit_circle.html:44
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#: snikket_web/admin.py:446 snikket_web/templates/admin_circles.html:47 #: snikket_web/admin.py:452 snikket_web/templates/admin_circles.html:47
msgid "Create circle" msgid "Create circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:476 #: snikket_web/admin.py:482
msgid "Circle created" msgid "Circle created"
msgstr "" msgstr ""
#: snikket_web/admin.py:494 #: snikket_web/admin.py:500
msgid "Select user" msgid "Select user"
msgstr "" msgstr ""
#: snikket_web/admin.py:499 #: snikket_web/admin.py:505
msgid "Update circle" msgid "Update circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:505 #: snikket_web/admin.py:511
msgid "Add user" msgid "Add user"
msgstr "" msgstr ""
#: snikket_web/admin.py:523 snikket_web/admin.py:622 snikket_web/admin.py:670 #: snikket_web/admin.py:529 snikket_web/admin.py:628 snikket_web/admin.py:676
msgid "No such circle exists" msgid "No such circle exists"
msgstr "" msgstr ""
#: snikket_web/admin.py:560 #: snikket_web/admin.py:566
msgid "Circle data updated" msgid "Circle data updated"
msgstr "" msgstr ""
#: snikket_web/admin.py:570 #: snikket_web/admin.py:576
msgid "User added to circle" msgid "User added to circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:579 #: snikket_web/admin.py:585
msgid "User removed from circle" msgid "User removed from circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:588 #: snikket_web/admin.py:594
msgid "Chat removed from circle" msgid "Chat removed from circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:606 #: snikket_web/admin.py:612
msgid "Delete circle permanently" msgid "Delete circle permanently"
msgstr "" msgstr ""
#: snikket_web/admin.py:633 #: snikket_web/admin.py:639
msgid "Circle deleted" msgid "Circle deleted"
msgstr "" msgstr ""
#: snikket_web/admin.py:647 #: snikket_web/admin.py:653
msgid "Group chat name" msgid "Group chat name"
msgstr "" msgstr ""
#: snikket_web/admin.py:652 #: snikket_web/admin.py:658
msgid "Create group chat" msgid "Create group chat"
msgstr "" msgstr ""
#: snikket_web/admin.py:682 #: snikket_web/admin.py:688
msgid "New group chat added to circle" msgid "New group chat added to circle"
msgstr "" msgstr ""
#: snikket_web/admin.py:749 #: snikket_web/admin.py:755
msgid "Message contents" msgid "Message contents"
msgstr "" msgstr ""
#: snikket_web/admin.py:755 #: snikket_web/admin.py:761
msgid "Only send to online users" msgid "Only send to online users"
msgstr "" msgstr ""
#: snikket_web/admin.py:759 #: snikket_web/admin.py:765
msgid "Post to all users" msgid "Post to all users"
msgstr "" msgstr ""
#: snikket_web/admin.py:763 #: snikket_web/admin.py:769
msgid "Send preview to yourself" msgid "Send preview to yourself"
msgstr "" msgstr ""
#: snikket_web/admin.py:785 #: snikket_web/admin.py:791
msgid "Announcement sent!" msgid "Announcement sent!"
msgstr "" msgstr ""
@@ -546,7 +550,7 @@ msgstr ""
#: snikket_web/templates/admin_circles.html:15 #: snikket_web/templates/admin_circles.html:15
#: snikket_web/templates/admin_edit_circle.html:45 #: snikket_web/templates/admin_edit_circle.html:45
#: snikket_web/templates/admin_edit_circle.html:74 #: snikket_web/templates/admin_edit_circle.html:74
#: snikket_web/templates/admin_invites.html:24 #: snikket_web/templates/admin_invites.html:25
#: snikket_web/templates/admin_users.html:10 #: snikket_web/templates/admin_users.html:10
msgid "Actions" msgid "Actions"
msgstr "" msgstr ""
@@ -774,7 +778,7 @@ msgid "The user has been deleted from the server."
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_circle.html:84 #: snikket_web/templates/admin_edit_circle.html:84
#: snikket_web/templates/library.j2:131 #: snikket_web/templates/library.j2:152
msgid "deleted" msgid "deleted"
msgstr "" msgstr ""
@@ -817,38 +821,42 @@ msgstr ""
msgid "Link" msgid "Link"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:22 #: snikket_web/templates/admin_edit_invite.html:16
msgid "Invitation to Snikket"
msgstr ""
#: snikket_web/templates/admin_edit_invite.html:23
#: snikket_web/templates/admin_home.html:19 #: snikket_web/templates/admin_home.html:19
msgid "Circles" msgid "Circles"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:23 #: snikket_web/templates/admin_edit_invite.html:24
msgid "Users joining via this invitation will be added to the following circles:" msgid "Users joining via this invitation will be added to the following circles:"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:29 #: snikket_web/templates/admin_edit_invite.html:30
#: snikket_web/templates/admin_invites.html:23 #: snikket_web/templates/admin_invites.html:22
msgid "Circle" msgid "Circle"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:35 #: snikket_web/templates/admin_edit_invite.html:36
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:41
msgid "Contact" msgid "Contact"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:41 #: snikket_web/templates/admin_edit_invite.html:42
#, python-format #, python-format
msgid "The user will get added as contact of %(peer_jid)s." msgid "The user will get added as contact of %(peer_jid)s."
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:43 #: snikket_web/templates/admin_edit_invite.html:44
msgid "Created" msgid "Created"
msgstr "" msgstr ""
#: snikket_web/templates/admin_edit_invite.html:48 #: snikket_web/templates/admin_edit_invite.html:49
msgid "Return to invitation list" msgid "Return to invitation list"
msgstr "" msgstr ""
@@ -1008,26 +1016,34 @@ msgid "Pending invitations"
msgstr "" msgstr ""
#: snikket_web/templates/admin_invites.html:21 #: snikket_web/templates/admin_invites.html:21
msgid "Expires"
msgstr ""
#: snikket_web/templates/admin_invites.html:22
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: snikket_web/templates/admin_invites.html:43 #: snikket_web/templates/admin_invites.html:23
msgid "Show invite details" msgid "Expires"
msgstr ""
#: snikket_web/templates/admin_invites.html:24
msgid "Comment"
msgstr "" msgstr ""
#: snikket_web/templates/admin_invites.html:46 #: snikket_web/templates/admin_invites.html:46
msgid "Copy invite link to clipboard" msgid "Show invite details"
msgstr "" msgstr ""
#: snikket_web/templates/admin_invites.html:49 #: snikket_web/templates/admin_invites.html:49
msgid "Copy invite link to clipboard"
msgstr ""
#: snikket_web/templates/admin_invites.html:52
msgid "Share invitation link"
msgstr ""
#: snikket_web/templates/admin_invites.html:55
msgid "Delete invitation" msgid "Delete invitation"
msgstr "" msgstr ""
#: snikket_web/templates/admin_invites.html:57 #: snikket_web/templates/admin_invites.html:63
msgid "Currently, there are no pending invitations." msgid "Currently, there are no pending invitations."
msgstr "" msgstr ""
@@ -1565,43 +1581,39 @@ msgstr ""
msgid " (Restricted)" msgid " (Restricted)"
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:41 #: snikket_web/templates/library.j2:42
msgid "Copy link" msgid "Copy link"
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:104 #: snikket_web/templates/library.j2:43
msgid "Share"
msgstr ""
#: snikket_web/templates/library.j2:125
msgid "Invalid input" msgid "Invalid input"
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:145 #: snikket_web/templates/library.j2:166
msgid "Can be used multiple times to create accounts on this Snikket service."
msgstr ""
#: snikket_web/templates/library.j2:147
msgid "Can be used once to create an account on this Snikket service."
msgstr ""
#: snikket_web/templates/library.j2:153
msgid "" msgid ""
"Limited users can interact with users on the same Snikket service and be " "Limited users can interact with users on the same Snikket service and be "
"members of circles." "members of circles."
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:155 #: snikket_web/templates/library.j2:168
msgid "" msgid ""
"Like limited users and can also interact with users on other Snikket " "Like limited users and can also interact with users on other Snikket "
"services." "services."
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:157 #: snikket_web/templates/library.j2:170
msgid "Like normal users and can access the admin panel in the web portal." msgid "Like normal users and can access the admin panel in the web portal."
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:171 #: snikket_web/templates/library.j2:184
msgid "Invite a single person (invitation link can only be used once)." msgid "Invite a single person (invitation link can only be used once)."
msgstr "" msgstr ""
#: snikket_web/templates/library.j2:173 #: snikket_web/templates/library.j2:186
msgid "Invite a group of people (invitation link can be used multiple times)." msgid "Invite a group of people (invitation link can be used multiple times)."
msgstr "" msgstr ""

View File

@@ -36,3 +36,4 @@ image/edit:edit
action/admin_panel_settings:admin action/admin_panel_settings:admin
content/link:link content/link:link
content/insights:insights content/insights:insights
social/share:share