mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-11 12:03:03 +00:00

# 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
309 lines
13 KiB
TypeScript
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());
|
|
}
|
|
|
|
}
|