Ej/fix message visibility (#11874)

<img width="257" alt="Screenshot 2025-05-05 at 15 30 09"
src="https://github.com/user-attachments/assets/5a8e18e0-efc5-4521-9c3a-bf73277ecdf9"
/>
<img width="257" alt="Screenshot 2025-05-05 at 15 29 05"
src="https://github.com/user-attachments/assets/c1a784af-a744-497a-b6ce-ec3a9e8b851a"
/>
<img width="257" alt="Screenshot 2025-05-05 at 15 33 06"
src="https://github.com/user-attachments/assets/c5fabd1d-a125-49d7-aade-0a208a0eff95"
/>

related to PR https://github.com/twentyhq/twenty/pull/11840 and issue
https://github.com/twentyhq/twenty/issues/9826
This commit is contained in:
Etienne
2025-05-05 17:23:27 +02:00
committed by GitHub
parent da0c7e679e
commit a60711c808
19 changed files with 578 additions and 481 deletions

View File

@ -1,62 +0,0 @@
import { BadRequestException, NotFoundException, Scope } from '@nestjs/common';
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { CanAccessCalendarEventsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-events.service';
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
@WorkspaceQueryHook({
key: `calendarEvent.findMany`,
scope: Scope.REQUEST,
})
export class CalendarEventFindManyPreQueryHook
implements WorkspaceQueryHookInstance
{
constructor(
private readonly twentyORMManager: TwentyORMManager,
private readonly canAccessCalendarEventsService: CanAccessCalendarEventsService,
) {}
async execute(
authContext: AuthContext,
objectName: string,
payload: FindManyResolverArgs,
): Promise<FindManyResolverArgs> {
if (!payload?.filter?.id?.eq) {
throw new BadRequestException('id filter is required');
}
if (!authContext.user?.id) {
throw new BadRequestException('User id is required');
}
const calendarChannelEventAssociationRepository =
await this.twentyORMManager.getRepository<CalendarChannelEventAssociationWorkspaceEntity>(
'calendarChannelEventAssociation',
);
const calendarChannelCalendarEventAssociations =
await calendarChannelEventAssociationRepository.find({
where: {
calendarEventId: payload?.filter?.id?.eq,
},
relations: ['calendarChannel.connectedAccount'],
});
if (calendarChannelCalendarEventAssociations.length === 0) {
throw new NotFoundException();
}
await this.canAccessCalendarEventsService.canAccessCalendarEvents(
authContext.user.id,
authContext.workspace.id,
calendarChannelCalendarEventAssociations,
);
return payload;
}
}

View File

@ -1,62 +0,0 @@
import { BadRequestException, NotFoundException, Scope } from '@nestjs/common';
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { CanAccessCalendarEventsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-events.service';
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
@WorkspaceQueryHook({
key: `calendarEvent.findOne`,
scope: Scope.REQUEST,
})
export class CalendarEventFindOnePreQueryHook
implements WorkspaceQueryHookInstance
{
constructor(
private readonly twentyORMManager: TwentyORMManager,
private readonly canAccessCalendarEventsService: CanAccessCalendarEventsService,
) {}
async execute(
authContext: AuthContext,
objectName: string,
payload: FindOneResolverArgs,
): Promise<FindOneResolverArgs> {
if (!payload?.filter?.id?.eq) {
throw new BadRequestException('id filter is required');
}
if (!authContext.user?.id) {
throw new BadRequestException('User id is required');
}
const calendarChannelEventAssociationRepository =
await this.twentyORMManager.getRepository<CalendarChannelEventAssociationWorkspaceEntity>(
'calendarChannelEventAssociation',
);
const calendarChannelCalendarEventAssociations =
await calendarChannelEventAssociationRepository.find({
where: {
calendarEventId: payload?.filter?.id?.eq,
},
relations: ['calendarChannel', 'calendarChannel.connectedAccount'],
});
if (calendarChannelCalendarEventAssociations.length === 0) {
throw new NotFoundException();
}
await this.canAccessCalendarEventsService.canAccessCalendarEvents(
authContext.user.id,
authContext.workspace.id,
calendarChannelCalendarEventAssociations,
);
return payload;
}
}

View File

@ -28,7 +28,7 @@ export class ApplyCalendarEventsVisibilityRestrictionsService {
where: {
calendarEventId: In(calendarEvents.map((event) => event.id)),
},
relations: ['calendarChannel', 'calendarChannel.connectedAccount'],
relations: ['calendarChannel'],
});
const connectedAccountRepository =

View File

@ -1,70 +0,0 @@
import { Injectable } from '@nestjs/common';
import groupBy from 'lodash.groupby';
import { In } from 'typeorm';
import { ForbiddenError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@Injectable()
export class CanAccessCalendarEventsService {
constructor(
private readonly twentyORMManager: TwentyORMManager,
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
private readonly workspaceMemberService: WorkspaceMemberRepository,
) {}
public async canAccessCalendarEvents(
userId: string,
workspaceId: string,
calendarChannelCalendarEventAssociations: CalendarChannelEventAssociationWorkspaceEntity[],
) {
const calendarChannels = calendarChannelCalendarEventAssociations.map(
(association) => association.calendarChannel,
);
const calendarChannelsGroupByVisibility = groupBy(
calendarChannels,
(channel) => channel.visibility,
);
if (
calendarChannelsGroupByVisibility[
CalendarChannelVisibility.SHARE_EVERYTHING
] ||
calendarChannelsGroupByVisibility[CalendarChannelVisibility.METADATA]
) {
return;
}
const currentWorkspaceMember =
await this.workspaceMemberService.getByIdOrFail(userId, workspaceId);
const connectedAccountRepository =
await this.twentyORMManager.getRepository<ConnectedAccountWorkspaceEntity>(
'connectedAccount',
);
const connectedAccounts = await connectedAccountRepository.find({
select: ['id'],
where: {
calendarChannels: {
id: In(calendarChannels.map((channel) => channel.id)),
},
accountOwnerId: currentWorkspaceMember.id,
},
});
if (connectedAccounts.length > 0) {
return;
}
throw new ForbiddenError('Calendar events not shared');
}
}

View File

@ -2,11 +2,8 @@ import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { CalendarEventFindManyPostQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.post-query.hook';
import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook';
import { CalendarEventFindOnePostQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.post-query.hook';
import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook';
import { ApplyCalendarEventsVisibilityRestrictionsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service';
import { CanAccessCalendarEventsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-events.service';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@Module({
@ -14,10 +11,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
ObjectMetadataRepositoryModule.forFeature([WorkspaceMemberWorkspaceEntity]),
],
providers: [
CanAccessCalendarEventsService,
ApplyCalendarEventsVisibilityRestrictionsService,
CalendarEventFindOnePreQueryHook,
CalendarEventFindManyPreQueryHook,
CalendarEventFindOnePostQueryHook,
CalendarEventFindManyPostQueryHook,
],