Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,28 @@ If restrict is false then enableAccessRequest and termsOfAccess are ignored
If restrict is true and enableAccessRequest is false then termsOfAccess is required.
The enableAccessRequest and termsOfAccess are applied to the Draft version of the Dataset and affect all of the restricted files in said Draft version.

#### Get File Version Summaries
Comment thread
ChengShi-1 marked this conversation as resolved.

Returns an array of [FileVersionSummaryInfo](../src/files/domain/models/FileVersionSummaryInfo.ts) that contains information about what changed in every specific version.

##### Example call:

```typescript
import { getFileVersionSummaries } from '@iqss/dataverse-client-javascript'

/* ... */

const fileId = 1

getFileVersionSummaries.execute(fileId).then((fileVersionSummaries: fileVersionSummaryInfo[]) => {
/* ... */
})

/* ... */
```

_See [use case](../src/files/domain/useCases/GetFileVersionSummaries.ts) implementation_.

## Metadata Blocks

### Metadata Blocks read use cases
Expand Down
43 changes: 43 additions & 0 deletions src/files/domain/models/FileVersionSummaryInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export interface FileVersionSummaryInfo {
datasetVersion: string
versionNumber?: number
versionMinorNumber?: number
contributors?: string
publishedDate?: string
fileDifferenceSummary?: FileDifferenceSummary
isDraft: boolean
isDeaccessioned: boolean
isReleased: boolean
versionState?: FileVersionState
datafileId: number
persistentId?: string
versionNote?: string
}

export enum FileVersionState {
Comment thread
ChengShi-1 marked this conversation as resolved.
Outdated
RELEASED = 'RELEASED',
DEACCESSIONED = 'DEACCESSIONED',
DRAFT = 'DRAFT'
}

export type FileDifferenceSummary = {
file?: FileChangeType
FileAccess?: FileAccessChangeType
FileMetadata?: FileMetadataChange[]
deaccessionedReason?: string
FileTags?: FileTagChange
Comment thread
g-saracca marked this conversation as resolved.
Outdated
}

export type FileChangeType = 'Added' | 'Deleted' | 'Replaced' | 'Changed'
export type FileAccessChangeType = 'Restricted' | 'Public'

export type FileTagChange = {
Added?: number
Deleted?: number
Changed?: number
}

export interface FileMetadataChange {
name: string
action: FileChangeType
}
3 changes: 3 additions & 0 deletions src/files/domain/repositories/IFilesRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { FileUploadDestination } from '../models/FileUploadDestination'
import { UploadedFileDTO } from '../dtos/UploadedFileDTO'
import { UpdateFileMetadataDTO } from '../dtos/UpdateFileMetadataDTO'
import { RestrictFileDTO } from '../dtos/RestrictFileDTO'
import { FileVersionSummaryInfo } from '../models/FileVersionSummaryInfo'

export interface IFilesRepository {
getDatasetFiles(
Expand Down Expand Up @@ -84,4 +85,6 @@ export interface IFilesRepository {
categories: string[],
replace?: boolean
): Promise<void>

getFileVersionSummaries(fileId: number | string): Promise<FileVersionSummaryInfo[]>
}
21 changes: 21 additions & 0 deletions src/files/domain/useCases/GetFileVersionSummaries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { FileVersionSummaryInfo } from '../models/FileVersionSummaryInfo'
import { IFilesRepository } from '../repositories/IFilesRepository'

export class GetFileVersionSummaries implements UseCase<FileVersionSummaryInfo[]> {
private filesRepository: IFilesRepository

constructor(filesRepository: IFilesRepository) {
this.filesRepository = filesRepository
}

/**
* Returns a list of versions for a given file including a summary of differences between consecutive versions
*
* @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
* @returns {Promise<FileVersionSummaryInfo[]>} - An array of FileVersionSummaryInfo.
*/
async execute(fileId: number | string): Promise<FileVersionSummaryInfo[]> {
return await this.filesRepository.getFileVersionSummaries(fileId)
}
}
5 changes: 4 additions & 1 deletion src/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { RestrictFile } from './domain/useCases/RestrictFile'
import { UpdateFileMetadata } from './domain/useCases/UpdateFileMetadata'
import { UpdateFileTabularTags } from './domain/useCases/UpdateFileTabularTags'
import { UpdateFileCategories } from './domain/useCases/UpdateFileCategories'
import { GetFileVersionSummaries } from './domain/useCases/GetFileVersionSummaries'

const filesRepository = new FilesRepository()
const directUploadClient = new DirectUploadClient(filesRepository)
Expand All @@ -38,6 +39,7 @@ const restrictFile = new RestrictFile(filesRepository)
const updateFileMetadata = new UpdateFileMetadata(filesRepository)
const updateFileTabularTags = new UpdateFileTabularTags(filesRepository)
const updateFileCategories = new UpdateFileCategories(filesRepository)
const getFileVersionSummaries = new GetFileVersionSummaries(filesRepository)

export {
getDatasetFiles,
Expand All @@ -56,7 +58,8 @@ export {
updateFileMetadata,
updateFileTabularTags,
updateFileCategories,
replaceFile
replaceFile,
getFileVersionSummaries
}

export { FileModel as File, FileEmbargo, FileChecksum } from './domain/models/FileModel'
Expand Down
12 changes: 12 additions & 0 deletions src/files/infra/repositories/FilesRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { UploadedFileDTO } from '../../domain/dtos/UploadedFileDTO'
import { UpdateFileMetadataDTO } from '../../domain/dtos/UpdateFileMetadataDTO'
import { ApiConstants } from '../../../core/infra/repositories/ApiConstants'
import { RestrictFileDTO } from '../../domain/dtos/RestrictFileDTO'
import { FileVersionSummaryInfo } from '../../domain/models/FileVersionSummaryInfo'

export interface GetFilesQueryParams {
includeDeaccessioned: boolean
Expand Down Expand Up @@ -415,4 +416,15 @@ export class FilesRepository extends ApiRepository implements IFilesRepository {
throw error
})
}

public async getFileVersionSummaries(fileId: number | string): Promise<FileVersionSummaryInfo[]> {
return this.doGet(
this.buildApiEndpoint(this.filesResourceName, 'versionDifferences', fileId),
true
)
.then((response) => response.data.data)
.catch((error) => {
throw error
})
}
}
180 changes: 180 additions & 0 deletions test/integration/files/FilesRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ import {
} from '../../testHelpers/collections/collectionHelper'
import { RestrictFileDTO } from '../../../src/files/domain/dtos/RestrictFileDTO'
import { DatasetsRepository } from '../../../src/datasets/infra/repositories/DatasetsRepository'
import {
FileVersionState,
FileVersionSummaryInfo
} from '../../../src/files/domain/models/FileVersionSummaryInfo'

