import { Project, ProjectMember, projects, projectMembers } from './db'; import { JwtUser } from './middleware/auth'; export function isOwner( project: Project, user: JwtUser ): boolean { return project.owner_id === user.userId; } function memberMatchesUser( member: ProjectMember, user: JwtUser ): boolean { if ( member.member_type !== 'user' ) return false; // Interim (Option B): member_id stores the email address. // When migrating to ID-based lookup, change this one line to: member.member_id === user.userId return member.member_id === user.email; } export function getMemberRole( members: ProjectMember[], user: JwtUser ): string | null { return members.find( m => memberMatchesUser( m, user ) )?.role ?? null; } export function canView( project: Project, members: ProjectMember[], user: JwtUser ): boolean { return isOwner( project, user ) || getMemberRole( members, user ) !== null; } export function canEdit( project: Project, members: ProjectMember[], user: JwtUser ): boolean { if ( isOwner( project, user ) ) return true; const role = getMemberRole( members, user ); return role === 'editor' || role === 'admin'; } export interface AccessDenial { status: number; error: string; } export function checkAccess( projectId: string, user: JwtUser, mode: 'view' | 'edit' ): AccessDenial | null { const project = projects.findById( projectId ); if ( !project ) return { status: 404, error: 'Not found' }; const members = projectMembers.forProject( projectId ); const allowed = mode === 'view' ? canView( project, members, user ) : canEdit( project, members, user ); if ( !allowed ) return { status: 403, error: 'Forbidden' }; return null; }