Cache redesign part 1, and add support for alternative links

This commit is contained in:
Art Lowel
2020-12-11 14:18:44 +01:00
parent f4853972cc
commit 4e18fa35ca
522 changed files with 7537 additions and 6933 deletions

View File

@@ -9,14 +9,13 @@ import { SharedModule } from '../../../shared/shared.module';
import { SectionsService } from '../sections.service';
import { SectionDataObject } from '../models/section-data.model';
import { SectionsType } from '../sections-type';
import { RemoteData } from '../../../core/data/remote-data';
import { TranslateModule } from '@ngx-translate/core';
import { PageInfo } from '../../../core/shared/page-info.model';
import { PaginatedList } from '../../../core/data/paginated-list';
import { SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model';
import { cold } from 'jasmine-marbles';
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { createPaginatedList } from '../../../shared/testing/utils.test';
describe('SubmissionSectionCcLicensesComponent', () => {
@@ -130,25 +129,15 @@ describe('SubmissionSectionCcLicensesComponent', () => {
];
const submissionCcLicensesDataService = jasmine.createSpyObj('submissionCcLicensesDataService', {
findAll: observableOf(new RemoteData(
false,
false,
true,
undefined,
new PaginatedList(new PageInfo(), submissionCcLicenses),
)),
findAll: createSuccessfulRemoteDataObject$(createPaginatedList(submissionCcLicenses)),
});
const submissionCcLicenseUrlDataService = jasmine.createSpyObj('submissionCcLicenseUrlDataService', {
getCcLicenseLink: observableOf(new RemoteData(
false,
false,
true,
undefined,
getCcLicenseLink: createSuccessfulRemoteDataObject$(
{
url: 'test cc license link',
}
)),
),
});
const sectionService = {

View File

@@ -5,7 +5,7 @@ import {
Option,
SubmissionCcLicence
} from '../../../core/submission/models/submission-cc-license.model';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { distinctUntilChanged, filter, map, take } from 'rxjs/operators';
import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
@@ -254,7 +254,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
this.sectionData.data = data;
}),
this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe(
getSucceededRemoteData(),
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
map((list) => list.page),
).subscribe(

View File

@@ -32,8 +32,6 @@ import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormComponent } from '../../../shared/form/form.component';
import { FormFieldModel } from '../../../shared/form/builder/models/form-field.model';
import { ConfigData } from '../../../core/config/config-data';
import { PageInfo } from '../../../core/shared/page-info.model';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
import { DynamicRowGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
import { DsDynamicInputModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model';
@@ -41,18 +39,19 @@ import { SubmissionSectionError } from '../../objects/submission-objects.reducer
import { DynamicFormControlEvent, DynamicFormControlEventType } from '@ng-dynamic-forms/core';
import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
import { FormRowModel } from '../../../core/config/models/config-submission-form.model';
import { RemoteData } from '../../../core/data/remote-data';
import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
import { SubmissionObjectDataService } from '../../../core/submission/submission-object-data.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RequestService } from '../../../core/data/request.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
function getMockSubmissionFormsConfigService(): SubmissionFormsConfigService {
return jasmine.createSpyObj('FormOperationsService', {
getConfigAll: jasmine.createSpy('getConfigAll'),
getConfigByHref: jasmine.createSpy('getConfigByHref'),
getConfigByName: jasmine.createSpy('getConfigByName'),
getConfigBySearch: jasmine.createSpy('getConfigBySearch')
getConfigBySearch: jasmine.createSpy('getConfigBySearch'),
findByHref: jasmine.createSpy('findByHref'),
});
}
@@ -153,7 +152,6 @@ describe('SubmissionSectionformComponent test suite', () => {
const submissionId = mockSubmissionId;
const collectionId = mockSubmissionCollectionId;
const parsedSectionErrors: any = mockUploadResponse1ParsedErrors.traditionalpageone;
const formConfigData = new ConfigData(new PageInfo(), testFormConfiguration);
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -178,12 +176,12 @@ describe('SubmissionSectionformComponent test suite', () => {
{ provide: SectionsService, useClass: SectionsServiceStub },
{ provide: SubmissionService, useClass: SubmissionServiceStub },
{ provide: TranslateService, useValue: getMockTranslateService() },
{ provide: ObjectCacheService, useValue: { remove: () => {/*do nothing*/}, hasBySelfLinkObservable: () => observableOf(false) } },
{ provide: RequestService, useValue: { removeByHrefSubstring: () => {/*do nothing*/}, hasByHrefObservable: () => observableOf(false) } },
{ provide: ObjectCacheService, useValue: { remove: () => {/*do nothing*/}, hasBySelfLinkObservable: () => observableOf(false), hasByHref$: () => observableOf(false) } },
{ provide: RequestService, useValue: { removeByHrefSubstring: () => {/*do nothing*/}, hasByHref$: () => observableOf(false) } },
{ provide: 'collectionIdProvider', useValue: collectionId },
{ provide: 'sectionDataProvider', useValue: sectionObject },
{ provide: 'submissionIdProvider', useValue: submissionId },
{ provide: SubmissionObjectDataService, useValue: { getHrefByID: () => observableOf('testUrl'), findById: () => observableOf(new RemoteData(false, false, true, null, new WorkspaceItem())) } },
{ provide: SubmissionObjectDataService, useValue: { getHrefByID: () => observableOf('testUrl'), findById: () => createSuccessfulRemoteDataObject$(new WorkspaceItem()) } },
ChangeDetectorRef,
SubmissionSectionformComponent
],
@@ -242,7 +240,7 @@ describe('SubmissionSectionformComponent test suite', () => {
it('should init section properly', () => {
const sectionData = {};
formService.isValid.and.returnValue(observableOf(true));
formConfigService.getConfigByHref.and.returnValue(observableOf(formConfigData));
formConfigService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(testFormConfiguration));
sectionsServiceStub.getSectionData.and.returnValue(observableOf(sectionData));
spyOn(comp, 'initForm');
spyOn(comp, 'subscriptions');
@@ -250,7 +248,7 @@ describe('SubmissionSectionformComponent test suite', () => {
comp.onSectionInit();
fixture.detectChanges();
expect(compAsAny.formConfig).toEqual(formConfigData.payload);
expect(compAsAny.formConfig).toEqual(testFormConfiguration);
expect(comp.sectionData.errors).toEqual([]);
expect(comp.sectionData.data).toEqual(sectionData);
expect(comp.isLoading).toBeFalsy();

View File

@@ -2,7 +2,16 @@ import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core';
import { DynamicFormControlEvent, DynamicFormControlModel } from '@ng-dynamic-forms/core';
import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, filter, find, flatMap, map, switchMap, take, tap } from 'rxjs/operators';
import {
distinctUntilChanged,
filter,
find,
flatMap,
map,
switchMap,
take,
tap
} from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { isEqual } from 'lodash';
@@ -12,10 +21,12 @@ import { FormService } from '../../../shared/form/form.service';
import { SectionModelComponent } from '../models/section.model';
import { SubmissionFormsConfigService } from '../../../core/config/submission-forms-config.service';
import { hasNoValue, hasValue, isNotEmpty, isUndefined } from '../../../shared/empty.util';
import { ConfigData } from '../../../core/config/config-data';
import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model';
import { SubmissionSectionError, SubmissionSectionObject } from '../../objects/submission-objects.reducer';
import {
SubmissionSectionError,
SubmissionSectionObject
} from '../../objects/submission-objects.reducer';
import { FormFieldPreviousValueObject } from '../../../shared/form/builder/models/form-field-previous-value-object';
import { SectionDataObject } from '../models/section-data.model';
import { renderSectionFor } from '../sections-decorator';
@@ -27,13 +38,15 @@ import { SectionsService } from '../sections.service';
import { difference } from '../../../shared/object.util';
import { WorkspaceitemSectionFormObject } from '../../../core/submission/models/workspaceitem-section-form.model';
import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
import { SubmissionObjectDataService } from '../../../core/submission/submission-object-data.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RequestService } from '../../../core/data/request.service';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { environment } from '../../../../environments/environment';
import { ConfigObject } from '../../../core/config/models/config.model';
import { RemoteData } from '../../../core/data/remote-data';
/**
* This component represents a section that contains a Form.
@@ -155,8 +168,8 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
onSectionInit() {
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
this.formId = this.formService.getUniqueId(this.sectionData.id);
this.formConfigService.getConfigByHref(this.sectionData.config).pipe(
map((configData: ConfigData) => configData.payload),
this.formConfigService.findByHref(this.sectionData.config).pipe(
map((configData: RemoteData<ConfigObject>) => configData.payload),
tap((config: SubmissionFormsModel) => this.formConfig = config),
flatMap(() =>
observableCombineLatest(
@@ -166,12 +179,12 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
this.objectCache.remove(href);
this.requestService.removeByHrefSubstring(this.submissionId);
return observableCombineLatest(
this.objectCache.hasBySelfLinkObservable(href),
this.requestService.hasByHrefObservable(href)
this.objectCache.hasByHref$(href),
this.requestService.hasByHref$(href)
).pipe(
filter(([existsInOC, existsInRC]) => !existsInOC && !existsInRC),
take(1),
switchMap(() => this.submissionObjectService.findById(this.submissionId, followLink('item')).pipe(getSucceededRemoteData(), getRemoteDataPayload()) as Observable<SubmissionObject>)
switchMap(() => this.submissionObjectService.findById(this.submissionId, false, followLink('item')).pipe(getFirstSucceededRemoteData(), getRemoteDataPayload()) as Observable<SubmissionObject>)
)
})
)

View File

@@ -133,7 +133,7 @@ export class SubmissionSectionLicenseComponent extends SectionModelComponent {
(model as DynamicCheckboxModel).valueUpdates.next(false);
}
this.licenseText$ = this.collectionDataService.findById(this.collectionId, followLink('license')).pipe(
this.licenseText$ = this.collectionDataService.findById(this.collectionId, true, followLink('license')).pipe(
filter((collectionData: RemoteData<Collection>) => isNotUndefined((collectionData.payload))),
flatMap((collectionData: RemoteData<Collection>) => (collectionData.payload as any).license),
find((licenseData: RemoteData<License>) => isNotUndefined((licenseData.payload))),

View File

@@ -21,6 +21,7 @@ import {
mockSubmissionCollectionId,
mockSubmissionId,
mockUploadConfigResponse,
mockUploadConfigResponseMetadata,
mockUploadFiles
} from '../../../../../shared/mocks/submission.mock';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@@ -47,7 +48,7 @@ describe('SubmissionSectionUploadFileEditComponent test suite', () => {
[mockUploadConfigResponse.accessConditionOptions[2].name, [mockGroup as any]],
]);
const collectionPolicyType = POLICY_DEFAULT_WITH_LIST;
const configMetadataForm: any = mockUploadConfigResponse.metadata;
const configMetadataForm: any = mockUploadConfigResponseMetadata;
const fileIndex = '0';
const fileId = '123456-test-upload';
const fileData: any = mockUploadFiles[0];

View File

@@ -34,17 +34,17 @@ import { GroupDataService } from '../../../core/eperson/group-data.service';
import { Collection } from '../../../core/shared/collection.model';
import { ResourcePolicy } from '../../../core/resource-policy/models/resource-policy.model';
import { ResourcePolicyService } from '../../../core/resource-policy/resource-policy.service';
import { ConfigData } from '../../../core/config/config-data';
import { PageInfo } from '../../../core/shared/page-info.model';
import { Group } from '../../../core/eperson/models/group.model';
import { getMockSectionUploadService } from '../../../shared/mocks/section-upload.service.mock';
import { SubmissionUploadsModel } from '../../../core/config/models/config-submission-uploads.model';
function getMockSubmissionUploadsConfigService(): SubmissionFormsConfigService {
return jasmine.createSpyObj('SubmissionUploadsConfigService', {
getConfigAll: jasmine.createSpy('getConfigAll'),
getConfigByHref: jasmine.createSpy('getConfigByHref'),
getConfigByName: jasmine.createSpy('getConfigByName'),
getConfigBySearch: jasmine.createSpy('getConfigBySearch')
getConfigBySearch: jasmine.createSpy('getConfigBySearch'),
findByHref: jasmine.createSpy('findByHref')
});
}
@@ -205,9 +205,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition));
uploadsConfigService.getConfigByHref.and.returnValue(observableOf(
new ConfigData(new PageInfo(), mockUploadConfigResponse as any)
));
uploadsConfigService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new SubmissionUploadsModel(), mockUploadConfigResponse)));
groupService.findById.and.returnValues(
createSuccessfulRemoteDataObject$(Object.assign(new Group(), mockGroup)),
@@ -245,9 +243,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition));
uploadsConfigService.getConfigByHref.and.returnValue(observableOf(
new ConfigData(new PageInfo(), mockUploadConfigResponse as any)
));
uploadsConfigService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new SubmissionUploadsModel(), mockUploadConfigResponse)));
groupService.findById.and.returnValues(
createSuccessfulRemoteDataObject$(Object.assign(new Group(), mockGroup)),
@@ -284,9 +280,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition));
uploadsConfigService.getConfigByHref.and.returnValue(observableOf(
new ConfigData(new PageInfo(), mockUploadConfigResponse as any)
));
uploadsConfigService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new SubmissionUploadsModel(), mockUploadConfigResponse)));
groupService.findById.and.returnValues(
createSuccessfulRemoteDataObject$(Object.assign(new Group(), mockGroup)),
@@ -315,9 +309,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition));
uploadsConfigService.getConfigByHref.and.returnValue(observableOf(
new ConfigData(new PageInfo(), mockUploadConfigResponseNotRequired as any)
));
uploadsConfigService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new SubmissionUploadsModel(), mockUploadConfigResponseNotRequired)));
groupService.findById.and.returnValues(
createSuccessfulRemoteDataObject$(Object.assign(new Group(), mockGroup)),

View File

@@ -1,7 +1,21 @@
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, filter, find, flatMap, map, reduce, take, tap } from 'rxjs/operators';
import {
BehaviorSubject,
combineLatest as observableCombineLatest,
Observable,
Subscription
} from 'rxjs';
import {
distinctUntilChanged,
filter,
find,
flatMap,
map,
reduce,
tap,
switchMap
} from 'rxjs/operators';
import { SectionModelComponent } from '../models/section.model';
import { hasValue, isNotEmpty, isNotUndefined, isUndefined } from '../../../shared/empty.util';
@@ -23,7 +37,9 @@ import { SectionsService } from '../sections.service';
import { SubmissionService } from '../../submission.service';
import { Collection } from '../../../core/shared/collection.model';
import { AccessConditionOption } from '../../../core/config/models/config-access-condition-option.model';
import { PaginatedList } from '../../../core/data/paginated-list';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
export const POLICY_DEFAULT_NO_LIST = 1; // Banner1
export const POLICY_DEFAULT_WITH_LIST = 2; // Banner2
@@ -146,13 +162,18 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
* Initialize all instance variables and retrieve collection default access conditions
*/
onSectionInit() {
const config$ = this.uploadsConfigService.getConfigByHref(this.sectionData.config).pipe(
const config$ = this.uploadsConfigService.findByHref(this.sectionData.config, false, followLink('metadata')).pipe(
getFirstSucceededRemoteData(),
map((config) => config.payload));
// retrieve configuration for the bitstream's metadata form
this.configMetadataForm$ = config$.pipe(
take(1),
map((config: SubmissionUploadsModel) => config.metadata));
switchMap((config: SubmissionUploadsModel) =>
config.metadata.pipe(
getFirstSucceededRemoteData(),
map((remoteData: RemoteData<SubmissionFormsModel>) => remoteData.payload)
)
));
this.subs.push(
this.submissionService.getSubmissionObject(this.submissionId).pipe(