describe('FilesRepository', () => {
const sut: FilesRepository = new FilesRepository()
Expand Down Expand Up @@ -761,6 +765,182 @@ describe('FilesRepository', () => {
})
})

describe('getFileVersionSummaries', () => {
let fileTestDatasetIds: CreatedDatasetIdentifiers
const testTextFile1Name = 'test-file-1.txt'

beforeEach(async () => {
try {
fileTestDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO)
} catch (error) {
throw new Error('Tests beforeEach(): Error while creating test dataset')
}
await uploadFileViaApi(fileTestDatasetIds.numericId, testTextFile1Name).catch(() => {
throw new Error(`Tests beforeEach(): Error while uploading file ${testTextFile1Name}`)
})
})

test('should return file version summaries when file draft exists', async () => {
const currentTestFilesSubset = await sut.getDatasetFiles(
fileTestDatasetIds.numericId,
latestDatasetVersionId,
false,
FileOrderCriteria.NAME_AZ
)
const testFile = currentTestFilesSubset.files[0]
const actual = await sut.getFileVersionSummaries(testFile.id)

const fileSummmaries: FileVersionSummaryInfo = {
datasetVersion: 'DRAFT',
isDraft: true,
isReleased: false,
isDeaccessioned: false,
versionState: FileVersionState.DRAFT,
contributors: 'Dataverse Admin',
datafileId: testFile.id,
persistentId: testFile.persistentId,
// publishedDate: '', Uncomment this line until the API is fixed
Comment thread
g-saracca marked this conversation as resolved.
Outdated
fileDifferenceSummary: { file: 'Added' }
}

expect(actual).toHaveLength(1)
expect(actual[0]).toEqual(fileSummmaries)
deleteUnpublishedDatasetViaApi(fileTestDatasetIds.numericId)
})

test('should return file version summaries when dataset is deaccessioned', async () => {
await publishDatasetViaApi(fileTestDatasetIds.numericId).catch(() => {
throw new Error('Error while publishing test Dataset')
})

await waitForNoLocks(fileTestDatasetIds.numericId, 10).catch(() => {
throw new Error('Error while waiting for no locks')
})

const datasetFiles = await sut.getDatasetFiles(
fileTestDatasetIds.numericId,
latestDatasetVersionId,
false,
FileOrderCriteria.NAME_AZ
)
const testFile = datasetFiles.files[0]
const publishedFileVersionSummariesActual = await sut.getFileVersionSummaries(testFile.id)

// const publishedFileVersionSummmaries: FileVersionSummaryInfo = {
// datasetVersion: '1.0',
// isDraft: false,
// isReleased: true,
// isDeaccessioned: false,
// versionNumber: 1,
// versionMinorNumber: 0,
// publishedDate: new Date().toISOString().split('T')[0], // Format: yyyy-mm-dd
// versionState: FileVersionState.RELEASED,
// contributors: 'Dataverse Admin',
// datafileId: testFile.id,
// persistentId: testFile.persistentId,
// fileDifferenceSummary: { file: 'Added' }
// }

expect(publishedFileVersionSummariesActual).toHaveLength(1)
// expect(publishedFileVersionSummariesActual[0]).toEqual(publishedFileVersionSummmaries) Uncomment this line until the API is fixed

await deaccessionDatasetViaApi(fileTestDatasetIds.numericId, '1.0').catch(() => {
throw new Error('Error while deaccessioning test Dataset')
})

const actual = await sut.getFileVersionSummaries(testFile.id)

// const fileSummmaries: FileVersionSummaryInfo = {
// datasetVersion: '1.0',
// versionNumber: 1,
// versionMinorNumber: 0,
// publishedDate: new Date().toISOString().split('T')[0],
// isDraft: false,
// isReleased: false,
// isDeaccessioned: true,
// versionState: FileVersionState.DEACCESSIONED,
// contributors: 'Dataverse Admin',
// datafileId: testFile.id,
// persistentId: testFile.persistentId,
// fileDifferenceSummary: {
// deaccessionedReason: 'Test reason.',
// file: 'Added'
// }
// }

expect(actual).toHaveLength(1)
// expect(actual[0]).toEqual(fileSummmaries) Uncomment this line until the API is fixed
deletePublishedDatasetViaApi(fileTestDatasetIds.persistentId)
})

test('should return file version summaries when file is updated', async () => {
await publishDatasetViaApi(fileTestDatasetIds.numericId).catch(() => {
throw new Error('Error while publishing test Dataset')
})

await waitForNoLocks(fileTestDatasetIds.numericId, 10).catch(() => {
throw new Error('Error while waiting for no locks')
})

const datasetFiles = await sut.getDatasetFiles(
fileTestDatasetIds.numericId,
latestDatasetVersionId,
false,
FileOrderCriteria.NAME_AZ
)
const testFile = datasetFiles.files[0]
const actual = await sut.getFileVersionSummaries(testFile.id)

expect(actual).toHaveLength(1)

await sut.updateFileMetadata(testFile.id, {
description: 'My description test.',
categories: ['Data', 'Test'],
label: 'myfile.txt',
directoryLabel: 'mydir',
restrict: true
})
const updatedFileVersionSummariesActual = await sut.getFileVersionSummaries(testFile.id)
// const updatedFileVersionSummaries: FileVersionSummaryInfo = {
// datasetVersion: 'DRAFT',
// publishedDate: '',
// isDraft: true,
// isReleased: false,
// isDeaccessioned: false,
// versionState: FileVersionState.DRAFT,
// contributors: 'Dataverse Admin',
// datafileId: testFile.id,
// persistentId: testFile.persistentId,
// fileDifferenceSummary: {
// FileMetadata: [
// {
// name: 'File Name',
// action: 'Changed'
// },
// {
// name: 'Description',
// action: 'Changed'
// }
// ],
// FileTags: {
// Added: 2
// },
// FileAccess: 'Restricted'
// }
// }

expect(updatedFileVersionSummariesActual).toHaveLength(2)
// expect(updatedFileVersionSummariesActual[0]).toEqual(updatedFileVersionSummaries) Uncomment this line until the API is fixed
deletePublishedDatasetViaApi(fileTestDatasetIds.persistentId)
})

test('should return error when file does not exist', async () => {
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)

await expect(sut.getFileVersionSummaries(nonExistentFiledId)).rejects.toThrow(expectedError)
})
})

