Files
dspace-angular/src/app/submission/sections/upload/section-upload.component.ts
Giuseppe Digilio 4d4e920f0d Merge remote-tracking branch 'origin/main' into upgrade_angular10
# Conflicts:
#	src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.spec.ts
#	src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts
#	src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts
#	src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.spec.ts
#	src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.spec.ts
#	src/app/+admin/admin-access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts
#	src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts
#	src/app/+admin/admin-import-metadata-page/metadata-import-page.component.ts
#	src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.ts
#	src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.ts
#	src/app/+admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
#	src/app/+admin/admin-search-page/admin-search-results/admin-search-result-list-element/item-search-result/item-admin-search-result-list-element.component.spec.ts
#	src/app/+bitstream-page/bitstream-page.resolver.ts
#	src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.spec.ts
#	src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts
#	src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
#	src/app/+collection-page/collection-page.component.ts
#	src/app/+collection-page/edit-collection-page/collection-roles/collection-roles.component.ts
#	src/app/+collection-page/edit-item-template-page/item-template-page.resolver.spec.ts
#	src/app/+collection-page/edit-item-template-page/item-template-page.resolver.ts
#	src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts
#	src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.spec.ts
#	src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts
#	src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
#	src/app/+item-page/edit-item-page/item-private/item-private.component.ts
#	src/app/+item-page/edit-item-page/item-public/item-public.component.ts
#	src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.ts
#	src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts
#	src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
#	src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.ts
#	src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
#	src/app/+my-dspace-page/collection-selector/collection-selector.component.spec.ts
#	src/app/+search-page/search-tracker.component.ts
#	src/app/app-routing.module.ts
#	src/app/community-list-page/community-list-service.ts
#	src/app/community-list-page/community-list.reducer.spec.ts
#	src/app/core/auth/auth-response-parsing.service.spec.ts
#	src/app/core/auth/auth.interceptor.spec.ts
#	src/app/core/browse/browse.service.spec.ts
#	src/app/core/browse/browse.service.ts
#	src/app/core/cache/builders/link.service.spec.ts
#	src/app/core/cache/builders/remote-data-build.service.ts
#	src/app/core/cache/object-cache.service.spec.ts
#	src/app/core/cache/response.models.ts
#	src/app/core/data/base-response-parsing.service.ts
#	src/app/core/data/bitstream-data.service.ts
#	src/app/core/data/bitstream-format-data.service.ts
#	src/app/core/data/bundle-data.service.spec.ts
#	src/app/core/data/bundle-data.service.ts
#	src/app/core/data/change-analyzer.ts
#	src/app/core/data/collection-data.service.spec.ts
#	src/app/core/data/collection-data.service.ts
#	src/app/core/data/comcol-data.service.spec.ts
#	src/app/core/data/comcol-data.service.ts
#	src/app/core/data/data.service.ts
#	src/app/core/data/entity-type-data.service.ts
#	src/app/core/data/entity-type.service.ts
#	src/app/core/data/feature-authorization/authorization-data.service.ts
#	src/app/core/data/feature-authorization/feature-data.service.ts
#	src/app/core/data/item-template-data.service.ts
#	src/app/core/data/license-data.service.ts
#	src/app/core/data/metadata-field-data.service.ts
#	src/app/core/data/processes/process-data.service.ts
#	src/app/core/data/processes/script-data.service.ts
#	src/app/core/data/relationship.service.spec.ts
#	src/app/core/data/relationship.service.ts
#	src/app/core/data/remote-data.ts
#	src/app/core/data/request.actions.ts
#	src/app/core/data/request.effects.ts
#	src/app/core/data/request.reducer.spec.ts
#	src/app/core/data/request.reducer.ts
#	src/app/core/data/request.service.spec.ts
#	src/app/core/data/request.service.ts
#	src/app/core/dspace-rest/dspace-rest.service.spec.ts
#	src/app/core/eperson/eperson-data.service.spec.ts
#	src/app/core/eperson/eperson-data.service.ts
#	src/app/core/eperson/group-data.service.spec.ts
#	src/app/core/eperson/group-data.service.ts
#	src/app/core/forward-client-ip/forward-client-ip.interceptor.spec.ts
#	src/app/core/index/index.reducer.ts
#	src/app/core/json-patch/json-patch-operations.service.spec.ts
#	src/app/core/json-patch/json-patch-operations.service.ts
#	src/app/core/locale/locale.interceptor.spec.ts
#	src/app/core/registry/registry.service.ts
#	src/app/core/resource-policy/resource-policy.service.ts
#	src/app/core/shared/operators.ts
#	src/app/core/shared/search/search.service.ts
#	src/app/core/submission/submission-object-data.service.ts
#	src/app/core/submission/submission-rest.service.ts
#	src/app/core/submission/vocabularies/vocabulary-entries-response-parsing.service.spec.ts
#	src/app/core/submission/vocabularies/vocabulary.service.spec.ts
#	src/app/core/submission/vocabularies/vocabulary.service.ts
#	src/app/core/submission/workflowitem-data.service.ts
#	src/app/core/tasks/tasks.service.ts
#	src/app/curation-form/curation-form.component.ts
#	src/app/process-page/process-page.resolver.ts
#	src/app/shared/collection-dropdown/collection-dropdown.component.spec.ts
#	src/app/shared/collection-dropdown/collection-dropdown.component.ts
#	src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts
#	src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
#	src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts
#	src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts
#	src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts
#	src/app/shared/dso-selector/dso-selector/dso-selector.component.ts
#	src/app/shared/dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component.ts
#	src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts
#	src/app/shared/form/builder/form-builder.service.ts
#	src/app/shared/item/item-versions/item-versions.component.ts
#	src/app/shared/mocks/remote-data-build.service.mock.ts
#	src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts
#	src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts
#	src/app/shared/object-select/collection-select/collection-select.component.spec.ts
#	src/app/shared/object-select/item-select/item-select.component.spec.ts
#	src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.spec.ts
#	src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts
#	src/app/shared/resource-policies/form/eperson-group-list/eperson-group-list.component.ts
#	src/app/shared/search/search-query-response.model.ts
#	src/app/statistics/statistics.module.ts
#	src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.spec.ts
#	src/app/submission/sections/form/section-form.component.ts
#	src/app/submission/sections/upload/section-upload.component.spec.ts
#	src/app/submission/sections/upload/section-upload.component.ts
#	src/app/submission/submission.service.spec.ts
#	src/app/submission/submission.service.ts
2021-01-07 19:17:19 +01:00

