From da70bf36f1712fcbe42eb635efe5a9b522a1bf12 Mon Sep 17 00:00:00 2001 From: Chris Parsons <438676+chrisparsons83@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:00:04 -0800 Subject: [PATCH] Fix draft room to respect isPublicDraftBoard setting for unauthenticated access (#32) When a league has the "Make draft board publicly accessible" setting enabled, unauthenticated users could view the draft-board route but were incorrectly blocked from the draft room route with a 401. Restructure the loader to check isPublicDraftBoard before enforcing auth/membership requirements, matching the behaviour already implemented in the draft-board route. https://claude.ai/code/session_016JiVAG2FrPYjAvSJi3daGD Co-authored-by: Claude --- .../leagues/$leagueId.draft.$seasonId.tsx | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx index b75b156..7cd6e81 100644 --- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx @@ -45,12 +45,6 @@ export async function loader(args: Route.LoaderArgs) { throw new Response("Season ID is required", { status: 400 }); } - if (!userId) { - throw new Response("You must be logged in to view the draft room", { - status: 401, - }); - } - const db = database(); // Get season details @@ -66,19 +60,32 @@ export async function loader(args: Route.LoaderArgs) { throw new Response("Season not found", { status: 404 }); } - // Verify user access: must be team owner or commissioner - const userTeam = season.teams.find((team: any) => team.ownerId === userId); - const isCommissioner = await db.query.commissioners.findFirst({ - where: and( - eq(schema.commissioners.leagueId, leagueId), - eq(schema.commissioners.userId, userId) - ), - }); + // Resolve user's team and commissioner status (null userId means neither) + const userTeam = userId + ? season.teams.find((team: any) => team.ownerId === userId) + : undefined; - if (!userTeam && !isCommissioner) { - throw new Response("You do not have access to this draft room", { - status: 403, - }); + const isCommissioner = userId + ? await db.query.commissioners.findFirst({ + where: and( + eq(schema.commissioners.leagueId, leagueId), + eq(schema.commissioners.userId, userId) + ), + }) + : null; + + // Access control: if draft board is not public, require authentication and membership + if (!season.league.isPublicDraftBoard) { + if (!userId) { + throw new Response("You must be logged in to view the draft room", { + status: 401, + }); + } + if (!userTeam && !isCommissioner) { + throw new Response("You do not have access to this draft room", { + status: 403, + }); + } } // Get draft slots (draft order) - using select instead of query builder @@ -220,7 +227,7 @@ export default function DraftRoom() { mode: notificationsMode, setMode: setNotificationsMode, sendNotification, - } = useDraftNotifications(season.id, currentUserId); + } = useDraftNotifications(season.id, currentUserId ?? ""); // Use refs so the socket effect doesn't re-register all handlers when the user // changes notification settings (which would change the sendNotification reference).