Merge branch 'feat/inventory'
This commit is contained in:
@@ -1,45 +1,78 @@
|
||||
import { clerkMiddleware, createRouteMatcher, clerkClient } from '@clerk/astro/server';
|
||||
import type { MiddlewareNext } from 'astro';
|
||||
import 'dotenv/config';
|
||||
|
||||
declare global {
|
||||
namespace App {
|
||||
interface Locals {
|
||||
canAddInventory: boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isProtectedRoute = createRouteMatcher(['/pokemon']);
|
||||
const isAdminRoute = createRouteMatcher(['/admin']);
|
||||
|
||||
const TARGET_ORG_ID = "org_3Baav9czkRLLlC7g89oJWqRRulK";
|
||||
|
||||
export const onRequest = clerkMiddleware(async (auth, context) => {
|
||||
const { isAuthenticated, userId, redirectToSignIn } = auth();
|
||||
export const onRequest = clerkMiddleware(async (auth, context, next) => {
|
||||
const { isAuthenticated, userId, redirectToSignIn, has } = auth();
|
||||
|
||||
if (!isAuthenticated && isProtectedRoute(context.request)) {
|
||||
return redirectToSignIn();
|
||||
}
|
||||
|
||||
// ── Inventory visibility check ──────────────────────────────────────────────
|
||||
// Resolves to true if the user belongs to the target org OR has the feature
|
||||
const canAddInventory = process.env.INVENTORY_ACCESS === 'true' ||
|
||||
(
|
||||
isAuthenticated &&
|
||||
userId &&
|
||||
(
|
||||
!!has({ permission: "org:feature:inventory_add" }) || // Clerk feature flag
|
||||
(await getUserOrgIds(context, userId)).includes(TARGET_ORG_ID)
|
||||
)
|
||||
);
|
||||
|
||||
// Expose the flag to your Astro pages via locals
|
||||
context.locals.canAddInventory = Boolean(canAddInventory);
|
||||
|
||||
// ── Admin route guard ───────────────────────────────────────────
|
||||
if (isAdminRoute(context.request)) {
|
||||
if (!isAuthenticated || !userId) {
|
||||
return redirectToSignIn();
|
||||
}
|
||||
|
||||
try {
|
||||
const client = await clerkClient(context); // pass context here
|
||||
const client = await clerkClient(context);
|
||||
const memberships = await client.organizations.getOrganizationMembershipList({
|
||||
organizationId: TARGET_ORG_ID,
|
||||
});
|
||||
|
||||
console.log("Total memberships found:", memberships.data.length);
|
||||
console.log("Current userId:", userId);
|
||||
console.log("Memberships:", JSON.stringify(memberships.data.map(m => ({
|
||||
userId: m.publicUserData?.userId,
|
||||
role: m.role,
|
||||
})), null, 2));
|
||||
|
||||
const userMembership = memberships.data.find(
|
||||
(m) => m.publicUserData?.userId === userId
|
||||
);
|
||||
|
||||
if (!userMembership || userMembership.role !== "org:admin") {
|
||||
return context.redirect("/");
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Clerk membership check failed:", e);
|
||||
return context.redirect("/");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
// ── Helper: fetch all org IDs the current user belongs to ───────────────────
|
||||
async function getUserOrgIds(context: any, userId: string): Promise<string[]> {
|
||||
try {
|
||||
const client = await clerkClient(context);
|
||||
const memberships = await client.users.getOrganizationMembershipList({ userId });
|
||||
return memberships.data.map((m) => m.organization.id);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch user org memberships:", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user