diff options
Diffstat (limited to 'packages/meshbay-hub/src')
12 files changed, 26 insertions, 27 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/invite_links.py b/packages/meshbay-hub/src/meshbay_hub/api/invite_links.py index d44576b..f33dc6e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/api/invite_links.py +++ b/packages/meshbay-hub/src/meshbay_hub/api/invite_links.py @@ -43,7 +43,9 @@ MAX_OUTSTANDING_PER_GROUP = 20 # A node's invitation lifetime is the operator's setting (7 days by default); # the ticket follows it, up to this. MAX_LIFETIME = timedelta(days=30) -# How long a redeemed link stays in the owner's list, saying who used it. +# How long a spent link is kept before it is forgotten. The owner is not shown +# it — the person is in the group — but while the row is here, a reload or a +# second tab of the invitation page still answers the account that used it. KEEP_REDEEMED = timedelta(days=30) _TICKET = re.compile(r"^[A-Za-z0-9_-]{22}$") # secrets.token_urlsafe(16) @@ -205,14 +207,21 @@ async def list_invite_links( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): - """The owner's view: who each link was for, masked, and whether it was used.""" + """ + The owner's view: the links nobody has used yet, masked. + + A redeemed one is left out. The person it let in has a row of their own in + the members list, so keeping the link there too says the same thing twice + and pushes down the links that still wait for somebody — which are the ones + the owner can act on, by cancelling them. + """ await _owned_group(db, group_id, current_user) rows = (await db.execute( - select(GroupInviteLink, User.username) - .outerjoin(User, User.id == GroupInviteLink.redeemed_by) - .where(GroupInviteLink.group_id == group_id) + select(GroupInviteLink) + .where(GroupInviteLink.group_id == group_id, + GroupInviteLink.redeemed_by.is_(None)) .order_by(GroupInviteLink.created_at.desc()) - .limit(200))).all() + .limit(200))).scalars().all() now = datetime.now(UTC) return {"links": [{ "link_id": r.id, @@ -220,10 +229,8 @@ async def list_invite_links( "node_invite_id": r.node_invite_id, "created_at": _aware(r.created_at).isoformat(), "expires_at": _aware(r.expires_at).isoformat(), - "status": ("redeemed" if r.redeemed_by - else "expired" if _aware(r.expires_at) <= now else "pending"), - "redeemed_by": name, - } for r, name in rows]} + "status": "expired" if _aware(r.expires_at) <= now else "pending", + } for r in rows]} @router.delete("/{group_id}/invite-links/{link_id}") diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js index 121c51b..529a33d 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -916,10 +916,14 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, : null; }, [transportRef]); + // A redeemed link is not shown: whoever used it is in the members list above, + // and what belongs here is what the owner can still cancel. The hub leaves + // them out already; the filter is for the desktop client, whose copy of this + // interface can be newer than the hub it is signed into. const loadLinks = useCallback(() => { if (!(group && group.is_admin)) return; hubFetch(`/v1/groups/${groupId}/invite-links`, { token }) - .then(data => setLinks(data.links || [])) + .then(data => setLinks((data.links || []).filter(l => l.status !== 'redeemed'))) .catch(() => {}); }, [groupId, token, group]); @@ -1102,12 +1106,10 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, flex-wrap:wrap;word-break:break-word;margin:4px 0"> <span>${l.email}</span> <span style="color:var(--text-dim)"> - ${l.status === 'redeemed' - ? t('members.link_status_redeemed', { user: l.redeemed_by || '' }) - : l.status === 'expired' - ? t('members.link_status_expired') - : t('members.link_expires', - { date: new Date(l.expires_at).toLocaleDateString() })} + ${l.status === 'expired' + ? t('members.link_status_expired') + : t('members.link_expires', + { date: new Date(l.expires_at).toLocaleDateString() })} </span> ${l.status === 'pending' && html` <button class="admin-btn" type="button" diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index 90f5c00..7008f79 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -697,7 +697,6 @@ export default { 'members.link_email_sent': "Der Link wurde per E-Mail gesendet.", 'members.link_email_refused': "Die E-Mail konnte nicht gesendet werden — teilen Sie den Link selbst.", 'members.links_pending': "Einladungslinks", - 'members.link_status_redeemed': "verwendet von {user}", 'members.link_status_expired': "abgelaufen", 'members.link_expires': "läuft ab am {date}", 'members.link_cancel': "Abbrechen", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js index 2b55d08..1ea6eda 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -813,7 +813,6 @@ export default { 'members.link_email_sent': "The link has been sent by e-mail.", 'members.link_email_refused': "The e-mail could not be sent — share the link yourself.", 'members.links_pending': "Invitation links", - 'members.link_status_redeemed': "used by {user}", 'members.link_status_expired': "expired", 'members.link_expires': "expires {date}", 'members.link_cancel': "Cancel", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index 5265976..df65367 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -692,7 +692,6 @@ export default { 'members.link_email_sent': "El enlace se ha enviado por correo.", 'members.link_email_refused': "No se pudo enviar el correo — comparta el enlace usted mismo.", 'members.links_pending': "Enlaces de invitación", - 'members.link_status_redeemed': "usado por {user}", 'members.link_status_expired': "caducado", 'members.link_expires': "caduca el {date}", 'members.link_cancel': "Cancelar", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js index b6b909e..e5d542a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -695,7 +695,6 @@ export default { 'members.link_email_sent': "Le lien a été envoyé par e-mail.", 'members.link_email_refused': "L’e-mail n’a pas pu être envoyé — partagez le lien vous-même.", 'members.links_pending': "Liens d’invitation", - 'members.link_status_redeemed': "utilisé par {user}", 'members.link_status_expired': "expiré", 'members.link_expires': "expire le {date}", 'members.link_cancel': "Annuler", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js index 2a95bf7..e376550 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -695,7 +695,6 @@ export default { 'members.link_email_sent': "Il link è stato inviato per e-mail.", 'members.link_email_refused': "Impossibile inviare l’e-mail — condivida il link di persona.", 'members.links_pending': "Link d’invito", - 'members.link_status_redeemed': "usato da {user}", 'members.link_status_expired': "scaduto", 'members.link_expires': "scade il {date}", 'members.link_cancel': "Annulla", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js index 4068e44..622fa5a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -687,7 +687,6 @@ export default { 'members.link_email_sent': "リンクをメールで送信しました。", 'members.link_email_refused': "メールを送信できませんでした。リンクを直接共有してください。", 'members.links_pending': "招待リンク", - 'members.link_status_redeemed': "{user} が使用", 'members.link_status_expired': "期限切れ", 'members.link_expires': "{date} に期限切れ", 'members.link_cancel': "取り消す", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js index edb6f6a..be0b43b 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -696,7 +696,6 @@ export default { 'members.link_email_sent': "De link is per e-mail verstuurd.", 'members.link_email_refused': "De e-mail kon niet worden verstuurd — deel de link zelf.", 'members.links_pending': "Uitnodigingslinks", - 'members.link_status_redeemed': "gebruikt door {user}", 'members.link_status_expired': "verlopen", 'members.link_expires': "verloopt op {date}", 'members.link_cancel': "Annuleren", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js index d042c48..6e88a65 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -708,7 +708,6 @@ export default { 'members.link_email_sent': "Link został wysłany e-mailem.", 'members.link_email_refused': "Nie udało się wysłać e-maila — przekaż link samodzielnie.", 'members.links_pending': "Linki zaproszeń", - 'members.link_status_redeemed': "użyty przez {user}", 'members.link_status_expired': "wygasł", 'members.link_expires': "wygasa {date}", 'members.link_cancel': "Anuluj", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js index 61e4d44..edb9146 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js @@ -694,7 +694,6 @@ export default { 'members.link_email_sent': "O link foi enviado por e-mail.", 'members.link_email_refused': "Não foi possível enviar o e-mail — compartilhe o link você mesmo.", 'members.links_pending': "Links de convite", - 'members.link_status_redeemed': "usado por {user}", 'members.link_status_expired': "expirado", 'members.link_expires': "expira em {date}", 'members.link_cancel': "Cancelar", diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index 34fb439..4f5034d 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -676,7 +676,6 @@ export default { 'members.link_email_sent': "链接已通过电子邮件发送。", 'members.link_email_refused': "无法发送电子邮件——请自行分享链接。", 'members.links_pending': "邀请链接", - 'members.link_status_redeemed': "已由 {user} 使用", 'members.link_status_expired': "已过期", 'members.link_expires': "{date} 过期", 'members.link_cancel': "取消", |