diff --git a/src/files/domain/models/File.ts b/src/files/domain/models/File.ts index b6f685c75..c83274844 100644 --- a/src/files/domain/models/File.ts +++ b/src/files/domain/models/File.ts @@ -158,12 +158,13 @@ export class File { readonly labels: FileLabel[], public readonly isDeleted: boolean, public readonly ingest: FileIngest, - readonly checksum?: FileChecksum, + public readonly originalFileDownloadUrl: string, public thumbnail?: string, readonly directory?: string, readonly embargo?: FileEmbargo, readonly tabularData?: FileTabularData, - readonly description?: string + readonly description?: string, + readonly checksum?: FileChecksum ) {} getLink(): string { diff --git a/src/files/domain/repositories/FileRepository.ts b/src/files/domain/repositories/FileRepository.ts index b913a5bb7..976fd5a66 100644 --- a/src/files/domain/repositories/FileRepository.ts +++ b/src/files/domain/repositories/FileRepository.ts @@ -23,5 +23,4 @@ export interface FileRepository { criteria?: FileCriteria ) => Promise getUserPermissionsById: (id: number) => Promise - getOriginalFileById: (id: number) => Promise } diff --git a/src/files/domain/useCases/getFile.ts b/src/files/domain/useCases/getFile.ts deleted file mode 100644 index 96f5f01c7..000000000 --- a/src/files/domain/useCases/getFile.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { FileRepository } from '../repositories/FileRepository' - -export async function getFile( - fileRepository: FileRepository, - id: number -): Promise { - return fileRepository.getOriginalFileById(id).catch((error: Error) => { - throw new Error(error.message) - }) -} diff --git a/src/files/infrastructure/FileJSDataverseRepository.ts b/src/files/infrastructure/FileJSDataverseRepository.ts index fe1328b1d..e16c3c004 100644 --- a/src/files/infrastructure/FileJSDataverseRepository.ts +++ b/src/files/infrastructure/FileJSDataverseRepository.ts @@ -147,20 +147,4 @@ export class FileJSDataverseRepository implements FileRepository { throw new Error(error.message) }) } - - getOriginalFileById(id: number): Promise { - return fetch(`${FileJSDataverseRepository.DATAVERSE_BACKEND_URL}/api/access/datafile/${id}`) - .then((response) => { - if (!response.ok) { - throw new Error('Network response was not ok') - } - return response.blob() - }) - .then((blob) => { - return URL.createObjectURL(blob) - }) - .catch(() => { - return undefined - }) - } } diff --git a/src/files/infrastructure/mappers/JSFileMapper.ts b/src/files/infrastructure/mappers/JSFileMapper.ts index 3956b6d25..4dc167a41 100644 --- a/src/files/infrastructure/mappers/JSFileMapper.ts +++ b/src/files/infrastructure/mappers/JSFileMapper.ts @@ -46,14 +46,15 @@ export class JSFileMapper { this.toFileDate(jsFile.creationDate, jsFile.publicationDate, jsFile.embargo), this.toFileDownloads(), this.toFileLabels(jsFile.categories, jsFile.tabularTags), - false, // TODO - Implement this when it is added to js-dataverse - { status: FileIngestStatus.NONE }, // TODO - Implement this when it is added to js-dataverse - this.toFileChecksum(jsFile.checksum), + false, + { status: FileIngestStatus.NONE }, + this.toFileOriginalFileDownloadUrl(jsFile.id), this.toFileThumbnail(), this.toFileDirectory(jsFile.directoryLabel), this.toFileEmbargo(jsFile.embargo), this.toFileTabularData(), - this.toFileDescription(jsFile.description) + this.toFileDescription(jsFile.description), + this.toFileChecksum(jsFile.checksum) ) } @@ -159,6 +160,10 @@ export class JSFileMapper { return undefined } + static toFileOriginalFileDownloadUrl(id: number): string { + return `/api/access/datafile/${id}` + } + static toFileThumbnail(): undefined { return undefined // This is always undefined because the thumbnails come from a different endpoint } diff --git a/src/sections/dataset/DatasetFactory.tsx b/src/sections/dataset/DatasetFactory.tsx index e303cc1c0..1ac3e1e15 100644 --- a/src/sections/dataset/DatasetFactory.tsx +++ b/src/sections/dataset/DatasetFactory.tsx @@ -11,7 +11,6 @@ import { SettingJSDataverseRepository } from '../../settings/infrastructure/Sett import { FilePermissionsProvider } from '../file/file-permissions/FilePermissionsProvider' import { SettingsProvider } from '../settings/SettingsProvider' import { DatasetProvider } from './DatasetProvider' -import { FileDownloadHelperProvider } from '../file/file-download-helper/FileDownloadHelperProvider' const datasetRepository = new DatasetJSDataverseRepository() const fileRepository = new FileJSDataverseRepository() @@ -21,17 +20,15 @@ const settingRepository = new SettingJSDataverseRepository() export class DatasetFactory { static create(): ReactElement { return ( - - - - - - - - - - - + + + + + + + + + ) } } diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx index 12a624318..e26049dab 100644 --- a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx @@ -3,7 +3,6 @@ import FileTypeToFriendlyTypeMap from '../../../../../../../../files/domain/mode import { DropdownButtonItem } from '@iqss/dataverse-design-system' import { useDataset } from '../../../../../../DatasetContext' import { useTranslation } from 'react-i18next' -import { useFileDownload } from '../../../../../../../file/file-download-helper/useFileDownload' interface FileNonTabularDownloadOptionsProps { file: File @@ -12,7 +11,6 @@ interface FileNonTabularDownloadOptionsProps { export function FileNonTabularDownloadOptions({ file }: FileNonTabularDownloadOptionsProps) { const { t } = useTranslation('files') const { dataset } = useDataset() - const { originalFile } = useFileDownload(file.id) const originalFileFormatIsKnown = file.type.toDisplayFormat() !== FileTypeToFriendlyTypeMap.unknown @@ -22,7 +20,7 @@ export function FileNonTabularDownloadOptions({ file }: FileNonTabularDownloadOp return ( Promise -} - -export const FileDownloadHelperContext = createContext({ - download: () => Promise.reject('Not implemented') -}) - -export const useFileDownloadHelper = () => useContext(FileDownloadHelperContext) diff --git a/src/sections/file/file-download-helper/FileDownloadHelperProvider.tsx b/src/sections/file/file-download-helper/FileDownloadHelperProvider.tsx deleted file mode 100644 index a2006db8a..000000000 --- a/src/sections/file/file-download-helper/FileDownloadHelperProvider.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { FileRepository } from '../../../files/domain/repositories/FileRepository' -import { PropsWithChildren } from 'react' -import { getFile } from '../../../files/domain/useCases/getFile' -import { FileDownloadHelperContext } from './FileDownloadHelperContext' - -interface FileDownloadProviderProps { - repository: FileRepository -} - -export function FileDownloadHelperProvider({ - repository, - children -}: PropsWithChildren) { - const download = (id: number): Promise => { - return getFile(repository, id) - } - - return ( - - {children} - - ) -} diff --git a/src/sections/file/file-download-helper/useFileDownload.tsx b/src/sections/file/file-download-helper/useFileDownload.tsx deleted file mode 100644 index 22cb7d418..000000000 --- a/src/sections/file/file-download-helper/useFileDownload.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useEffect, useState } from 'react' -import { useFileDownloadHelper } from './FileDownloadHelperContext' - -export function useFileDownload(id: number) { - const { download } = useFileDownloadHelper() - const [originalFile, setOriginalFile] = useState() - - useEffect(() => { - download(id) - .then((downloadedFile) => { - setOriginalFile(downloadedFile) - }) - .catch((error) => { - console.error('There was an error downloading the file', error) - }) - }, [id]) - - return { originalFile } -} diff --git a/src/stories/dataset/dataset-citation/DatasetCitation.stories.tsx b/src/stories/dataset/dataset-citation/DatasetCitation.stories.tsx index dc89d2f59..cd7d511d4 100644 --- a/src/stories/dataset/dataset-citation/DatasetCitation.stories.tsx +++ b/src/stories/dataset/dataset-citation/DatasetCitation.stories.tsx @@ -34,7 +34,6 @@ export const Default: Story = { export const WithThumbnail: Story = { render: () => { const dataset = DatasetMother.createRealistic({ thumbnail: faker.image.imageUrl() }) - console.log(dataset) return (


diff --git a/src/stories/files/FileMockLoadingRepository.ts b/src/stories/files/FileMockLoadingRepository.ts index 318631d86..eff4bd897 100644 --- a/src/stories/files/FileMockLoadingRepository.ts +++ b/src/stories/files/FileMockLoadingRepository.ts @@ -57,13 +57,4 @@ export class FileMockLoadingRepository implements FileRepository { }, 1000) }) } - - // eslint-disable-next-line unused-imports/no-unused-vars - getOriginalFileById(id: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(undefined) - }, 1000) - }) - } } diff --git a/src/stories/files/FileMockNoDataRepository.ts b/src/stories/files/FileMockNoDataRepository.ts index 2b8ff7b41..ba7c10a3b 100644 --- a/src/stories/files/FileMockNoDataRepository.ts +++ b/src/stories/files/FileMockNoDataRepository.ts @@ -57,13 +57,4 @@ export class FileMockNoDataRepository implements FileRepository { }, 1000) }) } - - // eslint-disable-next-line unused-imports/no-unused-vars - getOriginalFileById(id: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(undefined) - }, 1000) - }) - } } diff --git a/src/stories/files/FileMockNoFiltersRepository.ts b/src/stories/files/FileMockNoFiltersRepository.ts index aab3eb69b..eec689eaa 100644 --- a/src/stories/files/FileMockNoFiltersRepository.ts +++ b/src/stories/files/FileMockNoFiltersRepository.ts @@ -7,7 +7,6 @@ import { FileUserPermissions } from '../../files/domain/models/FileUserPermissio import { FileUserPermissionsMother } from '../../../tests/component/files/domain/models/FileUserPermissionsMother' import { DatasetVersion } from '../../dataset/domain/models/Dataset' import { FileCriteria } from '../../files/domain/models/FileCriteria' -import { FileMother } from '../../../tests/component/files/domain/models/FileMother' export class FileMockNoFiltersRepository implements FileRepository { getAllByDatasetPersistentId( @@ -60,13 +59,4 @@ export class FileMockNoFiltersRepository implements FileRepository { }, 1000) }) } - - // eslint-disable-next-line unused-imports/no-unused-vars - getOriginalFileById(id: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(FileMother.createToDownload()) - }, 1000) - }) - } } diff --git a/src/stories/files/FileMockRepository.ts b/src/stories/files/FileMockRepository.ts index 79d27aaed..63e1499fa 100644 --- a/src/stories/files/FileMockRepository.ts +++ b/src/stories/files/FileMockRepository.ts @@ -8,7 +8,6 @@ import { FileUserPermissionsMother } from '../../../tests/component/files/domain import { FileUserPermissions } from '../../files/domain/models/FileUserPermissions' import { DatasetVersion } from '../../dataset/domain/models/Dataset' import { FileCriteria } from '../../files/domain/models/FileCriteria' -import { FileMother } from '../../../tests/component/files/domain/models/FileMother' export class FileMockRepository implements FileRepository { // eslint-disable-next-line unused-imports/no-unused-vars @@ -60,13 +59,4 @@ export class FileMockRepository implements FileRepository { }, 1000) }) } - - // eslint-disable-next-line unused-imports/no-unused-vars - getOriginalFileById(id: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(FileMother.createToDownload()) - }, 1000) - }) - } } diff --git a/tests/component/files/domain/models/FileMother.ts b/tests/component/files/domain/models/FileMother.ts index 239d1dcaf..0b9b523ad 100644 --- a/tests/component/files/domain/models/FileMother.ts +++ b/tests/component/files/domain/models/FileMother.ts @@ -124,6 +124,7 @@ export class FileMother { description: valueOrUndefined(faker.lorem.paragraph()), isDeleted: faker.datatype.boolean(), ingest: { status: FileIngestStatus.NONE }, + originalFileDownloadUrl: this.createOriginalFileDownloadUrl(), ...props } @@ -139,16 +140,17 @@ export class FileMother { fileMockedData.labels, fileMockedData.isDeleted, fileMockedData.ingest, - fileMockedData.checksum, + fileMockedData.originalFileDownloadUrl, fileMockedData.thumbnail, fileMockedData.directory, fileMockedData.embargo, fileMockedData.tabularData, - fileMockedData.description + fileMockedData.description, + fileMockedData.checksum ) } - static createToDownload(): string { + static createOriginalFileDownloadUrl(): string { const blob = new Blob(['Name,Age,Location\nJohn,25,New York\nJane,30,San Francisco'], { type: 'text/csv' }) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx index 0c8d299cb..c8cc64737 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx @@ -17,7 +17,7 @@ describe('FileDownloadOptions', () => { it('renders the download options for a non-tabular file', () => { cy.customMount() - cy.findByRole('button', { name: 'Plain Text' }).should('exist') + cy.findByRole('link', { name: 'Plain Text' }).should('exist') }) it('renders the download options for a tabular file', () => { diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx index 1c3babc91..2fad88bc1 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx @@ -10,8 +10,6 @@ import { DatasetLockMother, DatasetMother } from '../../../../../../../../dataset/domain/models/DatasetMother' -import { FileDownloadHelperProvider } from '../../../../../../../../../../src/sections/file/file-download-helper/FileDownloadHelperProvider' -import { FileRepository } from '../../../../../../../../../../src/files/domain/repositories/FileRepository' const fileNonTabular = FileMother.create({ tabularData: undefined, @@ -25,25 +23,27 @@ describe('FileNonTabularDownloadOptions', () => { }) cy.customMount() - cy.findByRole('button', { name: 'Original File Format' }) + cy.findByRole('link', { name: 'Original File Format' }) .should('exist') .should('not.have.class', 'disabled') + .should('have.attr', 'href', fileNonTabularUnknown.originalFileDownloadUrl) }) it('renders the download options for a non-tabular file', () => { cy.customMount() - cy.findByRole('button', { name: 'Plain Text' }) + cy.findByRole('link', { name: 'Plain Text' }) .should('exist') .should('not.have.class', 'disabled') + .should('have.attr', 'href', fileNonTabular.originalFileDownloadUrl) }) it('does not render the download options for a tabular file', () => { const fileTabular = FileMother.createWithTabularData() cy.customMount() - cy.findByRole('button', { name: 'Original File Format' }).should('not.exist') - cy.findByRole('button', { name: 'Tab-Delimited' }).should('not.exist') + cy.findByRole('link', { name: 'Original File Format' }).should('not.exist') + cy.findByRole('link', { name: 'Tab-Delimited' }).should('not.exist') }) it('renders the options as disabled when the file ingest is in progress', () => { @@ -56,7 +56,7 @@ describe('FileNonTabularDownloadOptions', () => { }) cy.customMount() - cy.findByRole('button', { name: 'Plain Text' }).should('have.class', 'disabled') + cy.findByRole('link', { name: 'Plain Text' }).should('have.class', 'disabled') }) it('renders the options as disabled when the dataset is locked from file download', () => { @@ -74,20 +74,6 @@ describe('FileNonTabularDownloadOptions', () => { ) - cy.findByRole('button', { name: 'Plain Text' }).should('have.class', 'disabled') - }) - - it('calls the file repository to get the original file', () => { - const fileRepository: FileRepository = {} as FileRepository - const fileToDownload = FileMother.createToDownload() - fileRepository.getOriginalFileById = cy.stub().resolves(fileToDownload) - - cy.customMount( - - - - ) - - cy.wrap(fileRepository.getOriginalFileById).should('be.calledOnceWith', fileNonTabular.id) + cy.findByRole('link', { name: 'Plain Text' }).should('have.class', 'disabled') }) }) diff --git a/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts index 9133904e0..47bf0b851 100644 --- a/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts +++ b/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts @@ -36,36 +36,39 @@ const fileRepository = new FileJSDataverseRepository() const datasetRepository = new DatasetJSDataverseRepository() const dateNow = new Date() dateNow.setHours(2, 0, 0, 0) -const expectedFile = new File( - 1, - { number: 1, publishingStatus: FilePublishingStatus.DRAFT }, - 'blob', - { - restricted: false, - latestVersionRestricted: false, - canBeRequested: false, - requested: false - }, - new FileType('text/plain'), - new FileSize(25, FileSizeUnit.BYTES), - { - type: FileDateType.DEPOSITED, - date: dateNow - }, - 0, - [], - false, - { status: FileIngestStatus.NONE }, - { - algorithm: 'MD5', - value: '0187a54071542738aa47939e8218e5f2' - }, - undefined, - undefined, - undefined, - undefined, - 'This is an example file' -) +const fileData = (id: number) => { + return new File( + id, + { number: 1, publishingStatus: FilePublishingStatus.DRAFT }, + 'blob', + { + restricted: false, + latestVersionRestricted: false, + canBeRequested: false, + requested: false + }, + new FileType('text/plain'), + new FileSize(25, FileSizeUnit.BYTES), + { + type: FileDateType.DEPOSITED, + date: dateNow + }, + 0, + [], + false, + { status: FileIngestStatus.NONE }, + `/api/access/datafile/${id}`, + undefined, + undefined, + undefined, + undefined, + 'This is an example file', + { + algorithm: 'MD5', + value: '0187a54071542738aa47939e8218e5f2' + } + ) +} describe('File JSDataverse Repository', () => { before(() => { @@ -87,6 +90,7 @@ describe('File JSDataverse Repository', () => { .then((files) => { files.forEach((file, index) => { const expectedFileNames = ['blob', 'blob-1', 'blob-2'] + const expectedFile = fileData(file.id) expect(file.name).to.deep.equal(expectedFileNames[index]) expect(file.version).to.deep.equal(expectedFile.version) expect(file.access).to.deep.equal(expectedFile.access) @@ -100,6 +104,7 @@ describe('File JSDataverse Repository', () => { expect(file.embargo).to.deep.equal(expectedFile.embargo) expect(file.tabularData).to.deep.equal(expectedFile.tabularData) expect(file.description).to.deep.equal(expectedFile.description) + expect(file.originalFileDownloadUrl).to.deep.equal(expectedFile.originalFileDownloadUrl) }) }) }) @@ -145,13 +150,13 @@ describe('File JSDataverse Repository', () => { ) ) .then((files) => { - const expectedPublishedFile = expectedFile + const expectedPublishedFile = fileData(files[0].id) expectedPublishedFile.version.publishingStatus = FilePublishingStatus.RELEASED expectedPublishedFile.date.type = FileDateType.PUBLISHED files.forEach((file) => { expect(file.version).to.deep.equal(expectedPublishedFile.version) - cy.compareDate(file.date.date, expectedFile.date.date) + cy.compareDate(file.date.date, fileData(file.id).date.date) }) }) }) @@ -184,7 +189,7 @@ describe('File JSDataverse Repository', () => { ) ) .then((files) => { - const expectedDeaccessionedFile = expectedFile + const expectedDeaccessionedFile = fileData(files[0].id) expectedDeaccessionedFile.version.publishingStatus = FilePublishingStatus.DEACCESSIONED files.forEach((file) => { @@ -735,34 +740,4 @@ describe('File JSDataverse Repository', () => { }) }) }) - - describe('getOriginalFileById', () => { - it('gets the original file by id', async () => { - const file = FileHelper.create('csv', { - description: 'Some description', - categories: ['category'], - tabIngest: 'true' - }) - const dataset = await DatasetHelper.createWithFiles([file]).then((datasetResponse) => - datasetRepository.getByPersistentId(datasetResponse.persistentId) - ) - if (!dataset) throw new Error('Dataset not found') - - await TestsUtils.wait(2500) // wait for the files to be ingested - - const files = await fileRepository.getAllByDatasetPersistentId( - dataset.persistentId, - dataset.version - ) - - await fileRepository - .getOriginalFileById(files[0].id) - .then((originalFile) => { - expect(originalFile).to.not.be.undefined - }) - .catch((error) => { - throw error - }) - }) - }) })