From d5dbb7718da4dc684c5a263694f1058c137da1d9 Mon Sep 17 00:00:00 2001 From: Zach Harding Date: Wed, 8 Apr 2026 07:50:27 -0400 Subject: [PATCH] style updates and re-added auth with a new method (thad to confirm) --- .env.d.ts | 7 +++ src/middleware.ts | 67 ++++++++++++++++++++++++----- src/pages/partials/card-modal.astro | 35 ++++++--------- src/pages/partials/cards.astro | 18 ++------ 4 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 .env.d.ts diff --git a/.env.d.ts b/.env.d.ts new file mode 100644 index 0000000..151dc49 --- /dev/null +++ b/.env.d.ts @@ -0,0 +1,7 @@ +/// + +declare namespace App { + interface Locals { + canAddInventory: boolean; + } +} \ No newline at end of file diff --git a/src/middleware.ts b/src/middleware.ts index 2e21078..f7cae2d 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,17 +1,64 @@ -// src/middleware.ts -import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'; -import type { AstroMiddlewareRequest, AstroMiddlewareResponse } from 'astro'; +import { clerkMiddleware, createRouteMatcher, clerkClient } from '@clerk/astro/server'; -const isProtectedRoute = createRouteMatcher([ - '/pokemon', -]); +const isProtectedRoute = createRouteMatcher(['/pokemon']); +const isAdminRoute = createRouteMatcher(['/admin']); -export const onRequest = clerkMiddleware((auth, context) => { - const { isAuthenticated, redirectToSignIn } = auth() +const TARGET_ORG_ID = "org_3Baav9czkRLLlC7g89oJWqRRulK"; + +export const onRequest = clerkMiddleware(async (auth, context) => { + const { isAuthenticated, userId, redirectToSignIn, has } = auth(); if (!isAuthenticated && isProtectedRoute(context.request)) { - // Add custom logic to run before redirecting + return redirectToSignIn(); + } - return redirectToSignIn() + // ── Inventory visibility check ────────────────────────────────────────────── + // Resolves to true if the user belongs to the target org OR has the feature + const canAddInventory = + 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 = canAddInventory ?? false; + + // ── Admin route guard (unchanged) ─────────────────────────────────────────── + if (isAdminRoute(context.request)) { + if (!isAuthenticated || !userId) { + return redirectToSignIn(); + } + + try { + const client = await clerkClient(context); + const memberships = await client.organizations.getOrganizationMembershipList({ + organizationId: TARGET_ORG_ID, + }); + + const userMembership = memberships.data.find( + (m) => m.publicUserData?.userId === userId + ); + + if (!userMembership || userMembership.role !== "org:admin") { + return new Response(null, { status: 404 }); + } + } catch (e) { + console.error("Clerk membership check failed:", e); + return context.redirect("/"); + } } }); + +// ── Helper: fetch all org IDs the current user belongs to ─────────────────── +async function getUserOrgIds(context: any, userId: string): Promise { + 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 []; + } +} \ No newline at end of file diff --git a/src/pages/partials/card-modal.astro b/src/pages/partials/card-modal.astro index 3266052..988dba1 100644 --- a/src/pages/partials/card-modal.astro +++ b/src/pages/partials/card-modal.astro @@ -10,17 +10,8 @@ import FirstEditionIcon from "../../components/FirstEditionIcon.astro"; import { Tooltip } from "bootstrap"; -import { clerkClient } from '@clerk/astro/server'; - -const { userId, has } = Astro.locals.auth(); -const TARGET_ORG_ID = 'org_3Baav9czkRLLlC7g89oJWqRRulK'; - -let hasAccess = has({ feature: 'inventory_add' }); - -if (!hasAccess && userId) { - const memberships = await clerkClient(Astro).users.getOrganizationMembershipList({ userId }); - hasAccess = memberships.data.some(m => m.organization.id === TARGET_ORG_ID); -} +// auth check for inventory management features +const { canAddInventory } = Astro.locals; export const partial = true; export const prerender = false; @@ -239,8 +230,8 @@ const altSearchUrl = (card: any) => {
-
{card?.set?.setCode}
-
Illustrator: {card?.artist}
+
{card?.set?.setCode}{card?.set?.setName}
+
Illustrator: {card?.artist}
@@ -272,13 +263,13 @@ const altSearchUrl = (card: any) => { DamagedDMG - {/* {hasAccess && ( */} + {canAddInventory && ( - {/* )} */} + )}
@@ -361,15 +352,15 @@ const altSearchUrl = (card: any) => {
); })} - {/* {hasAccess && ( */} + {canAddInventory && (