From 2651379ccc7c0c5694f39c4e8cbe1f3169e3a5d8 Mon Sep 17 00:00:00 2001 From: Samyak Piya <76403666+samyakpiya@users.noreply.github.com> Date: Sun, 22 Dec 2024 03:24:27 -0500 Subject: [PATCH] Add automatic company logo fetching during workspace creation (#9158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #9151 ## Description This PR automatically sets a workspace's logo based on the user's work email domain during signup. When a user creates a new workspace using their work email (e.g., @airbnb.com), the system will fetch and set their company logo from twenty-icons.com as the default workspace logo. ## Implementation Details - Added a new `CompanyEnrichmentService` to handle company-related data enrichment - Created a modular architecture that supports future enrichment features (e.g., company name, details) - Integrated with existing work email detection - Maintains user ability to override the logo later ## Testing https://github.com/user-attachments/assets/f7855c99-462a-4053-9e52-29649e954275 I tested the following scenarios: - Signing up with a work email (e.g., @company.com) → Logo is automatically set - Signing up with a personal email (e.g., @gmail.com) → No logo is set - User can still upload a custom logo after automatic setting ## Technical Notes - Uses existing `isWorkEmail` utility - Structured for future extensibility (additional company data enrichment) - No breaking changes to existing functionality --------- Co-authored-by: Félix Malfait --- .vscode/twenty.code-workspace | 4 ++++ packages/twenty-server/jest-integration.config.ts | 1 + .../core-modules/auth/services/sign-in-up.service.ts | 12 ++++++++++-- .../services/create-company.service.ts | 3 ++- packages/twenty-server/tsconfig.json | 3 ++- .../src/constants/TwentyCompaniesBaseUrl.ts | 1 + .../src/constants/TwentyIconsBaseUrl.ts | 1 + packages/twenty-shared/src/index.ts | 2 ++ 8 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 packages/twenty-shared/src/constants/TwentyCompaniesBaseUrl.ts create mode 100644 packages/twenty-shared/src/constants/TwentyIconsBaseUrl.ts diff --git a/.vscode/twenty.code-workspace b/.vscode/twenty.code-workspace index 38d8b34543a6..57d28b0450b7 100644 --- a/.vscode/twenty.code-workspace +++ b/.vscode/twenty.code-workspace @@ -24,6 +24,10 @@ "name": "packages/twenty-emails", "path": "../packages/twenty-emails" }, + { + "name": "packages/twenty-shared", + "path": "../packages/twenty-shared" + }, { "name": "packages/twenty-server", "path": "../packages/twenty-server" diff --git a/packages/twenty-server/jest-integration.config.ts b/packages/twenty-server/jest-integration.config.ts index 5cf3ce61f371..cbb53051d1fd 100644 --- a/packages/twenty-server/jest-integration.config.ts +++ b/packages/twenty-server/jest-integration.config.ts @@ -21,6 +21,7 @@ const jestConfig: JestConfigWithTsJest = { }), '^test/(.*)$': '/test/$1', 'twenty-emails': '/../twenty-emails/dist/index.js', + 'twenty-shared': '/../twenty-shared/dist/index.js', }, fakeTimers: { enableGlobally: true, diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index f11b02d7dcd4..2f9a3beb8b2c 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'class-validator'; import FileType from 'file-type'; +import { TWENTY_ICONS_BASE_URL } from 'twenty-shared'; import { Repository } from 'typeorm'; import { v4 } from 'uuid'; @@ -23,17 +24,19 @@ import { EnvironmentService } from 'src/engine/core-modules/environment/environm import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; +import { UserService } from 'src/engine/core-modules/user/services/user.service'; import { User } from 'src/engine/core-modules/user/user.entity'; import { userValidator } from 'src/engine/core-modules/user/user.validate'; import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service'; +import { WorkspaceAuthProvider } from 'src/engine/core-modules/workspace/types/workspace.type'; import { Workspace, WorkspaceActivationStatus, } from 'src/engine/core-modules/workspace/workspace.entity'; import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate'; +import { getDomainNameByEmail } from 'src/utils/get-domain-name-by-email'; import { getImageBufferFromUrl } from 'src/utils/image'; -import { WorkspaceAuthProvider } from 'src/engine/core-modules/workspace/types/workspace.type'; -import { UserService } from 'src/engine/core-modules/user/services/user.service'; +import { isWorkEmail } from 'src/utils/is-work-email'; export type SignInUpServiceInput = { email: string; @@ -333,12 +336,17 @@ export class SignInUpService { } } + const logo = isWorkEmail(email) + ? `${TWENTY_ICONS_BASE_URL}/${getDomainNameByEmail(email)}` + : undefined; + const workspaceToCreate = this.workspaceRepository.create({ subdomain: await this.domainManagerService.generateSubdomain(), displayName: '', domainName: '', inviteHash: v4(), activationStatus: WorkspaceActivationStatus.PENDING_CREATION, + logo, }); const workspace = await this.workspaceRepository.save(workspaceToCreate); diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts index bed7f1509bb5..a8388ec2d285 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import axios, { AxiosInstance } from 'axios'; import uniqBy from 'lodash.uniqby'; +import { TWENTY_COMPANIES_BASE_URL } from 'twenty-shared'; import { DeepPartial, EntityManager, ILike } from 'typeorm'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; @@ -25,7 +26,7 @@ export class CreateCompanyService { constructor(private readonly twentyORMGlobalManager: TwentyORMGlobalManager) { this.httpService = axios.create({ - baseURL: 'https://twenty-companies.com', + baseURL: TWENTY_COMPANIES_BASE_URL, }); } diff --git a/packages/twenty-server/tsconfig.json b/packages/twenty-server/tsconfig.json index 272cbdde673c..fe1ccbd7a8f5 100644 --- a/packages/twenty-server/tsconfig.json +++ b/packages/twenty-server/tsconfig.json @@ -27,7 +27,8 @@ "paths": { "src/*": ["packages/twenty-server/src/*"], "test/*": ["packages/twenty-server/test/*"], - "twenty-emails": ["packages/twenty-emails/dist"] + "twenty-emails": ["packages/twenty-emails/dist"], + "twenty-shared": ["packages/twenty-shared/dist"] } }, "ts-node": { diff --git a/packages/twenty-shared/src/constants/TwentyCompaniesBaseUrl.ts b/packages/twenty-shared/src/constants/TwentyCompaniesBaseUrl.ts new file mode 100644 index 000000000000..544ae6e730a0 --- /dev/null +++ b/packages/twenty-shared/src/constants/TwentyCompaniesBaseUrl.ts @@ -0,0 +1 @@ +export const TWENTY_COMPANIES_BASE_URL = 'https://twenty-companies.com'; diff --git a/packages/twenty-shared/src/constants/TwentyIconsBaseUrl.ts b/packages/twenty-shared/src/constants/TwentyIconsBaseUrl.ts new file mode 100644 index 000000000000..82e460872b52 --- /dev/null +++ b/packages/twenty-shared/src/constants/TwentyIconsBaseUrl.ts @@ -0,0 +1 @@ +export const TWENTY_ICONS_BASE_URL = 'https://twenty-icons.com'; diff --git a/packages/twenty-shared/src/index.ts b/packages/twenty-shared/src/index.ts index 7665115392af..894818340dcc 100644 --- a/packages/twenty-shared/src/index.ts +++ b/packages/twenty-shared/src/index.ts @@ -1 +1,3 @@ +export * from './constants/TwentyCompaniesBaseUrl'; +export * from './constants/TwentyIconsBaseUrl'; export * from './utils/image/getImageAbsoluteURI';