2026-10-08 20:11:07 +03:30
|
|
|
import { describe, it } from 'node:test';
|
|
|
|
|
import assert from 'node:assert/strict';
|
2026-10-27 18:07:42 +03:30
|
|
|
import { leadsDeepWhere, resolveSectionAccess } from '../src/common/data-access';
|
2026-10-08 20:11:07 +03:30
|
|
|
import {
|
|
|
|
|
noteAccessWhere,
|
|
|
|
|
normalizeDataVisibility,
|
|
|
|
|
ownerWhere,
|
|
|
|
|
parseVisibilityScopes,
|
|
|
|
|
resolveOwnerId,
|
|
|
|
|
scopedOwnerIds,
|
|
|
|
|
seesAllRecords,
|
|
|
|
|
} from '../src/common/record-scope';
|
|
|
|
|
|
|
|
|
|
const sales = { userId: 'u1', role: 'sales' };
|
|
|
|
|
|
|
|
|
|
describe('سطح دسترسی به پروندهها', () => {
|
|
|
|
|
it('مدیر و مالک همه را میبینند', () => {
|
|
|
|
|
assert.ok(seesAllRecords({ role: 'owner' }));
|
|
|
|
|
assert.ok(seesAllRecords({ role: 'admin' }));
|
|
|
|
|
assert.deepEqual(ownerWhere({ userId: 'a', role: 'admin' }), {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('کارشناس فروش فقط پروندههای خودش را میبیند', () => {
|
|
|
|
|
assert.ok(!seesAllRecords(sales));
|
|
|
|
|
assert.deepEqual(scopedOwnerIds(sales), ['u1']);
|
|
|
|
|
assert.deepEqual(ownerWhere(sales), { ownerId: 'u1' });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('دید تیمی', () => {
|
|
|
|
|
const actor = { ...sales, dataVisibility: 'team' as const, visibleUserIds: ['u1', 'u2', 'u2'] };
|
|
|
|
|
assert.deepEqual(ownerWhere(actor), { ownerId: { in: ['u1', 'u2'] } });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('دید سازمانی یا visibleUserIds=null یعنی همه', () => {
|
|
|
|
|
assert.deepEqual(ownerWhere({ ...sales, dataVisibility: 'org' as const }), {});
|
|
|
|
|
assert.deepEqual(ownerWhere({ ...sales, visibleUserIds: null }), {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('سطح دید تفکیکی هر بخش بر پیشفرض اولویت دارد', () => {
|
|
|
|
|
const actor = {
|
|
|
|
|
...sales,
|
|
|
|
|
dataVisibility: 'org' as const,
|
|
|
|
|
scopes: { finance: { dataVisibility: 'own' as const, visibleUserIds: ['u1'] } },
|
|
|
|
|
};
|
|
|
|
|
assert.deepEqual(ownerWhere(actor, 'contacts'), {});
|
|
|
|
|
assert.deepEqual(ownerWhere(actor, 'finance'), { ownerId: 'u1' });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('یادداشت شخصی فقط برای نویسنده', () => {
|
|
|
|
|
const where = noteAccessWhere({ userId: 'a', role: 'admin' });
|
|
|
|
|
assert.deepEqual(where, {
|
|
|
|
|
OR: [
|
|
|
|
|
{ visibility: { not: 'personal' } },
|
|
|
|
|
{ visibility: 'personal', authorId: 'a' },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('فقط مدیر میتواند مالک را عوض کند', () => {
|
|
|
|
|
assert.equal(resolveOwnerId(sales, 'u9'), 'u1');
|
|
|
|
|
assert.equal(resolveOwnerId({ userId: 'a', role: 'admin' }, ' u9 '), 'u9');
|
|
|
|
|
assert.equal(resolveOwnerId({ userId: 'a', role: 'admin' }, ''), 'a');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('پارس تنظیمات دید', () => {
|
|
|
|
|
assert.deepEqual(parseVisibilityScopes({ contacts: 'team', finance: 'bad' }), { contacts: 'team' });
|
|
|
|
|
assert.deepEqual(parseVisibilityScopes(null), {});
|
|
|
|
|
assert.equal(normalizeDataVisibility('weird'), 'own');
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-10-27 18:07:42 +03:30
|
|
|
|
|
|
|
|
describe('عمق داده وقتی نقش فقط بعضی بخشها را ذخیره کرده', () => {
|
|
|
|
|
const legacyOwn = {
|
|
|
|
|
role: 'sales',
|
|
|
|
|
legacyVisibility: 'own' as const,
|
|
|
|
|
legacyScopes: {},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
it('بخش ننوشتهٔ نقشِ تنظیمشده بدون محدودیت است، نه فقط مسئول خودش', () => {
|
|
|
|
|
const leads = resolveSectionAccess('leads', {
|
|
|
|
|
...legacyOwn,
|
|
|
|
|
rolePolicy: { customers: { mode: 'rules', rules: [] } },
|
|
|
|
|
override: {},
|
|
|
|
|
});
|
|
|
|
|
assert.equal(leads.source, 'role');
|
|
|
|
|
assert.deepEqual(leads.section, { mode: 'all', rules: [] });
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
leadsDeepWhere({ userId: 'u1', role: 'sales', leadsAccess: leads.section, teamPeerIds: null }),
|
|
|
|
|
{},
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('نقش بدون سیاست جدید همچنان دید قدیمی را نگه میدارد', () => {
|
|
|
|
|
const leads = resolveSectionAccess('leads', {
|
|
|
|
|
...legacyOwn,
|
|
|
|
|
rolePolicy: {},
|
|
|
|
|
override: {},
|
|
|
|
|
});
|
|
|
|
|
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
leadsDeepWhere({ userId: 'u1', role: 'sales', leadsAccess: leads.section, teamPeerIds: null }),
|
|
|
|
|
{ assigneeId: 'u1' },
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('override کاربر بر بخش باز نقش اولویت دارد', () => {
|
|
|
|
|
const leads = resolveSectionAccess('leads', {
|
|
|
|
|
...legacyOwn,
|
|
|
|
|
rolePolicy: { customers: { mode: 'all', rules: [] } },
|
|
|
|
|
override: { leads: { mode: 'rules', rules: [{ owners: ['self'] }] } },
|
|
|
|
|
});
|
|
|
|
|
assert.equal(leads.source, 'override');
|
|
|
|
|
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('سفارشی کردن فقط مشتریان، لید را از دید قدیمی جدا نمیکند', () => {
|
|
|
|
|
const leads = resolveSectionAccess('leads', {
|
|
|
|
|
...legacyOwn,
|
|
|
|
|
rolePolicy: {},
|
|
|
|
|
override: { customers: { mode: 'all', rules: [] } },
|
|
|
|
|
});
|
|
|
|
|
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
|
|
|
|
|
});
|
|
|
|
|
});
|