summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/api
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/api')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/invite_links.py27
1 files changed, 17 insertions, 10 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}")