Co-authored-by: Michael Chihlas <michael@resolutionflow.com> Co-committed-by: Michael Chihlas <michael@resolutionflow.com>
55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
"""Public endpoint for resolving an account invite code into display info.
|
|
|
|
Mounted as a public route (no tenant context, no auth) — used by the
|
|
/accept-invite page on the frontend so an invitee can see what account they
|
|
are about to join before they sign up. Uses the BYPASSRLS admin session
|
|
factory because account_invites is account-scoped under Phase 4 RLS but the
|
|
caller has no tenant identity yet.
|
|
"""
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import joinedload
|
|
|
|
from app.core.admin_database import get_admin_db
|
|
from app.models.account_invite import AccountInvite
|
|
from app.schemas.oauth import InviteLookupResponse
|
|
|
|
router = APIRouter(prefix="/accounts", tags=["account-invite-lookup"])
|
|
|
|
|
|
@router.get("/invites/{code}/lookup", response_model=InviteLookupResponse)
|
|
async def lookup_invite(
|
|
code: str,
|
|
db: Annotated[AsyncSession, Depends(get_admin_db)],
|
|
) -> InviteLookupResponse:
|
|
"""Return minimal display data for a valid (unused, unexpired, not revoked)
|
|
invite. Returns 404 with `invite_invalid_or_expired_or_revoked` for any
|
|
invalid state — the AcceptInvitePage shows a single "ask the inviter to
|
|
resend" message regardless of which condition failed (anti-enumeration)."""
|
|
result = await db.execute(
|
|
select(AccountInvite)
|
|
.where(AccountInvite.code == code)
|
|
.options(
|
|
joinedload(AccountInvite.account),
|
|
joinedload(AccountInvite.invited_by),
|
|
)
|
|
)
|
|
invite = result.scalar_one_or_none()
|
|
|
|
if invite is None or not invite.is_valid:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail={"error": "invite_invalid_or_expired_or_revoked"},
|
|
)
|
|
|
|
return InviteLookupResponse(
|
|
account_name=invite.account.name,
|
|
inviter_name=invite.invited_by.name,
|
|
invited_email=invite.email,
|
|
role=invite.role,
|
|
)
|