from repositories.pocketbase_client import pb_client from repositories.tenant_repository import tenant_repository from repositories.seat_repository import seat_repository def get_seat_from_request(request): """ Resolves both the tenant_id AND the specific active seat record for a dashboard request from its `Authorization: Bearer {jwt}` header. The JWT itself is issued and verified by PocketBase (the dashboard authenticates directly against PocketBase) — this backend doesn't hold the JWT signing secret, so it validates the token by asking PocketBase to refresh it, then resolves the returned email to a tenant and seat. Needed by seat-scoped features (the trip watchlist's per-seat cap) where "which tenant" isn't enough — every other authenticated route only ever needed tenant_id, so the seat record this lookup already finds was previously discarded (see get_tenant_id_from_request() below, now a thin wrapper around this). Data flow: request.headers['Authorization'] → strip "Bearer " prefix → PocketBase POST /api/collections/users/auth-refresh → { record: { email } } → seat lookup by email across known tenants (via domain) → (tenant_id, seat) returned, or (None, None) if unresolvable """ auth_header = request.headers.get('Authorization', '') if not auth_header.startswith('Bearer '): return None, None token = auth_header[len('Bearer '):] record = pb_client.auth_refresh(token) if not record or not record.get('email'): return None, None email = record['email'] domain = email.split('@', 1)[1].lower() if '@' in email else None if not domain: return None, None tenant = tenant_repository.get_by_domain(domain) if not tenant: return None, None # Confirm this email actually holds an active seat on the tenant — # a verified PocketBase login alone isn't sufficient authorization, # the email must also be a registered, active seat. seat = seat_repository.get_active(tenant['id'], email) if not seat: return None, None return tenant['id'], seat def get_tenant_id_from_request(request): """Back-compat wrapper — most routes only need the tenant_id, not the seat.""" tenant_id, _ = get_seat_from_request(request) return tenant_id