Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@internxt/css-config": "^1.0.3",
"@internxt/inxt-js": "=1.2.21",
"@internxt/lib": "^1.2.0",
"@internxt/sdk": "=1.9.9",
"@internxt/sdk": "=1.9.18",
"@internxt/ui": "^0.0.23",
"@phosphor-icons/react": "^2.1.7",
"@popperjs/core": "^2.11.6",
Expand Down
13 changes: 10 additions & 3 deletions src/app/auth/services/user.service.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
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 = '[email protected]';

vi.mock('app/core/services/local-storage.service', () => ({
default: {
get: vi.fn(() => testToken),
set: vi.fn(),
clear: vi.fn(),
},
STORAGE_KEYS: {},
}));

const usersClientMock = {
initialize: vi.fn(),
refreshUser: vi.fn(),
Expand All @@ -25,7 +33,6 @@ const authClientMock = {
sendUserDeactivationEmail: vi.fn(),
};

vi.spyOn(localStorageService, 'get').mockReturnValue(testToken);
vi.mock('../../core/factory/sdk', () => ({
SdkFactory: {
getNewApiInstance: vi.fn(() => ({
Expand Down Expand Up @@ -109,7 +116,7 @@ describe('userService', () => {
it('should send a verification email', async () => {
usersClientMock.sendVerificationEmail.mockResolvedValue({ success: true });
await userService.sendVerificationEmail();
expect(usersClientMock.sendVerificationEmail).toHaveBeenCalled();
expect(usersClientMock.sendVerificationEmail).toHaveBeenCalledWith(testToken);
});

it('should get public key by email', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/components/Sidenav/Sidenav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useAppSelector } from 'app/store/hooks';
import workspacesSelectors from '../../../store/slices/workspaces/workspaces.selectors';
import WorkspaceSelectorContainer from './WorkspaceSelectorContainer';
import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { UserSubscription } from '@internxt/sdk/dist/drive/payments/types';
import { UserSubscription } from '@internxt/sdk/dist/drive/payments/types/types';
import { t } from 'i18next';
import { Loader } from '@internxt/ui';
import localStorageService, { STORAGE_KEYS } from '../../../core/services/local-storage.service';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ const FileViewerWrapper = ({

if (isDifferentThumbnailOrNotExists && thumbnailGenerated.file) {
const thumbnailToUpload: ThumbnailToUpload = {
fileUuid: driveFile.uuid,
fileId: driveFile.id,
size: thumbnailGenerated.file.size,
max_width: thumbnailGenerated.max_width,
Expand Down
4 changes: 2 additions & 2 deletions src/app/drive/services/download.service/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import downloadBackup from './downloadBackup';
import downloadFile from './downloadFile';
import downloadFileFromBlob from './downloadFileFromBlob';
import downloadFolder from './downloadFolder';
import fetchFileBlob from './fetchFileBlob';
import downloadFolder from './downloadFolder';

const downloadService = {
fetchFileBlob,
downloadFileFromBlob,
downloadFile,
downloadFolder,
downloadBackup,
downloadFolder,
};

export default downloadService;
246 changes: 246 additions & 0 deletions src/app/drive/services/file.service/uploadFile.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import uploadFile from './uploadFile';
import { Network, getEnvironmentConfig } from '../network.service';
import navigationService from '../../../core/services/navigation.service';
import localStorageService from '../../../core/services/local-storage.service';
import notificationsService from '../../../notifications/services/notifications.service';
import { SdkFactory } from '../../../core/factory/sdk';
import * as thumbnailService from '../thumbnail.service';
import workspacesService from '../../../core/services/workspace.service';

vi.mock('../network.service', () => ({
Network: vi.fn(),
getEnvironmentConfig: vi.fn(),
}));

vi.mock('../../../core/services/navigation.service', () => ({
default: {
push: vi.fn(),
},
}));

vi.mock('../../../core/services/local-storage.service', () => ({
default: {
clear: vi.fn(),
},
}));

vi.mock('../../../notifications/services/notifications.service', () => ({
default: {
show: vi.fn(),
},
ToastType: {
Warning: 'warning',
},
}));

vi.mock('../../../core/factory/sdk', () => ({
SdkFactory: {
getNewApiInstance: vi.fn(),
getInstance: vi.fn(),
},
}));

vi.mock('../thumbnail.service', () => ({
generateThumbnailFromFile: vi.fn(),
}));

vi.mock('../../../core/services/workspace.service', () => ({
default: {
createFileEntry: vi.fn(),
},
}));

describe('uploadFile', () => {
const mockFile = {
content: new File(['test content'], 'test.txt', { type: 'text/plain' }),
name: 'test.txt',
size: 12,
type: 'text/plain',
parentFolderId: 'parent-folder-uuid',
};

const mockBucketId = 'bucket-123';
const mockFileId = 'file-id-123';
const mockUserEmail = '[email protected]';
const mockEnvironmentConfig = {
bridgeUser: 'user',
bridgePass: 'pass',
encryptionKey: 'key',
bucketId: mockBucketId,
};

const mockStorageClient = {
createFileEntryByUuid: vi.fn(),
};

const mockUpdateProgressCallback = vi.fn();
const mockUploadPromise = Promise.resolve(mockFileId);
const mockUploadAbort = { abort: vi.fn() };
const mockNetworkUploadFile = vi.fn().mockReturnValue([mockUploadPromise, mockUploadAbort]);

beforeEach(() => {
vi.clearAllMocks();

(Network as unknown as ReturnType<typeof vi.fn>).mockImplementation(() => ({
uploadFile: mockNetworkUploadFile,
}));

(getEnvironmentConfig as ReturnType<typeof vi.fn>).mockReturnValue(mockEnvironmentConfig);

const mockNewApiInstance = {
createNewStorageClient: vi.fn().mockReturnValue(mockStorageClient),
};
(SdkFactory.getNewApiInstance as ReturnType<typeof vi.fn>).mockReturnValue(mockNewApiInstance);
});

it('should throw an error if bucketId is not found', async () => {
(getEnvironmentConfig as ReturnType<typeof vi.fn>).mockReturnValue({
...mockEnvironmentConfig,
bucketId: null,
});

await expect(
uploadFile(
mockUserEmail,
mockFile,
mockUpdateProgressCallback,
{ isTeam: false },
{ taskId: 'task-id', isPaused: false, isRetriedUpload: false },
),
).rejects.toThrow('Bucket not found!');

expect(notificationsService.show).toHaveBeenCalled();
expect(localStorageService.clear).toHaveBeenCalled();
expect(navigationService.push).toHaveBeenCalled();
});

it('should upload a file and create a file entry', async () => {
const mockResponse = {
id: 123,
uuid: 'file-uuid-123',
thumbnails: [],
};
mockStorageClient.createFileEntryByUuid.mockResolvedValue(mockResponse);
(thumbnailService.generateThumbnailFromFile as ReturnType<typeof vi.fn>).mockResolvedValue(null);

const result = await uploadFile(
mockUserEmail,
mockFile,
mockUpdateProgressCallback,
{ isTeam: false },
{ taskId: 'task-id', isPaused: false, isRetriedUpload: false },
);

expect(mockNetworkUploadFile).toHaveBeenCalledWith(
mockBucketId,
expect.objectContaining({
filecontent: mockFile.content,
filesize: mockFile.size,
}),
{ taskId: 'task-id', isPaused: false, isRetriedUpload: false },
);

expect(mockStorageClient.createFileEntryByUuid).toHaveBeenCalledWith(
expect.objectContaining({
id: mockFileId,
name: mockFile.name,
folder_id: mockFile.parentFolderId,
}),
undefined,
);

expect(result).toEqual(mockResponse);
});

it('should handle workspace file uploads', async () => {
const mockWorkspaceId = 'workspace-123';
const workspacesToken = 'workspace-token';
const resourcesToken = 'resources-token';
const mockResponse = {
id: 123,
uuid: 'file-uuid-123',
thumbnails: [],
};

(workspacesService.createFileEntry as ReturnType<typeof vi.fn>).mockResolvedValue(mockResponse);
(thumbnailService.generateThumbnailFromFile as ReturnType<typeof vi.fn>).mockResolvedValue(null);

// For workspace uploads, we need to set the owner authentication data AND mock the environment config
const ownerAuthData = {
workspaceId: mockWorkspaceId,
workspacesToken,
resourcesToken,
bridgeUser: 'workspace-user',
bridgePass: 'workspace-pass',
encryptionKey: 'workspace-key',
bucketId: 'workspace-bucket',
token: 'workspace-access-token',
};

const result = await uploadFile(
mockUserEmail,
mockFile,
mockUpdateProgressCallback,
{
isTeam: false,
ownerUserAuthenticationData: ownerAuthData,
},
{ taskId: 'task-id', isPaused: false, isRetriedUpload: false },
);

expect(workspacesService.createFileEntry).toHaveBeenCalledWith(
expect.objectContaining({
name: mockFile.name,
fileId: mockFileId,
folderUuid: mockFile.parentFolderId,
}),
mockWorkspaceId,
resourcesToken,
);

expect(result).toEqual(mockResponse);
});

it('should generate and attach a thumbnail when possible', async () => {
const mockFileResponse = {
id: 123,
uuid: 'file-uuid-123',
thumbnails: [],
};

const mockThumbnail = {
id: 'thumbnail-id',
bucket_id: 'bucket-id',
bucket_file: 'bucket-file',
};

const mockThumbnailFile = new File(['thumbnail content'], 'thumbnail.jpg');

mockStorageClient.createFileEntryByUuid.mockResolvedValue(mockFileResponse);
(thumbnailService.generateThumbnailFromFile as ReturnType<typeof vi.fn>).mockResolvedValue({
thumbnail: mockThumbnail,
thumbnailFile: mockThumbnailFile,
});

const result = await uploadFile(
mockUserEmail,
mockFile,
mockUpdateProgressCallback,
{ isTeam: false },
{ taskId: 'task-id', isPaused: false, isRetriedUpload: false },
);

expect(thumbnailService.generateThumbnailFromFile).toHaveBeenCalledWith(
mockFile,
mockFileResponse.id,
mockFileResponse.uuid,
mockUserEmail,
false,
);

expect(result.thumbnails).toContain(mockThumbnail);
expect(result.currentThumbnail).toBe(mockThumbnail);
expect(result.currentThumbnail?.urlObject).toBeDefined();
});
});
8 changes: 7 additions & 1 deletion src/app/drive/services/file.service/uploadFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ export async function uploadFile(
};
}

const generatedThumbnail = await generateThumbnailFromFile(file, response.id, userEmail, options.isTeam);
const generatedThumbnail = await generateThumbnailFromFile(
file,
response.id,
response.uuid,
userEmail,
options.isTeam,
);
if (generatedThumbnail?.thumbnail) {
response.thumbnails.push(generatedThumbnail.thumbnail);
if (generatedThumbnail.thumbnailFile) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/drive/services/plan.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StoragePlan } from '@internxt/sdk/dist/drive/payments/types';
import { StoragePlan } from '@internxt/sdk/dist/drive/payments/types/types';
import httpService from '../../core/services/http.service';
import { Workspace } from '../../core/types';

Expand Down
Loading
Loading