309 lines
13 KiB
TypeScript

import { ChangeDetectorRef, Component, Inject } from '@angular/core';
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, filter, find, map, mergeMap, reduce, switchMap, tap } from 'rxjs/operators';
import { SectionModelComponent } from '../models/section.model';
import { hasValue, isNotEmpty, isNotUndefined, isUndefined } from '../../../shared/empty.util';
import { SectionUploadService } from './section-upload.service';
import { CollectionDataService } from '../../../core/data/collection-data.service';
import { GroupDataService } from '../../../core/eperson/group-data.service';
import { ResourcePolicyService } from '../../../core/resource-policy/resource-policy.service';
import { SubmissionUploadsConfigService } from '../../../core/config/submission-uploads-config.service';
import { SubmissionUploadsModel } from '../../../core/config/models/config-submission-uploads.model';
import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model';
import { SectionsType } from '../sections-type';
import { renderSectionFor } from '../sections-decorator';
import { SectionDataObject } from '../models/section-data.model';
import { SubmissionObjectEntry } from '../../objects/submission-objects.reducer';
import { AlertType } from '../../../shared/alert/aletr-type';
import { RemoteData } from '../../../core/data/remote-data';
import { Group } from '../../../core/eperson/models/group.model';
import { SectionsService } from '../sections.service';
import { SubmissionService } from '../../submission.service';
import { Collection } from '../../../core/shared/collection.model';
import { AccessConditionOption } from '../../../core/config/models/config-access-condition-option.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
export const POLICY_DEFAULT_NO_LIST = 1; // Banner1
export const POLICY_DEFAULT_WITH_LIST = 2; // Banner2
export interface AccessConditionGroupsMapEntry {
accessCondition: string;
groups: Group[];
}
/**
* This component represents a section that contains submission's bitstreams
*/
@Component({
selector: 'ds-submission-section-upload',
styleUrls: ['./section-upload.component.scss'],
templateUrl: './section-upload.component.html',
})
@renderSectionFor(SectionsType.Upload)
export class SubmissionSectionUploadComponent extends SectionModelComponent {
/**
* The AlertType enumeration
* @type {AlertType}
*/
public AlertTypeEnum = AlertType;
/**
* The array containing the keys of file list array
* @type {Array}
*/
public fileIndexes: string[] = [];
/**
* The file list
* @type {Array}
*/
public fileList: any[] = [];
/**
* The array containing the name of the files
* @type {Array}
*/
public fileNames: string[] = [];
/**
* The collection name this submission belonging to
* @type {string}
*/
public collectionName: string;
/**
* Default access conditions of this collection
* @type {Array}
*/
public collectionDefaultAccessConditions: any[] = [];
/**
* Define if collection access conditions policy type :
* POLICY_DEFAULT_NO_LIST : is not possible to define additional access group/s for the single file
* POLICY_DEFAULT_WITH_LIST : is possible to define additional access group/s for the single file
* @type {number}
*/
public collectionPolicyType: number;
/**
* The configuration for the bitstream's metadata form
*/
public configMetadataForm$: Observable<SubmissionFormsModel>;
/**
* List of available access conditions that could be set to files
*/
public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select
/**
* List of Groups available for every access condition
*/
public availableGroups: Map<string, Group[]>; // Groups for any policy
/**
* Is the upload required
* @type {boolean}
*/
public required$ = new BehaviorSubject<boolean>(true);
/**
* Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array}
*/
protected subs: Subscription[] = [];
/**
* Initialize instance variables
*
* @param {SectionUploadService} bitstreamService
* @param {ChangeDetectorRef} changeDetectorRef
* @param {CollectionDataService} collectionDataService
* @param {GroupDataService} groupService
* @param {ResourcePolicyService} resourcePolicyService
* @param {SectionsService} sectionService
* @param {SubmissionService} submissionService
* @param {SubmissionUploadsConfigService} uploadsConfigService
* @param {SectionDataObject} injectedSectionData
* @param {string} injectedSubmissionId
*/
constructor(private bitstreamService: SectionUploadService,
private changeDetectorRef: ChangeDetectorRef,
private collectionDataService: CollectionDataService,
private groupService: GroupDataService,
private resourcePolicyService: ResourcePolicyService,
protected sectionService: SectionsService,
private submissionService: SubmissionService,
private uploadsConfigService: SubmissionUploadsConfigService,
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
super(undefined, injectedSectionData, injectedSubmissionId);
}
/**
* Initialize all instance variables and retrieve collection default access conditions
*/
onSectionInit() {
const config$ = this.uploadsConfigService.findByHref(this.sectionData.config, false, followLink('metadata')).pipe(
getFirstSucceededRemoteData(),
map((config) => config.payload));
// retrieve configuration for the bitstream's metadata form
this.configMetadataForm$ = config$.pipe(
switchMap((config: SubmissionUploadsModel) =>
config.metadata.pipe(
getFirstSucceededRemoteData(),
map((remoteData: RemoteData<SubmissionFormsModel>) => remoteData.payload)
)
));
this.subs.push(
this.submissionService.getSubmissionObject(this.submissionId).pipe(
filter((submissionObject: SubmissionObjectEntry) => isNotUndefined(submissionObject) && !submissionObject.isLoading),
filter((submissionObject: SubmissionObjectEntry) => isUndefined(this.collectionId) || this.collectionId !== submissionObject.collection),
tap((submissionObject: SubmissionObjectEntry) => this.collectionId = submissionObject.collection),
mergeMap((submissionObject: SubmissionObjectEntry) => this.collectionDataService.findById(submissionObject.collection)),
filter((rd: RemoteData<Collection>) => isNotUndefined((rd.payload))),
tap((collectionRemoteData: RemoteData<Collection>) => this.collectionName = collectionRemoteData.payload.name),
// TODO review this part when https://github.com/DSpace/dspace-angular/issues/575 is resolved
/* mergeMap((collectionRemoteData: RemoteData<Collection>) => {
return this.resourcePolicyService.findByHref(
(collectionRemoteData.payload as any)._links.defaultAccessConditions.href
);
}),
filter((defaultAccessConditionsRemoteData: RemoteData<ResourcePolicy>) =>
defaultAccessConditionsRemoteData.hasSucceeded),
tap((defaultAccessConditionsRemoteData: RemoteData<ResourcePolicy>) => {
if (isNotEmpty(defaultAccessConditionsRemoteData.payload)) {
this.collectionDefaultAccessConditions = Array.isArray(defaultAccessConditionsRemoteData.payload)
? defaultAccessConditionsRemoteData.payload : [defaultAccessConditionsRemoteData.payload];
}
}),*/
mergeMap(() => config$),
mergeMap((config: SubmissionUploadsModel) => {
this.required$.next(config.required);
this.availableAccessConditionOptions = isNotEmpty(config.accessConditionOptions) ? config.accessConditionOptions : [];
this.collectionPolicyType = this.availableAccessConditionOptions.length > 0
? POLICY_DEFAULT_WITH_LIST
: POLICY_DEFAULT_NO_LIST;
this.availableGroups = new Map();
const mapGroups$: Observable<AccessConditionGroupsMapEntry>[] = [];
// Retrieve Groups for accessCondition Policies
this.availableAccessConditionOptions.forEach((accessCondition: AccessConditionOption) => {
if (accessCondition.hasEndDate === true || accessCondition.hasStartDate === true) {
if (accessCondition.groupUUID) {
mapGroups$.push(
this.groupService.findById(accessCondition.groupUUID).pipe(
find((rd: RemoteData<Group>) => !rd.isResponsePending && rd.hasSucceeded),
map((rd: RemoteData<Group>) => ({
accessCondition: accessCondition.name,
groups: [rd.payload]
} as AccessConditionGroupsMapEntry)))
);
} else if (accessCondition.selectGroupUUID) {
mapGroups$.push(
this.groupService.findById(accessCondition.selectGroupUUID).pipe(
find((rd: RemoteData<Group>) => !rd.isResponsePending && rd.hasSucceeded),
mergeMap((group: RemoteData<Group>) => group.payload.subgroups),
find((rd: RemoteData<PaginatedList<Group>>) => !rd.isResponsePending && rd.hasSucceeded),
map((rd: RemoteData<PaginatedList<Group>>) => ({
accessCondition: accessCondition.name,
groups: rd.payload.page
} as AccessConditionGroupsMapEntry))
));
}
}
});
return mapGroups$;
}),
mergeMap((entry) => entry),
reduce((acc: any[], entry: AccessConditionGroupsMapEntry) => {
acc.push(entry);
return acc;
}, []),
).subscribe((entries: AccessConditionGroupsMapEntry[]) => {
entries.forEach((entry: AccessConditionGroupsMapEntry) => {
this.availableGroups.set(entry.accessCondition, entry.groups);
});
this.changeDetectorRef.detectChanges();
}),
// retrieve submission's bitstreams from state
observableCombineLatest(this.configMetadataForm$,
this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id)).pipe(
filter(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
return isNotEmpty(configMetadataForm) && isNotUndefined(fileList);
}),
distinctUntilChanged())
.subscribe(([configMetadataForm, fileList]: [SubmissionFormsModel, any[]]) => {
this.fileList = [];
this.fileIndexes = [];
this.fileNames = [];
this.changeDetectorRef.detectChanges();
if (isNotUndefined(fileList) && fileList.length > 0) {
fileList.forEach((file) => {
this.fileList.push(file);
this.fileIndexes.push(file.uuid);
this.fileNames.push(this.getFileName(configMetadataForm, file));
});
}
this.changeDetectorRef.detectChanges();
}
)
);
}
/**
* Return file name from metadata
*
* @param configMetadataForm
* the bitstream's form configuration
* @param fileData
* the file metadata
*/
private getFileName(configMetadataForm: SubmissionFormsModel, fileData: any): string {
const metadataName: string = configMetadataForm.rows[0].fields[0].selectableMetadata[0].metadata;
let title: string;
if (isNotEmpty(fileData.metadata) && isNotEmpty(fileData.metadata[metadataName])) {
title = fileData.metadata[metadataName][0].display;
} else {
title = fileData.uuid;
}
return title;
}
/**
* Get section status
*
* @return Observable<boolean>
* the section status
*/
protected getSectionStatus(): Observable<boolean> {
// if not mandatory, always true
// if mandatory, at least one file is required
return observableCombineLatest(this.required$,
this.bitstreamService.getUploadedFileList(this.submissionId, this.sectionData.id),
(required,fileList: any[]) => {
return (!required || (isNotUndefined(fileList) && fileList.length > 0));
});
}
/**
* Method provided by Angular. Invoked when the instance is destroyed.
*/
onSectionDestroy() {
this.subs
.filter((subscription) => hasValue(subscription))
.forEach((subscription) => subscription.unsubscribe());
}
}