From eb7fb704bd9b45e78769d064850b0a6bbefcef43 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 19 Jun 2024 13:11:40 +0200 Subject: [PATCH 1/3] [DURACOM-282] fix issue with removing duplicated json patch operations, which in some case changed the order in the queue --- .../json-patch-operations.reducer.spec.ts | 380 ++++++++++++++++++ .../json-patch-operations.reducer.ts | 10 +- 2 files changed, 387 insertions(+), 3 deletions(-) diff --git a/src/app/core/json-patch/json-patch-operations.reducer.spec.ts b/src/app/core/json-patch/json-patch-operations.reducer.spec.ts index dba5794ffc..6d513120dc 100644 --- a/src/app/core/json-patch/json-patch-operations.reducer.spec.ts +++ b/src/app/core/json-patch/json-patch-operations.reducer.spec.ts @@ -340,4 +340,384 @@ describe('jsonPatchOperationsReducer test suite', () => { }); }); + describe('dedupeOperationEntries', () => { + it('should not remove duplicated keys if operations are not sequential', () => { + initState = { + sections: { + children: { + publicationStep: { + body: [ + { + operation: { + op: 'add', + path: '/sections/publicationStep/dc.date.issued', + value: [ + { + value: '2024-06', + language: null, + authority: null, + display: '2024-06', + confidence: -1, + place: 0, + otherInformation: null, + }, + ], + }, + timeCompleted: timestampBeforeStart, + }, + { + operation: { + op: 'replace', + path: '/sections/publicationStep/dc.date.issued/0', + value: { + value: '2023-06-19', + language: null, + authority: null, + display: '2023-06-19', + confidence: -1, + place: 0, + otherInformation: null, + }, + }, + timeCompleted: timestampBeforeStart, + }, + ], + } as JsonPatchOperationsEntry, + }, + transactionStartTime: null, + commitPending: false, + } as JsonPatchOperationsResourceEntry, + }; + + const value = [ + { + value: '2024-06-19', + language: null, + authority: null, + display: '2024-06-19', + confidence: -1, + place: 0, + otherInformation: null, + }, + ]; + const action = new NewPatchAddOperationAction( + 'sections', + 'publicationStep', + '/sections/publicationStep/dc.date.issued', + value); + const newState = jsonPatchOperationsReducer(initState, action); + + const expectedBody: any = [ + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06', + 'language': null, + 'authority': null, + 'display': '2024-06', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + { + 'operation': { + 'op': 'replace', + 'path': '/sections/publicationStep/dc.date.issued/0', + 'value': { + 'value': '2023-06-19', + 'language': null, + 'authority': null, + 'display': '2023-06-19', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + }, + 'timeCompleted': timestampBeforeStart, + }, + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06-19', + 'language': null, + 'authority': null, + 'display': '2024-06-19', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + ]; + + expect(newState.sections.children.publicationStep.body).toEqual(expectedBody); + + }); + + it('should remove duplicated keys if operations are sequential', () => { + initState = { + sections: { + children: { + publicationStep: { + body: [ + { + operation: { + op: 'add', + path: '/sections/publicationStep/dc.date.issued', + value: [ + { + value: '2024-06', + language: null, + authority: null, + display: '2024-06', + confidence: -1, + place: 0, + otherInformation: null, + }, + ], + }, + timeCompleted: timestampBeforeStart, + }, + { + operation: { + op: 'replace', + path: '/sections/publicationStep/dc.date.issued/0', + value: { + value: '2023-06-19', + language: null, + authority: null, + display: '2023-06-19', + confidence: -1, + place: 0, + otherInformation: null, + }, + }, + timeCompleted: timestampBeforeStart, + }, + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06-19', + 'language': null, + 'authority': null, + 'display': '2024-06-19', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + ], + } as JsonPatchOperationsEntry, + }, + transactionStartTime: null, + commitPending: false, + } as JsonPatchOperationsResourceEntry, + }; + + const value = [ + { + value: '2024-06-20', + language: null, + authority: null, + display: '2024-06-20', + confidence: -1, + place: 0, + otherInformation: null, + }, + ]; + const action = new NewPatchAddOperationAction( + 'sections', + 'publicationStep', + '/sections/publicationStep/dc.date.issued', + value); + const newState = jsonPatchOperationsReducer(initState, action); + + const expectedBody: any = [ + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06', + 'language': null, + 'authority': null, + 'display': '2024-06', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + { + 'operation': { + 'op': 'replace', + 'path': '/sections/publicationStep/dc.date.issued/0', + 'value': { + 'value': '2023-06-19', + 'language': null, + 'authority': null, + 'display': '2023-06-19', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + }, + 'timeCompleted': timestampBeforeStart, + }, + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06-20', + 'language': null, + 'authority': null, + 'display': '2024-06-20', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + ]; + + expect(newState.sections.children.publicationStep.body).toEqual(expectedBody); + + }); + + it('should remove duplicated keys if all operations have same key', () => { + initState = { + sections: { + children: { + publicationStep: { + body: [ + { + operation: { + op: 'add', + path: '/sections/publicationStep/dc.date.issued', + value: [ + { + value: '2024', + language: null, + authority: null, + display: '2024-06', + confidence: -1, + place: 0, + otherInformation: null, + }, + ], + }, + timeCompleted: timestampBeforeStart, + }, + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06', + 'language': null, + 'authority': null, + 'display': '2024-06', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06-19', + 'language': null, + 'authority': null, + 'display': '2024-06-19', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + ], + } as JsonPatchOperationsEntry, + }, + transactionStartTime: null, + commitPending: false, + } as JsonPatchOperationsResourceEntry, + }; + + const value = [ + { + value: '2024-06-20', + language: null, + authority: null, + display: '2024-06-20', + confidence: -1, + place: 0, + otherInformation: null, + }, + ]; + const action = new NewPatchAddOperationAction( + 'sections', + 'publicationStep', + '/sections/publicationStep/dc.date.issued', + value); + const newState = jsonPatchOperationsReducer(initState, action); + + const expectedBody: any = [ + { + 'operation': { + 'op': 'add', + 'path': '/sections/publicationStep/dc.date.issued', + 'value': [ + { + 'value': '2024-06-20', + 'language': null, + 'authority': null, + 'display': '2024-06-20', + 'confidence': -1, + 'place': 0, + 'otherInformation': null, + }, + ], + }, + 'timeCompleted': timestampBeforeStart, + }, + ]; + + expect(newState.sections.children.publicationStep.body).toEqual(expectedBody); + + }); + }); }); diff --git a/src/app/core/json-patch/json-patch-operations.reducer.ts b/src/app/core/json-patch/json-patch-operations.reducer.ts index 53466d284d..149d81f3e1 100644 --- a/src/app/core/json-patch/json-patch-operations.reducer.ts +++ b/src/app/core/json-patch/json-patch-operations.reducer.ts @@ -406,14 +406,18 @@ function addOperationToList(body: JsonPatchOperationObject[], actionType, target * @returns deduped JSON patch operation object entries */ function dedupeOperationEntries(body: JsonPatchOperationObject[]): JsonPatchOperationObject[] { - const ops = new Map(); + const ops = new Map(); for (let i = body.length - 1; i >= 0; i--) { const patch = body[i].operation; const key = `${patch.op}-${patch.path}`; if (!ops.has(key)) { - ops.set(key, patch); + ops.set(key, i); } else { - body.splice(i, 1); + const entry = ops.get(key); + if (entry - 1 === i) { + body.splice(i, 1); + ops.set(key, i); + } } } From 4069cf8168706da20424bd226e9dbcde010d14a3 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 19 Jun 2024 13:32:58 +0200 Subject: [PATCH 2/3] [DURACOM-282] fix error when discarding submission with no uploaded files --- .../upload/section-upload.component.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/app/submission/sections/upload/section-upload.component.ts b/src/app/submission/sections/upload/section-upload.component.ts index 5e7388902e..58008c9dfb 100644 --- a/src/app/submission/sections/upload/section-upload.component.ts +++ b/src/app/submission/sections/upload/section-upload.component.ts @@ -227,20 +227,21 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent { this.changeDetectorRef.detectChanges(); }), - // retrieve submission's bitstream data from state - combineLatest([this.configMetadataForm$, - this.bitstreamService.getUploadedFilesData(this.submissionId, this.sectionData.id)]).pipe( - filter(([configMetadataForm, { files }]: [SubmissionFormsModel, WorkspaceitemSectionUploadObject]) => { - return isNotEmpty(configMetadataForm) && isNotEmpty(files); + combineLatest([ + this.configMetadataForm$, + this.bitstreamService.getUploadedFilesData(this.submissionId, this.sectionData.id), + ]).pipe( + filter(([configMetadataForm, sectionUploadObject]: [SubmissionFormsModel, WorkspaceitemSectionUploadObject]) => { + return isNotEmpty(configMetadataForm) && isNotEmpty(sectionUploadObject); }), - distinctUntilChanged()) - .subscribe(([configMetadataForm, { primary, files }]: [SubmissionFormsModel, WorkspaceitemSectionUploadObject]) => { - this.primaryBitstreamUUID = primary; - this.fileList = files; - this.fileNames = Array.from(files, file => this.getFileName(configMetadataForm, file)); - }, - ), + distinctUntilChanged(), + ).subscribe(([configMetadataForm, { primary, files }]: [SubmissionFormsModel, WorkspaceitemSectionUploadObject]) => { + this.primaryBitstreamUUID = primary; + this.fileList = files; + this.fileNames = Array.from(files, file => this.getFileName(configMetadataForm, file)); + this.changeDetectorRef.detectChanges(); + }), ); } From 7f8e0a1d1cd4b30c437bb089a1275a6b0a1fb8f0 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 19 Jun 2024 15:53:47 +0200 Subject: [PATCH 3/3] [DURACOM-282] fix issue with submission edit page when providing a not existing workspaceitem --- .../submission/submission-parent-breadcrumb.service.ts | 9 ++++++++- src/app/core/submission/submission-rest.service.ts | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/core/submission/submission-parent-breadcrumb.service.ts b/src/app/core/submission/submission-parent-breadcrumb.service.ts index 4241d00192..2f9051b858 100644 --- a/src/app/core/submission/submission-parent-breadcrumb.service.ts +++ b/src/app/core/submission/submission-parent-breadcrumb.service.ts @@ -8,7 +8,10 @@ import { import { getDSORoute } from '../../app-routing-paths'; import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; -import { hasValue } from '../../shared/empty.util'; +import { + hasValue, + isEmpty, +} from '../../shared/empty.util'; import { SubmissionService } from '../../submission/submission.service'; import { BreadcrumbsProviderService } from '../breadcrumbs/breadcrumbsProviderService'; import { DSOBreadcrumbsService } from '../breadcrumbs/dso-breadcrumbs.service'; @@ -46,6 +49,10 @@ export class SubmissionParentBreadcrumbsService implements BreadcrumbsProviderSe * @param submissionObject The {@link SubmissionObject} for which the parent breadcrumb structure needs to be created */ getBreadcrumbs(submissionObject: SubmissionObject): Observable { + if (isEmpty(submissionObject)) { + return observableOf([]); + } + return combineLatest([ (submissionObject.collection as Observable>).pipe( getFirstCompletedRemoteData(), diff --git a/src/app/core/submission/submission-rest.service.ts b/src/app/core/submission/submission-rest.service.ts index 7e62058ba6..b1f4ad9e1b 100644 --- a/src/app/core/submission/submission-rest.service.ts +++ b/src/app/core/submission/submission-rest.service.ts @@ -13,6 +13,7 @@ import { isNotEmpty, } from '../../shared/empty.util'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ErrorResponse } from '../cache/response.models'; import { RemoteData } from '../data/remote-data'; import { DeleteRequest, @@ -23,6 +24,7 @@ import { SubmissionRequest, } from '../data/request.models'; import { RequestService } from '../data/request.service'; +import { RequestError } from '../data/request-error.model'; import { RestRequest } from '../data/rest-request.model'; import { HttpOptions } from '../dspace-rest/dspace-rest.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; @@ -57,7 +59,7 @@ export class SubmissionRestService { getFirstCompletedRemoteData(), map((response: RemoteData) => { if (response.hasFailed) { - throw new Error(response.errorMessage); + throw new ErrorResponse({ statusText: response.errorMessage, statusCode: response.statusCode } as RequestError); } else { return hasValue(response.payload) ? response.payload.dataDefinition : response.payload; }