Move defaultAvatarUrl on userWorkspace + migration command (#12100)

closes https://github.com/twentyhq/core-team-issues/issues/883
This commit is contained in:
Etienne
2025-05-21 12:07:02 +02:00
committed by GitHub
parent 8e2d0139ed
commit 3702fefc89
13 changed files with 500 additions and 78 deletions
@@ -39,7 +39,6 @@ describe('SignInUpService', () => {
let service: SignInUpService;
let UserRepository: Repository<User>;
let WorkspaceRepository: Repository<Workspace>;
let fileUploadService: FileUploadService;
let workspaceInvitationService: WorkspaceInvitationService;
let userWorkspaceService: UserWorkspaceService;
let twentyConfigService: TwentyConfigService;
@@ -137,7 +136,6 @@ describe('SignInUpService', () => {
service = module.get<SignInUpService>(SignInUpService);
UserRepository = module.get(getRepositoryToken(User, 'core'));
WorkspaceRepository = module.get(getRepositoryToken(Workspace, 'core'));
fileUploadService = module.get<FileUploadService>(FileUploadService);
workspaceInvitationService = module.get<WorkspaceInvitationService>(
WorkspaceInvitationService,
);
@@ -249,11 +247,6 @@ describe('SignInUpService', () => {
id: 'newWorkspaceId',
activationStatus: WorkspaceActivationStatus.ACTIVE,
} as Workspace);
jest.spyOn(fileUploadService, 'uploadImage').mockResolvedValue({
id: '',
mimeType: '',
paths: ['path/to/image'],
});
jest.spyOn(UserRepository, 'create').mockReturnValue({} as User);
jest
.spyOn(domainManagerService, 'generateSubdomain')
@@ -274,7 +267,12 @@ describe('SignInUpService', () => {
expect(WorkspaceRepository.save).toHaveBeenCalled();
expect(UserRepository.create).toHaveBeenCalled();
expect(UserRepository.save).toHaveBeenCalled();
expect(fileUploadService.uploadImage).toHaveBeenCalled();
expect(userWorkspaceService.create).toHaveBeenCalledWith({
workspaceId: 'newWorkspaceId',
userId: 'newUserId',
isExistingUser: false,
pictureUrl: 'pictureUrl',
});
});
it('should handle signIn on workspace in pending state', async () => {
@@ -2,14 +2,11 @@ import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import FileType from 'file-type';
import { TWENTY_ICONS_BASE_URL } from 'twenty-shared/constants';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { Repository } from 'typeorm';
import { v4 } from 'uuid';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import {
AuthException,
@@ -39,7 +36,6 @@ import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-in
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { getDomainNameByEmail } from 'src/utils/get-domain-name-by-email';
import { getImageBufferFromUrl } from 'src/utils/image';
import { isWorkEmail } from 'src/utils/is-work-email';
@Injectable()
@@ -232,14 +228,10 @@ export class SignInUpService {
newUserWithPicture: PartialUserWithPicture;
};
const user = await this.saveNewUser(
userData.newUserWithPicture,
params.workspace.id,
{
canAccessFullAdminPanel: false,
canImpersonate: false,
},
);
const user = await this.saveNewUser(userData.newUserWithPicture, {
canAccessFullAdminPanel: false,
canImpersonate: false,
});
await this.activateOnboardingForUser(user, params.workspace);
@@ -284,7 +276,6 @@ export class SignInUpService {
private async saveNewUser(
newUserWithPicture: PartialUserWithPicture,
workspaceId: string,
{
canImpersonate,
canAccessFullAdminPanel,
@@ -293,13 +284,8 @@ export class SignInUpService {
canAccessFullAdminPanel: boolean;
},
) {
const defaultAvatarUrl = await this.uploadPicture(
newUserWithPicture.picture,
workspaceId,
);
const userCreated = this.userRepository.create({
...newUserWithPicture,
defaultAvatarUrl,
canImpersonate,
canAccessFullAdminPanel,
});
@@ -368,15 +354,22 @@ export class SignInUpService {
const workspace = await this.workspaceRepository.save(workspaceToCreate);
const user =
userData.type === 'existingUser'
? userData.existingUser
: await this.saveNewUser(userData.newUserWithPicture, workspace.id, {
canImpersonate,
canAccessFullAdminPanel,
});
const isExistingUser = userData.type === 'existingUser';
const user = isExistingUser
? userData.existingUser
: await this.saveNewUser(userData.newUserWithPicture, {
canImpersonate,
canAccessFullAdminPanel,
});
await this.userWorkspaceService.create(user.id, workspace.id);
await this.userWorkspaceService.create({
userId: user.id,
workspaceId: workspace.id,
isExistingUser,
pictureUrl: isExistingUser
? undefined
: userData.newUserWithPicture.picture,
});
await this.activateOnboardingForUser(user, workspace);
@@ -387,30 +380,4 @@ export class SignInUpService {
return { user, workspace };
}
async uploadPicture(
picture: string | null | undefined,
workspaceId: string,
): Promise<string | undefined> {
if (!picture) {
return;
}
const buffer = await getImageBufferFromUrl(
picture,
this.httpService.axiosRef,
);
const type = await FileType.fromBuffer(buffer);
const { paths } = await this.fileUploadService.uploadImage({
file: buffer,
filename: `${v4()}.${type?.ext}`,
mimeType: type?.mime,
fileFolder: FileFolder.ProfilePicture,
workspaceId,
});
return paths[0];
}
}