Add automatic company logo fetching during workspace creation (#9158)
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 <felix@twenty.com>
This commit is contained in:
4
.vscode/twenty.code-workspace
vendored
4
.vscode/twenty.code-workspace
vendored
@ -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"
|
||||
|
||||
@ -21,6 +21,7 @@ const jestConfig: JestConfigWithTsJest = {
|
||||
}),
|
||||
'^test/(.*)$': '<rootDir>/test/$1',
|
||||
'twenty-emails': '<rootDir>/../twenty-emails/dist/index.js',
|
||||
'twenty-shared': '<rootDir>/../twenty-shared/dist/index.js',
|
||||
},
|
||||
fakeTimers: {
|
||||
enableGlobally: true,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export const TWENTY_COMPANIES_BASE_URL = 'https://twenty-companies.com';
|
||||
@ -0,0 +1 @@
|
||||
export const TWENTY_ICONS_BASE_URL = 'https://twenty-icons.com';
|
||||
@ -1 +1,3 @@
|
||||
export * from './constants/TwentyCompaniesBaseUrl';
|
||||
export * from './constants/TwentyIconsBaseUrl';
|
||||
export * from './utils/image/getImageAbsoluteURI';
|
||||
|
||||
Reference in New Issue
Block a user