113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
import type { DataVisibility, UserRole } from '@mento/shared';
|
|
import { canViewAllRecords } from '@mento/shared';
|
|
import type { Prisma } from '@prisma/client';
|
|
|
|
export type Actor = {
|
|
userId: string;
|
|
role: string;
|
|
organizationId: string;
|
|
/** own | team | org — از Membership */
|
|
dataVisibility?: DataVisibility;
|
|
/**
|
|
* شناسه کاربرانی که پروندهشان برای این Actor قابلمشاهده است.
|
|
* اگر undefined باشد فقط خود کاربر؛ اگر null یعنی همه (elevated/org).
|
|
*/
|
|
visibleUserIds?: string[] | null;
|
|
};
|
|
|
|
export function elevated(role: string | null | undefined): boolean {
|
|
return canViewAllRecords(role);
|
|
}
|
|
|
|
export function seesAllRecords(
|
|
actor: Pick<Actor, 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
): boolean {
|
|
if (elevated(actor.role)) return true;
|
|
if (actor.dataVisibility === 'org') return true;
|
|
if (actor.visibleUserIds === null) return true;
|
|
return false;
|
|
}
|
|
|
|
function scopedOwnerIds(
|
|
actor: Pick<Actor, 'userId' | 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
): string[] | null {
|
|
if (seesAllRecords(actor)) return null;
|
|
const ids = actor.visibleUserIds?.length
|
|
? actor.visibleUserIds
|
|
: [actor.userId];
|
|
return [...new Set(ids.filter(Boolean))];
|
|
}
|
|
|
|
/** فیلتر مالکیت برای Deal / Quote / Invoice / Person / Company */
|
|
export function ownerWhere(
|
|
actor: Pick<Actor, 'userId' | 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
): { ownerId: string } | { ownerId: { in: string[] } } | Record<string, never> {
|
|
const ids = scopedOwnerIds(actor);
|
|
if (!ids) return {};
|
|
if (ids.length === 1) return { ownerId: ids[0]! };
|
|
return { ownerId: { in: ids } };
|
|
}
|
|
|
|
/** فعالیتها بر اساس مسئول */
|
|
export function assigneeWhere(
|
|
actor: Pick<Actor, 'userId' | 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
):
|
|
| { assigneeId: string }
|
|
| { assigneeId: { in: string[] } }
|
|
| Record<string, never> {
|
|
const ids = scopedOwnerIds(actor);
|
|
if (!ids) return {};
|
|
if (ids.length === 1) return { assigneeId: ids[0]! };
|
|
return { assigneeId: { in: ids } };
|
|
}
|
|
|
|
/** یادداشت: نویسنده یا پروندههای تحت مالکیت در محدوده دید */
|
|
export function noteAccessWhere(
|
|
actor: Pick<Actor, 'userId' | 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
): Prisma.NoteWhereInput {
|
|
const ids = scopedOwnerIds(actor);
|
|
if (!ids) return {};
|
|
return {
|
|
OR: [
|
|
{ authorId: { in: ids } },
|
|
{ deal: { ownerId: { in: ids } } },
|
|
{ person: { ownerId: { in: ids } } },
|
|
{ company: { ownerId: { in: ids } } },
|
|
],
|
|
};
|
|
}
|
|
|
|
export function resolveOwnerId(
|
|
actor: Pick<Actor, 'userId' | 'role'>,
|
|
requested?: string | null,
|
|
): string {
|
|
if (elevated(actor.role) && requested?.trim()) {
|
|
return requested.trim();
|
|
}
|
|
return actor.userId;
|
|
}
|
|
|
|
/** تیکت: مسئول یا ثبتکننده در محدوده دید */
|
|
export function ticketAccessWhere(
|
|
actor: Pick<Actor, 'userId' | 'role' | 'dataVisibility' | 'visibleUserIds'>,
|
|
): Prisma.TicketWhereInput {
|
|
const ids = scopedOwnerIds(actor);
|
|
if (!ids) return {};
|
|
return {
|
|
OR: [{ assigneeId: { in: ids } }, { reporterId: { in: ids } }],
|
|
};
|
|
}
|
|
|
|
export function canReassignOwner(role: string | null | undefined): boolean {
|
|
return elevated(role);
|
|
}
|
|
|
|
export type OrgRole = UserRole;
|
|
|
|
export function normalizeDataVisibility(
|
|
value: string | null | undefined,
|
|
): DataVisibility {
|
|
if (value === 'team' || value === 'org' || value === 'own') return value;
|
|
return 'own';
|
|
}
|