Skip to content

Commit

Permalink
feat: created by for calendar and email
Browse files Browse the repository at this point in the history
  • Loading branch information
magrinj committed Aug 6, 2024
1 parent 1e845e0 commit 1c5c2da
Show file tree
Hide file tree
Showing 15 changed files with 312 additions and 295 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
"tslib": "^2.3.0",
"tsup": "^8.0.1",
"type-fest": "4.10.1",
"typeorm": "^0.3.20",
"typeorm": "patch:typeorm@0.3.20#./packages/twenty-server/patches/typeorm+0.3.20.patch",
"typescript": "5.3.3",
"use-context-selector": "^2.0.0",
"use-debounce": "^10.0.0",
Expand Down
14 changes: 14 additions & 0 deletions packages/twenty-server/patches/typeorm+0.3.20.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
diff --git a/node_modules/typeorm/common/PickKeysByType.d.ts b/node_modules/typeorm/common/PickKeysByType.d.ts
index 55ad347..1a8a184 100644
--- a/common/PickKeysByType.d.ts
+++ b/common/PickKeysByType.d.ts
@@ -1,6 +1,6 @@
/**
* Pick only the keys that match the Type `U`
*/
-export type PickKeysByType<T, U> = string & keyof {
- [P in keyof T as T[P] extends U ? P : never]: T[P];
-};
+export type PickKeysByType<T, U> = string & {
+ [P in keyof T]: Exclude<T[P], null> extends U ? P : never;
+}[keyof T];
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository';
import { CompanyRepository } from 'src/modules/company/repositories/company.repository';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository';
import { MessageThreadRepository } from 'src/modules/messaging/common/repositories/message-thread.repository';
import { MessageRepository } from 'src/modules/messaging/common/repositories/message.repository';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
import { AuditLogRepository } from 'src/modules/timeline/repositiories/audit-log.repository';
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';

