diff --git a/package.json b/package.json index 24c5d80068..a75462886b 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "@internxt/css-config": "^1.0.2", "@internxt/inxt-js": "=1.2.21", "@internxt/lib": "^1.2.0", - "@internxt/sdk": "=1.9.6", "@internxt/ui": "^0.0.16", + "@internxt/sdk": "=1.9.8", "@phosphor-icons/react": "^2.1.7", "@popperjs/core": "^2.11.6", "@reduxjs/toolkit": "^1.6.0", diff --git a/src/app/auth/services/auth.service.test.ts b/src/app/auth/services/auth.service.test.ts index cbd026b099..513c7a048d 100644 --- a/src/app/auth/services/auth.service.test.ts +++ b/src/app/auth/services/auth.service.test.ts @@ -644,6 +644,19 @@ describe('Change password', () => { const privateKyberKeyEncrypted = inputs.keys.encryptedPrivateKyberKey; expect(privateKyberKeyEncrypted).toBe(''); }); + + it('should cancel account', async () => { + const mockSendDeactivationEmail = vi.fn().mockReturnValue({ success: true }); + vi.spyOn(SdkFactory, 'getNewApiInstance').mockReturnValue({ + createAuthClient: vi.fn().mockReturnValue({ + sendUserDeactivationEmail: mockSendDeactivationEmail, + }), + } as any); + vi.spyOn(localStorageService, 'get').mockReturnValue('token'); + + await authService.cancelAccount(); + expect(mockSendDeactivationEmail).toHaveBeenCalledWith('token'); + }); }); /* diff --git a/src/app/auth/services/auth.service.ts b/src/app/auth/services/auth.service.ts index 18f92700cc..933e5cbc71 100644 --- a/src/app/auth/services/auth.service.ts +++ b/src/app/auth/services/auth.service.ts @@ -102,9 +102,9 @@ export async function logOut(loginParams?: Record): Promise { - const email = localStorageService.getUser()?.email; - const authClient = SdkFactory.getInstance().createAuthClient(); - return authClient.sendDeactivationEmail(email); + const authClient = SdkFactory.getNewApiInstance().createAuthClient(); + const token = localStorageService.get('xNewToken') ?? undefined; + return authClient.sendUserDeactivationEmail(token); } export const is2FANeeded = async (email: string): Promise => { diff --git a/src/app/auth/services/user.service.test.ts b/src/app/auth/services/user.service.test.ts new file mode 100644 index 0000000000..dd895093bc --- /dev/null +++ b/src/app/auth/services/user.service.test.ts @@ -0,0 +1,138 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import localStorageService from 'app/core/services/local-storage.service'; +import userService from './user.service'; + +const testToken = 'testToken'; +const testEmail = 'test@initnxt.com'; + +const usersClientMock = { + initialize: vi.fn(), + refreshUser: vi.fn(), + getUserData: vi.fn(), + updateUserProfile: vi.fn(), + getFriendInvites: vi.fn(), + updateUserAvatar: vi.fn(), + deleteUserAvatar: vi.fn(), + sendVerificationEmail: vi.fn(), + getPublicKeyByEmail: vi.fn(), + preRegister: vi.fn(), + changeUserEmail: vi.fn(), + verifyEmailChange: vi.fn(), + checkChangeEmailExpiration: vi.fn(), +}; + +const authClientMock = { + sendUserDeactivationEmail: vi.fn(), +}; + +vi.spyOn(localStorageService, 'get').mockReturnValue(testToken); +vi.mock('../../core/factory/sdk', () => ({ + SdkFactory: { + getNewApiInstance: vi.fn(() => ({ + createDesktopAuthClient: vi.fn(() => ({ + login: vi.fn(), + })), + createNewUsersClient: vi.fn(() => usersClientMock), + createAuthClient: vi.fn(() => authClientMock), + createUsersClient: vi.fn(() => usersClientMock), + })), + getInstance: vi.fn(() => ({ + createUsersClient: vi.fn(() => usersClientMock), + })), + }, +})); + +describe('userService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should initialize a user', async () => { + usersClientMock.initialize.mockResolvedValue({ success: true }); + const result = await userService.initializeUser(testEmail, 'mnemonic'); + expect(result).toEqual({ success: true }); + expect(usersClientMock.initialize).toHaveBeenCalledWith(testEmail, 'mnemonic'); + }); + + it('should send a deactivation email', async () => { + authClientMock.sendUserDeactivationEmail.mockResolvedValue({ success: true }); + const result = await userService.sendDeactivationEmail(); + expect(result).toEqual({ success: true }); + expect(authClientMock.sendUserDeactivationEmail).toHaveBeenCalledWith(testToken); + }); + + it('should pre-create user', async () => { + usersClientMock.preRegister.mockResolvedValue('mockPreCreate'); + const response = await userService.preCreateUser(testEmail); + expect(response).toBe('mockPreCreate'); + }); + + it('should refresh user data', async () => { + usersClientMock.refreshUser.mockResolvedValue({ user: {}, token: 'newToken' }); + const result = await userService.refreshUser(); + expect(result).toEqual({ user: {}, token: 'newToken' }); + expect(usersClientMock.refreshUser).toHaveBeenCalled(); + }); + + it('should update user profile', async () => { + usersClientMock.updateUserProfile.mockResolvedValue({ success: true }); + await userService.updateUserProfile({ + name: 'New Name', + lastname: 'New Lastname', + }); + expect(usersClientMock.updateUserProfile).toHaveBeenCalledWith( + { name: 'New Name', lastname: 'New Lastname' }, + testToken, + ); + }); + + it('should get friend invites', async () => { + usersClientMock.getFriendInvites.mockResolvedValue([{ id: 1 }]); + const result = await userService.getFriendInvites(); + expect(result).toEqual([{ id: 1 }]); + expect(usersClientMock.getFriendInvites).toHaveBeenCalled(); + }); + + it('should update user avatar', async () => { + usersClientMock.updateUserAvatar.mockResolvedValue({ avatar: 'avatar-url' }); + const result = await userService.updateUserAvatar({ avatar: new Blob() }); + expect(result).toEqual({ avatar: 'avatar-url' }); + expect(usersClientMock.updateUserAvatar).toHaveBeenCalled(); + }); + + it('should delete user avatar', async () => { + usersClientMock.deleteUserAvatar.mockResolvedValue({ success: true }); + await userService.deleteUserAvatar(); + expect(usersClientMock.deleteUserAvatar).toHaveBeenCalledWith(testToken); + }); + + it('should send a verification email', async () => { + usersClientMock.sendVerificationEmail.mockResolvedValue({ success: true }); + await userService.sendVerificationEmail(); + expect(usersClientMock.sendVerificationEmail).toHaveBeenCalled(); + }); + + it('should get public key by email', async () => { + usersClientMock.getPublicKeyByEmail.mockResolvedValue({ publicKey: 'key' }); + const result = await userService.getPublicKeyByEmail(testEmail); + expect(result).toEqual({ publicKey: 'key' }); + expect(usersClientMock.getPublicKeyByEmail).toHaveBeenCalledWith({ email: testEmail }); + }); + + it('should change email', async () => { + await userService.changeEmail('newtest@inxt.com'); + expect(usersClientMock.changeUserEmail).toHaveBeenCalledWith('newtest@inxt.com'); + }); + + it('should verify email change', async () => { + usersClientMock.verifyEmailChange.mockResolvedValue('mockVerifyResponse'); + const response = await userService.verifyEmailChange('verifyToken'); + expect(response).toBe('mockVerifyResponse'); + }); + + it('should check change email link expiration', async () => { + usersClientMock.checkChangeEmailExpiration.mockResolvedValue('mockExpirationResponse'); + const response = await userService.checkChangeEmailLinkExpiration('verifyToken'); + expect(response).toBe('mockExpirationResponse'); + }); +}); diff --git a/src/app/auth/services/user.service.ts b/src/app/auth/services/user.service.ts index d408812155..417c485130 100644 --- a/src/app/auth/services/user.service.ts +++ b/src/app/auth/services/user.service.ts @@ -19,9 +19,10 @@ export async function initializeUser(email: string, mnemonic: string): Promise => { - const authClient = SdkFactory.getInstance().createAuthClient(); - return authClient.sendDeactivationEmail(email); +export const sendDeactivationEmail = (): Promise => { + const authClient = SdkFactory.getNewApiInstance().createAuthClient(); + const token = localStorageService.get('xNewToken') ?? undefined; + return authClient.sendUserDeactivationEmail(token); }; const preCreateUser = (email: string): Promise => { @@ -43,8 +44,9 @@ const refreshUserData = async (userUUID: string): Promise<{ user: UserSettings } }; const updateUserProfile = (payload: Required): Promise => { - const usersClient = SdkFactory.getInstance().createUsersClient(); - return usersClient.updateProfile(payload); + const usersClient = SdkFactory.getNewApiInstance().createUsersClient(); + const token = localStorageService.get('xNewToken') ?? undefined; + return usersClient.updateUserProfile(payload, token); }; const getFriendInvites = (): Promise => { @@ -53,13 +55,15 @@ const getFriendInvites = (): Promise => { }; const updateUserAvatar = (payload: { avatar: Blob }): Promise<{ avatar: string }> => { - const usersClient = SdkFactory.getInstance().createUsersClient(TEMPORAL_AVATAR_API_URL); - return usersClient.updateAvatar(payload); + const usersClient = SdkFactory.getNewApiInstance().createUsersClient(TEMPORAL_AVATAR_API_URL); + const token = localStorageService.get('xNewToken') ?? undefined; + return usersClient.updateUserAvatar(payload, token); }; const deleteUserAvatar = (): Promise => { - const usersClient = SdkFactory.getInstance().createUsersClient(); - return usersClient.deleteAvatar(); + const usersClient = SdkFactory.getNewApiInstance().createUsersClient(); + const token = localStorageService.get('xNewToken') ?? undefined; + return usersClient.deleteUserAvatar(token); }; const sendVerificationEmail = (): Promise => { diff --git a/src/app/core/views/DeactivationView/DeactivationView.tsx b/src/app/core/views/DeactivationView/DeactivationView.tsx index 2b204b1f2f..04f80d0f01 100644 --- a/src/app/core/views/DeactivationView/DeactivationView.tsx +++ b/src/app/core/views/DeactivationView/DeactivationView.tsx @@ -12,6 +12,7 @@ import { match } from 'react-router-dom'; import navigationService from '../../services/navigation.service'; import { AppView } from '../../types'; import { SdkFactory } from '../../factory/sdk'; +import localStorageService from 'app/core/services/local-storage.service'; export interface DeactivationViewProps { match?: match<{ token: string }>; @@ -41,9 +42,10 @@ class DeactivationView extends React.Component { }; ConfirmDeactivateUser = (token: string) => { - const authClient = SdkFactory.getInstance().createAuthClient(); + const authClient = SdkFactory.getNewApiInstance().createAuthClient(); + const userToken = localStorageService.get('xNewToken') ?? undefined; return authClient - .confirmDeactivation(token) + .confirmUserDeactivation(token, userToken) .then(() => { this.ClearAndRedirect(); }) diff --git a/yarn.lock b/yarn.lock index d0ce8fa4f0..2118389472 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2740,10 +2740,10 @@ resolved "https://npm.pkg.github.com/download/@internxt/prettier-config/1.0.2/5bd220b8de76734448db5475b3e0c01f9d22c19b#5bd220b8de76734448db5475b3e0c01f9d22c19b" integrity sha512-t4HiqvCbC7XgQepwWlIaFJe3iwW7HCf6xOSU9nKTV0tiGqOPz7xMtIgLEloQrDA34Cx4PkOYBXrvFPV6RxSFAA== -"@internxt/sdk@=1.9.6": - version "1.9.6" - resolved "https://npm.pkg.github.com/download/@internxt/sdk/1.9.6/50cee6271083829785c8fcfd850a28e51ef59962#50cee6271083829785c8fcfd850a28e51ef59962" - integrity sha512-96tAE/1PKQktUjO5wBfpKnf/AL3Ri/dF0ZJOsTikG/EsNtGUBENCsX2OI5Q2hZPagwDFjK1dkY+M5jEh+MFd3w== +"@internxt/sdk@=1.9.8": + version "1.9.8" + resolved "https://npm.pkg.github.com/download/@internxt/sdk/1.9.8/c69dfd1c47469eeaa9d753af720fb841f36579a3#c69dfd1c47469eeaa9d753af720fb841f36579a3" + integrity sha512-LpXRcz6SNYwc/IpTT6xr8emCCXOYFh+oEl7VMfDF1ODfA4tOvFzqGYKLpB0irSgjWjlzvTWq8v6qXgboDhcicw== dependencies: axios "^0.24.0" query-string "^7.1.0"