feat(acl): deep data access by section for roles and users
Role default + user override with OR rules; covers customers, leads, sales, activities, notes, routines, projects, and tickets.
This commit is contained in:
@@ -16,11 +16,11 @@ import {
|
||||
asCustomFields,
|
||||
toJsonCustomFields,
|
||||
} from '../common/custom-fields';
|
||||
import { customersCompanyWhere } from '../common/data-access';
|
||||
import {
|
||||
type Actor,
|
||||
canReassignOwner,
|
||||
elevated,
|
||||
ownerWhere,
|
||||
resolveOwnerId,
|
||||
} from '../common/record-scope';
|
||||
import { normalizeTags } from '../common/tags';
|
||||
@@ -112,7 +112,7 @@ export class CompaniesService {
|
||||
];
|
||||
const where: Prisma.CompanyWhereInput = {
|
||||
organizationId: actor.organizationId,
|
||||
...ownerWhere(actor),
|
||||
...customersCompanyWhere(actor),
|
||||
...(and.length ? { AND: and } : {}),
|
||||
};
|
||||
|
||||
@@ -137,7 +137,7 @@ export class CompaniesService {
|
||||
|
||||
async get(actor: Actor, id: string): Promise<CompanyDto> {
|
||||
const row = await this.prisma.company.findFirst({
|
||||
where: { id, organizationId: actor.organizationId, ...ownerWhere(actor) },
|
||||
where: { id, organizationId: actor.organizationId, ...customersCompanyWhere(actor) },
|
||||
include: companyInclude,
|
||||
});
|
||||
if (!row) throw new NotFoundException('شرکت پیدا نشد');
|
||||
|
||||
@@ -2,8 +2,9 @@ import { BadRequestException, ConflictException, Injectable } from '@nestjs/comm
|
||||
import type { ImportContactsResult, PersonMood } from '@mento/shared';
|
||||
import { PERSON_MOOD_LABELS, PERSON_MOODS } from '@mento/shared';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { customersCompanyWhere } from '../common/data-access';
|
||||
import type { Actor } from '../common/record-scope';
|
||||
import { ownerWhere, resolveOwnerId } from '../common/record-scope';
|
||||
import { resolveOwnerId } from '../common/record-scope';
|
||||
import {
|
||||
collectAddresses,
|
||||
} from '../common/custom-fields';
|
||||
@@ -776,7 +777,7 @@ export class ContactsExcelService {
|
||||
where: {
|
||||
organizationId: actor.organizationId,
|
||||
sourceRef: didarId,
|
||||
...ownerWhere(actor),
|
||||
...customersCompanyWhere(actor),
|
||||
},
|
||||
select: { id: true, customFields: true },
|
||||
});
|
||||
@@ -787,7 +788,7 @@ export class ContactsExcelService {
|
||||
organizationId: actor.organizationId,
|
||||
name: { equals: name, mode: 'insensitive' },
|
||||
...(didarId ? { sourceRef: null } : {}),
|
||||
...ownerWhere(actor),
|
||||
...customersCompanyWhere(actor),
|
||||
},
|
||||
select: { id: true, customFields: true },
|
||||
});
|
||||
@@ -805,7 +806,7 @@ export class ContactsExcelService {
|
||||
where: {
|
||||
organizationId: actor.organizationId,
|
||||
sourceRef: ref,
|
||||
...ownerWhere(actor),
|
||||
...customersCompanyWhere(actor),
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
@@ -815,7 +816,7 @@ export class ContactsExcelService {
|
||||
where: {
|
||||
organizationId: actor.organizationId,
|
||||
name: { equals: name, mode: 'insensitive' },
|
||||
...ownerWhere(actor),
|
||||
...customersCompanyWhere(actor),
|
||||
},
|
||||
select: { id: true, sourceRef: true },
|
||||
});
|
||||
|
||||
@@ -29,10 +29,10 @@ import {
|
||||
toJsonAddresses,
|
||||
toJsonCustomFields,
|
||||
} from '../common/custom-fields';
|
||||
import { customersPersonWhere } from '../common/data-access';
|
||||
import {
|
||||
type Actor,
|
||||
canReassignOwner,
|
||||
ownerWhere,
|
||||
resolveOwnerId,
|
||||
} from '../common/record-scope';
|
||||
import { LoyaltyService } from '../loyalty/loyalty.service';
|
||||
@@ -206,7 +206,7 @@ export class PeopleService implements OnModuleInit {
|
||||
if (groupIds.length) and.push({ groupLinks: { some: { groupId: { in: groupIds } } } });
|
||||
return {
|
||||
organizationId: actor.organizationId,
|
||||
...ownerWhere(actor),
|
||||
...customersPersonWhere(actor),
|
||||
...(moods.length ? { mood: { in: moods } } : {}),
|
||||
...(sources.length ? { importSource: { in: sources } } : {}),
|
||||
...(and.length ? { AND: and } : {}),
|
||||
@@ -290,7 +290,7 @@ export class PeopleService implements OnModuleInit {
|
||||
by: ['importSource'],
|
||||
where: {
|
||||
organizationId: actor.organizationId,
|
||||
...ownerWhere(actor),
|
||||
...customersPersonWhere(actor),
|
||||
},
|
||||
_count: { _all: true },
|
||||
});
|
||||
@@ -370,7 +370,7 @@ export class PeopleService implements OnModuleInit {
|
||||
|
||||
async get(actor: Actor, id: string): Promise<PersonDto> {
|
||||
const row = await this.prisma.person.findFirst({
|
||||
where: { id, organizationId: actor.organizationId, ...ownerWhere(actor) },
|
||||
where: { id, organizationId: actor.organizationId, ...customersPersonWhere(actor) },
|
||||
include: personInclude,
|
||||
});
|
||||
if (!row) throw new NotFoundException('شخص پیدا نشد');
|
||||
@@ -538,7 +538,7 @@ export class PeopleService implements OnModuleInit {
|
||||
where: {
|
||||
id: { in: unique },
|
||||
organizationId: actor.organizationId,
|
||||
...ownerWhere(actor),
|
||||
...customersPersonWhere(actor),
|
||||
},
|
||||
});
|
||||
return { deleted: res.count };
|
||||
@@ -546,7 +546,7 @@ export class PeopleService implements OnModuleInit {
|
||||
|
||||
private async ensureExists(actor: Actor, id: string) {
|
||||
const found = await this.prisma.person.findFirst({
|
||||
where: { id, organizationId: actor.organizationId, ...ownerWhere(actor) },
|
||||
where: { id, organizationId: actor.organizationId, ...customersPersonWhere(actor) },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!found) throw new NotFoundException('شخص پیدا نشد');
|
||||
|
||||
Reference in New Issue
Block a user