Add the ability to resend unaccepted invites (#60)

Previously the only way to resend was to re-invite the same email from
scratch, creating a whole new invite row. Adds a "Resend" action next
to Revoke on each pending invite -- rotates the token and refreshes the
7-day expiry on the same row (the old link stops working the moment
it's used, same instinct as a password-reset resend), then re-sends
the invite email.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 18:29:24 -06:00
co-authored by Claude Sonnet 5
parent aeaaef96ec
commit 66e9c80422
6 changed files with 168 additions and 15 deletions
+17
View File
@@ -38,6 +38,7 @@ from app.services.site_invite_service import (
SiteInviteNotPendingError,
create_site_invite,
list_site_invites,
resend_site_invite,
revoke_site_invite,
)
from app.services.smtp_settings_service import get_smtp_settings, upsert_smtp_settings
@@ -322,6 +323,22 @@ async def revoke_site_invite_endpoint(
raise HTTPException(status_code=400, detail="Invite is no longer pending")
@router.post("/invites/{invite_id}/resend", response_model=SiteInviteRead)
async def resend_site_invite_endpoint(
invite_id: uuid.UUID,
request: Request,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
require_site_admin(current_user)
try:
return await resend_site_invite(db, current_user, str(request.base_url), invite_id)
except SiteInviteNotFoundError:
raise HTTPException(status_code=404, detail="Invite not found")
except SiteInviteNotPendingError:
raise HTTPException(status_code=400, detail="Invite is no longer pending")
@router.get("/settings/smtp", response_model=SmtpSettingsRead | None)
async def get_smtp_settings_endpoint(
current_user: User = Depends(get_current_user),