2026-07-14 13:05:04 +00:00
|
|
|
import { Project, ProjectMember, projects, projectMembers } from './db';
|
2026-07-17 12:00:16 +00:00
|
|
|
import type { AuthPayload } from '../auth-connector/source/shared/types';
|
2026-07-14 13:05:04 +00:00
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
export function isOwner( project: Project, user: AuthPayload ): boolean
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
return project.owner_id === user.userId;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
function memberMatchesUser( member: ProjectMember, user: AuthPayload ): boolean
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
export function getMemberRole( members: ProjectMember[], user: AuthPayload ): string | null
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
return members.find( m => memberMatchesUser( m, user ) )?.role ?? null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
export function canView( project: Project, members: ProjectMember[], user: AuthPayload ): boolean
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
return isOwner( project, user ) || getMemberRole( members, user ) !== null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
export function canEdit( project: Project, members: ProjectMember[], user: AuthPayload ): boolean
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
if ( isOwner( project, user ) ) return true;
|
|
|
|
|
const role = getMemberRole( members, user );
|
|
|
|
|
return role === 'editor' || role === 'admin';
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-14 13:29:53 +00:00
|
|
|
export interface AccessDenial { status: number; error: string; }
|
2026-07-14 13:05:04 +00:00
|
|
|
|
2026-07-17 11:37:48 +00:00
|
|
|
export function checkAccess( projectId: string, user: AuthPayload, mode: 'view' | 'edit' ): AccessDenial | null
|
2026-07-14 13:05:04 +00:00
|
|
|
{
|
|
|
|
|
const project = projects.findById( projectId );
|
2026-07-14 13:29:53 +00:00
|
|
|
if ( !project ) return { status: 404, error: 'Not found' };
|
2026-07-14 13:05:04 +00:00
|
|
|
const members = projectMembers.forProject( projectId );
|
|
|
|
|
const allowed = mode === 'view' ? canView( project, members, user ) : canEdit( project, members, user );
|
2026-07-14 13:29:53 +00:00
|
|
|
if ( !allowed ) return { status: 403, error: 'Forbidden' };
|
|
|
|
|
return null;
|
2026-07-14 13:05:04 +00:00
|
|
|
}
|