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:
@ -0,0 +1,32 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
|
||||
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
import { AddPersonIdAndWorkspaceMemberIdModule } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module';
|
||||
import { CalendarEventParticipantListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener';
|
||||
import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
WorkspaceDataSourceModule,
|
||||
TwentyORMModule.forFeature([CalendarEventParticipantWorkspaceEntity]),
|
||||
ObjectMetadataRepositoryModule.forFeature([PersonWorkspaceEntity]),
|
||||
TypeOrmModule.forFeature(
|
||||
[ObjectMetadataEntity, FieldMetadataEntity],
|
||||
'metadata',
|
||||
),
|
||||
AddPersonIdAndWorkspaceMemberIdModule,
|
||||
],
|
||||
providers: [
|
||||
CalendarEventParticipantService,
|
||||
CalendarEventParticipantListener,
|
||||
],
|
||||
exports: [CalendarEventParticipantService],
|
||||
})
|
||||
export class CalendarEventParticipantModule {}
|
||||
@ -0,0 +1,70 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
|
||||
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
export class CalendarEventParticipantListener {
|
||||
constructor(
|
||||
@InjectObjectMetadataRepository(TimelineActivityWorkspaceEntity)
|
||||
private readonly timelineActivityRepository: TimelineActivityRepository,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
) {}
|
||||
|
||||
@OnEvent('calendarEventParticipant.matched')
|
||||
public async handleCalendarEventParticipantMatchedEvent(payload: {
|
||||
workspaceId: string;
|
||||
workspaceMemberId: string;
|
||||
calendarEventParticipants: CalendarEventParticipantWorkspaceEntity[];
|
||||
}): Promise<void> {
|
||||
const calendarEventParticipants = payload.calendarEventParticipants ?? [];
|
||||
|
||||
// TODO: move to a job?
|
||||
|
||||
const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(
|
||||
payload.workspaceId,
|
||||
);
|
||||
|
||||
const calendarEventObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneOrFail({
|
||||
where: {
|
||||
nameSingular: 'calendarEvent',
|
||||
workspaceId: payload.workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
const calendarEventParticipantsWithPersonId =
|
||||
calendarEventParticipants.filter((participant) => participant.personId);
|
||||
|
||||
if (calendarEventParticipantsWithPersonId.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.timelineActivityRepository.insertTimelineActivitiesForObject(
|
||||
'person',
|
||||
calendarEventParticipantsWithPersonId.map((participant) => ({
|
||||
dataSourceSchema,
|
||||
name: 'calendarEvent.linked',
|
||||
properties: null,
|
||||
objectName: 'calendarEvent',
|
||||
recordId: participant.personId,
|
||||
workspaceMemberId: payload.workspaceMemberId,
|
||||
workspaceId: payload.workspaceId,
|
||||
linkedObjectMetadataId: calendarEventObjectMetadata.id,
|
||||
linkedRecordId: participant.calendarEventId,
|
||||
linkedRecordCachedName: '',
|
||||
})),
|
||||
payload.workspaceId,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
|
||||
import { Any, EntityManager } from 'typeorm';
|
||||
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
|
||||
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util';
|
||||
import { CalendarEventParticipant } from 'src/modules/calendar/common/types/calendar-event';
|
||||
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
|
||||
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
export class CalendarEventParticipantService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectWorkspaceRepository(CalendarEventParticipantWorkspaceEntity)
|
||||
private readonly calendarEventParticipantRepository: WorkspaceRepository<CalendarEventParticipantWorkspaceEntity>,
|
||||
@InjectObjectMetadataRepository(PersonWorkspaceEntity)
|
||||
private readonly personRepository: PersonRepository,
|
||||
private readonly addPersonIdAndWorkspaceMemberIdService: AddPersonIdAndWorkspaceMemberIdService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
public async updateCalendarEventParticipantsAfterPeopleCreation(
|
||||
createdPeople: PersonWorkspaceEntity[],
|
||||
workspaceId: string,
|
||||
transactionManager?: EntityManager,
|
||||
): Promise<CalendarEventParticipantWorkspaceEntity[]> {
|
||||
const participants = await this.calendarEventParticipantRepository.find({
|
||||
where: {
|
||||
handle: Any(createdPeople.map((person) => person.email)),
|
||||
},
|
||||
});
|
||||
|
||||
if (!participants) return [];
|
||||
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
const handles = participants.map((participant) => participant.handle);
|
||||
|
||||
const participantPersonIds = await this.personRepository.getByEmails(
|
||||
handles,
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
const calendarEventParticipantsToUpdate = participants.map(
|
||||
(participant) => ({
|
||||
id: participant.id,
|
||||
personId: participantPersonIds.find(
|
||||
(e: { id: string; email: string }) => e.email === participant.handle,
|
||||
)?.id,
|
||||
}),
|
||||
);
|
||||
|
||||
if (calendarEventParticipantsToUpdate.length === 0) return [];
|
||||
|
||||
const { flattenedValues, valuesString } =
|
||||
getFlattenedValuesAndValuesStringForBatchRawQuery(
|
||||
calendarEventParticipantsToUpdate,
|
||||
{
|
||||
id: 'uuid',
|
||||
personId: 'uuid',
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
await this.workspaceDataSourceService.executeRawQuery(
|
||||
`UPDATE ${dataSourceSchema}."calendarEventParticipant" AS "calendarEventParticipant" SET "personId" = "data"."personId"
|
||||
FROM (VALUES ${valuesString}) AS "data"("id", "personId")
|
||||
WHERE "calendarEventParticipant"."id" = "data"."id"
|
||||
RETURNING *`,
|
||||
flattenedValues,
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
)
|
||||
).flat();
|
||||
}
|
||||
|
||||
public async saveCalendarEventParticipants(
|
||||
calendarEventParticipants: CalendarEventParticipant[],
|
||||
workspaceId: string,
|
||||
transactionManager?: EntityManager,
|
||||
): Promise<CalendarEventParticipantWorkspaceEntity[]> {
|
||||
if (calendarEventParticipants.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
const calendarEventParticipantsToSave =
|
||||
await this.addPersonIdAndWorkspaceMemberIdService.addPersonIdAndWorkspaceMemberId(
|
||||
calendarEventParticipants,
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
const { flattenedValues, valuesString } =
|
||||
getFlattenedValuesAndValuesStringForBatchRawQuery(
|
||||
calendarEventParticipantsToSave,
|
||||
{
|
||||
calendarEventId: 'uuid',
|
||||
handle: 'text',
|
||||
displayName: 'text',
|
||||
isOrganizer: 'boolean',
|
||||
responseStatus: `${dataSourceSchema}."calendarEventParticipant_responseStatus_enum"`,
|
||||
personId: 'uuid',
|
||||
workspaceMemberId: 'uuid',
|
||||
},
|
||||
);
|
||||
|
||||
return await this.workspaceDataSourceService.executeRawQuery(
|
||||
`INSERT INTO ${dataSourceSchema}."calendarEventParticipant" ("calendarEventId", "handle", "displayName", "isOrganizer", "responseStatus", "personId", "workspaceMemberId") VALUES ${valuesString}
|
||||
RETURNING *`,
|
||||
flattenedValues,
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
|
||||
public async matchCalendarEventParticipants(
|
||||
workspaceId: string,
|
||||
email: string,
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
const calendarEventParticipantsToUpdate =
|
||||
await this.calendarEventParticipantRepository.find({
|
||||
where: {
|
||||
handle: email,
|
||||
},
|
||||
});
|
||||
|
||||
const calendarEventParticipantIdsToUpdate =
|
||||
calendarEventParticipantsToUpdate.map((participant) => participant.id);
|
||||
|
||||
if (personId) {
|
||||
await this.calendarEventParticipantRepository.update(
|
||||
{
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
person: {
|
||||
id: personId,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const updatedCalendarEventParticipants =
|
||||
await this.calendarEventParticipantRepository.find({
|
||||
where: {
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(`calendarEventParticipant.matched`, {
|
||||
workspaceId,
|
||||
workspaceMemberId: null,
|
||||
calendarEventParticipants: updatedCalendarEventParticipants,
|
||||
});
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await this.calendarEventParticipantRepository.update(
|
||||
{
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
workspaceMember: {
|
||||
id: workspaceMemberId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async unmatchCalendarEventParticipants(
|
||||
workspaceId: string,
|
||||
handle: string,
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
if (personId) {
|
||||
await this.calendarEventParticipantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
person: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await this.calendarEventParticipantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
workspaceMember: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user