From 797f2c79a771a3e084e42e5fbacdf09bfc75a832 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 16 Aug 2024 12:55:10 +0200 Subject: [PATCH 01/28] dataset files upload factory fix --- .../upload-dataset-files/UploadDatasetFilesFactory.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFilesFactory.tsx b/src/sections/upload-dataset-files/UploadDatasetFilesFactory.tsx index 20dd69293..b061e9bb5 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFilesFactory.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFilesFactory.tsx @@ -4,6 +4,7 @@ import { DatasetJSDataverseRepository } from '../../dataset/infrastructure/repos import { FileJSDataverseRepository } from '../../files/infrastructure/FileJSDataverseRepository' import { DatasetProvider } from '../dataset/DatasetProvider' import { UploadDatasetFiles } from './UploadDatasetFiles' +import { DatasetNonNumericVersion } from '../../dataset/domain/models/Dataset' const datasetRepository = new DatasetJSDataverseRepository() const fileRepository = new FileJSDataverseRepository() @@ -17,9 +18,12 @@ export class UploadDatasetFilesFactory { function UploadDatasetFilesWithSearchParams() { const [searchParams] = useSearchParams() const persistentId = searchParams.get('persistentId') ?? undefined + const version = searchParams.get('version') ?? DatasetNonNumericVersion.DRAFT return ( - + ) From b9085f74b68e5b0fb34b753ab44a5106c3363a0f Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 16 Aug 2024 15:34:20 +0200 Subject: [PATCH 02/28] initial integration with the upload files use case --- package-lock.json | 8 +++--- package.json | 2 +- src/files/domain/models/FileUploadState.ts | 13 ++++++++++ .../domain/repositories/FileRepository.ts | 5 ---- src/files/domain/useCases/addUploadedFiles.ts | 15 ----------- .../FileJSDataverseRepository.ts | 23 ++++++++++------ .../UploadDatasetFiles.tsx | 26 +++++++++---------- src/stories/file/FileMockRepository.ts | 12 --------- 8 files changed, 46 insertions(+), 58 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1bdce50e3..0273f4e3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr155.be01a3f", + "@iqss/dataverse-client-javascript": "2.0.0-pr169.aa49f06", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", @@ -3610,9 +3610,9 @@ }, "node_modules/@iqss/dataverse-client-javascript": { "name": "@IQSS/dataverse-client-javascript", - "version": "2.0.0-pr155.be01a3f", - "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr155.be01a3f/dea4dac3ef3aab1802b444ccc08326843c530d80", - "integrity": "sha512-Q2KhE3JGu3BaTD1TB3l0iQ6yZIvpUOkds8Zk0nezNymm4pL8gjdISomJDUXFFW9tQuAZ0PkXuOEQGmVfzEUKNA==", + "version": "2.0.0-pr169.aa49f06", + "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr169.aa49f06/d8061b0af0068e530c6ef78b89e0a4ce668df4b3", + "integrity": "sha512-2D3wxWA87kU8EXltK7pBMGX9OoK7aecX869zbalbdtSNcPz9ATbZOOhDYbfaU+J526AyNTVQ6xlPTY5hWIRFvQ==", "license": "MIT", "dependencies": { "@types/node": "^18.15.11", diff --git a/package.json b/package.json index bf43ed983..894d361f3 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr155.be01a3f", + "@iqss/dataverse-client-javascript": "2.0.0-pr169.aa49f06", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", diff --git a/src/files/domain/models/FileUploadState.ts b/src/files/domain/models/FileUploadState.ts index 854cb3035..02c5f7051 100644 --- a/src/files/domain/models/FileUploadState.ts +++ b/src/files/domain/models/FileUploadState.ts @@ -17,6 +17,7 @@ export interface FileUploadState { description?: string tags: string[] restricted: boolean + checksumValue?: string } export interface FileUploaderState { @@ -94,6 +95,18 @@ export class FileUploadTools { return { state: oldState.state, uploaded: this.toUploaded(oldState.state) } } + static checksum( + file: File, + checksumValue: string, + oldState: FileUploaderState + ): FileUploaderState { + const fileUploadState = oldState.state.get(this.key(file)) + if (fileUploadState) { + fileUploadState.checksumValue = checksumValue + } + return { state: oldState.state, uploaded: this.toUploaded(oldState.state) } + } + static failed(file: File, oldState: FileUploaderState): FileUploaderState { const fileUploadState = oldState.state.get(this.key(file)) if (fileUploadState) { diff --git a/src/files/domain/repositories/FileRepository.ts b/src/files/domain/repositories/FileRepository.ts index 9c2c30478..772faa58d 100644 --- a/src/files/domain/repositories/FileRepository.ts +++ b/src/files/domain/repositories/FileRepository.ts @@ -43,9 +43,4 @@ export interface FileRepository { storageIdSetter: (storageId: string) => void ) => Promise addUploadedFiles: (datasetId: number | string, files: FileUploadState[]) => Promise - addUploadedFile: ( - datasetId: number | string, - file: FileHolder, - storageId: string - ) => Promise } diff --git a/src/files/domain/useCases/addUploadedFiles.ts b/src/files/domain/useCases/addUploadedFiles.ts index b1ef42065..5d017492b 100644 --- a/src/files/domain/useCases/addUploadedFiles.ts +++ b/src/files/domain/useCases/addUploadedFiles.ts @@ -14,18 +14,3 @@ export function addUploadedFiles( }) .finally(done) } - -export function addUploadedFile( - fileRepository: FileRepository, - datasetId: number | string, - file: File, - storageId: string, - done: () => void -): void { - fileRepository - .addUploadedFile(datasetId, { file: file }, storageId) - .catch((error: Error) => { - throw new Error(error.message) - }) - .finally(done) -} diff --git a/src/files/infrastructure/FileJSDataverseRepository.ts b/src/files/infrastructure/FileJSDataverseRepository.ts index 89d6fea4b..9d1925dd3 100644 --- a/src/files/infrastructure/FileJSDataverseRepository.ts +++ b/src/files/infrastructure/FileJSDataverseRepository.ts @@ -15,7 +15,8 @@ import { getFileDownloadCount, getFileUserPermissions, uploadFile as jsUploadFile, - addUploadedFileToDataset, + addUploadedFilesToDataset, + UploadedFileDTO, ReadError } from '@iqss/dataverse-client-javascript' import { FileCriteria } from '../domain/models/FileCriteria' @@ -301,12 +302,18 @@ export class FileJSDataverseRepository implements FileRepository { }) } - addUploadedFiles(_datasetId: number | string, _files: FileUploadState[]): Promise { - // TODO: not yet implemented - return new Promise(() => {}) - } - - addUploadedFile(datasetId: number | string, file: FileHolder, storageId: string): Promise { - return addUploadedFileToDataset.execute(datasetId, file.file, storageId) + addUploadedFiles(datasetId: number | string, files: FileUploadState[]): Promise { + const uploadedFiles: UploadedFileDTO[] = files.map((x) => ({ + fileName: x.fileName, + description: x.description, + directoryLabel: x.fileDir, + categories: x.tags, + restrict: x.restricted, + storageId: x.storageId as string, + checksumValue: x.checksumValue as string, + checksumType: 'md5', + mimeType: x.fileType + })) + return addUploadedFilesToDataset.execute(datasetId, uploadedFiles) } } diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index 7a21e05ed..cc91c1ef0 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -9,7 +9,7 @@ import { FileUploader } from './FileUploader' import { FileUploadState, FileUploadTools } from '../../files/domain/models/FileUploadState' import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' -import { addUploadedFile, addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' +import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' interface UploadDatasetFilesProps { fileRepository: FileRepository @@ -44,11 +44,18 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat const fileUploadFinished = (file: File) => { const key = FileUploadTools.key(file) - setUploadingToCancelMap((x) => { - x.delete(key) - return x - }) - releaseSemaphore(file) + const reader = new FileReader() + reader.onload = () => { + // const buffer = reader.result as ArrayBuffer + const checksumValue = '???' + FileUploadTools.checksum(file, checksumValue, fileUploaderState) + setUploadingToCancelMap((x) => { + x.delete(key) + return x + }) + releaseSemaphore(file) + } + reader.readAsArrayBuffer(file) } const canUpload = (file: File) => @@ -71,13 +78,6 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat () => { setState(FileUploadTools.done(file, fileUploaderState)) fileUploadFinished(file) - addUploadedFile( - fileRepository, - dataset?.persistentId as string, - file, - FileUploadTools.get(file, fileUploaderState).storageId as string, - () => {} - ) }, () => { setState(FileUploadTools.failed(file, fileUploaderState)) diff --git a/src/stories/file/FileMockRepository.ts b/src/stories/file/FileMockRepository.ts index 48e7064b9..ccc590cb7 100644 --- a/src/stories/file/FileMockRepository.ts +++ b/src/stories/file/FileMockRepository.ts @@ -114,16 +114,4 @@ export class FileMockRepository implements FileRepository { }, FakerHelper.loadingTimout()) }) } - - addUploadedFile( - _datasetId: number | string, - _file: FileHolder, - _storageId: string - ): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve() - }, FakerHelper.loadingTimout()) - }) - } } From c4737b476e14466dc8e10c2662bf4d3ad7bb20b4 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 16 Aug 2024 16:37:05 +0200 Subject: [PATCH 03/28] md5 calculate --- src/sections/upload-dataset-files/UploadDatasetFiles.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index cc91c1ef0..fca3ff5f3 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -10,6 +10,7 @@ import { FileUploadState, FileUploadTools } from '../../files/domain/models/File import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' +import { createHash } from 'crypto' interface UploadDatasetFilesProps { fileRepository: FileRepository @@ -46,9 +47,11 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat const key = FileUploadTools.key(file) const reader = new FileReader() reader.onload = () => { - // const buffer = reader.result as ArrayBuffer - const checksumValue = '???' - FileUploadTools.checksum(file, checksumValue, fileUploaderState) + const buffer = new Uint8Array(reader.result as ArrayBuffer) + const hash = createHash('md5') + hash.update(buffer) + const checksum = hash.digest('hex') + FileUploadTools.checksum(file, checksum, fileUploaderState) setUploadingToCancelMap((x) => { x.delete(key) return x From aa3535443007f87aa0869ce50c34e8b1aab98d4b Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 19 Aug 2024 12:34:46 +0200 Subject: [PATCH 04/28] added crypto-browserify dependency --- package-lock.json | 440 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 4 +- 2 files changed, 436 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0273f4e3a..da58d0f59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,8 @@ "@types/react-dom": "18.0.10", "bootstrap": "5.2.3", "classnames": "2.5.1", + "crypto": "npm:crypto-browserify", + "crypto-browserify": "3.12.0", "html-react-parser": "3.0.16", "i18next": "22.4.9", "i18next-browser-languagedetector": "7.0.1", @@ -17680,6 +17682,21 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -18387,6 +18404,11 @@ "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -18560,12 +18582,117 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "node_modules/browser-assert": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", "dev": true }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/browserify-zlib": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", @@ -18666,6 +18793,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -19269,6 +19401,15 @@ "node": ">=8" } }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", @@ -20467,8 +20608,7 @@ "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" }, "node_modules/cosmiconfig": { "version": "7.0.0", @@ -20486,6 +20626,45 @@ "node": ">=10" } }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -20514,6 +20693,49 @@ "node": ">= 8" } }, + "node_modules/crypto": { + "name": "crypto-browserify", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -21184,6 +21406,15 @@ "node": ">=6" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -21389,6 +21620,21 @@ "readable-stream": "^3.1.1" } }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -21621,6 +21867,25 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz", "integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==" }, + "node_modules/elliptic": { + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", + "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/emittery": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", @@ -22623,6 +22888,15 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/execa": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", @@ -24766,6 +25040,27 @@ "node": ">=0.10.0" } }, + "node_modules/hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -24800,6 +25095,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -31009,6 +31314,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/mdast-util-compact": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", @@ -31696,6 +32011,23 @@ "node": ">=8.6" } }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -31753,6 +32085,16 @@ "node": ">=4" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -33936,6 +34278,22 @@ "node": ">=6" } }, + "node_modules/parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-author": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz", @@ -34172,6 +34530,21 @@ "node": "*" } }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/peek-stream": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", @@ -35022,8 +35395,7 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/process-on-spawn": { "version": "1.0.0", @@ -35207,6 +35579,24 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -35476,6 +35866,23 @@ "url": "https://opencollective.com/ramda" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -37064,6 +37471,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "node_modules/rollup": { "version": "3.29.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.3.tgz", @@ -37154,7 +37570,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -37430,6 +37845,18 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -41903,8 +42330,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", diff --git a/package.json b/package.json index 894d361f3..3b4800fea 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,9 @@ "typescript": "4.9.5", "use-deep-compare": "1.2.1", "vite-plugin-istanbul": "4.0.1", - "web-vitals": "2.1.4" + "web-vitals": "2.1.4", + "crypto-browserify": "3.12.0", + "crypto": "npm:crypto-browserify" }, "scripts": { "start": "vite --base=/spa", From 6e66b3d297ad968449542884476506c8c661fbee Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 19 Aug 2024 13:54:17 +0200 Subject: [PATCH 05/28] changed dependency from crypto-browserify to js-md5 --- package-lock.json | 446 ++-------------------------------------------- package.json | 3 +- 2 files changed, 14 insertions(+), 435 deletions(-) diff --git a/package-lock.json b/package-lock.json index da58d0f59..06e39c388 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,12 +21,11 @@ "@types/react-dom": "18.0.10", "bootstrap": "5.2.3", "classnames": "2.5.1", - "crypto": "npm:crypto-browserify", - "crypto-browserify": "3.12.0", "html-react-parser": "3.0.16", "i18next": "22.4.9", "i18next-browser-languagedetector": "7.0.1", "i18next-http-backend": "2.1.1", + "js-md5": "0.8.3", "lodash": "^4.17.21", "moment-timezone": "0.5.43", "react-bootstrap": "2.7.2", @@ -17682,21 +17681,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -18404,11 +18388,6 @@ "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" - }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -18582,117 +18561,12 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, "node_modules/browser-assert": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", "dev": true }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/browserify-zlib": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", @@ -18793,11 +18667,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" - }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -19401,15 +19270,6 @@ "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", @@ -20608,7 +20468,8 @@ "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true }, "node_modules/cosmiconfig": { "version": "7.0.0", @@ -20626,45 +20487,6 @@ "node": ">=10" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -20693,49 +20515,6 @@ "node": ">= 8" } }, - "node_modules/crypto": { - "name": "crypto-browserify", - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -21406,15 +21185,6 @@ "node": ">=6" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -21620,21 +21390,6 @@ "readable-stream": "^3.1.1" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -21867,25 +21622,6 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz", "integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==" }, - "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/emittery": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", @@ -22888,15 +22624,6 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", @@ -25040,27 +24767,6 @@ "node": ">=0.10.0" } }, - "node_modules/hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -25095,16 +24801,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -29457,6 +29153,11 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/js-md5": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz", + "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==" + }, "node_modules/js-sdsl": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", @@ -31314,16 +31015,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdast-util-compact": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", @@ -32011,23 +31702,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -32085,16 +31759,6 @@ "node": ">=4" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -34278,22 +33942,6 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/parse-author": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz", @@ -34530,21 +34178,6 @@ "node": "*" } }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/peek-stream": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", @@ -35395,7 +35028,8 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, "node_modules/process-on-spawn": { "version": "1.0.0", @@ -35579,24 +35213,6 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -35866,23 +35482,6 @@ "url": "https://opencollective.com/ramda" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -37471,15 +37070,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/rollup": { "version": "3.29.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.3.tgz", @@ -37570,6 +37160,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -37845,18 +37436,6 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -42330,7 +41909,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", diff --git a/package.json b/package.json index 3b4800fea..7fe4d5cec 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,7 @@ "use-deep-compare": "1.2.1", "vite-plugin-istanbul": "4.0.1", "web-vitals": "2.1.4", - "crypto-browserify": "3.12.0", - "crypto": "npm:crypto-browserify" + "js-md5": "0.8.3" }, "scripts": { "start": "vite --base=/spa", From b8560e8b8d99f94ef3d59ce68aba61e662f6b3ab Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 19 Aug 2024 13:56:59 +0200 Subject: [PATCH 06/28] streaming md5 implementation --- .../UploadDatasetFiles.tsx | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index fca3ff5f3..045e1ce1a 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -10,7 +10,7 @@ import { FileUploadState, FileUploadTools } from '../../files/domain/models/File import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' -import { createHash } from 'crypto' +import { md5 } from 'js-md5' interface UploadDatasetFilesProps { fileRepository: FileRepository @@ -44,21 +44,25 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat } const fileUploadFinished = (file: File) => { - const key = FileUploadTools.key(file) - const reader = new FileReader() - reader.onload = () => { - const buffer = new Uint8Array(reader.result as ArrayBuffer) - const hash = createHash('md5') - hash.update(buffer) - const checksum = hash.digest('hex') - FileUploadTools.checksum(file, checksum, fileUploaderState) - setUploadingToCancelMap((x) => { - x.delete(key) - return x + const hash = md5.create() + file + .stream() + .getReader() + .read() + .then((stream) => { + for (const chunk in stream) { + hash.update(chunk) + } + }) + .finally(() => { + const checksum = hash.hex() + FileUploadTools.checksum(file, checksum, fileUploaderState) + setUploadingToCancelMap((x) => { + x.delete(FileUploadTools.key(file)) + return x + }) + releaseSemaphore(file) }) - releaseSemaphore(file) - } - reader.readAsArrayBuffer(file) } const canUpload = (file: File) => From 3af826a473f08fb3d96840d3eb237a99ee6a9ceb Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 19 Aug 2024 16:04:45 +0200 Subject: [PATCH 07/28] fixed md5 calculation --- .../UploadDatasetFiles.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index 045e1ce1a..ad470a80b 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -43,20 +43,28 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat }) } + const fileUploadFailed = (file: File) => { + setUploadingToCancelMap((x) => { + x.delete(FileUploadTools.key(file)) + return x + }) + releaseSemaphore(file) + } + const fileUploadFinished = (file: File) => { const hash = md5.create() - file - .stream() - .getReader() + const reader = file.stream().getReader() + reader .read() - .then((stream) => { - for (const chunk in stream) { - hash.update(chunk) + .then(async function updateHash({ done, value }) { + if (done) { + FileUploadTools.checksum(file, hash.hex(), fileUploaderState) + } else { + hash.update(value) + await updateHash(await reader.read()) } }) .finally(() => { - const checksum = hash.hex() - FileUploadTools.checksum(file, checksum, fileUploaderState) setUploadingToCancelMap((x) => { x.delete(FileUploadTools.key(file)) return x @@ -88,7 +96,7 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat }, () => { setState(FileUploadTools.failed(file, fileUploaderState)) - fileUploadFinished(file) + fileUploadFailed(file) }, (now) => setState(FileUploadTools.progress(file, now, fileUploaderState)), (storageId) => setState(FileUploadTools.storageId(file, storageId, fileUploaderState)) From 5196d69615af4bdf687a9b71abd3f36865e8fe87 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Thu, 22 Aug 2024 15:05:26 +0200 Subject: [PATCH 08/28] integration test preparation --- .../integration/files/FileUpload.spec.ts | 61 +++++++++++++++++++ .../shared/files/FileHelper.ts | 26 ++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/e2e-integration/integration/files/FileUpload.spec.ts diff --git a/tests/e2e-integration/integration/files/FileUpload.spec.ts b/tests/e2e-integration/integration/files/FileUpload.spec.ts new file mode 100644 index 000000000..9a544d7c1 --- /dev/null +++ b/tests/e2e-integration/integration/files/FileUpload.spec.ts @@ -0,0 +1,61 @@ +import { TestsUtils } from '../../shared/TestsUtils' +import { FileJSDataverseRepository } from '../../../../src/files/infrastructure/FileJSDataverseRepository' +import { DatasetJSDataverseRepository } from '../../../../src/dataset/infrastructure/repositories/DatasetJSDataverseRepository' +import { DatasetHelper } from '../../shared/datasets/DatasetHelper' +import { FileHelper } from '../../shared/files/FileHelper' +import { DatasetNonNumericVersion } from '../../../../src/dataset/domain/models/Dataset' + +const fileRepository = new FileJSDataverseRepository() +const datasetRepository = new DatasetJSDataverseRepository() + +describe('DirectUpload', () => { + before(() => { + TestsUtils.setup() + }) + + beforeEach(() => { + TestsUtils.login() + }) + + it('should upload file and add it to the dataset when there is only one destination URL', async () => { + const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( + (datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) + ) + if (!dataset) throw new Error('Dataset not found') + const singlePartFile = FileHelper.createSinglePartFileBlob() + + await DatasetHelper.destroy(dataset.persistentId) + }) + + it('should upload file and add it to the dataset when there are multiple destination URLs', async () => { + const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( + (datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) + ) + if (!dataset) throw new Error('Dataset not found') + const multipartFile = FileHelper.createMultipartFileBlob() + + await DatasetHelper.destroy(dataset.persistentId) + }) + + it('should not finish uploading file to destinations when user cancels immediately and there are multiple destination urls', async () => { + const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( + (datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) + ) + if (!dataset) throw new Error('Dataset not found') + const multipartFile = FileHelper.createMultipartFileBlob() + + await DatasetHelper.destroy(dataset.persistentId) + }) +}) diff --git a/tests/e2e-integration/shared/files/FileHelper.ts b/tests/e2e-integration/shared/files/FileHelper.ts index fbf783dbb..a36958217 100644 --- a/tests/e2e-integration/shared/files/FileHelper.ts +++ b/tests/e2e-integration/shared/files/FileHelper.ts @@ -156,4 +156,30 @@ export class FileHelper extends DataverseApiHelper { static async delete(id: number) { return this.request(`/files/${id}`, 'DELETE') } + + static createSinglePartFileBlob(): File { + try { + return FileHelper.createFileBlobWithSize(1000, 'singlepart-file') + } catch (error) { + throw new Error(`Error while creating test singlepart file`) + } + } + + static createMultipartFileBlob(): File { + try { + return FileHelper.createFileBlobWithSize(1273741824, 'multipart-file') + } catch (error) { + throw new Error(`Error while creating test multipart file`) + } + } + + private static createFileBlobWithSize(fileSizeInBytes: number, fileName: string): File { + const blob = FileHelper.createBlobWithSize(fileSizeInBytes) + return new File([blob], fileName, { type: 'text/plain' }) + } + + private static createBlobWithSize(size: number): Blob { + const arrayBuffer = new ArrayBuffer(size) + return new Blob([arrayBuffer]) + } } From 264771548618c6bf8d23992fbb5cf32789905c21 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Thu, 22 Aug 2024 16:06:57 +0200 Subject: [PATCH 09/28] integration tests --- .../integration/files/FileUpload.spec.ts | 93 ++++++++++++++----- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/tests/e2e-integration/integration/files/FileUpload.spec.ts b/tests/e2e-integration/integration/files/FileUpload.spec.ts index 9a544d7c1..fdbb88303 100644 --- a/tests/e2e-integration/integration/files/FileUpload.spec.ts +++ b/tests/e2e-integration/integration/files/FileUpload.spec.ts @@ -4,6 +4,10 @@ import { DatasetJSDataverseRepository } from '../../../../src/dataset/infrastruc import { DatasetHelper } from '../../shared/datasets/DatasetHelper' import { FileHelper } from '../../shared/files/FileHelper' import { DatasetNonNumericVersion } from '../../../../src/dataset/domain/models/Dataset' +import chaiAsPromised from 'chai-as-promised' + +chai.use(chaiAsPromised) +const expect = chai.expect const fileRepository = new FileJSDataverseRepository() const datasetRepository = new DatasetJSDataverseRepository() @@ -18,43 +22,86 @@ describe('DirectUpload', () => { }) it('should upload file and add it to the dataset when there is only one destination URL', async () => { - const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( - (datasetResponse) => - datasetRepository.getByPersistentId( - datasetResponse.persistentId, - DatasetNonNumericVersion.DRAFT - ) + const dataset = await DatasetHelper.create().then((datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) ) if (!dataset) throw new Error('Dataset not found') + const singlePartFile = FileHelper.createSinglePartFileBlob() + const controller = new AbortController() + let storageId: string | undefined = undefined - await DatasetHelper.destroy(dataset.persistentId) - }) + await fileRepository.uploadFile( + dataset.persistentId, + { file: singlePartFile }, + () => {}, + controller, + (sId) => { + storageId = sId + } + ) + + expect(storageId).to.be.not.undefined - it('should upload file and add it to the dataset when there are multiple destination URLs', async () => { - const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( - (datasetResponse) => - datasetRepository.getByPersistentId( - datasetResponse.persistentId, - DatasetNonNumericVersion.DRAFT - ) + await fileRepository.addUploadedFiles(dataset.persistentId, [ + { + progress: 100, + progressHidden: false, + fileSizeString: '1000 B', + fileSize: 1000, + fileLastModified: 0, + failed: false, + done: true, + removed: false, + fileName: 'test.json', + fileDir: '', + fileType: 'application/json', + key: 'test.json', + tags: ['tag'], + restricted: false, + storageId: storageId, + checksumValue: 'abc123' + } + ]) + + const files = await fileRepository.getAllByDatasetPersistentId( + dataset.persistentId, + dataset.version ) - if (!dataset) throw new Error('Dataset not found') - const multipartFile = FileHelper.createMultipartFileBlob() + expect(files).to.be.not.empty + expect(files[0].name).to.be.equal('test.json') await DatasetHelper.destroy(dataset.persistentId) }) it('should not finish uploading file to destinations when user cancels immediately and there are multiple destination urls', async () => { - const dataset = await DatasetHelper.createWithFiles(FileHelper.createMany(3)).then( - (datasetResponse) => - datasetRepository.getByPersistentId( - datasetResponse.persistentId, - DatasetNonNumericVersion.DRAFT - ) + const dataset = await DatasetHelper.create().then((datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) ) if (!dataset) throw new Error('Dataset not found') + const multipartFile = FileHelper.createMultipartFileBlob() + const controller = new AbortController() + + const upload = fileRepository.uploadFile( + dataset.persistentId, + { file: multipartFile }, + () => {}, + controller, + () => {} + ) + controller.abort() + await upload + .then(() => { + throw new Error('upload succeeded') + }) + .catch(() => {}) await DatasetHelper.destroy(dataset.persistentId) }) From 485671cadd8237f58fd3ec2dd9a7c1084f33b193 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 23 Aug 2024 13:09:32 +0200 Subject: [PATCH 10/28] upload multiple files test case --- .../integration/files/FileUpload.spec.ts | 94 ++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/tests/e2e-integration/integration/files/FileUpload.spec.ts b/tests/e2e-integration/integration/files/FileUpload.spec.ts index fdbb88303..525112957 100644 --- a/tests/e2e-integration/integration/files/FileUpload.spec.ts +++ b/tests/e2e-integration/integration/files/FileUpload.spec.ts @@ -21,7 +21,7 @@ describe('DirectUpload', () => { TestsUtils.login() }) - it('should upload file and add it to the dataset when there is only one destination URL', async () => { + it('should upload file and add it to the dataset', async () => { const dataset = await DatasetHelper.create().then((datasetResponse) => datasetRepository.getByPersistentId( datasetResponse.persistentId, @@ -77,7 +77,97 @@ describe('DirectUpload', () => { await DatasetHelper.destroy(dataset.persistentId) }) - it('should not finish uploading file to destinations when user cancels immediately and there are multiple destination urls', async () => { + it('should upload 2 files and add it to the dataset', async () => { + const dataset = await DatasetHelper.create().then((datasetResponse) => + datasetRepository.getByPersistentId( + datasetResponse.persistentId, + DatasetNonNumericVersion.DRAFT + ) + ) + if (!dataset) throw new Error('Dataset not found') + + const singlePartFile1 = FileHelper.createSinglePartFileBlob() + const singlePartFile2 = FileHelper.createSinglePartFileBlob() + let storageId1: string | undefined = undefined + let storageId2: string | undefined = undefined + + const upload1 = fileRepository.uploadFile( + dataset.persistentId, + { file: singlePartFile1 }, + () => {}, + new AbortController(), + (sId) => { + storageId1 = sId + } + ) + + const upload2 = fileRepository.uploadFile( + dataset.persistentId, + { file: singlePartFile2 }, + () => {}, + new AbortController(), + (sId) => { + storageId2 = sId + } + ) + + await upload1 + await upload2 + + expect(storageId1).to.be.not.undefined + expect(storageId2).to.be.not.undefined + + await fileRepository.addUploadedFiles(dataset.persistentId, [ + { + progress: 100, + progressHidden: false, + fileSizeString: '1000 B', + fileSize: 1000, + fileLastModified: 0, + failed: false, + done: true, + removed: false, + fileName: 'test1.json', + fileDir: '', + fileType: 'application/json', + key: 'test1.json', + tags: ['tag'], + restricted: false, + storageId: storageId1, + checksumValue: 'abc123' + }, + { + progress: 100, + progressHidden: false, + fileSizeString: '1000 B', + fileSize: 1000, + fileLastModified: 0, + failed: false, + done: true, + removed: false, + fileName: 'test2.json', + fileDir: '', + fileType: 'application/json', + key: 'test2.json', + tags: ['tag'], + restricted: false, + storageId: storageId2, + checksumValue: 'def456' + } + ]) + + const files = await fileRepository.getAllByDatasetPersistentId( + dataset.persistentId, + dataset.version + ) + expect(files).to.be.not.empty + expect(files[0].name).to.be.equal('test1.json') + expect(files[1].name).to.be.equal('test2.json') + + await DatasetHelper.destroy(dataset.persistentId) + }) + + it('should not finish uploading file to destinations when user cancels immediately', async () => { const dataset = await DatasetHelper.create().then((datasetResponse) => datasetRepository.getByPersistentId( datasetResponse.persistentId, From fb85e8049a782085f1fab86add7fad91ffa76e21 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 23 Aug 2024 13:28:29 +0200 Subject: [PATCH 11/28] navigate to dataset after upload finished --- src/sections/upload-dataset-files/UploadDatasetFiles.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index ad470a80b..3b94369bd 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -11,6 +11,8 @@ import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' import { md5 } from 'js-md5' +import { useNavigate } from 'react-router-dom' +import { Route } from '../Route.enum' interface UploadDatasetFilesProps { fileRepository: FileRepository @@ -23,6 +25,7 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat const [fileUploaderState, setState] = useState(FileUploadTools.createNewState([])) const [uploadingToCancelMap, setUploadingToCancelMap] = useState(new Map void>()) const [semaphore, setSemaphore] = useState(new Set()) + const navigate = useNavigate() const sleep = (delay: number) => new Promise((res) => setTimeout(res, delay)) const limit = 6 @@ -156,7 +159,10 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat const addFiles = (state: FileUploadState[]) => { setIsLoading(true) - const done = () => setIsLoading(false) + const done = () => { + setIsLoading(false) + navigate(`${Route.UPLOAD_DATASET_FILES}?persistentId=${dataset?.persistentId as string}`) + } addUploadedFiles(fileRepository, dataset?.persistentId as string, state, done) cleanAllState() } From 5566efaaad821ecb048adc73f4c908bb80b402bd Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 23 Aug 2024 13:43:34 +0200 Subject: [PATCH 12/28] navigate to dataset after upload finished --- src/sections/upload-dataset-files/UploadDatasetFiles.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index 3b94369bd..c72153d0f 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -161,7 +161,7 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat setIsLoading(true) const done = () => { setIsLoading(false) - navigate(`${Route.UPLOAD_DATASET_FILES}?persistentId=${dataset?.persistentId as string}`) + navigate(`${Route.DATASETS}?persistentId=${dataset?.persistentId as string}&version=:draft`) } addUploadedFiles(fileRepository, dataset?.persistentId as string, state, done) cleanAllState() From be77c1554021b187179ddd6f4959011b6c629b1b Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 26 Aug 2024 17:14:50 +0200 Subject: [PATCH 13/28] uploaded files DTO refactoring --- src/files/domain/models/FileUploadState.ts | 17 ++++++++++++ .../domain/repositories/FileRepository.ts | 4 +-- src/files/domain/useCases/addUploadedFiles.ts | 4 +-- .../FileJSDataverseRepository.ts | 14 +--------- .../mappers/UploadedFileDTOMapper.ts | 26 +++++++++++++++++++ .../UploadDatasetFiles.tsx | 3 ++- src/stories/file/FileMockRepository.ts | 4 +-- 7 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 src/files/infrastructure/mappers/UploadedFileDTOMapper.ts diff --git a/src/files/domain/models/FileUploadState.ts b/src/files/domain/models/FileUploadState.ts index 02c5f7051..71716fe1d 100644 --- a/src/files/domain/models/FileUploadState.ts +++ b/src/files/domain/models/FileUploadState.ts @@ -1,4 +1,6 @@ +import { UploadedFileDTO } from '@iqss/dataverse-client-javascript' import { FileSize, FileSizeUnit } from './FileMetadata' +import { UploadedFileDTOMapper } from '../../infrastructure/mappers/UploadedFileDTOMapper' export interface FileUploadState { progress: number @@ -140,6 +142,21 @@ export class FileUploadTools { return { state: oldState.state, uploaded: this.toUploaded(oldState.state) } } + static mapToUploadedFilesDTOs(state: FileUploadState[]): UploadedFileDTO[] { + return state.map((uploadedFile) => + UploadedFileDTOMapper.toUploadedFileDTO( + uploadedFile.fileName, + uploadedFile.description, + uploadedFile.fileDir, + uploadedFile.tags, + uploadedFile.restricted, + uploadedFile.storageId as string, + uploadedFile.checksumValue as string, + uploadedFile.fileType + ) + ) + } + private static toNewState( file: File, oldState: FileUploaderState diff --git a/src/files/domain/repositories/FileRepository.ts b/src/files/domain/repositories/FileRepository.ts index 772faa58d..6888bd3a1 100644 --- a/src/files/domain/repositories/FileRepository.ts +++ b/src/files/domain/repositories/FileRepository.ts @@ -7,7 +7,7 @@ import { FilePaginationInfo } from '../models/FilePaginationInfo' import { FilePreview } from '../models/FilePreview' import { FilesWithCount } from '../models/FilesWithCount' import { FileHolder } from '../models/FileHolder' -import { FileUploadState } from '../models/FileUploadState' +import { UploadedFileDTO } from '@iqss/dataverse-client-javascript' export interface FileRepository { getAllByDatasetPersistentId: ( @@ -42,5 +42,5 @@ export interface FileRepository { abortController: AbortController, storageIdSetter: (storageId: string) => void ) => Promise - addUploadedFiles: (datasetId: number | string, files: FileUploadState[]) => Promise + addUploadedFiles: (datasetId: number | string, files: UploadedFileDTO[]) => Promise } diff --git a/src/files/domain/useCases/addUploadedFiles.ts b/src/files/domain/useCases/addUploadedFiles.ts index 5d017492b..2f935aec9 100644 --- a/src/files/domain/useCases/addUploadedFiles.ts +++ b/src/files/domain/useCases/addUploadedFiles.ts @@ -1,10 +1,10 @@ -import { FileUploadState } from '../models/FileUploadState' +import { UploadedFileDTO } from '@iqss/dataverse-client-javascript' import { FileRepository } from '../repositories/FileRepository' export function addUploadedFiles( fileRepository: FileRepository, datasetId: number | string, - files: FileUploadState[], + files: UploadedFileDTO[], done: () => void ): void { fileRepository diff --git a/src/files/infrastructure/FileJSDataverseRepository.ts b/src/files/infrastructure/FileJSDataverseRepository.ts index 9d1925dd3..2b204a17f 100644 --- a/src/files/infrastructure/FileJSDataverseRepository.ts +++ b/src/files/infrastructure/FileJSDataverseRepository.ts @@ -33,7 +33,6 @@ import { FilePermissions } from '../domain/models/FilePermissions' import { JSFilePermissionsMapper } from './mappers/JSFilePermissionsMapper' import { FilesWithCount } from '../domain/models/FilesWithCount' import { FileHolder } from '../domain/models/FileHolder' -import { FileUploadState } from '../domain/models/FileUploadState' const includeDeaccessioned = true @@ -302,18 +301,7 @@ export class FileJSDataverseRepository implements FileRepository { }) } - addUploadedFiles(datasetId: number | string, files: FileUploadState[]): Promise { - const uploadedFiles: UploadedFileDTO[] = files.map((x) => ({ - fileName: x.fileName, - description: x.description, - directoryLabel: x.fileDir, - categories: x.tags, - restrict: x.restricted, - storageId: x.storageId as string, - checksumValue: x.checksumValue as string, - checksumType: 'md5', - mimeType: x.fileType - })) + addUploadedFiles(datasetId: number | string, uploadedFiles: UploadedFileDTO[]): Promise { return addUploadedFilesToDataset.execute(datasetId, uploadedFiles) } } diff --git a/src/files/infrastructure/mappers/UploadedFileDTOMapper.ts b/src/files/infrastructure/mappers/UploadedFileDTOMapper.ts new file mode 100644 index 000000000..238027eba --- /dev/null +++ b/src/files/infrastructure/mappers/UploadedFileDTOMapper.ts @@ -0,0 +1,26 @@ +import { UploadedFileDTO } from '@iqss/dataverse-client-javascript' + +export class UploadedFileDTOMapper { + static toUploadedFileDTO( + fileName: string, + description: string | undefined, + fileDir: string, + tags: string[], + restricted: boolean, + storageId: string, + checksumValue: string, + fileType: string + ): UploadedFileDTO { + return { + fileName: fileName, + description: description, + directoryLabel: fileDir, + categories: tags, + restrict: restricted, + storageId: storageId, + checksumValue: checksumValue, + checksumType: 'md5', + mimeType: fileType + } + } +} diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index c72153d0f..3a937ebea 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -163,7 +163,8 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat setIsLoading(false) navigate(`${Route.DATASETS}?persistentId=${dataset?.persistentId as string}&version=:draft`) } - addUploadedFiles(fileRepository, dataset?.persistentId as string, state, done) + const uploadedFiles = FileUploadTools.mapToUploadedFilesDTOs(state) + addUploadedFiles(fileRepository, dataset?.persistentId as string, uploadedFiles, done) cleanAllState() } diff --git a/src/stories/file/FileMockRepository.ts b/src/stories/file/FileMockRepository.ts index ccc590cb7..9bc8aba55 100644 --- a/src/stories/file/FileMockRepository.ts +++ b/src/stories/file/FileMockRepository.ts @@ -13,7 +13,7 @@ import { FilePreview } from '../../files/domain/models/FilePreview' import { FakerHelper } from '../../../tests/component/shared/FakerHelper' import { FilesWithCount } from '../../files/domain/models/FilesWithCount' import { FileHolder } from '../../files/domain/models/FileHolder' -import { FileUploadState } from '../../files/domain/models/FileUploadState' +import { UploadedFileDTO } from '@iqss/dataverse-client-javascript' export class FileMockRepository implements FileRepository { constructor(public readonly fileMock?: File) {} @@ -107,7 +107,7 @@ export class FileMockRepository implements FileRepository { return res() } - addUploadedFiles(_datasetId: number | string, _files: FileUploadState[]): Promise { + addUploadedFiles(_datasetId: number | string, _files: UploadedFileDTO[]): Promise { return new Promise((resolve) => { setTimeout(() => { resolve() From 6f88ff18e7276e050cf7a48919ae99641cfc0055 Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 26 Aug 2024 17:17:54 +0200 Subject: [PATCH 14/28] moved external libraries imports higher up --- src/sections/upload-dataset-files/UploadDatasetFiles.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index 3a937ebea..df8605905 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' +import { md5 } from 'js-md5' +import { useNavigate } from 'react-router-dom' import { FileRepository } from '../../files/domain/repositories/FileRepository' import { useLoading } from '../loading/LoadingContext' import { useDataset } from '../dataset/DatasetContext' @@ -10,8 +12,6 @@ import { FileUploadState, FileUploadTools } from '../../files/domain/models/File import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' -import { md5 } from 'js-md5' -import { useNavigate } from 'react-router-dom' import { Route } from '../Route.enum' interface UploadDatasetFilesProps { From 288407a3eceea0847eb7100afb2caab88a00b06e Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Mon, 26 Aug 2024 17:21:47 +0200 Subject: [PATCH 15/28] 'then' i.s.o. 'finally' in addUploadedFiles --- src/files/domain/useCases/addUploadedFiles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/files/domain/useCases/addUploadedFiles.ts b/src/files/domain/useCases/addUploadedFiles.ts index 2f935aec9..360a8497a 100644 --- a/src/files/domain/useCases/addUploadedFiles.ts +++ b/src/files/domain/useCases/addUploadedFiles.ts @@ -9,8 +9,8 @@ export function addUploadedFiles( ): void { fileRepository .addUploadedFiles(datasetId, files) + .then(done) .catch((error: Error) => { throw new Error(error.message) }) - .finally(done) } From c4efe453da9bf52c5dd0249ded1c9dcb05db248f Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Tue, 27 Aug 2024 14:32:33 +0200 Subject: [PATCH 16/28] fixed select checkbox problem --- .../uploaded-files-list/UploadedFiles.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sections/upload-dataset-files/uploaded-files-list/UploadedFiles.tsx b/src/sections/upload-dataset-files/uploaded-files-list/UploadedFiles.tsx index afd54715d..0dc60a345 100644 --- a/src/sections/upload-dataset-files/uploaded-files-list/UploadedFiles.tsx +++ b/src/sections/upload-dataset-files/uploaded-files-list/UploadedFiles.tsx @@ -79,14 +79,13 @@ export function UploadedFiles({ updateFiles([file]) } const updateSelected = (file: FileUploadState) => { - setSelected((current) => { - if (current.has(file)) { - current.delete(file) - } else { - current.add(file) - } - return new Set(current) - }) + const newSelected = new Set(selected) + if (newSelected.has(file)) { + newSelected.delete(file) + } else { + newSelected.add(file) + } + setSelected(newSelected) } const save = () => { addFiles(fileUploadState) From c2a27266ba89b9daccbb4529f0eac6d9b6c1a46d Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Wed, 28 Aug 2024 15:26:47 +0200 Subject: [PATCH 17/28] command timeout set to 10 seconds for integration tests --- cypress.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress.config.ts b/cypress.config.ts index 668f4100a..106a068eb 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -15,7 +15,8 @@ export default defineConfig({ supportFile: 'tests/support/e2e.ts', setupNodeEvents(on) { on('file:preprocessor', vitePreprocessor(path.resolve(__dirname, './vite.config.ts'))) - } + }, + defaultCommandTimeout: 10_000 // https://docs.cypress.io/guides/references/configuration#Timeouts }, component: { indexHtmlFile: 'tests/support/component-index.html', From c150ebfc7d0969c8640734e9faaa294053511249 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Wed, 28 Aug 2024 16:15:47 +0200 Subject: [PATCH 18/28] e2e upload file test fix after uploaded file DTO refactoring --- .../integration/files/FileUpload.spec.ts | 72 ++++++++----------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/tests/e2e-integration/integration/files/FileUpload.spec.ts b/tests/e2e-integration/integration/files/FileUpload.spec.ts index 525112957..64b2ed688 100644 --- a/tests/e2e-integration/integration/files/FileUpload.spec.ts +++ b/tests/e2e-integration/integration/files/FileUpload.spec.ts @@ -45,25 +45,21 @@ describe('DirectUpload', () => { ) expect(storageId).to.be.not.undefined + if (storageId == undefined) { + throw new Error('storageId is undefined') + } await fileRepository.addUploadedFiles(dataset.persistentId, [ { - progress: 100, - progressHidden: false, - fileSizeString: '1000 B', - fileSize: 1000, - fileLastModified: 0, - failed: false, - done: true, - removed: false, fileName: 'test.json', - fileDir: '', - fileType: 'application/json', - key: 'test.json', - tags: ['tag'], - restricted: false, + description: 'description text', + directoryLabel: '', + categories: ['tag'], + restrict: false, storageId: storageId, - checksumValue: 'abc123' + checksumValue: 'abc123', + checksumType: 'md5', + mimeType: 'application/json' } ]) @@ -116,43 +112,35 @@ describe('DirectUpload', () => { expect(storageId1).to.be.not.undefined expect(storageId2).to.be.not.undefined + if (storageId1 == undefined) { + throw new Error('storageId1 is undefined') + } + if (storageId2 == undefined) { + throw new Error('storageId2 is undefined') + } await fileRepository.addUploadedFiles(dataset.persistentId, [ { - progress: 100, - progressHidden: false, - fileSizeString: '1000 B', - fileSize: 1000, - fileLastModified: 0, - failed: false, - done: true, - removed: false, fileName: 'test1.json', - fileDir: '', - fileType: 'application/json', - key: 'test1.json', - tags: ['tag'], - restricted: false, + description: 'description text', + directoryLabel: '', + categories: ['tag'], + restrict: false, storageId: storageId1, - checksumValue: 'abc123' + checksumValue: 'abc123', + checksumType: 'md5', + mimeType: 'application/json' }, { - progress: 100, - progressHidden: false, - fileSizeString: '1000 B', - fileSize: 1000, - fileLastModified: 0, - failed: false, - done: true, - removed: false, fileName: 'test2.json', - fileDir: '', - fileType: 'application/json', - key: 'test2.json', - tags: ['tag'], - restricted: false, + description: 'description text', + directoryLabel: '', + categories: ['tag'], + restrict: false, storageId: storageId2, - checksumValue: 'def456' + checksumValue: 'def456', + checksumType: 'md5', + mimeType: 'application/json' } ]) From 5794c4218fae2f5b1c740a9d8e3ade5b42a5dce8 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 15:54:27 +0200 Subject: [PATCH 19/28] hardcoded mime-type to prevent file upload problems --- src/files/domain/models/FileUploadState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/files/domain/models/FileUploadState.ts b/src/files/domain/models/FileUploadState.ts index 71716fe1d..bbc237384 100644 --- a/src/files/domain/models/FileUploadState.ts +++ b/src/files/domain/models/FileUploadState.ts @@ -152,7 +152,7 @@ export class FileUploadTools { uploadedFile.restricted, uploadedFile.storageId as string, uploadedFile.checksumValue as string, - uploadedFile.fileType + 'application/octet-stream' ) ) } From bbcc170141320fc16212aff16a5bf5ac02cd0860 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 19:59:39 +0200 Subject: [PATCH 20/28] replaced the semaphore with the one from async-mutex package and improved upload callback --- package.json | 3 +- .../upload-dataset-files/FileUploader.tsx | 22 ++++-------- .../UploadDatasetFiles.tsx | 35 ++++--------------- 3 files changed, 15 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index 7fe4d5cec..c9b85c66c 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "use-deep-compare": "1.2.1", "vite-plugin-istanbul": "4.0.1", "web-vitals": "2.1.4", - "js-md5": "0.8.3" + "js-md5": "0.8.3", + "async-mutex": "0.5.0" }, "scripts": { "start": "vite --base=/spa", diff --git a/src/sections/upload-dataset-files/FileUploader.tsx b/src/sections/upload-dataset-files/FileUploader.tsx index 2807722a3..01a2e020d 100644 --- a/src/sections/upload-dataset-files/FileUploader.tsx +++ b/src/sections/upload-dataset-files/FileUploader.tsx @@ -1,12 +1,13 @@ import { Button, Card, ProgressBar, useTheme } from '@iqss/dataverse-design-system' import cn from 'classnames' -import { ChangeEventHandler, DragEventHandler, useEffect, useRef, useState } from 'react' +import { ChangeEventHandler, DragEventHandler, useRef, useState } from 'react' import { Plus, X } from 'react-bootstrap-icons' +import { useDeepCompareEffect } from 'use-deep-compare' import { FileUploadTools, FileUploaderState } from '../../files/domain/models/FileUploadState' import styles from './FileUploader.module.scss' export interface FileUploaderProps { - upload: (files: File[]) => void + upload: (file: File) => void cancelTitle: string info: string selectText: string @@ -30,21 +31,14 @@ export function FileUploader({ const addFiles = (selectedFiles: FileList | null) => { if (selectedFiles && selectedFiles.length > 0) { - setFiles((alreadyAdded) => { - const selectedFilesArray = Array.from(selectedFiles) - const selectedFilesSet = new Set(selectedFilesArray.map((x) => FileUploadTools.key(x))) - const alreadyAddedFiltered = alreadyAdded.filter( - /* istanbul ignore next */ - (x) => !selectedFilesSet.has(FileUploadTools.key(x)) - ) - return [...alreadyAddedFiltered, ...selectedFilesArray] - }) + Array.from(selectedFiles).forEach((file) => addFile(file)) } } const addFile = (file: File) => { if (!files.some((x) => FileUploadTools.key(x) === FileUploadTools.key(file))) { setFiles((oldFiles) => [...oldFiles, file]) + upload(file) } } @@ -105,11 +99,7 @@ export function FileUploader({ } } - useEffect(() => { - upload(files) - }, [files, upload]) - - useEffect(() => { + useDeepCompareEffect(() => { setFiles((newFiles) => newFiles.filter((x) => { const res = !FileUploadTools.get(x, fileUploaderState).removed diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index df8605905..0cc1adb25 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { md5 } from 'js-md5' +import { Semaphore } from 'async-mutex' import { useNavigate } from 'react-router-dom' import { FileRepository } from '../../files/domain/repositories/FileRepository' import { useLoading } from '../loading/LoadingContext' @@ -24,34 +25,17 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat const { t } = useTranslation('uploadDatasetFiles') const [fileUploaderState, setState] = useState(FileUploadTools.createNewState([])) const [uploadingToCancelMap, setUploadingToCancelMap] = useState(new Map void>()) - const [semaphore, setSemaphore] = useState(new Set()) const navigate = useNavigate() - const sleep = (delay: number) => new Promise((res) => setTimeout(res, delay)) const limit = 6 - - const acquireSemaphore = async (file: File) => { - const key = FileUploadTools.key(file) - setSemaphore((x) => (x.size >= limit ? x : x.add(key))) - while (!semaphore.has(key)) { - await sleep(500) - setSemaphore((x) => (x.size >= limit ? x : x.add(key))) - } - } - - const releaseSemaphore = (file: File) => { - setSemaphore((x) => { - x.delete(FileUploadTools.key(file)) - return x - }) - } + const semaphore = new Semaphore(limit) const fileUploadFailed = (file: File) => { setUploadingToCancelMap((x) => { x.delete(FileUploadTools.key(file)) return x }) - releaseSemaphore(file) + semaphore.release(1) } const fileUploadFinished = (file: File) => { @@ -72,7 +56,7 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat x.delete(FileUploadTools.key(file)) return x }) - releaseSemaphore(file) + semaphore.release(1) }) } @@ -107,13 +91,9 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat setUploadingToCancelMap((x) => x.set(key, cancel)) } - const upload = async (files: File[]) => { - for (const file of files) { - if (canUpload(file)) { - await acquireSemaphore(file) - uploadOneFile(file) - } - } + const upload = async (file: File) => { + await semaphore.acquire(1) + uploadOneFile(file) } const cleanup = (file: File) => { @@ -126,7 +106,6 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat x.delete(key) return x }) - releaseSemaphore(file) } const cancelUpload = (file: File) => { From c9fc268771bded274a804b643d5fb4dfdd24d3a6 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 20:06:46 +0200 Subject: [PATCH 21/28] hardcoded mime type only if browser did not detect it correctly (empty string) --- src/files/domain/models/FileUploadState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/files/domain/models/FileUploadState.ts b/src/files/domain/models/FileUploadState.ts index bbc237384..074b3f7e5 100644 --- a/src/files/domain/models/FileUploadState.ts +++ b/src/files/domain/models/FileUploadState.ts @@ -152,7 +152,7 @@ export class FileUploadTools { uploadedFile.restricted, uploadedFile.storageId as string, uploadedFile.checksumValue as string, - 'application/octet-stream' + uploadedFile.fileType === '' ? 'application/octet-stream' : uploadedFile.fileType ) ) } From 3aad2bc38e07f4925d9bd82aa9226babd150ac21 Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 20:42:30 +0200 Subject: [PATCH 22/28] removed flaky test --- .../UploadDatasetFiles.spec.tsx | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/tests/component/sections/upload-dataset-files/UploadDatasetFiles.spec.tsx b/tests/component/sections/upload-dataset-files/UploadDatasetFiles.spec.tsx index 7de43e55a..5a30bc95d 100644 --- a/tests/component/sections/upload-dataset-files/UploadDatasetFiles.spec.tsx +++ b/tests/component/sections/upload-dataset-files/UploadDatasetFiles.spec.tsx @@ -217,58 +217,6 @@ describe('UploadDatasetFiles', () => { cy.findByText('Select files to add').should('exist') }) - it('prevents more than 6 simultaneous uploads', () => { - const testDataset = DatasetMother.create() - - mountWithDataset(, testDataset) - - cy.findByTestId('drag-and-drop').as('dnd') - cy.get('@dnd').should('exist') - - const filenames: string[] = [ - 'users1.json', - 'users2.json', - 'users3.json', - 'users4.json', - 'users5.json', - 'users6.json', - 'users7.json', - 'users8.json', - 'users9.json', - 'users10.json' - ] - filenames.forEach((element) => { - cy.get('@dnd').selectFile( - { fileName: element, contents: [{ name: 'John Doe' }] }, - { action: 'drag-drop' } - ) - }) - cy.findAllByTitle('Cancel upload').should('have.length', 10) - cy.findAllByRole('progressbar').should('have.length', 6) - cy.findByText('Select files to add').should('exist') - const filenames2: string[] = [ - 'users11.json', - 'users12.json', - 'users13.json', - 'users14.json', - 'users15.json', - 'users16.json', - 'users17.json', - 'users18.json', - 'users19.json', - 'users20.json' - ] - filenames2.forEach((element) => { - cy.get('@dnd').selectFile( - { fileName: element, contents: [{ name: 'John Doe' }] }, - { action: 'drag-drop' } - ) - }) - cy.findByText('users20.json').should('exist') - cy.findAllByRole('progressbar').should('have.length', 6) - cy.findByText('Select files to add').should('exist') - }) - it('saves uploaded files', () => { const testDataset = DatasetMother.create() From ad60ab2ccf37d0849030fcdf7b520a2c1a6361bc Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 20:43:51 +0200 Subject: [PATCH 23/28] reverted to useEffect i.s.o. effect with deep compare --- src/sections/upload-dataset-files/FileUploader.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sections/upload-dataset-files/FileUploader.tsx b/src/sections/upload-dataset-files/FileUploader.tsx index 01a2e020d..77fbd03b9 100644 --- a/src/sections/upload-dataset-files/FileUploader.tsx +++ b/src/sections/upload-dataset-files/FileUploader.tsx @@ -1,8 +1,7 @@ import { Button, Card, ProgressBar, useTheme } from '@iqss/dataverse-design-system' import cn from 'classnames' -import { ChangeEventHandler, DragEventHandler, useRef, useState } from 'react' +import { ChangeEventHandler, DragEventHandler, useEffect, useRef, useState } from 'react' import { Plus, X } from 'react-bootstrap-icons' -import { useDeepCompareEffect } from 'use-deep-compare' import { FileUploadTools, FileUploaderState } from '../../files/domain/models/FileUploadState' import styles from './FileUploader.module.scss' @@ -99,7 +98,7 @@ export function FileUploader({ } } - useDeepCompareEffect(() => { + useEffect(() => { setFiles((newFiles) => newFiles.filter((x) => { const res = !FileUploadTools.get(x, fileUploaderState).removed From 76f5972186c4112acd5e75e592eb770e6d76032b Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 20:44:53 +0200 Subject: [PATCH 24/28] rename: newFiles -> currentFiles, x -> file --- src/sections/upload-dataset-files/FileUploader.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sections/upload-dataset-files/FileUploader.tsx b/src/sections/upload-dataset-files/FileUploader.tsx index 77fbd03b9..99846397a 100644 --- a/src/sections/upload-dataset-files/FileUploader.tsx +++ b/src/sections/upload-dataset-files/FileUploader.tsx @@ -99,11 +99,11 @@ export function FileUploader({ } useEffect(() => { - setFiles((newFiles) => - newFiles.filter((x) => { - const res = !FileUploadTools.get(x, fileUploaderState).removed + setFiles((currentFiles) => + currentFiles.filter((file) => { + const res = !FileUploadTools.get(file, fileUploaderState).removed if (!res) { - cleanFileState(x) + cleanFileState(file) } return res }) From a30f0fddeef709c865800f4970a741c2ac270f8f Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Fri, 30 Aug 2024 20:49:38 +0200 Subject: [PATCH 25/28] added comment on fileType possibly being an empty string in specific cases --- src/files/domain/models/FileUploadState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/files/domain/models/FileUploadState.ts b/src/files/domain/models/FileUploadState.ts index 074b3f7e5..672e9c42b 100644 --- a/src/files/domain/models/FileUploadState.ts +++ b/src/files/domain/models/FileUploadState.ts @@ -152,7 +152,7 @@ export class FileUploadTools { uploadedFile.restricted, uploadedFile.storageId as string, uploadedFile.checksumValue as string, - uploadedFile.fileType === '' ? 'application/octet-stream' : uploadedFile.fileType + uploadedFile.fileType === '' ? 'application/octet-stream' : uploadedFile.fileType // some browsers (e.g., chromium for .java files) fail to detect the mime type for some files and leave the fileType as an empty string, we use the default value 'application/octet-stream' in that case ) ) } From 1b7eb460999d01855790a618950c9a6821e0c32d Mon Sep 17 00:00:00 2001 From: Eryk Kullikowski Date: Tue, 3 Sep 2024 17:34:01 +0200 Subject: [PATCH 26/28] added a gap between the drop zone and the file list --- .../UploadDatasetFiles.tsx | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx index 0cc1adb25..6846a8a1c 100644 --- a/src/sections/upload-dataset-files/UploadDatasetFiles.tsx +++ b/src/sections/upload-dataset-files/UploadDatasetFiles.tsx @@ -14,6 +14,7 @@ import { uploadFile } from '../../files/domain/useCases/uploadFile' import { UploadedFiles } from './uploaded-files-list/UploadedFiles' import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles' import { Route } from '../Route.enum' +import { Stack } from '@iqss/dataverse-design-system' interface UploadDatasetFilesProps { fileRepository: FileRepository @@ -170,23 +171,25 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat actionItemText={t('breadcrumbActionItem')} />
- - + + + +
)} From cc6da55f6489397d0e68554b58ae83ed19f1dbfa Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Wed, 4 Sep 2024 12:21:27 +0200 Subject: [PATCH 27/28] updated dv js client dependency with PR version fixing the progress bar and content header error --- package-lock.json | 24 ++++++++++++++++++++---- package.json | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fbc1483f..f05688c7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr169.aa49f06", + "@iqss/dataverse-client-javascript": "2.0.0-pr187.a9d8e72", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", @@ -19,6 +19,7 @@ "@types/node": "16.18.12", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", + "async-mutex": "0.5.0", "bootstrap": "5.2.3", "classnames": "2.5.1", "html-react-parser": "3.0.16", @@ -3673,9 +3674,9 @@ }, "node_modules/@iqss/dataverse-client-javascript": { "name": "@IQSS/dataverse-client-javascript", - "version": "2.0.0-pr169.aa49f06", - "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr169.aa49f06/d8061b0af0068e530c6ef78b89e0a4ce668df4b3", - "integrity": "sha512-2D3wxWA87kU8EXltK7pBMGX9OoK7aecX869zbalbdtSNcPz9ATbZOOhDYbfaU+J526AyNTVQ6xlPTY5hWIRFvQ==", + "version": "2.0.0-pr187.a9d8e72", + "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr187.a9d8e72/21e1daf57745e9851e51ecd781a78f19aced307b", + "integrity": "sha512-GmF14/CFpjzJsygiiUDDVr0123feTXSpZM8fMKizjUfXx0cbTEKIjOusL+wysYmXzvIDnap1BpsWcbndg9U2cw==", "license": "MIT", "dependencies": { "@types/node": "^18.15.11", @@ -17816,6 +17817,21 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/async-mutex/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", diff --git a/package.json b/package.json index c9b85c66c..46a11fb4d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr169.aa49f06", + "@iqss/dataverse-client-javascript": "2.0.0-pr187.a9d8e72", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", From f1ff52d832afe1bb1d5275fb49cc680224ae82c6 Mon Sep 17 00:00:00 2001 From: Eryk Kulikowski Date: Wed, 4 Sep 2024 13:15:48 +0200 Subject: [PATCH 28/28] updated dv js client dependency --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index f05688c7b..6af6ac5b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr187.a9d8e72", + "@iqss/dataverse-client-javascript": "2.0.0-pr187.f29c0e6", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", @@ -3674,9 +3674,9 @@ }, "node_modules/@iqss/dataverse-client-javascript": { "name": "@IQSS/dataverse-client-javascript", - "version": "2.0.0-pr187.a9d8e72", - "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr187.a9d8e72/21e1daf57745e9851e51ecd781a78f19aced307b", - "integrity": "sha512-GmF14/CFpjzJsygiiUDDVr0123feTXSpZM8fMKizjUfXx0cbTEKIjOusL+wysYmXzvIDnap1BpsWcbndg9U2cw==", + "version": "2.0.0-pr187.f29c0e6", + "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr187.f29c0e6/324f487a2b1437df668e34159404161888279638", + "integrity": "sha512-0OX9nmh7dY3Gg5euE7buCqTeyh+1B+GhFcDz2gJoND4oM3kIZalYS+bLsEoEekR2o25agP6b+ANyQ5kvZeFuig==", "license": "MIT", "dependencies": { "@types/node": "^18.15.11", diff --git a/package.json b/package.json index 46a11fb4d..446462aaa 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr187.a9d8e72", + "@iqss/dataverse-client-javascript": "2.0.0-pr187.f29c0e6", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2",