describe('deleteFile', () => {
let deleFileTestDatasetIds: CreatedDatasetIdentifiers
const testTextFile1Name = 'test-file-1.txt'
Expand Down
44 changes: 44 additions & 0 deletions test/unit/files/GetFileVersionSummaries.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository'
import { ReadError } from '../../../src'
import { GetFileVersionSummaries } from '../../../src/files/domain/useCases/GetFileVersionSummaries'
import { FileVersionSummaryInfo } from '../../../src/files/domain/models/FileVersionSummaryInfo'

describe('execute', () => {
test('should return file on repository success when passing numeric id', async () => {
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
const fileVersionSummaries: FileVersionSummaryInfo[] = [
{
datasetVersion: '1.0',
versionNumber: 1,
versionMinorNumber: 0,
contributors: 'John Doe',
publishedDate: '2023-01-01',
fileDifferenceSummary: {
FileMetadata: [
{
name: 'file.txt',
action: 'Added'
}
]
},
isDraft: false,
isDeaccessioned: false,
isReleased: false,
datafileId: 1
}
]
filesRepositoryStub.getFileVersionSummaries = jest.fn().mockResolvedValue(fileVersionSummaries)

const sut = new GetFileVersionSummaries(filesRepositoryStub)
const actualFileVersionSummaries = await sut.execute(1)
expect(actualFileVersionSummaries).toEqual(fileVersionSummaries)
})

test('should return error result on repository error', async () => {
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
filesRepositoryStub.getFileVersionSummaries = jest.fn().mockRejectedValue(new ReadError())
const sut = new GetFileVersionSummaries(filesRepositoryStub)

await expect(sut.execute(1)).rejects.toThrow(ReadError)
})
})
Loading