From c3c82453eff1f13fc9210d3e3f5856f8821b86f6 Mon Sep 17 00:00:00 2001 From: nd0ut Date: Wed, 18 Oct 2023 14:23:13 +0300 Subject: [PATCH 1/4] fix(upload-client): do not request fileInfo before creating group from uuid --- packages/upload-client/src/api/types.ts | 6 +- packages/upload-client/src/index.ts | 1 + .../src/tools/UploadcareGroup.ts | 14 +++- .../src/uploadFileGroup/uploadFileGroup.ts | 70 ++++++++++--------- .../upload-client/test/_fixtureFactory.ts | 2 +- packages/upload-client/test/api/group.test.ts | 7 +- .../uploadFileGroup/groupFromUploaded.test.ts | 13 ++-- 7 files changed, 72 insertions(+), 41 deletions(-) diff --git a/packages/upload-client/src/api/types.ts b/packages/upload-client/src/api/types.ts index 7f82d4e07..952cb1d54 100644 --- a/packages/upload-client/src/api/types.ts +++ b/packages/upload-client/src/api/types.ts @@ -25,12 +25,16 @@ export type FileInfo = { metadata?: Metadata } +export type GroupFileInfo = FileInfo & { + defaultEffects: string +} + export type GroupInfo = { datetimeCreated: string datetimeStored: string | null filesCount: string cdnUrl: string - files: FileInfo[] + files: GroupFileInfo[] url: string id: GroupId } diff --git a/packages/upload-client/src/index.ts b/packages/upload-client/src/index.ts index 37022b60a..c46c35a9e 100644 --- a/packages/upload-client/src/index.ts +++ b/packages/upload-client/src/index.ts @@ -95,6 +95,7 @@ export { FileInfo, GroupId, GroupInfo, + GroupFileInfo, Token, Url, Uuid, diff --git a/packages/upload-client/src/tools/UploadcareGroup.ts b/packages/upload-client/src/tools/UploadcareGroup.ts index 54bcf1a9c..f9ff5ae80 100644 --- a/packages/upload-client/src/tools/UploadcareGroup.ts +++ b/packages/upload-client/src/tools/UploadcareGroup.ts @@ -1,4 +1,5 @@ import { GroupId, GroupInfo } from '../api/types' +import defaultSettings from '../defaultSettings' import { UploadcareFile } from './UploadcareFile' export class UploadcareGroup { @@ -12,7 +13,14 @@ export class UploadcareGroup { readonly createdAt: string readonly storedAt: string | null = null - constructor(groupInfo: GroupInfo, files: UploadcareFile[]) { + constructor( + groupInfo: GroupInfo, + { + baseCDN = defaultSettings.baseCDN + }: { + baseCDN?: string + } = {} + ) { this.uuid = groupInfo.id this.filesCount = groupInfo.filesCount this.totalSize = Object.values(groupInfo.files).reduce( @@ -24,7 +32,9 @@ export class UploadcareGroup { (file) => file.isImage ).length this.cdnUrl = groupInfo.cdnUrl - this.files = files + this.files = groupInfo.files.map( + (fileInfo) => new UploadcareFile(fileInfo, { baseCDN }) + ) this.createdAt = groupInfo.datetimeCreated this.storedAt = groupInfo.datetimeStored } diff --git a/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts b/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts index 756c8cdfc..6ff753f78 100644 --- a/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts +++ b/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts @@ -14,6 +14,8 @@ import { } from '../api/types' import { SupportedFileInput } from '../types' import { isFileDataArray, isUrlArray, isUuidArray } from './types' +import { isFileData } from '../tools/isFileData' +import { isUrl } from '../uploadFile/types' export type GroupFromOptions = { jsonpCallback?: string @@ -80,39 +82,43 @@ export function uploadFileGroup( } } - return Promise.all( + return Promise.all( (data as SupportedFileInput[]).map( - (file: SupportedFileInput | Url | Uuid, index: number) => - uploadFile(file, { - publicKey, - - fileName, - baseURL, - secureSignature, - secureExpire, - store, - - signal, - onProgress: createProgressHandler(filesCount, index), - - source, - integration, - userAgent, - - retryThrottledRequestMaxTimes, - retryNetworkErrorMaxTimes, - - contentType, - multipartChunkSize, - - baseCDN, - checkForUrlDuplicates, - saveUrlForRecurrentUploads - }) + (file: SupportedFileInput | Url | Uuid, index: number) => { + if (isFileData(file) || isUrl(file)) { + return uploadFile(file, { + publicKey, + + fileName, + baseURL, + secureSignature, + secureExpire, + store, + + signal, + onProgress: createProgressHandler(filesCount, index), + + source, + integration, + userAgent, + + retryThrottledRequestMaxTimes, + retryNetworkErrorMaxTimes, + + contentType, + multipartChunkSize, + + baseCDN, + checkForUrlDuplicates, + saveUrlForRecurrentUploads + }).then((fileInfo) => fileInfo.uuid) + } else { + // Do not request file info by uuid before creating group because this isn't necessary + return file + } + } ) - ).then((files) => { - const uuids = files.map((file) => file.uuid) - + ).then((uuids) => { return group(uuids, { publicKey, baseURL, @@ -126,7 +132,7 @@ export function uploadFileGroup( retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }) - .then((groupInfo) => new UploadcareGroup(groupInfo, files)) + .then((groupInfo) => new UploadcareGroup(groupInfo, { baseCDN })) .then((group) => { onProgress && onProgress({ isComputable: true, value: 1 }) return group diff --git a/packages/upload-client/test/_fixtureFactory.ts b/packages/upload-client/test/_fixtureFactory.ts index d04a7629f..18a1b7b03 100644 --- a/packages/upload-client/test/_fixtureFactory.ts +++ b/packages/upload-client/test/_fixtureFactory.ts @@ -158,7 +158,7 @@ export function groupOfFiles(id: string): Array { const groupOfFiles = { valid: [ '392e3aa3-5ed6-4ad6-a67e-b3a7c1d5b9e9', - '49b4c5a1-31b3-4349-ba07-d97a2d883c37' + '49b4c5a1-31b3-4349-ba07-d97a2d883c37/-/resize/x800/' ], invalid: [ '2e6b7f23-9143-4b71-94e7-338bb', diff --git a/packages/upload-client/test/api/group.test.ts b/packages/upload-client/test/api/group.test.ts index bac68cc65..395722fcf 100644 --- a/packages/upload-client/test/api/group.test.ts +++ b/packages/upload-client/test/api/group.test.ts @@ -9,12 +9,17 @@ describe('API - group', () => { publicKey: factory.publicKey('image') }) - it('should upload group of files', async () => { + it('should create group of files', async () => { const data = await group(files, settings) expect(data).toBeTruthy() + console.log(data.id) expect(data.id).toBeTruthy() expect(data.files).toBeTruthy() + expect(data.files[0].uuid).toBe(files[0]) + expect(data.files[0].defaultEffects).toBe('') + expect(data.files[1].uuid).toBe(files[1].split('/')[0]) + expect(data.files[1].defaultEffects).toBe('resize/x800/') }) it('should fail with [HTTP 400] No files[N] parameters found.', async () => { diff --git a/packages/upload-client/test/uploadFileGroup/groupFromUploaded.test.ts b/packages/upload-client/test/uploadFileGroup/groupFromUploaded.test.ts index cf4bd706d..1488647ef 100644 --- a/packages/upload-client/test/uploadFileGroup/groupFromUploaded.test.ts +++ b/packages/upload-client/test/uploadFileGroup/groupFromUploaded.test.ts @@ -5,16 +5,21 @@ import { UploadClientError } from '../../src/tools/errors' import { jest, expect } from '@jest/globals' describe('groupFrom Uploaded[]', () => { - const uuid = factory.uuid('image') - const files = [uuid, uuid] + const files = factory.groupOfFiles('valid') const settings = getSettingsForTesting({ publicKey: factory.publicKey('image') }) it('should resolves when file is ready on CDN', async () => { - const { cdnUrl } = await uploadFileGroup(files, settings) + const data = await uploadFileGroup(files, settings) - expect(cdnUrl).toBeTruthy() + expect(data).toBeTruthy() + expect(data.uuid).toBeTruthy() + expect(data.files).toBeTruthy() + expect(data.files[0].uuid).toBe(files[0]) + expect(data.files[0].defaultEffects).toBe('') + expect(data.files[1].uuid).toBe(files[1].split('/')[0]) + expect(data.files[1].defaultEffects).toBe('resize/x800/') }) it('should accept store setting', async () => { From abe39c4312eac341fd4e7e6e238890b398167a7f Mon Sep 17 00:00:00 2001 From: nd0ut Date: Wed, 18 Oct 2023 15:59:43 +0300 Subject: [PATCH 2/4] feat(upload-client): add property `defaultEffects` to the `UploadcareFile` instance returned by `uploadFileGroup` method --- .../mock-server/controllers/group.ts | 12 +++++++- .../upload-client/mock-server/data/group.ts | 29 ++----------------- .../upload-client/src/tools/UploadcareFile.ts | 14 +++++++-- packages/upload-client/test/api/group.test.ts | 12 ++++---- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/packages/upload-client/mock-server/controllers/group.ts b/packages/upload-client/mock-server/controllers/group.ts index 4ba350ece..02893d120 100644 --- a/packages/upload-client/mock-server/controllers/group.ts +++ b/packages/upload-client/mock-server/controllers/group.ts @@ -86,7 +86,17 @@ const index = (ctx) => { }) } - ctx.body = find(json, 'info') + const response = find(json, 'info') as (typeof json)['info'] + response.files = files.map((file) => { + const uuid = file.split('/')[0] + const effects = file.split('/-/')[1] ?? '' + return { + ...response.files[0], + uuid, + default_effects: effects.replace(/^-\//, '') + } + }) + ctx.body = response } /** diff --git a/packages/upload-client/mock-server/data/group.ts b/packages/upload-client/mock-server/data/group.ts index 786077c35..249622255 100644 --- a/packages/upload-client/mock-server/data/group.ts +++ b/packages/upload-client/mock-server/data/group.ts @@ -31,33 +31,8 @@ export default { datetime_original: '2018-08-20T08:59:50', dpi: [72, 72] }, - mime_type: 'image/jpeg' - }, - { - is_stored: false, - done: 2667636, - file_id: 'd3275f8b-686d-4980-916a-53a1fc17450b', - total: 2667636, - size: 2667636, - uuid: 'd3275f8b-686d-4980-916a-53a1fc17450b', - is_image: true, - filename: 'newFileName.jpg', - video_info: null, - is_ready: true, - original_filename: 'newFileName.jpg', - image_info: { - orientation: 6, - format: 'JPEG', - height: 4032, - width: 3024, - geo_location: { - latitude: 55.62013611111111, - longitude: 37.66299166666666 - }, - datetime_original: '2018-08-20T08:59:50', - dpi: [72, 72] - }, - mime_type: 'image/jpeg' + mime_type: 'image/jpeg', + default_effects: '' } ] } diff --git a/packages/upload-client/src/tools/UploadcareFile.ts b/packages/upload-client/src/tools/UploadcareFile.ts index 1389ea258..0f3737f48 100644 --- a/packages/upload-client/src/tools/UploadcareFile.ts +++ b/packages/upload-client/src/tools/UploadcareFile.ts @@ -1,4 +1,4 @@ -import { FileInfo, Uuid } from '../api/types' +import { FileInfo, GroupFileInfo, Uuid } from '../api/types' import { ContentInfo, ImageInfo, @@ -8,6 +8,11 @@ import { import getUrl from './getUrl' import defaultSettings from '../defaultSettings' +function isGroupFileInfo( + fileInfo: FileInfo | GroupFileInfo +): fileInfo is GroupFileInfo { + return 'defaultEffects' in fileInfo +} export class UploadcareFile { readonly uuid: Uuid readonly name: null | string = null @@ -23,9 +28,10 @@ export class UploadcareFile { readonly contentInfo: null | ContentInfo = null readonly metadata: null | Metadata = null readonly s3Bucket: null | string = null + readonly defaultEffects: null | string = null constructor( - fileInfo: FileInfo, + fileInfo: FileInfo | GroupFileInfo, { baseCDN = defaultSettings.baseCDN, fileName @@ -57,5 +63,9 @@ export class UploadcareFile { this.metadata = fileInfo.metadata || null this.s3Bucket = s3Bucket || null this.s3Url = s3Url + + if (isGroupFileInfo(fileInfo)) { + this.defaultEffects = fileInfo.defaultEffects + } } } diff --git a/packages/upload-client/test/api/group.test.ts b/packages/upload-client/test/api/group.test.ts index 395722fcf..111baebd8 100644 --- a/packages/upload-client/test/api/group.test.ts +++ b/packages/upload-client/test/api/group.test.ts @@ -2,6 +2,7 @@ import * as factory from '../_fixtureFactory' import { getSettingsForTesting } from '../_helpers' import group from '../../src/api/group' import { UploadClientError } from '../../src/tools/errors' +import { GroupFileInfo } from '../../src' describe('API - group', () => { const files = factory.groupOfFiles('valid') @@ -11,15 +12,14 @@ describe('API - group', () => { it('should create group of files', async () => { const data = await group(files, settings) - + const groupFiles = data.files.filter(Boolean) as GroupFileInfo[] expect(data).toBeTruthy() - console.log(data.id) expect(data.id).toBeTruthy() expect(data.files).toBeTruthy() - expect(data.files[0].uuid).toBe(files[0]) - expect(data.files[0].defaultEffects).toBe('') - expect(data.files[1].uuid).toBe(files[1].split('/')[0]) - expect(data.files[1].defaultEffects).toBe('resize/x800/') + expect(groupFiles[0].uuid).toBe(files[0]) + expect(groupFiles[0].defaultEffects).toBe('') + expect(groupFiles[1].uuid).toBe(files[1].split('/')[0]) + expect(groupFiles[1].defaultEffects).toBe('resize/x800/') }) it('should fail with [HTTP 400] No files[N] parameters found.', async () => { From 83c0b6c7ef4b6e467795cf280dea67bb9608605b Mon Sep 17 00:00:00 2001 From: nd0ut Date: Wed, 18 Oct 2023 16:06:02 +0300 Subject: [PATCH 3/4] fix(upload-client): filter `null` values from the `files` property of group info --- packages/upload-client/src/api/types.ts | 3 ++- packages/upload-client/src/tools/UploadcareGroup.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/upload-client/src/api/types.ts b/packages/upload-client/src/api/types.ts index 952cb1d54..164092c77 100644 --- a/packages/upload-client/src/api/types.ts +++ b/packages/upload-client/src/api/types.ts @@ -34,7 +34,8 @@ export type GroupInfo = { datetimeStored: string | null filesCount: string cdnUrl: string - files: GroupFileInfo[] + // An array may contain null values if a file has been removed. + files: (GroupFileInfo | null)[] url: string id: GroupId } diff --git a/packages/upload-client/src/tools/UploadcareGroup.ts b/packages/upload-client/src/tools/UploadcareGroup.ts index f9ff5ae80..7abe8a0d2 100644 --- a/packages/upload-client/src/tools/UploadcareGroup.ts +++ b/packages/upload-client/src/tools/UploadcareGroup.ts @@ -1,4 +1,4 @@ -import { GroupId, GroupInfo } from '../api/types' +import { GroupFileInfo, GroupId, GroupInfo } from '../api/types' import defaultSettings from '../defaultSettings' import { UploadcareFile } from './UploadcareFile' @@ -23,16 +23,16 @@ export class UploadcareGroup { ) { this.uuid = groupInfo.id this.filesCount = groupInfo.filesCount - this.totalSize = Object.values(groupInfo.files).reduce( + const groupFiles = groupInfo.files.filter(Boolean) as GroupFileInfo[] + this.totalSize = Object.values(groupFiles).reduce( (acc, file) => acc + file.size, 0 ) this.isStored = !!groupInfo.datetimeStored - this.isImage = !!Object.values(groupInfo.files).filter( - (file) => file.isImage - ).length + this.isImage = !!Object.values(groupFiles).filter((file) => file.isImage) + .length this.cdnUrl = groupInfo.cdnUrl - this.files = groupInfo.files.map( + this.files = groupFiles.map( (fileInfo) => new UploadcareFile(fileInfo, { baseCDN }) ) this.createdAt = groupInfo.datetimeCreated From 8fc0211e36bb35ba7797ed7206d0e1d0f81d9a8a Mon Sep 17 00:00:00 2001 From: nd0ut Date: Wed, 18 Oct 2023 17:24:04 +0300 Subject: [PATCH 4/4] chore: organize imports --- .../upload-client/src/uploadFileGroup/uploadFileGroup.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts b/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts index 6ff753f78..3d0f5dece 100644 --- a/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts +++ b/packages/upload-client/src/uploadFileGroup/uploadFileGroup.ts @@ -1,8 +1,7 @@ import group from '../api/group' import defaultSettings from '../defaultSettings' -import { UploadcareFile } from '../tools/UploadcareFile' import { UploadcareGroup } from '../tools/UploadcareGroup' -import { uploadFile, FileFromOptions } from '../uploadFile' +import { FileFromOptions, uploadFile } from '../uploadFile' /* Types */ import { @@ -12,10 +11,10 @@ import { Url, Uuid } from '../api/types' -import { SupportedFileInput } from '../types' -import { isFileDataArray, isUrlArray, isUuidArray } from './types' import { isFileData } from '../tools/isFileData' +import { SupportedFileInput } from '../types' import { isUrl } from '../uploadFile/types' +import { isFileDataArray, isUrlArray, isUuidArray } from './types' export type GroupFromOptions = { jsonpCallback?: string