Reorganise calendar module (#6089)

Refactor Calendar into functional sub modules
<img width="437" alt="image"
src="https://github.com/twentyhq/twenty/assets/12035771/d9de3285-a226-4fe8-b3ef-2d8a21def2a5">

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
This commit is contained in:
Charles Bochet
2024-07-02 13:55:11 +02:00
committed by GitHub
parent ea7d52fba8
commit f8dd2cc733
66 changed files with 267 additions and 401 deletions

View File

@ -0,0 +1,52 @@
import { BadRequestException, NotFoundException, Scope } from '@nestjs/common';
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.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(
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>,
private readonly canAccessCalendarEventService: CanAccessCalendarEventService,
) {}
async execute(
userId: string,
workspaceId: string,
payload: FindManyResolverArgs,
): Promise<void> {
if (!payload?.filter?.id?.eq) {
throw new BadRequestException('id filter is required');
}
const calendarChannelCalendarEventAssociations =
await this.calendarChannelEventAssociationRepository.find({
where: {
calendarEventId: payload?.filter?.id?.eq,
},
relations: ['calendarChannel.connectedAccount'],
});
if (calendarChannelCalendarEventAssociations.length === 0) {
throw new NotFoundException();
}
await this.canAccessCalendarEventService.canAccessCalendarEvent(
userId,
workspaceId,
calendarChannelCalendarEventAssociations,
);
}
}

View File

@ -0,0 +1,53 @@
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 { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.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(
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>,
private readonly canAccessCalendarEventService: CanAccessCalendarEventService,
) {}
async execute(
userId: string,
workspaceId: string,
payload: FindOneResolverArgs,
): Promise<void> {
if (!payload?.filter?.id?.eq) {
throw new BadRequestException('id filter is required');
}
// TODO: Re-implement this using twenty ORM
const calendarChannelCalendarEventAssociations =
await this.calendarChannelEventAssociationRepository.find({
where: {
calendarEventId: payload?.filter?.id?.eq,
},
relations: ['calendarChannel.connectedAccount'],
});
if (calendarChannelCalendarEventAssociations.length === 0) {
throw new NotFoundException();
}
await this.canAccessCalendarEventService.canAccessCalendarEvent(
userId,
workspaceId,
calendarChannelCalendarEventAssociations,
);
}
}

View File

@ -0,0 +1,80 @@
import { ForbiddenException, Injectable } from '@nestjs/common';
import groupBy from 'lodash.groupby';
import { Any } from 'typeorm';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
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';
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
import {
CalendarChannelWorkspaceEntity,
CalendarChannelVisibility,
} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
@Injectable()
export class CanAccessCalendarEventService {
constructor(
@InjectWorkspaceRepository(CalendarChannelWorkspaceEntity)
private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>,
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
private readonly connectedAccountRepository: ConnectedAccountRepository,
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
private readonly workspaceMemberService: WorkspaceMemberRepository,
) {}
public async canAccessCalendarEvent(
userId: string,
workspaceId: string,
calendarChannelCalendarEventAssociations: CalendarChannelEventAssociationWorkspaceEntity[],
) {
const calendarChannels = await this.calendarChannelRepository.find({
where: {
id: Any(
calendarChannelCalendarEventAssociations.map(
(association) => association.calendarChannel.id,
),
),
},
});
const calendarChannelsGroupByVisibility = groupBy(
calendarChannels,
(channel) => channel.visibility,
);
if (
calendarChannelsGroupByVisibility[
CalendarChannelVisibility.SHARE_EVERYTHING
]
) {
return;
}
const currentWorkspaceMember =
await this.workspaceMemberService.getByIdOrFail(userId, workspaceId);
const calendarChannelsConnectedAccounts =
await this.connectedAccountRepository.getByIds(
calendarChannels.map((channel) => channel.connectedAccountId),
workspaceId,
);
const calendarChannelsWorkspaceMemberIds =
calendarChannelsConnectedAccounts.map(
(connectedAccount) => connectedAccount.accountOwnerId,
);
if (
calendarChannelsWorkspaceMemberIds.includes(currentWorkspaceMember.id)
) {
return;
}
throw new ForbiddenException();
}
}

View File

@ -0,0 +1,30 @@
import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook';
import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook';
import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service';
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
@Module({
imports: [
TwentyORMModule.forFeature([
CalendarChannelEventAssociationWorkspaceEntity,
CalendarChannelWorkspaceEntity,
]),
ObjectMetadataRepositoryModule.forFeature([
ConnectedAccountWorkspaceEntity,
WorkspaceMemberWorkspaceEntity,
]),
],
providers: [
CanAccessCalendarEventService,
CalendarEventFindOnePreQueryHook,
CalendarEventFindManyPreQueryHook,
],
})
export class CalendarQueryHookModule {}