Skip to content
Open
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
82 changes: 81 additions & 1 deletion src/app/drive/services/thumbnail.service.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
import Resizer from 'react-image-file-resizer';
import { ErrorLoadingVideoFileError } from './errors/thumbnail.service.errors';
import { getVideoFrame, getImageThumbnail } from './thumbnail.service';
import { getVideoFrame, getImageThumbnail, downloadThumbnail } from './thumbnail.service';
import localStorageService from 'services/local-storage.service';
import fetchFileBlob from './download.service/fetchFileBlob';
import { Thumbnail } from '@internxt/sdk/dist/drive/storage/types';

vi.mock('react-image-file-resizer');
vi.mock('services/local-storage.service');
vi.mock('./download.service/fetchFileBlob');

const flushPromises = () => new Promise((resolve) => setTimeout(resolve, 0));

Expand Down Expand Up @@ -240,4 +245,79 @@ describe('Thumbnail Service', () => {
expect(result).toBeNull();
});
});

describe('Download Thumbnail', () => {
const workspaceBucket = 'workspace-bucket-123';
const personalBucket = 'personal-bucket-456';

const mockThumbnail: Thumbnail = {
id: 1,
file_id: 123,
bucket_id: workspaceBucket,
bucket_file: 'bucket-file-hash',
type: 'image/png',
size: 1024,
max_width: 300,
max_height: 300,
encrypt_version: '03-aes',
};

beforeEach(() => {
vi.clearAllMocks();
vi.mocked(fetchFileBlob).mockResolvedValue(new Blob(['thumbnail-data']));
});

test('When downloading thumbnail in workspace context with workspace bucket, then it uses workspace credentials', async () => {
vi.mocked(localStorageService.getUser).mockReturnValue({ bucket: personalBucket } as any);

await downloadThumbnail(mockThumbnail, true);

expect(fetchFileBlob).toHaveBeenCalledWith(
expect.objectContaining({
fileId: mockThumbnail.bucket_file,
bucketId: mockThumbnail.bucket_id,
}),
expect.objectContaining({
isWorkspace: true,
}),
);
});

test('When downloading thumbnail in workspace context with personal bucket, then it uses personal credentials for backward compatibility', async () => {
const thumbnailInPersonalBucket: Thumbnail = {
...mockThumbnail,
bucket_id: personalBucket,
};

vi.mocked(localStorageService.getUser).mockReturnValue({ bucket: personalBucket } as any);

await downloadThumbnail(thumbnailInPersonalBucket, true);

expect(fetchFileBlob).toHaveBeenCalledWith(
expect.objectContaining({
fileId: thumbnailInPersonalBucket.bucket_file,
bucketId: thumbnailInPersonalBucket.bucket_id,
}),
expect.objectContaining({
isWorkspace: false,
}),
);
});

test('When downloading thumbnail in personal context, then it uses personal credentials', async () => {
vi.mocked(localStorageService.getUser).mockReturnValue({ bucket: personalBucket } as any);

await downloadThumbnail(mockThumbnail, false);

expect(fetchFileBlob).toHaveBeenCalledWith(
expect.objectContaining({
fileId: mockThumbnail.bucket_file,
bucketId: mockThumbnail.bucket_id,
}),
expect.objectContaining({
isWorkspace: false,
}),
);
});
});
});
16 changes: 14 additions & 2 deletions src/app/drive/services/thumbnail.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StorageTypes } from '@internxt/sdk/dist/drive';
import { Thumbnail } from '@internxt/sdk/dist/drive/storage/types';
import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import {
thumbnailableExtension,
thumbnailableImageExtension,
Expand Down Expand Up @@ -283,10 +284,21 @@ export const downloadThumbnail = async (thumbnailToDownload: Thumbnail, isWorksp
return;
};
const abortController = new AbortController();
// TODO: CHECK WHY WITH THUMBNAILS NOT HAS TO USE WORKSPACE CREDENTIALS

let useWorkspaceCredentials = isWorkspace;

if (isWorkspace) {
const user = localStorageService.getUser() as UserSettings;
const isInPersonalBucket = thumbnailToDownload.bucket_id === user.bucket;

if (isInPersonalBucket) {
useWorkspaceCredentials = false;
}
}

return await fetchFileBlob(
{ fileId: thumbnailToDownload.bucket_file, bucketId: thumbnailToDownload.bucket_id } as Downloadable,
{ isWorkspace: false, updateProgressCallback, abortController },
{ isWorkspace: useWorkspaceCredentials, updateProgressCallback, abortController },
);
};

