rojects/source/server/projectAccess.ts

45 lines
1.7 KiB
TypeScript
Raw Normal View History

2026-07-14 13:05:04 +00:00
import { Project, ProjectMember, projects, projectMembers } from './db';
2026-07-17 11:37:48 +00:00
import type { AuthPayload } from 'auth-connector/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
}