diff --git a/dev.Dockerfile b/dev.Dockerfile index 5e474faf8..fb0b8ee2e 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -10,6 +10,7 @@ RUN npm run build WORKDIR /usr/src/app COPY package.json ./ +COPY package-lock.json ./ COPY .npmrc ./ RUN npm install diff --git a/package-lock.json b/package-lock.json index 07dff0099..a73e91aca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "i18next": "22.4.9", "i18next-browser-languagedetector": "7.0.1", "i18next-http-backend": "2.1.1", - "moment-timezone": "^0.5.43", + "moment-timezone": "0.5.43", "react-bootstrap": "2.7.2", "react-bootstrap-icons": "1.10.3", "react-i18next": "12.1.5", diff --git a/package.json b/package.json index 7de72ef50..af7cf0bdb 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "i18next": "22.4.9", "i18next-browser-languagedetector": "7.0.1", "i18next-http-backend": "2.1.1", - "moment-timezone": "^0.5.43", + "moment-timezone": "0.5.43", "react-bootstrap": "2.7.2", "react-bootstrap-icons": "1.10.3", "react-i18next": "12.1.5", diff --git a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts index d4475c287..be6f7ce1c 100644 --- a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts +++ b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts @@ -4,6 +4,7 @@ import { DatasetMetadataBlocks as JSDatasetMetadataBlocks, DatasetMetadataFields as JSDatasetMetadataFields, DatasetVersionInfo as JSDatasetVersionInfo, + DatasetUserPermissions as JSDatasetPermissions, DatasetLock as JSDatasetLock } from '@iqss/dataverse-client-javascript' import { DatasetVersionState as JSDatasetVersionState } from '@iqss/dataverse-client-javascript/dist/datasets/domain/models/Dataset' @@ -15,9 +16,10 @@ import { DatasetMetadataFields, DatasetVersion, MetadataBlockName, - PrivateUrl, + DatasetPermissions, DatasetLock, - DatasetLockReason + DatasetLockReason, + PrivateUrl } from '../../domain/models/Dataset' export class JSDatasetMapper { @@ -25,6 +27,7 @@ export class JSDatasetMapper { jsDataset: JSDataset, citation: string, summaryFieldsNames: string[], + jsDatasetPermissions: JSDatasetPermissions, jsDatasetLocks: JSDatasetLock[], requestedVersion?: string, privateUrl?: PrivateUrl @@ -41,19 +44,11 @@ export class JSDatasetMapper { jsDataset.publicationDate, jsDataset.citationDate ), - { - canDownloadFiles: true, - canUpdateDataset: true, - canPublishDataset: true, - canManageDatasetPermissions: true, - canManageFilesPermissions: true, - canDeleteDataset: true - }, // TODO Connect with dataset permissions + JSDatasetMapper.toDatasetPermissions(jsDatasetPermissions), JSDatasetMapper.toLocks(jsDatasetLocks), true, // TODO Connect with dataset hasValidTermsOfAccess true, // TODO Connect with dataset isValid - jsDataset.versionInfo.releaseTime !== undefined && - !isNaN(jsDataset.versionInfo.releaseTime.getTime()), // TODO Connect with dataset isReleased, + JSDatasetMapper.toIsReleased(jsDataset.versionInfo), undefined, // TODO: get dataset thumbnail from Dataverse https://github.com/IQSS/dataverse-frontend/issues/203 privateUrl ).build() @@ -190,6 +185,23 @@ export class JSDatasetMapper { return extraFields } + static toIsReleased(jsDatasetVersionInfo: JSDatasetVersionInfo): boolean { + return ( + jsDatasetVersionInfo.releaseTime !== undefined && + !isNaN(jsDatasetVersionInfo.releaseTime.getTime()) + ) + } + + static toDatasetPermissions(jsDatasetPermissions: JSDatasetPermissions): DatasetPermissions { + return { + canDownloadFiles: true, // TODO: connect with js-dataverse + canUpdateDataset: jsDatasetPermissions.canEditDataset, + canPublishDataset: jsDatasetPermissions.canPublishDataset, + canManageDatasetPermissions: jsDatasetPermissions.canManageDatasetPermissions, + canManageFilesPermissions: true, // TODO: connect with js-dataverse DatasetPermissions.canManageFilesPermissions + canDeleteDataset: jsDatasetPermissions.canManageDatasetPermissions + } + } static toLocks(jsDatasetLocks: JSDatasetLock[]): DatasetLock[] { return jsDatasetLocks.map((jsDatasetLock) => { return { diff --git a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts index 239724296..2b624ca35 100644 --- a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts +++ b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts @@ -5,8 +5,10 @@ import { getDatasetCitation, getDatasetSummaryFieldNames, Dataset as JSDataset, + DatasetUserPermissions as JSDatasetPermissions, getPrivateUrlDataset, getPrivateUrlDatasetCitation, + getDatasetUserPermissions, ReadError, getDatasetLocks, DatasetLock as JSDatasetLock @@ -26,20 +28,23 @@ export class DatasetJSDataverseRepository implements DatasetRepository { jsDataset, getDatasetSummaryFieldNames.execute(), getDatasetCitation.execute(jsDataset.id, this.versionToVersionId(version)), + getDatasetUserPermissions.execute(jsDataset.id), getDatasetLocks.execute(jsDataset.id) ]) ) .then( - ([jsDataset, summaryFieldsNames, citation, jsDatasetLocks]: [ + ([jsDataset, summaryFieldsNames, citation, jsDatasetPermissions, jsDatasetLocks]: [ JSDataset, string[], string, + JSDatasetPermissions, JSDatasetLock[] ]) => JSDatasetMapper.toDataset( jsDataset, citation, summaryFieldsNames, + jsDatasetPermissions, jsDatasetLocks, requestedVersion ) @@ -57,10 +62,22 @@ export class DatasetJSDataverseRepository implements DatasetRepository { getPrivateUrlDataset.execute(privateUrlToken), getDatasetSummaryFieldNames.execute(), getPrivateUrlDatasetCitation.execute(privateUrlToken) - ]) // TODO - Add getDatasetLocks.execute(privateUrlToken) when it is available in js-dataverse + ]) .then(([jsDataset, summaryFieldsNames, citation]: [JSDataset, string[], string]) => - JSDatasetMapper.toDataset(jsDataset, citation, summaryFieldsNames, []) - ) + JSDatasetMapper.toDataset( + jsDataset, + citation, + summaryFieldsNames, + { + canEditDataset: true, + canPublishDataset: true, + canManageDatasetPermissions: true, + canDeleteDatasetDraft: true, + canViewUnpublishedDataset: true + }, + [] + ) + ) // TODO Connect with JS dataset permissions and getDatasetLocks.execute(privateUrlToken) when it is available in js-dataverse .catch((error: ReadError) => { throw new Error(error.message) }) diff --git a/src/settings/infrastructure/SettingJSDataverseRepository.ts b/src/settings/infrastructure/SettingJSDataverseRepository.ts index eb5801de7..e55e995fe 100644 --- a/src/settings/infrastructure/SettingJSDataverseRepository.ts +++ b/src/settings/infrastructure/SettingJSDataverseRepository.ts @@ -9,11 +9,33 @@ export class SettingJSDataverseRepository implements SettingRepository { // TODO - implement using js-dataverse return new Promise((resolve) => { setTimeout(() => { - resolve({ - name: SettingName.ZIP_DOWNLOAD_LIMIT, - value: new ZipDownloadLimit(1, FileSizeUnit.BYTES) - } as Setting) + resolve(mockedSettingResponse(name)) }, 1000) }) } } + +function mockedSettingResponse(name: SettingName): Setting { + switch (name) { + case SettingName.ZIP_DOWNLOAD_LIMIT: + return { + name: SettingName.ZIP_DOWNLOAD_LIMIT, + value: new ZipDownloadLimit(1, FileSizeUnit.BYTES) + } as Setting + case SettingName.ALLOWED_EXTERNAL_STATUSES: + return { + name: SettingName.ALLOWED_EXTERNAL_STATUSES, + value: [ + 'Author Contacted', + 'Privacy Review', + 'Awaiting Paper Publication', + 'Final Approval' + ] + } as Setting + case SettingName.HAS_PUBLIC_STORE: + return { + name: SettingName.HAS_PUBLIC_STORE, + value: false + } as Setting + } +} diff --git a/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts index 201e89754..ed3a65b19 100644 --- a/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts +++ b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts @@ -56,6 +56,13 @@ const jsDataset = { const citation = 'Finch, Fiona, 2023, "Darwin\'s Finches", https://doi.org/10.5072/FK2/B4B2MJ, Root, DRAFT VERSION' const datasetSummaryFields = ['dsDescription', 'subject', 'keyword', 'publication', 'notesText'] +const jsDatasetPermissions = { + canEditDataset: true, + canPublishDataset: true, + canManageDatasetPermissions: true, + canDeleteDatasetDraft: true, + canViewUnpublishedDataset: true +} const jsDatasetLocks: JSDatasetLock[] = [ { lockType: DatasetLockType.IN_REVIEW, @@ -234,6 +241,7 @@ describe('JS Dataset Mapper', () => { jsDataset, citation, datasetSummaryFields, + jsDatasetPermissions, jsDatasetLocks ) expect(expectedDataset).to.deep.equal(mapped) @@ -243,6 +251,7 @@ describe('JS Dataset Mapper', () => { jsDataset, citation, datasetSummaryFields, + jsDatasetPermissions, jsDatasetLocks, '4.0' ) @@ -284,6 +293,7 @@ describe('JS Dataset Mapper', () => { jsDatasetWithAlternativePersistentId, citation, datasetSummaryFields, + jsDatasetPermissions, jsDatasetLocks ) ) @@ -323,6 +333,7 @@ describe('JS Dataset Mapper', () => { jsDatasetWithCitationDate, citation, datasetSummaryFields, + jsDatasetPermissions, jsDatasetLocks ) ) @@ -361,6 +372,7 @@ describe('JS Dataset Mapper', () => { jsDatasetWithPublicationDate, citation, datasetSummaryFields, + jsDatasetPermissions, jsDatasetLocks ) ) diff --git a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx index bcaa94aad..53dfc1f8f 100644 --- a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx +++ b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx @@ -29,10 +29,38 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label + cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') cy.findByText('Metadata').should('exist') cy.findByText('Files').should('exist') + + cy.findByRole('button', { name: 'Edit Dataset' }).should('exist').click() + cy.findByRole('button', { name: 'Permissions' }).should('exist').click() + cy.findByRole('button', { name: 'Dataset' }).should('exist') + cy.findByRole('button', { name: 'Delete Dataset' }).should('exist') + cy.findByRole('button', { name: 'Publish Dataset' }).should('exist') + }) + }) + }) + + it('successfully loads a published dataset when the user is not authenticated', () => { + cy.wrap(DatasetHelper.create().then((dataset) => DatasetHelper.publish(dataset.persistentId))) + .its('persistentId') + .then((persistentId: string) => { + cy.wrap(TestsUtils.logout()) + cy.wait(1500) // Wait for the dataset to be published + cy.visit(`/spa/datasets?persistentId=${persistentId}`) + + cy.fixture('dataset-finch1.json').then((dataset: Dataset) => { + cy.findByRole('heading', { + name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value + }).should('exist') + + cy.findByRole('button', { name: 'Edit Dataset' }).should('not.exist') + cy.findByRole('button', { name: 'Publish Dataset' }).should('not.exist') + cy.findByRole('button', { name: 'Upload Files' }).should('not.exist') + cy.findByText('Metadata').should('exist') + cy.findByText('Files').should('exist') }) }) }) @@ -52,7 +80,7 @@ describe('Dataset', () => { cy.wrap(DatasetHelper.create().then((dataset) => DatasetHelper.publish(dataset.persistentId))) .its('persistentId') .then((persistentId: string) => { - cy.wait(1500) + cy.wait(1500) // Wait for the dataset to be published cy.visit(`/spa/datasets?persistentId=${persistentId}&version=1.0`) cy.fixture('dataset-finch1.json').then((dataset: Dataset) => { @@ -60,7 +88,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('not.exist') - // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('not.exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label + cy.findByText(DatasetLabelValue.UNPUBLISHED).should('not.exist') cy.findByText('Version 1.0').should('exist') }) }) @@ -100,7 +128,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label + cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') }) }) }) @@ -120,7 +148,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label + cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') cy.findAllByText('withheld').should('exist') }) diff --git a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts index 4c9d47929..1230aeeb8 100644 --- a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts +++ b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts @@ -82,6 +82,14 @@ const datasetData = (persistentId: string, versionId: number) => { isLatest: true, isInReview: false }, + permissions: { + canDownloadFiles: true, + canUpdateDataset: true, + canPublishDataset: true, + canManageDatasetPermissions: true, + canManageFilesPermissions: true, + canDeleteDataset: true + }, locks: [] } } @@ -102,17 +110,60 @@ describe('Dataset JSDataverse Repository', () => { expect(dataset.getTitle()).to.deep.equal(datasetExpected.title) expect(dataset.citation).to.deep.equal(datasetExpected.citation) - // expect(dataset.labels).to.deep.equal(datasetExpected.labels) TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label + expect(dataset.labels).to.deep.equal(datasetExpected.labels) expect(dataset.license).to.deep.equal(datasetExpected.license) expect(dataset.metadataBlocks).to.deep.equal(datasetExpected.metadataBlocks) expect(dataset.summaryFields).to.deep.equal(datasetExpected.summaryFields) expect(dataset.version).to.deep.equal(datasetExpected.version) expect(dataset.metadataBlocks[0].fields.publicationDate).not.to.exist expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist + expect(dataset.permissions).to.deep.equal(datasetExpected.permissions) expect(dataset.locks).to.deep.equal(datasetExpected.locks) }) }) + it('gets a published dataset by persistentId without user authentication', async () => { + const datasetResponse = await DatasetHelper.create() + await DatasetHelper.publish(datasetResponse.persistentId) + + await TestsUtils.wait(1500) + + await TestsUtils.logout() + + await datasetRepository + .getByPersistentId(datasetResponse.persistentId, '1.0') + .then((dataset) => { + if (!dataset) { + throw new Error('Dataset not found') + } + const datasetExpected = datasetData(dataset.persistentId, dataset.version.id) + const newVersion = new DatasetVersion( + dataset.version.id, + DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.RELEASED, + 1, + 0 + ) + const expectedPublicationDate = getCurrentDateInYYYYMMDDFormat() + expect(dataset.getTitle()).to.deep.equal(datasetExpected.title) + expect(dataset.version).to.deep.equal(newVersion) + expect(dataset.metadataBlocks[0].fields.publicationDate).to.deep.equal( + expectedPublicationDate + ) + expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist + expect(dataset.permissions).to.deep.equal({ + canDownloadFiles: true, + canUpdateDataset: false, + canPublishDataset: false, + canManageDatasetPermissions: false, + canManageFilesPermissions: true, + canDeleteDataset: false + }) + }) + }) + it('gets the dataset by persistentId and version number', async () => { const datasetResponse = await DatasetHelper.create() await DatasetHelper.publish(datasetResponse.persistentId) @@ -140,6 +191,7 @@ describe('Dataset JSDataverse Repository', () => { expectedPublicationDate ) expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist + expect(dataset.permissions).to.deep.equal(datasetExpected.permissions) }) }) @@ -171,6 +223,7 @@ describe('Dataset JSDataverse Repository', () => { expect(dataset.getTitle()).to.deep.equal(datasetExpected.title) expect(dataset.version).to.deep.equal(datasetExpected.version) + expect(dataset.permissions).to.deep.equal(datasetExpected.permissions) }) })