export const metadataToRepositoryMapping = {
AuditLogWorkspaceEntity: AuditLogRepository,
BlocklistWorkspaceEntity: BlocklistRepository,
CompanyWorkspaceEntity: CompanyRepository,
ConnectedAccountWorkspaceEntity: ConnectedAccountRepository,
MessageChannelMessageAssociationWorkspaceEntity:
MessageChannelMessageAssociationRepository,
MessageChannelWorkspaceEntity: MessageChannelRepository,
MessageWorkspaceEntity: MessageRepository,
MessageParticipantWorkspaceEntity: MessageParticipantRepository,
MessageThreadWorkspaceEntity: MessageThreadRepository,
PersonWorkspaceEntity: PersonRepository,
TimelineActivityWorkspaceEntity: TimelineActivityRepository,
WorkspaceMemberWorkspaceEntity: WorkspaceMemberRepository,
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import {
SaveOptions,
UpdateResult,
} from 'typeorm';
import { PickKeysByType } from 'typeorm/common/PickKeysByType';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { UpsertOptions } from 'typeorm/repository/UpsertOptions';
import { PickKeysByType } from 'typeorm/common/PickKeysByType';

import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/co
import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity';
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';

@Module({
Expand All @@ -41,7 +40,6 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
ObjectMetadataRepositoryModule.forFeature([
ConnectedAccountWorkspaceEntity,
BlocklistWorkspaceEntity,
PersonWorkspaceEntity,
WorkspaceMemberWorkspaceEntity,
]),
CalendarEventParticipantManagerModule,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Address } from 'nodemailer/lib/mailer';

import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';

import {
Expand Down Expand Up @@ -32,6 +30,7 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { AddressMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/address.composite-type';

@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.company,
Expand Down Expand Up @@ -60,7 +59,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
'The company website URL. We use this url to fetch the company icon',
icon: 'IconLink',
})
domainName?: string;
domainName?: LinksMetadata;

@WorkspaceField({
standardId: COMPANY_STANDARD_FIELD_IDS.employees,
Expand Down Expand Up @@ -111,7 +110,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconMap',
})
@WorkspaceIsNullable()
address: Address;
address: AddressMetadata;

@WorkspaceField({
standardId: COMPANY_STANDARD_FIELD_IDS.idealCustomerProfile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
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 { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity';
import { AutoCompaniesAndContactsCreationCalendarChannelListener } from 'src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener';
import { AutoCompaniesAndContactsCreationMessageChannelListener } from 'src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener';
import { CreateCompanyAndContactService } from 'src/modules/contact-creation-manager/services/create-company-and-contact.service';
Expand All @@ -16,14 +14,10 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta

@Module({
imports: [
ObjectMetadataRepositoryModule.forFeature([
WorkspaceMemberWorkspaceEntity,
CompanyWorkspaceEntity,
]),
ObjectMetadataRepositoryModule.forFeature([WorkspaceMemberWorkspaceEntity]),
WorkspaceDataSourceModule,
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
TypeOrmModule.forFeature([FieldMetadataEntity], 'metadata'),
],
providers: [
CreateCompanyService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@ import { InjectRepository } from '@nestjs/typeorm';

import chunk from 'lodash.chunk';
import compact from 'lodash.compact';
import { EntityManager, Repository } from 'typeorm';
import { Any, EntityManager, Repository } from 'typeorm';

import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event';
import {
FieldMetadataEntity,
FieldMetadataType,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
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 { COMPANY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { CONTACTS_CREATION_BATCH_SIZE } from 'src/modules/contact-creation-manager/constants/contacts-creation-batch-size.constant';
Expand All @@ -23,41 +18,43 @@ import { Contact } from 'src/modules/contact-creation-manager/types/contact.type
import { filterOutSelfAndContactsFromCompanyOrWorkspace } from 'src/modules/contact-creation-manager/utils/filter-out-contacts-from-company-or-workspace.util';
import { getDomainNameFromHandle } from 'src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util';
import { getUniqueContactsAndHandles } from 'src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.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 { isWorkEmail } from 'src/utils/is-work-email';
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';

@Injectable()
export class CreateCompanyAndContactService {
constructor(
private readonly createContactService: CreateContactService,
private readonly createCompaniesService: CreateCompanyService,
@InjectObjectMetadataRepository(PersonWorkspaceEntity)
private readonly personRepository: PersonRepository,
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
private readonly workspaceMemberRepository: WorkspaceMemberRepository,
private readonly eventEmitter: EventEmitter2,
@InjectRepository(ObjectMetadataEntity, 'metadata')
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
@InjectRepository(FieldMetadataEntity, 'metadata')
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {}

private async createCompaniesAndPeople(
connectedAccount: ConnectedAccountWorkspaceEntity,
contactsToCreate: Contact[],
workspaceId: string,
companyDomainNameColumnName: string,
source: FieldActorSource,
transactionManager?: EntityManager,
): Promise<DeepPartial<PersonWorkspaceEntity>[]> {
if (!contactsToCreate || contactsToCreate.length === 0) {
return [];
}

const personRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
PersonWorkspaceEntity,
);

const workspaceMembers =
await this.workspaceMemberRepository.getAllByWorkspaceId(
workspaceId,
Expand All @@ -79,11 +76,11 @@ export class CreateCompanyAndContactService {
return [];
}

const alreadyCreatedContacts = await this.personRepository.getByEmails(
uniqueHandles,
workspaceId,
transactionManager,
);
const alreadyCreatedContacts = await personRepository.find({
where: {
email: Any(uniqueHandles),
},
});

const alreadyCreatedContactEmails: string[] = alreadyCreatedContacts?.map(
({ email }) => email,
Expand All @@ -105,15 +102,18 @@ export class CreateCompanyAndContactService {
}));

const domainNamesToCreate = compact(
filteredContactsToCreateWithCompanyDomainNames.map(
(participant) => participant.companyDomainName,
),
filteredContactsToCreateWithCompanyDomainNames
.filter((participant) => participant.companyDomainName)
.map((participant) => ({
domainName: participant.companyDomainName!,
createdBySource: source,
createdByWorkspaceMember: connectedAccount.accountOwner,
})),
);

const companiesObject = await this.createCompaniesService.createCompanies(
domainNamesToCreate,
workspaceId,
companyDomainNameColumnName,
transactionManager,
);

Expand All @@ -125,7 +125,8 @@ export class CreateCompanyAndContactService {
contact.companyDomainName && contact.companyDomainName !== ''
? companiesObject[contact.companyDomainName]
: undefined,
source,
createdBySource: source,
createdByWorkspaceMember: connectedAccount.accountOwner,
}));

return this.createContactService.createPeople(
Expand Down Expand Up @@ -159,24 +160,34 @@ export class CreateCompanyAndContactService {
throw new Error('Object metadata not found');
}

const domainNameFieldMetadata = await this.fieldMetadataRepository.findOne({
where: {
workspaceId: workspaceId,
standardId: COMPANY_STANDARD_FIELD_IDS.domainName,
},
});
// In some jobs the accountOwner is not populated
if (!connectedAccount.accountOwner) {
const workspaceMemberRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
WorkspaceMemberWorkspaceEntity,
);

const workspaceMember = await workspaceMemberRepository.findOne({
where: {
id: connectedAccount.accountOwnerId,
},
});

if (!workspaceMember) {
throw new Error(
`Workspace member with id ${connectedAccount.accountOwnerId} not found in workspace ${workspaceId}`,
);
}

const companyDomainNameColumnName =
domainNameFieldMetadata?.type === FieldMetadataType.LINKS
? 'domainNamePrimaryLinkUrl'
: 'domainName';
connectedAccount.accountOwner = workspaceMember;
}

for (const contactsBatch of contactsBatches) {
const createdPeople = await this.createCompaniesAndPeople(
connectedAccount,
contactsBatch,
workspaceId,
companyDomainNameColumnName,
source,
);

Expand Down
Loading

0 comments on commit 1c5c2da

Please sign in to comment.