fix: VisibilityLevel als lokalen String-Type statt Prisma-Enum verwenden

Prisma-Enums sind zur Laufzeit nicht als Objekt verfuegbar wenn ts-node
den Import vor der Client-Generierung auflöst. Ersetzt durch eigenen
Type-Export aus build-visibility-filter.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Reitz 2026-03-14 22:24:18 +01:00
parent de4af77c5c
commit b484f4380f
7 changed files with 30 additions and 23 deletions

View file

@ -10,7 +10,8 @@ import { QueryActivitiesDto } from './dto/query-activities.dto';
import { VisibilityService } from '../visibility/visibility.service'; import { VisibilityService } from '../visibility/visibility.service';
import { TeamResolverService } from '../visibility/team-resolver.service'; import { TeamResolverService } from '../visibility/team-resolver.service';
import { JwtPayload } from '../common/decorators/current-user.decorator'; import { JwtPayload } from '../common/decorators/current-user.decorator';
import { Prisma, VisibilityLevel } from '.prisma/crm-client'; import { Prisma } from '.prisma/crm-client';
import { VisibilityLevel } from '../common/utils/build-visibility-filter';
@Injectable() @Injectable()
export class ActivitiesService { export class ActivitiesService {

View file

@ -1,6 +1,7 @@
import { VisibilityLevel } from '.prisma/crm-client';
import { JwtPayload } from '../decorators/current-user.decorator'; import { JwtPayload } from '../decorators/current-user.decorator';
export type VisibilityLevel = 'OWN' | 'TEAM' | 'ALL';
/** /**
* Erzeugt einen Prisma WHERE-Filter basierend auf dem Sichtbarkeitslevel. * Erzeugt einen Prisma WHERE-Filter basierend auf dem Sichtbarkeitslevel.
* *
@ -30,16 +31,16 @@ export function buildVisibilityFilter(params: {
} }
// Effektives Level bestimmen (TEAM_LEAD sieht mindestens TEAM) // Effektives Level bestimmen (TEAM_LEAD sieht mindestens TEAM)
let effectiveLevel = level; let effectiveLevel: VisibilityLevel = level;
if (user.tenantRole === 'TEAM_LEAD' && level === VisibilityLevel.OWN) { if (user.tenantRole === 'TEAM_LEAD' && level === 'OWN') {
effectiveLevel = VisibilityLevel.TEAM; effectiveLevel = 'TEAM';
} }
switch (effectiveLevel) { switch (effectiveLevel) {
case VisibilityLevel.ALL: case 'ALL':
return { tenantId }; return { tenantId };
case VisibilityLevel.OWN: case 'OWN':
return { return {
tenantId, tenantId,
[ownerRelation]: { [ownerRelation]: {
@ -47,7 +48,7 @@ export function buildVisibilityFilter(params: {
}, },
}; };
case VisibilityLevel.TEAM: { case 'TEAM': {
// Wenn Team-Member-IDs vorhanden: nach diesen filtern // Wenn Team-Member-IDs vorhanden: nach diesen filtern
if (teamMemberIds && teamMemberIds.length > 0) { if (teamMemberIds && teamMemberIds.length > 0) {
// Eigene ID immer einschliessen // Eigene ID immer einschliessen

View file

@ -10,7 +10,8 @@ import { VisibilityService } from '../visibility/visibility.service';
import { TeamResolverService } from '../visibility/team-resolver.service'; import { TeamResolverService } from '../visibility/team-resolver.service';
import { buildVisibilityFilter } from '../common/utils/build-visibility-filter'; import { buildVisibilityFilter } from '../common/utils/build-visibility-filter';
import { JwtPayload } from '../common/decorators/current-user.decorator'; import { JwtPayload } from '../common/decorators/current-user.decorator';
import { Prisma, VisibilityLevel } from '.prisma/crm-client'; import { Prisma } from '.prisma/crm-client';
import { VisibilityLevel } from '../common/utils/build-visibility-filter';
import { EntityStatus } from '../common/dto/contact-info.dto'; import { EntityStatus } from '../common/dto/contact-info.dto';
@Injectable() @Injectable()

View file

@ -11,7 +11,8 @@ import { VisibilityService } from '../visibility/visibility.service';
import { TeamResolverService } from '../visibility/team-resolver.service'; import { TeamResolverService } from '../visibility/team-resolver.service';
import { buildVisibilityFilter } from '../common/utils/build-visibility-filter'; import { buildVisibilityFilter } from '../common/utils/build-visibility-filter';
import { JwtPayload } from '../common/decorators/current-user.decorator'; import { JwtPayload } from '../common/decorators/current-user.decorator';
import { Prisma, VisibilityLevel } from '.prisma/crm-client'; import { Prisma } from '.prisma/crm-client';
import { VisibilityLevel } from '../common/utils/build-visibility-filter';
import { EntityStatus } from '../common/dto/contact-info.dto'; import { EntityStatus } from '../common/dto/contact-info.dto';
@Injectable() @Injectable()

View file

@ -15,7 +15,8 @@ import { VisibilityService } from '../visibility/visibility.service';
import { TeamResolverService } from '../visibility/team-resolver.service'; import { TeamResolverService } from '../visibility/team-resolver.service';
import { buildVisibilityFilter } from '../common/utils/build-visibility-filter'; import { buildVisibilityFilter } from '../common/utils/build-visibility-filter';
import { JwtPayload } from '../common/decorators/current-user.decorator'; import { JwtPayload } from '../common/decorators/current-user.decorator';
import { Prisma, VisibilityLevel } from '.prisma/crm-client'; import { Prisma } from '.prisma/crm-client';
import { VisibilityLevel } from '../common/utils/build-visibility-filter';
@Injectable() @Injectable()
export class DealsService { export class DealsService {

View file

@ -1,13 +1,15 @@
import { IsEnum } from 'class-validator'; import { IsIn, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { VisibilityLevel } from '.prisma/crm-client';
const VISIBILITY_LEVELS = ['OWN', 'TEAM', 'ALL'] as const;
export class SetVisibilityDto { export class SetVisibilityDto {
@ApiProperty({ @ApiProperty({
enum: VisibilityLevel, enum: VISIBILITY_LEVELS,
description: 'Sichtbarkeitslevel: OWN, TEAM oder ALL', description: 'Sichtbarkeitslevel: OWN, TEAM oder ALL',
example: 'ALL', example: 'ALL',
}) })
@IsEnum(VisibilityLevel) @IsString()
level!: VisibilityLevel; @IsIn(VISIBILITY_LEVELS)
level!: 'OWN' | 'TEAM' | 'ALL';
} }

View file

@ -1,7 +1,7 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { CrmPrismaService } from '../prisma/crm-prisma.service'; import { CrmPrismaService } from '../prisma/crm-prisma.service';
import { RedisService } from '../redis/redis.service'; import { RedisService } from '../redis/redis.service';
import { VisibilityLevel } from '.prisma/crm-client'; import { VisibilityLevel } from '../common/utils/build-visibility-filter';
const CACHE_PREFIX = 'crm_visibility'; const CACHE_PREFIX = 'crm_visibility';
const CACHE_TTL = 300; // 5 Minuten const CACHE_TTL = 300; // 5 Minuten
@ -36,7 +36,7 @@ export class VisibilityService {
where: { tenantId_entity: { tenantId, entity } }, where: { tenantId_entity: { tenantId, entity } },
}); });
const level = setting?.level ?? VisibilityLevel.ALL; const level = (setting?.level as VisibilityLevel) ?? 'ALL';
// In Cache schreiben // In Cache schreiben
await this.redis.set(cacheKey, level, CACHE_TTL); await this.redis.set(cacheKey, level, CACHE_TTL);
@ -78,14 +78,14 @@ export class VisibilityService {
}); });
const result: Record<string, VisibilityLevel> = { const result: Record<string, VisibilityLevel> = {
COMPANY: VisibilityLevel.ALL, COMPANY: 'ALL',
CONTACT: VisibilityLevel.ALL, CONTACT: 'ALL',
DEAL: VisibilityLevel.ALL, DEAL: 'ALL',
ACTIVITY: VisibilityLevel.ALL, ACTIVITY: 'ALL',
}; };
for (const s of settings) { for (const s of settings) {
result[s.entity] = s.level; result[s.entity] = s.level as VisibilityLevel;
} }
return result; return result;