Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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.15",
"@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