47 lines
1.7 KiB
TypeScript
47 lines
1.7 KiB
TypeScript
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 type AccessResult =
|
|
| { ok: true }
|
|
| { ok: false; status: number; error: string };
|
|
|
|
export function checkAccess( projectId: string, user: JwtUser, mode: 'view' | 'edit' ): AccessResult
|
|
{
|
|
const project = projects.findById( projectId );
|
|
if ( !project ) return { ok: false, 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 { ok: false, status: 403, error: 'Forbidden' };
|
|
return { ok: true };
|
|
}
|