import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Observable, of as observableOf, race as observableRace } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; import { DynamicDatePickerModel, DynamicFormControlModel, DynamicFormGroupModel, DynamicSelectModel } from '@ng-dynamic-forms/core'; import { ResourcePolicy } from '../../../core/resource-policy/models/resource-policy.model'; import { DsDynamicInputModel } from '../../form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model'; import { RESOURCE_POLICY_FORM_ACTION_TYPE_CONFIG, RESOURCE_POLICY_FORM_DATE_GROUP_CONFIG, RESOURCE_POLICY_FORM_DATE_GROUP_LAYOUT, RESOURCE_POLICY_FORM_DESCRIPTION_CONFIG, RESOURCE_POLICY_FORM_END_DATE_CONFIG, RESOURCE_POLICY_FORM_END_DATE_LAYOUT, RESOURCE_POLICY_FORM_NAME_CONFIG, RESOURCE_POLICY_FORM_POLICY_TYPE_CONFIG, RESOURCE_POLICY_FORM_START_DATE_CONFIG, RESOURCE_POLICY_FORM_START_DATE_LAYOUT } from './resource-policy-form.model'; import { DsDynamicTextAreaModel } from '../../form/builder/ds-dynamic-form-ui/models/ds-dynamic-textarea.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { hasValue, isEmpty, isNotEmpty } from '../../empty.util'; import { FormService } from '../../form/form.service'; import { RESOURCE_POLICY } from '../../../core/resource-policy/models/resource-policy.resource-type'; import { RemoteData } from '../../../core/data/remote-data'; import { Subscription } from 'rxjs/internal/Subscription'; import { dateToISOFormat, stringToNgbDateStruct } from '../../date.util'; import { EPersonDataService } from '../../../core/eperson/eperson-data.service'; import { GroupDataService } from '../../../core/eperson/group-data.service'; import { getSucceededRemoteData } from '../../../core/shared/operators'; import { RequestService } from '../../../core/data/request.service'; export interface ResourcePolicyEvent { object: ResourcePolicy, target: { type: string, uuid: string } } @Component({ selector: 'ds-resource-policy-form', templateUrl: './resource-policy-form.component.html', }) /** * Component that show form for adding/editing a resource policy */ export class ResourcePolicyFormComponent implements OnInit, OnDestroy { /** * If given contains the resource policy to edit * @type {ResourcePolicy} */ @Input() resourcePolicy: ResourcePolicy; /** * A boolean representing if form submit operation is processing * @type {boolean} */ @Input() isProcessing: Observable = observableOf(false); /** * An event fired when form is canceled. * Event's payload is empty. */ @Output() reset: EventEmitter = new EventEmitter(); /** * An event fired when form is submitted. * Event's payload equals to a new ResourcePolicy. */ @Output() submit: EventEmitter = new EventEmitter(); /** * The form id * @type {string} */ public formId: string; /** * The form model * @type {DynamicFormControlModel[]} */ public formModel: DynamicFormControlModel[]; /** * The eperson or group that will be grant of the permission * @type {DSpaceObject} */ public resourcePolicyGrant: DSpaceObject; /** * The type of the object that will be grant of the permission. It could be 'eperson' or 'group' * @type {string} */ public resourcePolicyGrantType: string; /** * A boolean representing if component is active * @type {boolean} */ private isActive: boolean; /** * Array to track all subscriptions and unsubscribe them onDestroy * @type {Array} */ private subs: Subscription[] = []; /** * Initialize instance variables * * @param {DSONameService} dsoNameService * @param {EPersonDataService} ePersonService * @param {FormService} formService * @param {GroupDataService} groupService * @param {RequestService} requestService */ constructor( private dsoNameService: DSONameService, private ePersonService: EPersonDataService, private formService: FormService, private groupService: GroupDataService, private requestService: RequestService, ) { } /** * Initialize the component, setting up the form model */ ngOnInit(): void { this.isActive = true; this.formId = this.formService.getUniqueId('resource-policy-form'); this.formModel = this.buildResourcePolicyForm(); if (!this.canSetGrant()) { this.requestService.removeByHrefSubstring(this.resourcePolicy._links.eperson.href); this.requestService.removeByHrefSubstring(this.resourcePolicy._links.group.href); const epersonRD$ = this.ePersonService.findByHref(this.resourcePolicy._links.eperson.href).pipe( getSucceededRemoteData() ); const groupRD$ = this.groupService.findByHref(this.resourcePolicy._links.group.href).pipe( getSucceededRemoteData() ); const dsoRD$: Observable> = observableRace(epersonRD$, groupRD$); this.subs.push( dsoRD$.pipe( filter(() => this.isActive), ).subscribe((dsoRD: RemoteData) => { this.resourcePolicyGrant = dsoRD.payload; }) ) } } /** * Method to check if the form status is valid or not * * @return Observable that emits the form status */ isFormValid(): Observable { return this.formService.isValid(this.formId).pipe( map((isValid: boolean) => isValid && isNotEmpty(this.resourcePolicyGrant)) ) } /** * Initialize the form model * * @return the form models */ private buildResourcePolicyForm(): DynamicFormControlModel[] { const formModel: DynamicFormControlModel[] = []; // TODO to be removed when https://jira.lyrasis.org/browse/DS-4477 will be implemented const policyTypeConf = Object.assign({}, RESOURCE_POLICY_FORM_POLICY_TYPE_CONFIG, { disabled: isNotEmpty(this.resourcePolicy) }); // TODO to be removed when https://jira.lyrasis.org/browse/DS-4477 will be implemented const actionConf = Object.assign({}, RESOURCE_POLICY_FORM_ACTION_TYPE_CONFIG, { disabled: isNotEmpty(this.resourcePolicy) }); formModel.push( new DsDynamicInputModel(RESOURCE_POLICY_FORM_NAME_CONFIG), new DsDynamicTextAreaModel(RESOURCE_POLICY_FORM_DESCRIPTION_CONFIG), new DynamicSelectModel(policyTypeConf), new DynamicSelectModel(actionConf) ); const startDateModel = new DynamicDatePickerModel( RESOURCE_POLICY_FORM_START_DATE_CONFIG, RESOURCE_POLICY_FORM_START_DATE_LAYOUT ); const endDateModel = new DynamicDatePickerModel( RESOURCE_POLICY_FORM_END_DATE_CONFIG, RESOURCE_POLICY_FORM_END_DATE_LAYOUT ); const dateGroupConfig = Object.assign({}, RESOURCE_POLICY_FORM_DATE_GROUP_CONFIG, { group: [] }); dateGroupConfig.group.push(startDateModel, endDateModel); formModel.push(new DynamicFormGroupModel(dateGroupConfig, RESOURCE_POLICY_FORM_DATE_GROUP_LAYOUT)); this.initModelsValue(formModel); return formModel } /** * Setting up the form models value * * @return the form models */ initModelsValue(formModel: DynamicFormControlModel[]): DynamicFormControlModel[] { if (this.resourcePolicy) { formModel.forEach((model: any) => { if (model.id === 'date') { if (hasValue(this.resourcePolicy.startDate)) { model.get(0).valueUpdates.next(stringToNgbDateStruct(this.resourcePolicy.startDate)); } if (hasValue(this.resourcePolicy.endDate)) { model.get(1).valueUpdates.next(stringToNgbDateStruct(this.resourcePolicy.endDate)); } } else { if (this.resourcePolicy.hasOwnProperty(model.id) && this.resourcePolicy[model.id]) { model.valueUpdates.next(this.resourcePolicy[model.id]); } } }) } return formModel; } /** * Return a boolean representing If is possible to set policy grant * * @return true if is possible, false otherwise */ canSetGrant(): boolean { return isEmpty(this.resourcePolicy); } /** * Return the name of the eperson or group that will be grant of the permission * * @return the object name */ getResourcePolicyTargetName(): string { return isNotEmpty(this.resourcePolicyGrant) ? this.dsoNameService.getName(this.resourcePolicyGrant) : ''; } /** * Update reference to the eperson or group that will be grant of the permission */ updateObjectSelected(object: DSpaceObject, isEPerson: boolean): void { this.resourcePolicyGrant = object; this.resourcePolicyGrantType = isEPerson ? 'eperson' : 'group'; } /** * Method called on reset * Emit a new reset Event */ onReset(): void { this.reset.emit(); } /** * Method called on submit. * Emit a new submit Event whether the form is valid */ onSubmit(): void { this.formService.getFormData(this.formId).pipe(take(1)) .subscribe((data) => { const eventPayload: ResourcePolicyEvent = Object.create({}); eventPayload.object = this.createResourcePolicyByFormData(data); eventPayload.target = { type: this.resourcePolicyGrantType, uuid: this.resourcePolicyGrant.id }; this.submit.emit(eventPayload); }) } /** * Create e new ResourcePolicy by form data * * @return the new ResourcePolicy object */ createResourcePolicyByFormData(data): ResourcePolicy { const resourcePolicy = new ResourcePolicy(); resourcePolicy.name = (data.name) ? data.name[0].value : null; resourcePolicy.description = (data.description) ? data.description[0].value : null; resourcePolicy.policyType = (data.policyType) ? data.policyType[0].value : null; resourcePolicy.action = (data.action) ? data.action[0].value : null; resourcePolicy.startDate = (data.date && data.date.start) ? dateToISOFormat(data.date.start[0].value) : null; resourcePolicy.endDate = (data.date && data.date.end) ? dateToISOFormat(data.date.end[0].value) : null; resourcePolicy.type = RESOURCE_POLICY; return resourcePolicy; } /** * Unsubscribe from all subscriptions */ ngOnDestroy(): void { this.isActive = false; this.formModel = null; this.subs .filter((subscription) => hasValue(subscription)) .forEach((subscription) => subscription.unsubscribe()) } }