Expand Down
112 changes: 112 additions & 0 deletions src/app/network/UploadManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,4 +558,116 @@ describe('checkUploadFiles', () => {
merge: { status: TaskStatus.Error, subtitle: expect.any(String) },
});
});

it('When uploading a file to a workspace, then it uses workspace credentials and same bucket for file and thumbnail', async () => {
const workspaceBucket = 'workspace-bucket-123';
const workspaceId = 'workspace-id-456';
const uploadFileSpy = (uploadFile as Mock).mockResolvedValueOnce(mockFile1);

vi.spyOn(tasksService, 'create').mockReturnValue('taskId');
vi.spyOn(tasksService, 'updateTask').mockReturnValue();
vi.spyOn(tasksService, 'addListener').mockReturnValue();
vi.spyOn(tasksService, 'removeListener').mockReturnValue();
vi.spyOn(errorService, 'castError').mockResolvedValue(new AppError('error'));

await uploadFileWithManager(
[
{
taskId: 'taskId',
filecontent: {
content: 'file-content' as unknown as File,
type: 'text/plain',
name: 'file.txt',
size: 1024,
parentFolderId: 'folder-1',
},
userEmail: 'user@test.com',
parentFolderId: '',
},
],
openMaxSpaceOccupiedDialogMock,
DatabaseUploadRepository.getInstance(),
undefined,
{
ownerUserAuthenticationData: {
bucketId: workspaceBucket,
workspaceId: workspaceId,
bridgeUser: 'bridge-user',
bridgePass: 'bridge-pass',
encryptionKey: 'encryption-key',
token: 'token',
workspacesToken: 'workspaces-token',
resourcesToken: 'resources-token',
},
sharedItemData: {
isDeepFolder: false,
currentFolderId: 'parentFolderId',
},
isUploadedFromFolder: true,
},
);

expect(uploadFileSpy).toHaveBeenCalledWith(
'user@test.com',
expect.any(Object),
expect.any(Function),
expect.objectContaining({
isTeam: true,
ownerUserAuthenticationData: expect.objectContaining({
bucketId: workspaceBucket,
workspaceId: workspaceId,
}),
}),
expect.any(Object),
);
});

it('When uploading a personal file, then it uses personal credentials', async () => {
const uploadFileSpy = (uploadFile as Mock).mockResolvedValueOnce(mockFile1);

vi.spyOn(tasksService, 'create').mockReturnValue('taskId');
vi.spyOn(tasksService, 'updateTask').mockReturnValue();
vi.spyOn(tasksService, 'addListener').mockReturnValue();
vi.spyOn(tasksService, 'removeListener').mockReturnValue();
vi.spyOn(errorService, 'castError').mockResolvedValue(new AppError('error'));

await uploadFileWithManager(
[
{
taskId: 'taskId',
filecontent: {
content: 'file-content' as unknown as File,
type: 'text/plain',
name: 'file.txt',
size: 1024,
parentFolderId: 'folder-1',
},
userEmail: 'user@test.com',
parentFolderId: '',
},
],
openMaxSpaceOccupiedDialogMock,
DatabaseUploadRepository.getInstance(),
undefined,
{
ownerUserAuthenticationData: undefined,
sharedItemData: {
isDeepFolder: false,
currentFolderId: 'parentFolderId',
},
isUploadedFromFolder: true,
},
);

expect(uploadFileSpy).toHaveBeenCalledWith(
'user@test.com',
expect.any(Object),
expect.any(Function),
expect.objectContaining({
isTeam: false,
ownerUserAuthenticationData: undefined,
}),
expect.any(Object),
);
});
});
2 changes: 1 addition & 1 deletion src/app/network/UploadManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class UploadManager {
}
},
{
isTeam: false,
isTeam: !!this.options?.ownerUserAuthenticationData?.workspaceId,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this flag the workspace correct flag or a deprecated flag of the previous deprecated version? Provide a GitHub ref demonstrating so pls

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isTeam is the name of an external boolean variable (ref) that's passed as an argument to get environment config (ref). The confusion likely comes from outdated JSDoc (ref) that references isTeam, but the actual parameter is isWorkspace.

abortController: this.abortController ?? fileData.abortController,
ownerUserAuthenticationData: this.options?.ownerUserAuthenticationData,
abortCallback: (abort?: () => void) => {
Expand Down
Loading