fix: harden getActiveContext and add error logging on presentations page
- getActiveContext now verifies team still exists (teams.get) before trusting the cookie/prefs tenantId, preventing stale E Ofis cookie from causing an onboarding redirect loop - Resolved tenantId from getUserTeams() is now persisted to cookie so subsequent requests skip the resolution path - Added catch+log on presentations data fetch to surface the actual error in server logs
This commit is contained in:
@@ -25,7 +25,10 @@ export default async function PresentationsPage() {
|
|||||||
Query.limit(200),
|
Query.limit(200),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
]);
|
]).catch((e) => {
|
||||||
|
console.error("[PresentationsPage] data fetch failed:", e);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
|
||||||
const presentations = JSON.parse(JSON.stringify(presResult.rows)) as Presentation[];
|
const presentations = JSON.parse(JSON.stringify(presResult.rows)) as Presentation[];
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ export type ActiveContext = {
|
|||||||
settings: TenantSettings | null;
|
settings: TenantSettings | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function setActiveTenantCookie(tenantId: string) {
|
||||||
|
try {
|
||||||
|
(await cookies()).set(ACTIVE_TENANT_COOKIE, tenantId, {
|
||||||
|
path: "/",
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "strict",
|
||||||
|
secure: process.env.NODE_ENV === "production",
|
||||||
|
maxAge: 60 * 60 * 24 * 365,
|
||||||
|
});
|
||||||
|
} catch { /* ignore in middleware context */ }
|
||||||
|
}
|
||||||
|
|
||||||
export async function getActiveContext(): Promise<ActiveContext | null> {
|
export async function getActiveContext(): Promise<ActiveContext | null> {
|
||||||
const user = await getCurrentUser();
|
const user = await getCurrentUser();
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
@@ -22,17 +34,19 @@ export async function getActiveContext(): Promise<ActiveContext | null> {
|
|||||||
|
|
||||||
let tenantId = await getActiveTenantId();
|
let tenantId = await getActiveTenantId();
|
||||||
|
|
||||||
// Validate cookie tenantId — user must actually be a member of that team.
|
// Validate cookie/prefs tenantId — team must exist and user must be a member.
|
||||||
if (tenantId) {
|
if (tenantId) {
|
||||||
try {
|
try {
|
||||||
|
await adminTeams.get(tenantId); // throws if team was deleted
|
||||||
const memberships = await adminTeams.listMemberships(tenantId);
|
const memberships = await adminTeams.listMemberships(tenantId);
|
||||||
const isMember = memberships.memberships.some((m) => m.userId === user.$id);
|
const isMember = memberships.memberships.some((m) => m.userId === user.$id);
|
||||||
if (!isMember) {
|
if (!isMember) {
|
||||||
// Stale or cross-account cookie — clear and re-resolve.
|
|
||||||
try { (await cookies()).delete(ACTIVE_TENANT_COOKIE); } catch { /* ignore */ }
|
try { (await cookies()).delete(ACTIVE_TENANT_COOKIE); } catch { /* ignore */ }
|
||||||
tenantId = null;
|
tenantId = null;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
// Team deleted or inaccessible — clear stale pointer.
|
||||||
|
try { (await cookies()).delete(ACTIVE_TENANT_COOKIE); } catch { /* ignore */ }
|
||||||
tenantId = null;
|
tenantId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,6 +54,8 @@ export async function getActiveContext(): Promise<ActiveContext | null> {
|
|||||||
if (!tenantId) {
|
if (!tenantId) {
|
||||||
const userTeams = await getUserTeams();
|
const userTeams = await getUserTeams();
|
||||||
tenantId = userTeams?.teams[0]?.$id ?? null;
|
tenantId = userTeams?.teams[0]?.$id ?? null;
|
||||||
|
// Persist so the next request skips this resolution path.
|
||||||
|
if (tenantId) await setActiveTenantCookie(tenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tenantId) return null;
|
if (!tenantId) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user