From 245cb4550355835126419a4c040262da1016d071 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 28 Apr 2020 15:08:42 +0200 Subject: [PATCH 01/12] CC License Submission Step --- src/app/core/core.module.ts | 4 + .../submission-cc-licenses-data.service.ts | 34 +++ src/app/core/shared/hal-resource.model.ts | 4 + .../submission-cc-licences.resource-type.ts | 9 + .../shared/submission-cc-license.model.ts | 35 +++ .../workspaceitem-section-cc-license.model.ts | 11 + .../models/workspaceitem-sections.model.ts | 2 + .../shared/ds-select/ds-select.component.html | 31 +++ .../ds-select/ds-select.component.spec.ts | 25 ++ .../shared/ds-select/ds-select.component.ts | 36 +++ src/app/shared/shared.module.ts | 2 + ...mission-section-cc-licenses.component.html | 114 +++++++++ ...sion-section-cc-licenses.component.spec.ts | 220 ++++++++++++++++++ ...ubmission-section-cc-licenses.component.ts | 197 ++++++++++++++++ .../submission-form-collection.component.html | 90 ++++--- src/app/submission/submission.module.ts | 8 +- src/assets/i18n/en.json5 | 10 +- 17 files changed, 781 insertions(+), 51 deletions(-) create mode 100644 src/app/core/data/submission-cc-licenses-data.service.ts create mode 100644 src/app/core/shared/submission-cc-licences.resource-type.ts create mode 100644 src/app/core/shared/submission-cc-license.model.ts create mode 100644 src/app/core/submission/models/workspaceitem-section-cc-license.model.ts create mode 100644 src/app/shared/ds-select/ds-select.component.html create mode 100644 src/app/shared/ds-select/ds-select.component.spec.ts create mode 100644 src/app/shared/ds-select/ds-select.component.ts create mode 100644 src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html create mode 100644 src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts create mode 100644 src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 356dad5ed8..c8f6dcedcd 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -145,6 +145,8 @@ import { Version } from './shared/version.model'; import { VersionHistory } from './shared/version-history.model'; import { WorkflowActionDataService } from './data/workflow-action-data.service'; import { WorkflowAction } from './tasks/models/workflow-action-object.model'; +import { SubmissionCcLicensesDataService } from './data/submission-cc-licenses-data.service'; +import { SubmissionCcLicence } from './shared/submission-cc-license.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -214,6 +216,7 @@ const PROVIDERS = [ BrowseItemsResponseParsingService, BrowseService, ConfigResponseParsingService, + SubmissionCcLicensesDataService, SubmissionDefinitionsConfigService, SubmissionFormsConfigService, SubmissionRestService, @@ -296,6 +299,7 @@ export const models = License, WorkflowItem, WorkspaceItem, + SubmissionCcLicence, SubmissionDefinitionsModel, SubmissionFormsModel, SubmissionSectionModel, diff --git a/src/app/core/data/submission-cc-licenses-data.service.ts b/src/app/core/data/submission-cc-licenses-data.service.ts new file mode 100644 index 0000000000..057c4389f7 --- /dev/null +++ b/src/app/core/data/submission-cc-licenses-data.service.ts @@ -0,0 +1,34 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { DataService } from './data.service'; +import { RequestService } from './request.service'; +import { SUBMISSION_CC_LICENSE } from '../shared/submission-cc-licences.resource-type'; +import { SubmissionCcLicence } from '../shared/submission-cc-license.model'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; + +@Injectable() +@dataService(SUBMISSION_CC_LICENSE) +export class SubmissionCcLicensesDataService extends DataService { + + protected linkPath = 'submissioncclicenses'; + + constructor( + protected comparator: DefaultChangeAnalyzer, + protected halService: HALEndpointService, + protected http: HttpClient, + protected notificationsService: NotificationsService, + protected objectCache: ObjectCacheService, + protected rdbService: RemoteDataBuildService, + protected requestService: RequestService, + protected store: Store, + ) { + super(); + } +} diff --git a/src/app/core/shared/hal-resource.model.ts b/src/app/core/shared/hal-resource.model.ts index b6ef822a23..334509007b 100644 --- a/src/app/core/shared/hal-resource.model.ts +++ b/src/app/core/shared/hal-resource.model.ts @@ -1,4 +1,5 @@ import { HALLink } from './hal-link.model'; +import { deserialize } from 'cerialize'; /** * Represents HAL resources. @@ -6,10 +7,13 @@ import { HALLink } from './hal-link.model'; * A HAL resource has a _links section with at least a self link. */ export class HALResource { + /** * The {@link HALLink}s for this {@link HALResource} */ + @deserialize _links: { + /** * The {@link HALLink} that refers to this {@link HALResource} */ diff --git a/src/app/core/shared/submission-cc-licences.resource-type.ts b/src/app/core/shared/submission-cc-licences.resource-type.ts new file mode 100644 index 0000000000..1e65a433f6 --- /dev/null +++ b/src/app/core/shared/submission-cc-licences.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for License + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const SUBMISSION_CC_LICENSE = new ResourceType('submissioncclicense'); diff --git a/src/app/core/shared/submission-cc-license.model.ts b/src/app/core/shared/submission-cc-license.model.ts new file mode 100644 index 0000000000..0b2cfbcca6 --- /dev/null +++ b/src/app/core/shared/submission-cc-license.model.ts @@ -0,0 +1,35 @@ +import { autoserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { ResourceType } from './resource-type'; +import { HALResource } from './hal-resource.model'; +import { SUBMISSION_CC_LICENSE } from './submission-cc-licences.resource-type'; + +@typedObject +@inheritSerialization(HALResource) +export class SubmissionCcLicence extends HALResource { + + static type = SUBMISSION_CC_LICENSE; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + @autoserialize + name: string; + + @autoserialize + fields: Array<{ + id: string; + label: string; + description: string; + enums: Array<{ + id: string; + label: string; + description: string; + }>; + }>; +} diff --git a/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts b/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts new file mode 100644 index 0000000000..65f6a5b9e4 --- /dev/null +++ b/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts @@ -0,0 +1,11 @@ +/** + * An interface to represent the submission's creative commons license section data. + */ +export interface WorkspaceitemSectionCcLicenseObject { + ccLicense: { + name: string; + fields: { + [field: string]: string; + } + }; +} diff --git a/src/app/core/submission/models/workspaceitem-sections.model.ts b/src/app/core/submission/models/workspaceitem-sections.model.ts index 165e69869c..6ff756a323 100644 --- a/src/app/core/submission/models/workspaceitem-sections.model.ts +++ b/src/app/core/submission/models/workspaceitem-sections.model.ts @@ -1,6 +1,7 @@ import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model'; import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model'; import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model'; +import { WorkspaceitemSectionCcLicenseObject } from './workspaceitem-section-cc-license.model'; /** * An interface to represent submission's section object. @@ -17,4 +18,5 @@ export type WorkspaceitemSectionDataType = WorkspaceitemSectionUploadObject | WorkspaceitemSectionFormObject | WorkspaceitemSectionLicenseObject + | WorkspaceitemSectionCcLicenseObject | string; diff --git a/src/app/shared/ds-select/ds-select.component.html b/src/app/shared/ds-select/ds-select.component.html new file mode 100644 index 0000000000..5a15155d4f --- /dev/null +++ b/src/app/shared/ds-select/ds-select.component.html @@ -0,0 +1,31 @@ +
+ +
+ +
+ + {{ label | translate }} + +
+ + + + +
+ +
diff --git a/src/app/shared/ds-select/ds-select.component.spec.ts b/src/app/shared/ds-select/ds-select.component.spec.ts new file mode 100644 index 0000000000..a3e70808d9 --- /dev/null +++ b/src/app/shared/ds-select/ds-select.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DsSelectComponent } from './ds-select.component'; + +describe('DsSelectComponent', () => { + let component: DsSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DsSelectComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DsSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/ds-select/ds-select.component.ts b/src/app/shared/ds-select/ds-select.component.ts new file mode 100644 index 0000000000..4e2a1f6973 --- /dev/null +++ b/src/app/shared/ds-select/ds-select.component.ts @@ -0,0 +1,36 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +/** + * Component which represent a DSpace dropdown selector. + */ +@Component({ + selector: 'ds-select', + templateUrl: './ds-select.component.html', + styleUrls: ['./ds-select.component.css'] +}) +export class DsSelectComponent { + + /** + * An optional label for the dropdown selector. + */ + @Input() + label: string; + + /** + * Whether the dropdown selector is disabled. + */ + @Input() + disabled: boolean; + + /** + * Emits an event when the dropdown selector is opened or closed. + */ + @Output() + toggled = new EventEmitter(); + + /** + * Emits an event when the dropdown selector or closed. + */ + @Output() + close = new EventEmitter(); +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 3d00f6bc35..4dd46941ea 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -193,6 +193,7 @@ import { ModifyItemOverviewComponent } from '../+item-page/edit-item-page/modify import { ClaimedTaskActionsLoaderComponent } from './mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component'; import { ClaimedTaskActionsDirective } from './mydspace-actions/claimed-task/switcher/claimed-task-actions.directive'; import { ClaimedTaskActionsEditMetadataComponent } from './mydspace-actions/claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component'; +import { DsSelectComponent } from './ds-select/ds-select.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -269,6 +270,7 @@ const COMPONENTS = [ DsDynamicFormGroupComponent, DsDynamicFormArrayComponent, DsDatePickerInlineComponent, + DsSelectComponent, ErrorComponent, FormComponent, LangSwitchComponent, diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html new file mode 100644 index 0000000000..f598be7af8 --- /dev/null +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html @@ -0,0 +1,114 @@ +
+ + + + + + + + {{ getSelectedCcLicense().name }} + + + {{ 'submission.sections.ccLicense.select' | translate }} + + + + + + + + + +
+ + + +
+ +
+
+ {{ field.label }} +
+ +
+ + + +
+ + + + + +
+ +
+ + + + + {{ option }} + + + {{ 'submission.sections.ccLicense.option.select' | translate }} + + + + + + + + +
+ +
+ {{ value.label }} +
+
+
+ +
+ +
diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts new file mode 100644 index 0000000000..38e4384b2e --- /dev/null +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts @@ -0,0 +1,220 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SubmissionSectionCcLicensesComponent } from './submission-section-cc-licenses.component'; +import { SUBMISSION_CC_LICENSE } from '../../core/shared/submission-cc-licences.resource-type'; +import { of as observableOf } from 'rxjs'; +import { SubmissionCcLicensesDataService } from '../../core/data/submission-cc-licenses-data.service'; +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { SharedModule } from '../shared.module'; +import { SectionsService } from '../../submission/sections/sections.service'; +import { SectionDataObject } from '../../submission/sections/models/section-data.model'; +import { SectionsType } from '../../submission/sections/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/shared/submission-cc-license.model'; +import { cold } from 'jasmine-marbles'; + +describe('SubmissionSectionCcLicensesComponent', () => { + + let component: SubmissionSectionCcLicensesComponent; + let fixture: ComponentFixture; + let de: DebugElement; + + const sectionObject: SectionDataObject = { + config: 'test config', + mandatory: true, + data: {}, + errors: [], + header: 'test header', + id: 'test section id', + sectionType: SectionsType.SubmissionForm + }; + + const submissionCcLicenses: SubmissionCcLicence[] = [ + { + type: SUBMISSION_CC_LICENSE, + name: 'test license name 1', + fields: [ + { + id: 'test-field-id-1a', + label: 'test field label 1a', + description: 'test field description 1a', + enums: [ + { + id: 'test enum id 1a I', + label: 'test enum label 1a I', + description: 'test enum description 1a I', + }, + { + id: 'test enum id 1a II', + label: 'test enum label 1a II', + description: 'test enum description 1a II', + }, + ], + }, + { + id: 'test-field-id-1b', + label: 'test field label 1b', + description: 'test field description 1b', + enums: [ + { + id: 'test enum id 1b I', + label: 'test enum label 1b I', + description: 'test enum description 1b I', + }, + { + id: 'test enum id 1b II', + label: 'test enum label 1b II', + description: 'test enum description 1b II', + }, + ], + }, + ], + _links: { + self: { + href: 'test link', + }, + }, + }, + { + type: SUBMISSION_CC_LICENSE, + name: 'test license name 2', + fields: [ + { + id: 'test-field-id-2a', + label: 'test field label 2a', + description: 'test field description 2a', + enums: [ + { + id: 'test enum id 2a I', + label: 'test enum label 2a I', + description: 'test enum description 2a I' + }, + { + id: 'test enum id 2a II', + label: 'test enum label 2a II', + description: 'test enum description 2a II' + }, + ], + }, + { + id: 'test-field-id-2b', + label: 'test field label 2b', + description: 'test field description 2b', + enums: [ + { + id: 'test enum id 2b I', + label: 'test enum label 2b I', + description: 'test enum description 2b I' + }, + { + id: 'test enum id 2b II', + label: 'test enum label 2b II', + description: 'test enum description 2b II' + }, + ], + }, + ], + _links: { + self: { + href: 'test link', + }, + }, + }, + ]; + const submissionCcLicensesDataService = { + findAll: () => observableOf(new RemoteData( + false, + false, + true, + undefined, + new PaginatedList(new PageInfo(), submissionCcLicenses), + )), + }; + + const sectionService = { + getSectionState: () => observableOf( + { + data: {}, + } + ), + setSectionStatus: () => undefined, + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + SharedModule, + TranslateModule.forRoot(), + ], + declarations: [ + SubmissionSectionCcLicensesComponent, + ], + providers: [ + {provide: SubmissionCcLicensesDataService, useValue: submissionCcLicensesDataService}, + {provide: SectionsService, useValue: sectionService}, + {provide: 'collectionIdProvider', useValue: 'test collection id'}, + {provide: 'sectionDataProvider', useValue: sectionObject}, + {provide: 'submissionIdProvider', useValue: 'test submission id'}, + ], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SubmissionSectionCcLicensesComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + fixture.detectChanges(); + }); + + it('should display a dropdown with the different cc licenses', () => { + expect( + de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(1)')).nativeElement.innerText + ).toContain('test license name 1'); + expect( + de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(2)')).nativeElement.innerText + ).toContain('test license name 2'); + }); + + describe('when a license is selected', () => { + + beforeEach(() => { + component.select(submissionCcLicenses[1]); + fixture.detectChanges(); + }); + + it('should display the selected cc license', () => { + expect( + de.query(By.css('.ccLicense-select ds-select button.selection')).nativeElement.innerText + ).toContain('test license name 2'); + }); + + it('should display all field labels of the selected cc license only', () => { + expect(de.query(By.css('div.test-field-id-1a'))).toBeNull(); + expect(de.query(By.css('div.test-field-id-1b'))).toBeNull(); + expect(de.query(By.css('div.test-field-id-2a'))).toBeTruthy(); + expect(de.query(By.css('div.test-field-id-2b'))).toBeTruthy(); + }); + + it('should have section status incomplete', () => { + expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false })); + }); + + describe('when all options have a value selected', () => { + + beforeEach(() => { + const ccLicence = submissionCcLicenses[1]; + component.selectOption(ccLicence, ccLicence.fields[0].id, ccLicence.fields[0].enums[1].label); + component.selectOption(ccLicence, ccLicence.fields[1].id, ccLicence.fields[1].enums[0].label); + fixture.detectChanges(); + }); + + it('should have section status complete', () => { + expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true })); + }); + }); + }); +}); diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts new file mode 100644 index 0000000000..d7241a3220 --- /dev/null +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts @@ -0,0 +1,197 @@ +import { Component, Inject } from '@angular/core'; +import { Observable, of as observableOf, Subscription } from 'rxjs'; +import { SubmissionCcLicence } from '../../core/shared/submission-cc-license.model'; +import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; +import { SubmissionCcLicensesDataService } from '../../core/data/submission-cc-licenses-data.service'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { renderSectionFor } from '../../submission/sections/sections-decorator'; +import { SectionsType } from '../../submission/sections/sections-type'; +import { SectionModelComponent } from '../../submission/sections/models/section.model'; +import { SectionDataObject } from '../../submission/sections/models/section-data.model'; +import { SectionsService } from '../../submission/sections/sections.service'; +import { WorkspaceitemSectionCcLicenseObject } from '../../core/submission/models/workspaceitem-section-cc-license.model'; +import { JsonPatchOperationPathCombiner } from '../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { isNotEmpty } from '../empty.util'; + +/** + * This component represents the submission section to select the Creative Commons license. + */ +@Component({ + selector: 'ds-submission-section-cc-licenses', + templateUrl: './submission-section-cc-licenses.component.html', + styleUrls: ['./submission-section-cc-licenses.component.css'] +}) +@renderSectionFor(SectionsType.CcLicense) +export class SubmissionSectionCcLicensesComponent extends SectionModelComponent { + + /** + * The form id + * @type {string} + */ + public formId: string; + + /** + * A boolean representing if this section is loading + * @type {boolean} + */ + public isLoading = true; + + /** + * The [JsonPatchOperationPathCombiner] object + * @type {JsonPatchOperationPathCombiner} + */ + protected pathCombiner: JsonPatchOperationPathCombiner; + + /** + * The list of Subscriptions this component subscribes to. + */ + private subscriptions: Subscription[] = []; + + /** + * Cache of the available Creative Commons licenses. + */ + submissionCcLicenses: SubmissionCcLicence[]; + + /** + * Reference to NgbModal + */ + protected modalRef: NgbModalRef; + + constructor( + protected modalService: NgbModal, + protected sectionService: SectionsService, + protected submissionCcLicensesDataService: SubmissionCcLicensesDataService, + @Inject('collectionIdProvider') public injectedCollectionId: string, + @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, + @Inject('submissionIdProvider') public injectedSubmissionId: string + ) { + super( + injectedCollectionId, + injectedSectionData, + injectedSubmissionId, + ); + } + + /** + * The data of this section. + */ + get data(): WorkspaceitemSectionCcLicenseObject { + return this.sectionData.data as WorkspaceitemSectionCcLicenseObject; + } + + /** + * Select a given Creative Commons license. + * @param ccLicense the Creative Commons license to select. + */ + select(ccLicense: SubmissionCcLicence) { + if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().name === ccLicense.name) { + return; + } + this.data.ccLicense = { + name: ccLicense.name, + fields: {}, + }; + this.updateSectionStatus(); + } + + /** + * Get the selected Creative Commons license. + */ + getSelectedCcLicense(): SubmissionCcLicence { + if (!this.submissionCcLicenses || !this.data.ccLicense) { + return null; + } + return this.submissionCcLicenses.filter((ccLicense) => ccLicense.name === this.data.ccLicense.name)[0]; + } + + /** + * Select an option for a given license field. + * @param ccLicense the related Creative Commons license. + * @param field the field for which to select an option. + * @param value the value of the selected option,. + */ + selectOption(ccLicense: SubmissionCcLicence, field: string, value: string) { + + this.data.ccLicense.fields[field] = value; + this.updateSectionStatus(); + } + + /** + * Get the selected option value for a given license field. + * @param ccLicense the related Creative Commons license. + * @param field the field for which to get the selected option value. + */ + getSelectedOption(ccLicense: SubmissionCcLicence, field: string): string { + return this.data.ccLicense.fields[field]; + } + + /** + * Whether a given option value is selected for a given license field. + * @param ccLicense the related Creative Commons license. + * @param field the field for which to check whether the option is selected. + * @param value the value for which to check whether it is selected. + */ + isSelectedOption(ccLicense: SubmissionCcLicence, field: string, value: string): boolean { + return this.getSelectedOption(ccLicense, field) === value; + } + + /** + * Open a given info modal. + * @param content the modal content. + */ + openInfoModal(content) { + this.modalRef = this.modalService.open(content); + } + + /** + * Close the info modal. + */ + closeInfoModal() { + this.modalRef.close(); + } + + /** + * Get section status + * + * @return Observable + * the section status + */ + getSectionStatus(): Observable { + return observableOf( + !!this.getSelectedCcLicense() && this.getSelectedCcLicense().fields.every( + (field) => !!this.getSelectedOption(this.getSelectedCcLicense(), field.id) + ) + ); + } + + /** + * Unsubscribe from all subscriptions + */ + onSectionDestroy(): void { + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); + } + + /** + * Initialize the section. + */ + onSectionInit(): void { + this.subscriptions.push( + this.sectionService.getSectionState(this.submissionId, this.sectionData.id).pipe( + filter((sectionState) => { + return isNotEmpty(sectionState) && (isNotEmpty(sectionState.data) || isNotEmpty(sectionState.errors)) + }), + distinctUntilChanged(), + ).subscribe((sectionState) => { + this.sectionData.data = sectionState.data; + }), + this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe( + getSucceededRemoteData(), + getRemoteDataPayload(), + map((list) => list.page), + ).subscribe( + (licenses) => this.submissionCcLicenses = licenses + ), + ); + } +} diff --git a/src/app/submission/form/collection/submission-form-collection.component.html b/src/app/submission/form/collection/submission-form-collection.component.html index 6f4a8a864c..1e3c07c703 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.html +++ b/src/app/submission/form/collection/submission-form-collection.component.html @@ -1,50 +1,44 @@ -
-
-
- - {{ 'submission.sections.general.collection' | translate }} - -
- + - -
+ +
+ + +
+ + + diff --git a/src/app/submission/submission.module.ts b/src/app/submission/submission.module.ts index 806258baa8..dc38c976e0 100644 --- a/src/app/submission/submission.module.ts +++ b/src/app/submission/submission.module.ts @@ -29,6 +29,7 @@ import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upl import { SubmissionSubmitComponent } from './submit/submission-submit.component'; import { storeModuleConfig } from '../app.reducer'; import { CoreState } from '../core/core.reducers'; +import { SubmissionSectionCcLicensesComponent } from '../shared/submission-section-cc-licenses/submission-section-cc-licenses.component'; @NgModule({ imports: [ @@ -44,8 +45,8 @@ import { CoreState } from '../core/core.reducers'; SubmissionSectionUploadComponent, SubmissionSectionformComponent, SubmissionSectionLicenseComponent, + SubmissionSectionCcLicensesComponent, SectionsDirective, - SubmissionSectionContainerComponent, SubmissionEditComponent, SubmissionFormSectionAddComponent, SubmissionFormCollectionComponent, @@ -53,6 +54,7 @@ import { CoreState } from '../core/core.reducers'; SubmissionFormFooterComponent, SubmissionSubmitComponent, SubmissionUploadFilesComponent, + SubmissionSectionContainerComponent, SubmissionSectionUploadFileComponent, SubmissionSectionUploadFileEditComponent, SubmissionSectionUploadFileViewComponent @@ -61,7 +63,9 @@ import { CoreState } from '../core/core.reducers'; SubmissionSectionUploadComponent, SubmissionSectionformComponent, SubmissionSectionLicenseComponent, - SubmissionSectionContainerComponent], + SubmissionSectionContainerComponent, + SubmissionSectionCcLicensesComponent, + ], exports: [ SubmissionEditComponent, SubmissionFormComponent, diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 686ac66813..2dc1599396 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2426,6 +2426,14 @@ "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Use only for this submission", + "submission.sections.ccLicense.type": "License Type", + + "submission.sections.ccLicense.select": "Select a license…", + + "submission.sections.ccLicense.none": "No licenses available", + + "submission.sections.ccLicense.option.select": "Select an option…", + "submission.sections.general.add-more": "Add more", "submission.sections.general.collection": "Collection", @@ -2456,7 +2464,7 @@ - "submission.sections.submit.progressbar.cclicense": "Creative commons license", + "submission.sections.submit.progressbar.CClicense": "Creative commons license", "submission.sections.submit.progressbar.describe.recycle": "Recycle", From e8021856573ebd364a65c06980f0d9a578a57f24 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 29 Apr 2020 18:48:47 +0200 Subject: [PATCH 02/12] CC License Submission Step - fix tests --- src/app/shared/ds-select/ds-select.component.spec.ts | 9 +++++++-- .../submission-form-collection.component.spec.ts | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/app/shared/ds-select/ds-select.component.spec.ts b/src/app/shared/ds-select/ds-select.component.spec.ts index a3e70808d9..ddec73348c 100644 --- a/src/app/shared/ds-select/ds-select.component.spec.ts +++ b/src/app/shared/ds-select/ds-select.component.spec.ts @@ -1,6 +1,6 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - import { DsSelectComponent } from './ds-select.component'; +import { TranslateModule } from '@ngx-translate/core'; describe('DsSelectComponent', () => { let component: DsSelectComponent; @@ -8,7 +8,12 @@ describe('DsSelectComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ DsSelectComponent ] + imports: [ + TranslateModule.forRoot(), + ], + declarations: [ + DsSelectComponent, + ], }) .compileComponents(); })); diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index 105d94b966..a964d9cd81 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -26,6 +26,7 @@ import { PageInfo } from '../../../core/shared/page-info.model'; import { Collection } from '../../../core/shared/collection.model'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { CollectionDataService } from '../../../core/data/collection-data.service'; +import { SharedModule } from '../../../shared/shared.module'; const subcommunities = [Object.assign(new Community(), { name: 'SubCommunity 1', @@ -223,6 +224,7 @@ describe('SubmissionFormCollectionComponent Component', () => { FormsModule, ReactiveFormsModule, NgbModule, + SharedModule, TranslateModule.forRoot() ], declarations: [ @@ -366,8 +368,8 @@ describe('SubmissionFormCollectionComponent Component', () => { comp.searchListCollection$ = observableOf(mockCollectionList); fixture.detectChanges(); - dropdowBtn = fixture.debugElement.query(By.css('#collectionControlsMenuButton')); - dropdownMenu = fixture.debugElement.query(By.css('#collectionControlsDropdownMenu')); + dropdowBtn = fixture.debugElement.query(By.css('#dsSelectMenuButton')); + dropdownMenu = fixture.debugElement.query(By.css('#dsSelectDropdownMenu')); }); it('should have dropdown menu closed', () => { From 1071506133aa08fbe7f0658a0d0d1158718144a6 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 6 May 2020 14:58:41 +0200 Subject: [PATCH 03/12] CC License Submission Step 2 - Storing the results --- src/app/core/cache/response.models.ts | 15 +++ src/app/core/core.module.ts | 2 + .../data/string-response-parsing.service.ts | 23 ++++ .../submission-cc-licenses-data.service.ts | 49 ++++++- .../shared/submission-cc-license.model.ts | 27 ++-- .../workspaceitem-section-cc-license.model.ts | 10 +- ...mission-section-cc-licenses.component.html | 60 ++++++--- ...sion-section-cc-licenses.component.spec.ts | 88 ++++++++++--- ...ubmission-section-cc-licenses.component.ts | 122 ++++++++++++++---- src/assets/i18n/en.json5 | 6 + 10 files changed, 328 insertions(+), 74 deletions(-) create mode 100644 src/app/core/data/string-response-parsing.service.ts diff --git a/src/app/core/cache/response.models.ts b/src/app/core/cache/response.models.ts index 3f46ecf647..56b8947e08 100644 --- a/src/app/core/cache/response.models.ts +++ b/src/app/core/cache/response.models.ts @@ -29,6 +29,21 @@ export class RestResponse { } } +/** + * A response containing a string. + */ +export class StringResponse extends RestResponse { + + constructor( + public isSuccessful: boolean, + public statusCode: number, + public statusText: string, + public content: string, + ) { + super(isSuccessful, statusCode, statusText); + } +} + export class DSOSuccessResponse extends RestResponse { constructor( public resourceSelfLinks: string[], diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index c8f6dcedcd..0c3555a023 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -147,6 +147,7 @@ import { WorkflowActionDataService } from './data/workflow-action-data.service'; import { WorkflowAction } from './tasks/models/workflow-action-object.model'; import { SubmissionCcLicensesDataService } from './data/submission-cc-licenses-data.service'; import { SubmissionCcLicence } from './shared/submission-cc-license.model'; +import { StringResponseParsingService } from './data/string-response-parsing.service'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -214,6 +215,7 @@ const PROVIDERS = [ BrowseResponseParsingService, BrowseEntriesResponseParsingService, BrowseItemsResponseParsingService, + StringResponseParsingService, BrowseService, ConfigResponseParsingService, SubmissionCcLicensesDataService, diff --git a/src/app/core/data/string-response-parsing.service.ts b/src/app/core/data/string-response-parsing.service.ts new file mode 100644 index 0000000000..aea314e27a --- /dev/null +++ b/src/app/core/data/string-response-parsing.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import {RestResponse, StringResponse} from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; + +/** + * A responseparser that will parse the response body to a string. + */ +@Injectable() +export class StringResponseParsingService implements ResponseParsingService { + + /** + * Parse the response to a string. + * + * @param request The request that was sent to the server + * @param data The response to parse + */ + parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { + const isSuccessful = data.statusCode >= 200 && data.statusCode < 300; + return new StringResponse(isSuccessful, data.statusCode, data.statusText, data.payload as undefined as string); + } +} diff --git a/src/app/core/data/submission-cc-licenses-data.service.ts b/src/app/core/data/submission-cc-licenses-data.service.ts index 057c4389f7..3610e4a3c6 100644 --- a/src/app/core/data/submission-cc-licenses-data.service.ts +++ b/src/app/core/data/submission-cc-licenses-data.service.ts @@ -10,8 +10,14 @@ import { HALEndpointService } from '../shared/hal-endpoint.service'; import { DataService } from './data.service'; import { RequestService } from './request.service'; import { SUBMISSION_CC_LICENSE } from '../shared/submission-cc-licences.resource-type'; -import { SubmissionCcLicence } from '../shared/submission-cc-license.model'; +import { Field, Option, SubmissionCcLicence } from '../shared/submission-cc-license.model'; import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { GetRequest } from './request.models'; +import { configureRequest, getResponseFromEntry } from '../shared/operators'; +import { map, switchMap, tap } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { StringResponse } from '../cache/response.models'; +import { StringResponseParsingService } from './string-response-parsing.service'; @Injectable() @dataService(SUBMISSION_CC_LICENSE) @@ -31,4 +37,45 @@ export class SubmissionCcLicensesDataService extends DataService): Observable { + + const requestId = this.requestService.generateRequestId(); + + return this.getSearchByHref( + 'rightsByQuestions',{ + searchParams: [ + { + fieldName: 'license', + fieldValue: ccLicense.id + }, + ...ccLicense.fields.map( + (field) => { + return { + fieldName: `answer_${field.id}`, + fieldValue: options.get(field).id, + } + }), + ] + } + ).pipe( + map((endpoint) => new GetRequest( + requestId, + endpoint, + undefined, { + responseType: 'text', + }, + )), + tap((request) => request.getResponseParser = () => StringResponseParsingService), + configureRequest(this.requestService), + switchMap(() => this.requestService.getByUUID(requestId)), + getResponseFromEntry(), + map((response) => response as StringResponse), + ); + } } diff --git a/src/app/core/shared/submission-cc-license.model.ts b/src/app/core/shared/submission-cc-license.model.ts index 0b2cfbcca6..2796edf6f2 100644 --- a/src/app/core/shared/submission-cc-license.model.ts +++ b/src/app/core/shared/submission-cc-license.model.ts @@ -18,18 +18,25 @@ export class SubmissionCcLicence extends HALResource { @autoserialize type: ResourceType; + @autoserialize + id: string; + @autoserialize name: string; @autoserialize - fields: Array<{ - id: string; - label: string; - description: string; - enums: Array<{ - id: string; - label: string; - description: string; - }>; - }>; + fields: Field[]; +} + +export interface Field { + id: string; + label: string; + description: string; + enums: Option[]; +} + +export interface Option { + id: string; + label: string; + description: string; } diff --git a/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts b/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts index 65f6a5b9e4..9cc7af771c 100644 --- a/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts +++ b/src/app/core/submission/models/workspaceitem-section-cc-license.model.ts @@ -1,11 +1,15 @@ +import {Option} from '../../shared/submission-cc-license.model'; + /** * An interface to represent the submission's creative commons license section data. */ export interface WorkspaceitemSectionCcLicenseObject { - ccLicense: { - name: string; + ccLicense?: { + id: string; fields: { - [field: string]: string; + [fieldId: string]: Option; } }; + uri?: string; + accepted?: boolean; } diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html index f598be7af8..52e6a6f1fa 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html @@ -11,7 +11,12 @@ {{ getSelectedCcLicense().name }} - {{ 'submission.sections.ccLicense.select' | translate }} + + {{ 'submission.sections.ccLicense.change' | translate }} + + + {{ 'submission.sections.ccLicense.select' | translate }} + @@ -22,7 +27,7 @@ @@ -78,33 +83,32 @@ - + - {{ option }} + {{ option.label }} {{ 'submission.sections.ccLicense.option.select' | translate }} - -
- -
- {{ value.label }} +
+
+ + {{ option.label }}
@@ -112,3 +116,27 @@
+ + + +
+ +
+ +
+ {{ 'submission.sections.ccLicense.link' | translate }} +
+ + {{ licenseLink }} + +
+
+ + {{ 'submission.sections.ccLicense.confirmation' | translate }} +
+
+
+
+
diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts index 38e4384b2e..125cfdadc9 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts @@ -15,6 +15,8 @@ import { PageInfo } from '../../core/shared/page-info.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { SubmissionCcLicence } from '../../core/shared/submission-cc-license.model'; import { cold } from 'jasmine-marbles'; +import { JsonPatchOperationsBuilder } from '../../core/json-patch/builder/json-patch-operations-builder'; +import { StringResponse } from '../../core/cache/response.models'; describe('SubmissionSectionCcLicensesComponent', () => { @@ -34,6 +36,7 @@ describe('SubmissionSectionCcLicensesComponent', () => { const submissionCcLicenses: SubmissionCcLicence[] = [ { + id: 'test license id 1', type: SUBMISSION_CC_LICENSE, name: 'test license name 1', fields: [ @@ -79,6 +82,7 @@ describe('SubmissionSectionCcLicensesComponent', () => { }, }, { + id: 'test license id 2', type: SUBMISSION_CC_LICENSE, name: 'test license name 2', fields: [ @@ -124,25 +128,31 @@ describe('SubmissionSectionCcLicensesComponent', () => { }, }, ]; - const submissionCcLicensesDataService = { - findAll: () => observableOf(new RemoteData( + + const submissionCcLicensesDataService = jasmine.createSpyObj('submissionCcLicensesDataService', { + getCcLicenseLink: observableOf(new StringResponse(true, 200, '200', 'test cc license link')), + findAll: observableOf(new RemoteData( false, false, true, undefined, new PaginatedList(new PageInfo(), submissionCcLicenses), )), - }; + }); const sectionService = { - getSectionState: () => observableOf( - { - data: {}, - } - ), + getSectionState: () => observableOf({ + data: {} + }), setSectionStatus: () => undefined, + updateSectionData: () => undefined, }; + const operationsBuilder = jasmine.createSpyObj('operationsBuilder', { + add: undefined, + remove: undefined, + }); + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -153,11 +163,12 @@ describe('SubmissionSectionCcLicensesComponent', () => { SubmissionSectionCcLicensesComponent, ], providers: [ - {provide: SubmissionCcLicensesDataService, useValue: submissionCcLicensesDataService}, - {provide: SectionsService, useValue: sectionService}, - {provide: 'collectionIdProvider', useValue: 'test collection id'}, - {provide: 'sectionDataProvider', useValue: sectionObject}, - {provide: 'submissionIdProvider', useValue: 'test submission id'}, + { provide: SubmissionCcLicensesDataService, useValue: submissionCcLicensesDataService }, + { provide: SectionsService, useValue: sectionService }, + { provide: JsonPatchOperationsBuilder, useValue: operationsBuilder }, + { provide: 'collectionIdProvider', useValue: 'test collection id' }, + { provide: 'sectionDataProvider', useValue: sectionObject }, + { provide: 'submissionIdProvider', useValue: 'test submission id' }, ], }) .compileComponents(); @@ -181,8 +192,10 @@ describe('SubmissionSectionCcLicensesComponent', () => { describe('when a license is selected', () => { + const ccLicence = submissionCcLicenses[1]; + beforeEach(() => { - component.select(submissionCcLicenses[1]); + component.selectCcLicense(ccLicence); fixture.detectChanges(); }); @@ -199,6 +212,10 @@ describe('SubmissionSectionCcLicensesComponent', () => { expect(de.query(By.css('div.test-field-id-2b'))).toBeTruthy(); }); + it('should not display a license link', () => { + expect(de.query(By.css('.license-link'))).toBeNull(); + }); + it('should have section status incomplete', () => { expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false })); }); @@ -206,14 +223,47 @@ describe('SubmissionSectionCcLicensesComponent', () => { describe('when all options have a value selected', () => { beforeEach(() => { - const ccLicence = submissionCcLicenses[1]; - component.selectOption(ccLicence, ccLicence.fields[0].id, ccLicence.fields[0].enums[1].label); - component.selectOption(ccLicence, ccLicence.fields[1].id, ccLicence.fields[1].enums[0].label); + component.selectOption(ccLicence, ccLicence.fields[0], ccLicence.fields[0].enums[1]); + component.selectOption(ccLicence, ccLicence.fields[1], ccLicence.fields[1].enums[0]); fixture.detectChanges(); }); - it('should have section status complete', () => { - expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true })); + it('should call the submission cc licenses data service getCcLicenseLink method', () => { + expect(submissionCcLicensesDataService.getCcLicenseLink).toHaveBeenCalledWith( + ccLicence, + new Map([ + [ccLicence.fields[0], ccLicence.fields[0].enums[1]], + [ccLicence.fields[1], ccLicence.fields[1].enums[0]], + ]) + ); + }); + + it('should display a cc license link', () => { + expect(de.query(By.css('.license-link'))).toBeTruthy(); + }); + + it('should not be accepted', () => { + expect(component.accepted).toBeFalse(); + }); + + it('should have section status incomplete', () => { + expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false })); + }); + + describe('when the cc license is accepted', () => { + + beforeEach(() => { + component.setAccepted(true); + fixture.detectChanges(); + }); + + it('should call the operations builder add method', () => { + expect(operationsBuilder.add).toHaveBeenCalled(); + }); + + it('should have section status complete', () => { + expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true })); + }); }); }); }); diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts index d7241a3220..b76b67dcb3 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts @@ -1,6 +1,6 @@ import { Component, Inject } from '@angular/core'; import { Observable, of as observableOf, Subscription } from 'rxjs'; -import { SubmissionCcLicence } from '../../core/shared/submission-cc-license.model'; +import { Field, Option, SubmissionCcLicence } from '../../core/shared/submission-cc-license.model'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators'; import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { SubmissionCcLicensesDataService } from '../../core/data/submission-cc-licenses-data.service'; @@ -13,6 +13,7 @@ import { SectionsService } from '../../submission/sections/sections.service'; import { WorkspaceitemSectionCcLicenseObject } from '../../core/submission/models/workspaceitem-section-cc-license.model'; import { JsonPatchOperationPathCombiner } from '../../core/json-patch/builder/json-patch-operation-path-combiner'; import { isNotEmpty } from '../empty.util'; +import { JsonPatchOperationsBuilder } from '../../core/json-patch/builder/json-patch-operations-builder'; /** * This component represents the submission section to select the Creative Commons license. @@ -58,10 +59,28 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent */ protected modalRef: NgbModalRef; + /** + * The Creative Commons link saved in the workspace item. + */ + get storedCcLicenseLink(): string { + return this.data.uri; + } + + /** + * The accepted state for the selected Creative Commons license. + */ + get accepted(): boolean { + if (this.data.accepted === undefined) { + return !!this.data.uri; + } + return this.data.accepted; + } + constructor( protected modalService: NgbModal, protected sectionService: SectionsService, protected submissionCcLicensesDataService: SubmissionCcLicensesDataService, + protected operationsBuilder: JsonPatchOperationsBuilder, @Inject('collectionIdProvider') public injectedCollectionId: string, @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, @Inject('submissionIdProvider') public injectedSubmissionId: string @@ -84,15 +103,16 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent * Select a given Creative Commons license. * @param ccLicense the Creative Commons license to select. */ - select(ccLicense: SubmissionCcLicence) { - if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().name === ccLicense.name) { + selectCcLicense(ccLicense: SubmissionCcLicence) { + if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().id === ccLicense.id) { return; } this.data.ccLicense = { - name: ccLicense.name, + id: ccLicense.id, fields: {}, }; - this.updateSectionStatus(); + this.data.uri = undefined; + this.setAccepted(false); } /** @@ -102,38 +122,63 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent if (!this.submissionCcLicenses || !this.data.ccLicense) { return null; } - return this.submissionCcLicenses.filter((ccLicense) => ccLicense.name === this.data.ccLicense.name)[0]; + return this.submissionCcLicenses.filter((ccLicense) => ccLicense.id === this.data.ccLicense.id)[0]; } /** * Select an option for a given license field. * @param ccLicense the related Creative Commons license. * @param field the field for which to select an option. - * @param value the value of the selected option,. + * @param option the option to select. */ - selectOption(ccLicense: SubmissionCcLicence, field: string, value: string) { - - this.data.ccLicense.fields[field] = value; - this.updateSectionStatus(); + selectOption(ccLicense: SubmissionCcLicence, field: Field, option: Option) { + if (this.isSelectedOption(ccLicense, field, option)) { + return; + } + this.data.ccLicense.fields[field.id] = option; + this.setAccepted(false); } /** - * Get the selected option value for a given license field. + * Get the selected option for a given license field. * @param ccLicense the related Creative Commons license. * @param field the field for which to get the selected option value. */ - getSelectedOption(ccLicense: SubmissionCcLicence, field: string): string { - return this.data.ccLicense.fields[field]; + getSelectedOption(ccLicense: SubmissionCcLicence, field: Field): Option { + return this.data.ccLicense.fields[field.id]; } /** - * Whether a given option value is selected for a given license field. + * Whether a given option is selected for a given Creative Commons license field. * @param ccLicense the related Creative Commons license. * @param field the field for which to check whether the option is selected. - * @param value the value for which to check whether it is selected. + * @param option the option for which to check whether it is selected. */ - isSelectedOption(ccLicense: SubmissionCcLicence, field: string, value: string): boolean { - return this.getSelectedOption(ccLicense, field) === value; + isSelectedOption(ccLicense: SubmissionCcLicence, field: Field, option: Option): boolean { + return this.getSelectedOption(ccLicense, field) && this.getSelectedOption(ccLicense, field).id === option.id; + } + + /** + * Get the link to the Creative Commons license corresponding with the selected options. + */ + getCcLicenseLink$(): Observable { + + if (!!this.storedCcLicenseLink) { + return observableOf(this.storedCcLicenseLink); + } + if (!this.getSelectedCcLicense() || this.getSelectedCcLicense().fields.some( + (field) => !this.getSelectedOption(this.getSelectedCcLicense(), field))) { + return undefined; + } + const selectedCcLicense = this.getSelectedCcLicense(); + return this.submissionCcLicensesDataService.getCcLicenseLink( + selectedCcLicense, + new Map(selectedCcLicense.fields.map( + (field) => [field, this.getSelectedOption(selectedCcLicense, field)] + )), + ).pipe( + map((response) => response.content), + ); } /** @@ -158,11 +203,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent * the section status */ getSectionStatus(): Observable { - return observableOf( - !!this.getSelectedCcLicense() && this.getSelectedCcLicense().fields.every( - (field) => !!this.getSelectedOption(this.getSelectedCcLicense(), field.id) - ) - ); + return observableOf(this.accepted); } /** @@ -176,14 +217,16 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent * Initialize the section. */ onSectionInit(): void { + this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id); this.subscriptions.push( this.sectionService.getSectionState(this.submissionId, this.sectionData.id).pipe( filter((sectionState) => { return isNotEmpty(sectionState) && (isNotEmpty(sectionState.data) || isNotEmpty(sectionState.errors)) }), distinctUntilChanged(), - ).subscribe((sectionState) => { - this.sectionData.data = sectionState.data; + map((sectionState) => sectionState.data as WorkspaceitemSectionCcLicenseObject), + ).subscribe((data) => { + this.sectionData.data = data; }), this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe( getSucceededRemoteData(), @@ -194,4 +237,33 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent ), ); } + + /** + * Set the accepted state for the Creative Commons license. + * @param accepted the accepted state for the cc license. + */ + setAccepted(accepted: boolean) { + const path = this.pathCombiner.getPath('uri'); + if (accepted) { + this.getCcLicenseLink$().subscribe((link) => { + this.operationsBuilder.add(path, link.toString(), false, true); + this.data.accepted = true; + this.updateSectionData(); + this.updateSectionStatus(); + } + ); + } else { + this.operationsBuilder.remove(path); + this.data.accepted = false; + this.updateSectionData(); + this.updateSectionStatus(); + } + } + + /** + * Update the section data for this section. + */ + updateSectionData() { + this.sectionService.updateSectionData(this.submissionId, this.sectionData.id, this.data); + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 2dc1599396..5931ae5491 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2430,10 +2430,16 @@ "submission.sections.ccLicense.select": "Select a license…", + "submission.sections.ccLicense.change": "Change your license…", + "submission.sections.ccLicense.none": "No licenses available", "submission.sections.ccLicense.option.select": "Select an option…", + "submission.sections.ccLicense.link": "You’ve selected the following license:", + + "submission.sections.ccLicense.confirmation": "I grant the license above", + "submission.sections.general.add-more": "Add more", "submission.sections.general.collection": "Collection", From 18007048a32c9ee34708d777236c3fb2cb664a76 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 20 May 2020 13:55:42 +0200 Subject: [PATCH 04/12] CC License Submission Step 2 - Storing the results - feedback --- .../shared/ds-select/ds-select.component.scss | 0 .../shared/ds-select/ds-select.component.ts | 2 +- ...mission-section-cc-licenses.component.html | 25 +++++---- ...mission-section-cc-licenses.component.scss | 0 ...ubmission-section-cc-licenses.component.ts | 56 ++++++++++--------- 5 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 src/app/shared/ds-select/ds-select.component.scss create mode 100644 src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.scss diff --git a/src/app/shared/ds-select/ds-select.component.scss b/src/app/shared/ds-select/ds-select.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/ds-select/ds-select.component.ts b/src/app/shared/ds-select/ds-select.component.ts index 4e2a1f6973..26d1560c01 100644 --- a/src/app/shared/ds-select/ds-select.component.ts +++ b/src/app/shared/ds-select/ds-select.component.ts @@ -6,7 +6,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'ds-select', templateUrl: './ds-select.component.html', - styleUrls: ['./ds-select.component.css'] + styleUrls: ['./ds-select.component.scss'] }) export class DsSelectComponent { diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html index 52e6a6f1fa..6818b4d254 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html +++ b/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html @@ -1,4 +1,4 @@ -
+
@@ -38,10 +38,10 @@
+ class="mb-4"> -
-
+
+
{{ field.label }}
- -
- + - + +
+
diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index a964d9cd81..105d94b966 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -26,7 +26,6 @@ import { PageInfo } from '../../../core/shared/page-info.model'; import { Collection } from '../../../core/shared/collection.model'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { CollectionDataService } from '../../../core/data/collection-data.service'; -import { SharedModule } from '../../../shared/shared.module'; const subcommunities = [Object.assign(new Community(), { name: 'SubCommunity 1', @@ -224,7 +223,6 @@ describe('SubmissionFormCollectionComponent Component', () => { FormsModule, ReactiveFormsModule, NgbModule, - SharedModule, TranslateModule.forRoot() ], declarations: [ @@ -368,8 +366,8 @@ describe('SubmissionFormCollectionComponent Component', () => { comp.searchListCollection$ = observableOf(mockCollectionList); fixture.detectChanges(); - dropdowBtn = fixture.debugElement.query(By.css('#dsSelectMenuButton')); - dropdownMenu = fixture.debugElement.query(By.css('#dsSelectDropdownMenu')); + dropdowBtn = fixture.debugElement.query(By.css('#collectionControlsMenuButton')); + dropdownMenu = fixture.debugElement.query(By.css('#collectionControlsDropdownMenu')); }); it('should have dropdown menu closed', () => { diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html similarity index 90% rename from src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html rename to src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html index 6818b4d254..d862cb598a 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.html +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html @@ -1,11 +1,10 @@
+ [disabled]="!submissionCcLicenses"> - + {{ getSelectedCcLicense().name }} @@ -92,11 +91,13 @@ - +
+ +
@@ -120,7 +121,7 @@
- +
diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.scss b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.scss new file mode 100644 index 0000000000..62a902b79a --- /dev/null +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.scss @@ -0,0 +1,3 @@ +.options-select-menu { + max-height: 25vh; +} diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts similarity index 89% rename from src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts rename to src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts index 78ea927af6..a69ab2971d 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.spec.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts @@ -1,22 +1,22 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { SubmissionSectionCcLicensesComponent } from './submission-section-cc-licenses.component'; -import { SUBMISSION_CC_LICENSE } from '../../core/shared/submission-cc-licence.resource-type'; +import { SUBMISSION_CC_LICENSE } from '../../../core/submission/models/submission-cc-licence.resource-type'; import { of as observableOf } from 'rxjs'; -import { SubmissionCcLicenseDataService } from '../../core/data/submission-cc-license-data.service'; +import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service'; import { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { SharedModule } from '../shared.module'; -import { SectionsService } from '../../submission/sections/sections.service'; -import { SectionDataObject } from '../../submission/sections/models/section-data.model'; -import { SectionsType } from '../../submission/sections/sections-type'; -import { RemoteData } from '../../core/data/remote-data'; +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/shared/submission-cc-license.model'; +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/data/submission-cc-license-url-data.service'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service'; describe('SubmissionSectionCcLicensesComponent', () => { diff --git a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts similarity index 88% rename from src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts rename to src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts index 6c3d52de55..d2aa78d030 100644 --- a/src/app/shared/submission-section-cc-licenses/submission-section-cc-licenses.component.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts @@ -1,19 +1,19 @@ import { Component, Inject } from '@angular/core'; import { Observable, of as observableOf, Subscription } from 'rxjs'; -import { Field, Option, SubmissionCcLicence } from '../../core/shared/submission-cc-license.model'; -import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators'; +import { Field, Option, SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model'; +import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators'; import { distinctUntilChanged, filter, map } from 'rxjs/operators'; -import { SubmissionCcLicenseDataService } from '../../core/data/submission-cc-license-data.service'; +import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; -import { renderSectionFor } from '../../submission/sections/sections-decorator'; -import { SectionsType } from '../../submission/sections/sections-type'; -import { SectionModelComponent } from '../../submission/sections/models/section.model'; -import { SectionDataObject } from '../../submission/sections/models/section-data.model'; -import { SectionsService } from '../../submission/sections/sections.service'; -import { WorkspaceitemSectionCcLicenseObject } from '../../core/submission/models/workspaceitem-section-cc-license.model'; -import { JsonPatchOperationPathCombiner } from '../../core/json-patch/builder/json-patch-operation-path-combiner'; -import { isNotEmpty } from '../empty.util'; -import { JsonPatchOperationsBuilder } from '../../core/json-patch/builder/json-patch-operations-builder'; +import { renderSectionFor } from '../sections-decorator'; +import { SectionsType } from '../sections-type'; +import { SectionModelComponent } from '../models/section.model'; +import { SectionDataObject } from '../models/section-data.model'; +import { SectionsService } from '../sections.service'; +import { WorkspaceitemSectionCcLicenseObject } from '../../../core/submission/models/workspaceitem-section-cc-license.model'; +import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { isNotEmpty } from '../../../shared/empty.util'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; /** * This component represents the submission section to select the Creative Commons license. diff --git a/src/app/submission/submission.module.ts b/src/app/submission/submission.module.ts index dc38c976e0..93bf06b193 100644 --- a/src/app/submission/submission.module.ts +++ b/src/app/submission/submission.module.ts @@ -28,8 +28,7 @@ import { SubmissionSectionUploadFileViewComponent } from './sections/upload/file import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upload/accessConditions/submission-section-upload-access-conditions.component'; import { SubmissionSubmitComponent } from './submit/submission-submit.component'; import { storeModuleConfig } from '../app.reducer'; -import { CoreState } from '../core/core.reducers'; -import { SubmissionSectionCcLicensesComponent } from '../shared/submission-section-cc-licenses/submission-section-cc-licenses.component'; +import { SubmissionSectionCcLicensesComponent } from './sections/cc-license/submission-section-cc-licenses.component'; @NgModule({ imports: [ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index f60ef5c08b..5d1ae0f9f9 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2537,9 +2537,9 @@ "submission.sections.ccLicense.type": "License Type", - "submission.sections.ccLicense.select": "Select a license…", + "submission.sections.ccLicense.select": "Select a license type…", - "submission.sections.ccLicense.change": "Change your license…", + "submission.sections.ccLicense.change": "Change your license type…", "submission.sections.ccLicense.none": "No licenses available", From 02ddf7c8c532060b75c29bfbb05ea18c43e238f2 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 26 Jun 2020 16:58:45 +0200 Subject: [PATCH 07/12] CC License Submission Step - implement contract change --- .../submission-cc-license-data.service.ts | 41 +---------------- .../submission-cc-license-url-data.service.ts | 44 ++++++++++++++++++- ...ubmission-section-cc-licenses.component.ts | 4 +- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/app/core/submission/submission-cc-license-data.service.ts b/src/app/core/submission/submission-cc-license-data.service.ts index 5e738e0327..5a3fa1ec2b 100644 --- a/src/app/core/submission/submission-cc-license-data.service.ts +++ b/src/app/core/submission/submission-cc-license-data.service.ts @@ -10,15 +10,8 @@ import { HALEndpointService } from '../shared/hal-endpoint.service'; import { DataService } from '../data/data.service'; import { RequestService } from '../data/request.service'; import { SUBMISSION_CC_LICENSE } from './models/submission-cc-licence.resource-type'; -import { Field, Option, SubmissionCcLicence } from './models/submission-cc-license.model'; +import { SubmissionCcLicence } from './models/submission-cc-license.model'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; -import { - getRemoteDataPayload, - getSucceededRemoteData, -} from '../shared/operators'; -import { map, switchMap } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { SubmissionCcLicenseUrlDataService } from './submission-cc-license-url-data.service'; @Injectable() @dataService(SUBMISSION_CC_LICENSE) @@ -35,39 +28,7 @@ export class SubmissionCcLicenseDataService extends DataService, - protected submissionCcLicenseUrlDataService: SubmissionCcLicenseUrlDataService, ) { super(); } - - /** - * Get the link to the Creative Commons license corresponding to the given type and options. - * @param ccLicense the Creative Commons license type - * @param options the selected options of the license fields - */ - getCcLicenseLink(ccLicense: SubmissionCcLicence, options: Map): Observable { - - return this.getSearchByHref( - 'rightsByQuestions',{ - searchParams: [ - { - fieldName: 'license', - fieldValue: ccLicense.id - }, - ...ccLicense.fields.map( - (field) => { - return { - fieldName: `answer_${field.id}`, - fieldValue: options.get(field).id, - } - }), - ] - } - ).pipe( - switchMap((href) => this.submissionCcLicenseUrlDataService.findByHref(href)), - getSucceededRemoteData(), - getRemoteDataPayload(), - map((response) => response.url), - ); - } } diff --git a/src/app/core/submission/submission-cc-license-url-data.service.ts b/src/app/core/submission/submission-cc-license-url-data.service.ts index 08e1c16fa3..fc7547b3a6 100644 --- a/src/app/core/submission/submission-cc-license-url-data.service.ts +++ b/src/app/core/submission/submission-cc-license-url-data.service.ts @@ -12,12 +12,17 @@ import { RequestService } from '../data/request.service'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; import { SubmissionCcLicenceUrl } from './models/submission-cc-license-url.model'; import { SUBMISSION_CC_LICENSE_URL } from './models/submission-cc-licence-link.resource-type'; +import { Field, Option, SubmissionCcLicence } from "./models/submission-cc-license.model"; +import { Observable } from "rxjs"; +import { filter, map, switchMap } from "rxjs/operators"; +import { getRemoteDataPayload, getSucceededRemoteData } from "../shared/operators"; +import { isNotEmpty } from "../../shared/empty.util"; @Injectable() @dataService(SUBMISSION_CC_LICENSE_URL) export class SubmissionCcLicenseUrlDataService extends DataService { - protected linkPath = 'submissioncclicenses'; + protected linkPath = 'submissioncclicenseUrl-search'; constructor( protected comparator: DefaultChangeAnalyzer, @@ -31,4 +36,41 @@ export class SubmissionCcLicenseUrlDataService extends DataService): Observable { + + return this.getSearchByHref( + 'rightsByQuestions',{ + searchParams: [ + { + fieldName: 'license', + fieldValue: ccLicense.id + }, + ...ccLicense.fields.map( + (field) => { + return { + fieldName: `answer_${field.id}`, + fieldValue: options.get(field).id, + } + }), + ] + } + ).pipe( + switchMap((href) => this.findByHref(href)), + getSucceededRemoteData(), + getRemoteDataPayload(), + map((response) => response.url), + ); + } + + protected getSearchEndpoint(searchMethod: string): Observable { + return this.halService.getEndpoint(`${this.linkPath}`).pipe( + filter((href: string) => isNotEmpty(href)), + map((href: string) => `${href}/${searchMethod}`)); + } } diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts index d2aa78d030..d608f21fbc 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts @@ -14,6 +14,7 @@ import { WorkspaceitemSectionCcLicenseObject } from '../../../core/submission/mo import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { isNotEmpty } from '../../../shared/empty.util'; import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { SubmissionCcLicenseUrlDataService } from "../../../core/submission/submission-cc-license-url-data.service"; /** * This component represents the submission section to select the Creative Commons license. @@ -80,6 +81,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent protected modalService: NgbModal, protected sectionService: SectionsService, protected submissionCcLicensesDataService: SubmissionCcLicenseDataService, + protected submissionCcLicenseUrlDataService: SubmissionCcLicenseUrlDataService, protected operationsBuilder: JsonPatchOperationsBuilder, @Inject('collectionIdProvider') public injectedCollectionId: string, @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, @@ -180,7 +182,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent return undefined; } const selectedCcLicense = this.getSelectedCcLicense(); - return this.submissionCcLicensesDataService.getCcLicenseLink( + return this.submissionCcLicenseUrlDataService.getCcLicenseLink( selectedCcLicense, new Map(selectedCcLicense.fields.map( (field) => [field, this.getSelectedOption(selectedCcLicense, field)] From 0888d8131014e4e292afedaeecda7f9589bc710f Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 26 Jun 2020 17:30:06 +0200 Subject: [PATCH 08/12] CC License Submission Step - fix lint issues --- .../submission-cc-license-url-data.service.ts | 10 +++++----- .../submission-section-cc-licenses.component.html | 2 +- .../submission-section-cc-licenses.component.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/core/submission/submission-cc-license-url-data.service.ts b/src/app/core/submission/submission-cc-license-url-data.service.ts index fc7547b3a6..0ec40e1403 100644 --- a/src/app/core/submission/submission-cc-license-url-data.service.ts +++ b/src/app/core/submission/submission-cc-license-url-data.service.ts @@ -12,11 +12,11 @@ import { RequestService } from '../data/request.service'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; import { SubmissionCcLicenceUrl } from './models/submission-cc-license-url.model'; import { SUBMISSION_CC_LICENSE_URL } from './models/submission-cc-licence-link.resource-type'; -import { Field, Option, SubmissionCcLicence } from "./models/submission-cc-license.model"; -import { Observable } from "rxjs"; -import { filter, map, switchMap } from "rxjs/operators"; -import { getRemoteDataPayload, getSucceededRemoteData } from "../shared/operators"; -import { isNotEmpty } from "../../shared/empty.util"; +import { Field, Option, SubmissionCcLicence } from './models/submission-cc-license.model'; +import { Observable } from 'rxjs'; +import { filter, map, switchMap } from 'rxjs/operators'; +import { getRemoteDataPayload, getSucceededRemoteData } from '../shared/operators'; +import { isNotEmpty } from '../../shared/empty.util'; @Injectable() @dataService(SUBMISSION_CC_LICENSE_URL) diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html index d862cb598a..20743540a8 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html @@ -128,7 +128,7 @@
{{ 'submission.sections.ccLicense.link' | translate }}
- + {{ licenseLink }}
diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts index d608f21fbc..97c6ba85e0 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts @@ -14,7 +14,7 @@ import { WorkspaceitemSectionCcLicenseObject } from '../../../core/submission/mo import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { isNotEmpty } from '../../../shared/empty.util'; import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; -import { SubmissionCcLicenseUrlDataService } from "../../../core/submission/submission-cc-license-url-data.service"; +import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service'; /** * This component represents the submission section to select the Creative Commons license. From 3f397525507d958bb18dd2f1ed2ff43e7f11bd64 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 30 Jun 2020 10:53:56 +0200 Subject: [PATCH 09/12] CC License Submission Step - fix tests --- ...sion-section-cc-licenses.component.spec.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts index a69ab2971d..230c72b522 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts @@ -130,6 +130,16 @@ describe('SubmissionSectionCcLicensesComponent', () => { ]; const submissionCcLicensesDataService = jasmine.createSpyObj('submissionCcLicensesDataService', { + findAll: observableOf(new RemoteData( + false, + false, + true, + undefined, + new PaginatedList(new PageInfo(), submissionCcLicenses), + )), + }); + + const submissionCcLicenseUrlDataService = jasmine.createSpyObj('submissionCcLicenseUrlDataService', { getCcLicenseLink: observableOf(new RemoteData( false, false, @@ -139,13 +149,6 @@ describe('SubmissionSectionCcLicensesComponent', () => { url: 'test cc license link', } )), - findAll: observableOf(new RemoteData( - false, - false, - true, - undefined, - new PaginatedList(new PageInfo(), submissionCcLicenses), - )), }); const sectionService = { @@ -174,7 +177,7 @@ describe('SubmissionSectionCcLicensesComponent', () => { ], providers: [ { provide: SubmissionCcLicenseDataService, useValue: submissionCcLicensesDataService }, - { provide: SubmissionCcLicenseUrlDataService, useValue: {} }, + { provide: SubmissionCcLicenseUrlDataService, useValue: submissionCcLicenseUrlDataService }, { provide: SectionsService, useValue: sectionService }, { provide: JsonPatchOperationsBuilder, useValue: operationsBuilder }, { provide: 'collectionIdProvider', useValue: 'test collection id' }, @@ -240,7 +243,7 @@ describe('SubmissionSectionCcLicensesComponent', () => { }); it('should call the submission cc licenses data service getCcLicenseLink method', () => { - expect(submissionCcLicensesDataService.getCcLicenseLink).toHaveBeenCalledWith( + expect(submissionCcLicenseUrlDataService.getCcLicenseLink).toHaveBeenCalledWith( ccLicence, new Map([ [ccLicence.fields[0], ccLicence.fields[0].enums[1]], From ea28998bc1ffc4c1ab3af315cd313efa9355a5fe Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 30 Jun 2020 17:31:32 +0200 Subject: [PATCH 10/12] CC License Submission Step - fix tests bis --- src/app/community-list-page/community-list-service.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/community-list-page/community-list-service.spec.ts b/src/app/community-list-page/community-list-service.spec.ts index f4955b2a36..e1a0f5c17f 100644 --- a/src/app/community-list-page/community-list-service.spec.ts +++ b/src/app/community-list-page/community-list-service.spec.ts @@ -450,7 +450,7 @@ describe('CommunityListService', () => { }); let flatNodeList; describe('should return list containing only flatnode corresponding to that community', () => { - beforeAll((done) => { + beforeEach((done) => { service.transformCommunity(communityWithSubcoms, 0, null, null) .pipe(take(1)) .subscribe((value) => { From 9bbdf95bee6df99016e90a5c492ed9edd6941908 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 1 Jul 2020 18:28:48 +0200 Subject: [PATCH 11/12] CC License Submission Step - fix error when changing accepted license --- .../cc-license/submission-section-cc-licenses.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts index 97c6ba85e0..46e1cd12ec 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts @@ -109,6 +109,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().id === ccLicense.id) { return; } + this.setAccepted(false); this.updateSectionData({ ccLicense: { id: ccLicense.id, @@ -116,7 +117,6 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent }, uri: undefined, }); - this.setAccepted(false); } /** From f655f5d1490d28ead5dfce8ce1be348ddaf05db5 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 2 Jul 2020 12:54:27 +0200 Subject: [PATCH 12/12] CC License Submission Step - fix error when saving submission --- ...ubmission-section-cc-licenses.component.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts index 46e1cd12ec..d455bd5e22 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts @@ -2,7 +2,7 @@ import { Component, Inject } from '@angular/core'; import { Observable, of as observableOf, Subscription } from 'rxjs'; import { Field, Option, SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators'; -import { distinctUntilChanged, filter, map } from 'rxjs/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'; import { renderSectionFor } from '../sections-decorator'; @@ -235,15 +235,19 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent distinctUntilChanged(), map((sectionState) => sectionState.data as WorkspaceitemSectionCcLicenseObject), ).subscribe((data) => { - this.sectionData.data = data; - const path = this.pathCombiner.getPath('uri'); - if (this.accepted) { - this.getCcLicenseLink$().subscribe((link) => { - this.operationsBuilder.add(path, link.toString(), false, true); - }); - } else { - this.operationsBuilder.remove(path); + if (this.data.accepted !== data.accepted) { + const path = this.pathCombiner.getPath('uri'); + if (data.accepted) { + this.getCcLicenseLink$().pipe( + take(1), + ).subscribe((link) => { + this.operationsBuilder.add(path, link.toString(), false, true); + }); + } else if (!!this.data.uri) { + this.operationsBuilder.remove(path); + } } + this.sectionData.data = data; }), this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe( getSucceededRemoteData(),