mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
64503: Content Source fetched from API
This commit is contained in:
@@ -101,17 +101,17 @@
|
||||
"collection.edit.tabs.roles.title": "Collection Edit - Roles",
|
||||
"collection.edit.tabs.source.external": "This collection harvests its content from an external source",
|
||||
"collection.edit.tabs.source.form.errors.provider.required": "You must provide a set id of the target collection.",
|
||||
"collection.edit.tabs.source.form.format": "Metadata Format",
|
||||
"collection.edit.tabs.source.form.harvest": "Content being harvested",
|
||||
"collection.edit.tabs.source.form.harvestType": "Content being harvested",
|
||||
"collection.edit.tabs.source.form.head": "Configure an external source",
|
||||
"collection.edit.tabs.source.form.options.format.dc": "Simple Dublin Core",
|
||||
"collection.edit.tabs.source.form.options.format.dim": "DSpace Intermediate Metadata",
|
||||
"collection.edit.tabs.source.form.options.format.qdc": "Qualified Dublin Core",
|
||||
"collection.edit.tabs.source.form.options.harvest.1": "Harvest metadata only",
|
||||
"collection.edit.tabs.source.form.options.harvest.2": "Harvest metadata and references to bitstreams (requires ORE support)",
|
||||
"collection.edit.tabs.source.form.options.harvest.3": "Harvest metadata and bitstreams (requires ORE support)",
|
||||
"collection.edit.tabs.source.form.provider": "OAI Provider",
|
||||
"collection.edit.tabs.source.form.set": "OAI specific set id",
|
||||
"collection.edit.tabs.source.form.metadataConfigId": "Metadata Format",
|
||||
"collection.edit.tabs.source.form.oaiSetId": "OAI specific set id",
|
||||
"collection.edit.tabs.source.form.oaiSource": "OAI Provider",
|
||||
"collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Harvest metadata and bitstreams (requires ORE support)",
|
||||
"collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Harvest metadata and references to bitstreams (requires ORE support)",
|
||||
"collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Harvest metadata only",
|
||||
"collection.edit.tabs.source.form.options.metadataConfigId.dc": "Simple Dublin Core",
|
||||
"collection.edit.tabs.source.form.options.metadataConfigId.dim": "DSpace Intermediate Metadata",
|
||||
"collection.edit.tabs.source.form.options.metadataConfigId.qdc": "Qualified Dublin Core",
|
||||
"collection.edit.tabs.source.head": "Content Source",
|
||||
"collection.edit.tabs.source.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
|
||||
"collection.edit.tabs.source.notifications.discarded.title": "Changed discarded",
|
||||
|
@@ -1,55 +1,57 @@
|
||||
<div class="container-fluid">
|
||||
<div class="d-inline-block float-right">
|
||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||
[disabled]="!(hasChanges() | async)"
|
||||
(click)="discard()"><i
|
||||
class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||
(click)="reinstate()"><i
|
||||
class="fas fa-undo-alt"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid()"
|
||||
(click)="onSubmit()"><i
|
||||
class="fas fa-save"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||
</button>
|
||||
<ng-container *ngIf="contentSource">
|
||||
<div class="container-fluid">
|
||||
<div class="d-inline-block float-right">
|
||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||
[disabled]="!(hasChanges() | async)"
|
||||
(click)="discard()"><i
|
||||
class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||
(click)="reinstate()"><i
|
||||
class="fas fa-undo-alt"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid()"
|
||||
(click)="onSubmit()"><i
|
||||
class="fas fa-save"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
||||
<div class="form-check mb-4">
|
||||
<input type="checkbox" class="form-check-input" id="externalSourceCheck" [checked]="(contentSource.harvestType !== harvestTypeNone)" (change)="changeExternalSource()">
|
||||
<label class="form-check-label" for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label>
|
||||
</div>
|
||||
<h4 *ngIf="(contentSource.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
||||
</div>
|
||||
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
||||
<div class="form-check mb-4">
|
||||
<input type="checkbox" class="form-check-input" id="externalSourceCheck" [checked]="contentSource.enabled" (change)="changeExternalSource()">
|
||||
<label class="form-check-label" for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label>
|
||||
<ds-form *ngIf="formGroup && (contentSource.harvestType !== harvestTypeNone)"
|
||||
[formId]="'collection-source-form-id'"
|
||||
[formGroup]="formGroup"
|
||||
[formModel]="formModel"
|
||||
[formLayout]="formLayout"
|
||||
[displaySubmit]="false"
|
||||
(dfChange)="onChange($event)"
|
||||
(submitForm)="onSubmit()"
|
||||
(cancel)="onCancel()"></ds-form>
|
||||
<div class="container-fluid" *ngIf="(contentSource.harvestType !== harvestTypeNone)">
|
||||
<div class="d-inline-block float-right">
|
||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||
[disabled]="!(hasChanges() | async)"
|
||||
(click)="discard()"><i
|
||||
class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||
(click)="reinstate()"><i
|
||||
class="fas fa-undo-alt"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid()"
|
||||
(click)="onSubmit()"><i
|
||||
class="fas fa-save"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h4 *ngIf="contentSource.enabled">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
||||
</div>
|
||||
<ds-form *ngIf="formGroup && contentSource.enabled"
|
||||
[formId]="'collection-source-form-id'"
|
||||
[formGroup]="formGroup"
|
||||
[formModel]="formModel"
|
||||
[formLayout]="formLayout"
|
||||
[displaySubmit]="false"
|
||||
(dfChange)="onChange($event)"
|
||||
(submitForm)="onSubmit()"
|
||||
(cancel)="onCancel()"></ds-form>
|
||||
<div class="container-fluid" *ngIf="contentSource.enabled">
|
||||
<div class="d-inline-block float-right">
|
||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||
[disabled]="!(hasChanges() | async)"
|
||||
(click)="discard()"><i
|
||||
class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||
(click)="reinstate()"><i
|
||||
class="fas fa-undo-alt"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid()"
|
||||
(click)="onSubmit()"><i
|
||||
class="fas fa-save"></i>
|
||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@@ -1,8 +1,13 @@
|
||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component';
|
||||
import {
|
||||
DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService,
|
||||
DynamicInputModel, DynamicOptionControlModel, DynamicRadioGroupModel,
|
||||
DynamicFormControlModel,
|
||||
DynamicFormGroupModel,
|
||||
DynamicFormLayout,
|
||||
DynamicFormService,
|
||||
DynamicInputModel,
|
||||
DynamicOptionControlModel,
|
||||
DynamicRadioGroupModel,
|
||||
DynamicSelectModel,
|
||||
DynamicTextAreaModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
@@ -12,16 +17,18 @@ import { ObjectUpdatesService } from '../../../core/data/object-updates/object-u
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { ContentSource } from '../../../core/shared/content-source.model';
|
||||
import { ContentSource, ContentSourceHarvestType } from '../../../core/shared/content-source.model';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { first, map, switchMap, take } from 'rxjs/operators';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
||||
import { Subscription } from 'rxjs/internal/Subscription';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||
|
||||
/**
|
||||
* Component for managing the content source of the collection
|
||||
@@ -64,9 +71,9 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
/**
|
||||
* The Dynamic Input Model for the OAI Provider
|
||||
*/
|
||||
providerModel = new DynamicInputModel({
|
||||
id: 'provider',
|
||||
name: 'provider',
|
||||
oaiSourceModel = new DynamicInputModel({
|
||||
id: 'oaiSource',
|
||||
name: 'oaiSource',
|
||||
required: true,
|
||||
validators: {
|
||||
required: null
|
||||
@@ -79,17 +86,17 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
/**
|
||||
* The Dynamic Input Model for the OAI Set
|
||||
*/
|
||||
setModel = new DynamicInputModel({
|
||||
id: 'set',
|
||||
name: 'set'
|
||||
oaiSetIdModel = new DynamicInputModel({
|
||||
id: 'oaiSetId',
|
||||
name: 'oaiSetId'
|
||||
});
|
||||
|
||||
/**
|
||||
* The Dynamic Input Model for the Metadata Format used
|
||||
*/
|
||||
formatModel = new DynamicSelectModel({
|
||||
id: 'format',
|
||||
name: 'format',
|
||||
metadataConfigIdModel = new DynamicSelectModel({
|
||||
id: 'metadataConfigId',
|
||||
name: 'metadataConfigId',
|
||||
options: [
|
||||
{
|
||||
value: 'dc'
|
||||
@@ -100,24 +107,25 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
{
|
||||
value: 'dim'
|
||||
}
|
||||
]
|
||||
],
|
||||
value: 'dc'
|
||||
});
|
||||
|
||||
/**
|
||||
* The Dynamic Input Model for the type of harvesting
|
||||
*/
|
||||
harvestModel = new DynamicRadioGroupModel<number>({
|
||||
id: 'harvest',
|
||||
name: 'harvest',
|
||||
harvestTypeModel = new DynamicRadioGroupModel<string>({
|
||||
id: 'harvestType',
|
||||
name: 'harvestType',
|
||||
options: [
|
||||
{
|
||||
value: 1
|
||||
value: ContentSourceHarvestType.Metadata
|
||||
},
|
||||
{
|
||||
value: 2
|
||||
value: ContentSourceHarvestType.MetadataAndRef
|
||||
},
|
||||
{
|
||||
value: 3
|
||||
value: ContentSourceHarvestType.MetadataAndBitstreams
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -125,7 +133,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
/**
|
||||
* All input models in a simple array for easier iterations
|
||||
*/
|
||||
inputModels = [this.providerModel, this.setModel, this.formatModel, this.harvestModel];
|
||||
inputModels = [this.oaiSourceModel, this.oaiSetIdModel, this.metadataConfigIdModel, this.harvestTypeModel];
|
||||
|
||||
/**
|
||||
* The dynamic form fields used for editing the content source of a collection
|
||||
@@ -133,22 +141,22 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
*/
|
||||
formModel: DynamicFormControlModel[] = [
|
||||
new DynamicFormGroupModel({
|
||||
id: 'providerContainer',
|
||||
id: 'oaiSourceContainer',
|
||||
group: [
|
||||
this.providerModel
|
||||
this.oaiSourceModel
|
||||
]
|
||||
}),
|
||||
new DynamicFormGroupModel({
|
||||
id: 'setContainer',
|
||||
id: 'oaiSetContainer',
|
||||
group: [
|
||||
this.setModel,
|
||||
this.formatModel
|
||||
this.oaiSetIdModel,
|
||||
this.metadataConfigIdModel
|
||||
]
|
||||
}),
|
||||
new DynamicFormGroupModel({
|
||||
id: 'harvestContainer',
|
||||
id: 'harvestTypeContainer',
|
||||
group: [
|
||||
this.harvestModel
|
||||
this.harvestTypeModel
|
||||
]
|
||||
})
|
||||
];
|
||||
@@ -157,38 +165,38 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
* Layout used for structuring the form inputs
|
||||
*/
|
||||
formLayout: DynamicFormLayout = {
|
||||
provider: {
|
||||
oaiSource: {
|
||||
grid: {
|
||||
host: 'col-12 d-inline-block'
|
||||
}
|
||||
},
|
||||
set: {
|
||||
oaiSetId: {
|
||||
grid: {
|
||||
host: 'col col-sm-6 d-inline-block'
|
||||
}
|
||||
},
|
||||
format: {
|
||||
metadataConfigId: {
|
||||
grid: {
|
||||
host: 'col col-sm-6 d-inline-block'
|
||||
}
|
||||
},
|
||||
harvest: {
|
||||
harvestType: {
|
||||
grid: {
|
||||
host: 'col-12',
|
||||
option: 'btn-outline-secondary'
|
||||
}
|
||||
},
|
||||
setContainer: {
|
||||
oaiSetContainer: {
|
||||
grid: {
|
||||
host: 'row'
|
||||
}
|
||||
},
|
||||
providerContainer: {
|
||||
oaiSourceContainer: {
|
||||
grid: {
|
||||
host: 'row'
|
||||
}
|
||||
},
|
||||
harvestContainer: {
|
||||
harvestTypeContainer: {
|
||||
grid: {
|
||||
host: 'row'
|
||||
}
|
||||
@@ -205,6 +213,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
*/
|
||||
updateSub: Subscription;
|
||||
|
||||
harvestTypeNone = ContentSourceHarvestType.None;
|
||||
|
||||
public constructor(public objectUpdatesService: ObjectUpdatesService,
|
||||
public notificationsService: NotificationsService,
|
||||
protected location: Location,
|
||||
@@ -212,7 +222,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
protected translate: TranslateService,
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,) {
|
||||
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||
protected collectionService: CollectionDataService) {
|
||||
super(objectUpdatesService, notificationsService, translate);
|
||||
}
|
||||
|
||||
@@ -229,16 +240,21 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
this.collectionRD$ = this.route.parent.data.pipe(first(), map((data) => data.dso));
|
||||
|
||||
/* Create a new ContentSource object - TODO: Update to be fetched from the collection */
|
||||
this.contentSource = new ContentSource();
|
||||
this.collectionRD$.pipe(
|
||||
getSucceededRemoteData(),
|
||||
map((col) => col.payload.uuid),
|
||||
switchMap((uuid) => this.collectionService.getContentSource(uuid)),
|
||||
take(1)
|
||||
).subscribe((contentSource: ContentSource) => {
|
||||
this.contentSource = contentSource;
|
||||
this.initializeOriginalContentSource();
|
||||
});
|
||||
|
||||
this.updateFieldTranslations();
|
||||
this.translate.onLangChange
|
||||
.subscribe(() => {
|
||||
this.updateFieldTranslations();
|
||||
});
|
||||
|
||||
this.initializeOriginalContentSource();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,15 +270,15 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
if (update) {
|
||||
const field = update.field as ContentSource;
|
||||
this.formGroup.patchValue({
|
||||
providerContainer: {
|
||||
provider: field.provider
|
||||
oaiSourceContainer: {
|
||||
oaiSource: field.oaiSource
|
||||
},
|
||||
setContainer: {
|
||||
set: field.set,
|
||||
format: field.format
|
||||
oaiSetContainer: {
|
||||
oaiSetId: field.oaiSetId,
|
||||
metadataConfigId: field.metadataConfigId
|
||||
},
|
||||
harvestContainer: {
|
||||
harvest: field.harvest
|
||||
harvestTypeContainer: {
|
||||
harvestType: field.harvestType
|
||||
}
|
||||
});
|
||||
this.contentSource = cloneDeep(field);
|
||||
@@ -307,7 +323,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
* @param event
|
||||
*/
|
||||
onChange(event) {
|
||||
this.updateContentSourceField(event.model);
|
||||
this.updateContentSourceField(event.model, true);
|
||||
this.saveFieldUpdate();
|
||||
}
|
||||
|
||||
@@ -331,24 +347,28 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
* Is the current form valid to be submitted ?
|
||||
*/
|
||||
isValid(): boolean {
|
||||
return !this.contentSource.enabled || this.formGroup.valid;
|
||||
return (this.contentSource.harvestType === ContentSourceHarvestType.None) || this.formGroup.valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the external source on or off and fire a field update
|
||||
*/
|
||||
changeExternalSource() {
|
||||
this.contentSource.enabled = !this.contentSource.enabled;
|
||||
this.updateContentSource();
|
||||
if (this.contentSource.harvestType === ContentSourceHarvestType.None) {
|
||||
this.contentSource.harvestType = ContentSourceHarvestType.Metadata;
|
||||
} else {
|
||||
this.contentSource.harvestType = ContentSourceHarvestType.None;
|
||||
}
|
||||
this.updateContentSource(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop over all inputs and update the Content Source with their value
|
||||
*/
|
||||
updateContentSource() {
|
||||
updateContentSource(updateHarvestType: boolean) {
|
||||
this.inputModels.forEach(
|
||||
(fieldModel: DynamicInputModel) => {
|
||||
this.updateContentSourceField(fieldModel)
|
||||
this.updateContentSourceField(fieldModel, updateHarvestType)
|
||||
}
|
||||
);
|
||||
this.saveFieldUpdate();
|
||||
@@ -358,8 +378,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
||||
* Update the Content Source with the value from a DynamicInputModel
|
||||
* @param fieldModel
|
||||
*/
|
||||
updateContentSourceField(fieldModel: DynamicInputModel) {
|
||||
if (hasValue(fieldModel.value)) {
|
||||
updateContentSourceField(fieldModel: DynamicInputModel, updateHarvestType: boolean) {
|
||||
if (hasValue(fieldModel.value) && !(fieldModel.id === this.harvestTypeModel.id && !updateHarvestType)) {
|
||||
this.contentSource[fieldModel.id] = fieldModel.value;
|
||||
}
|
||||
}
|
||||
|
14
src/app/core/cache/response.models.ts
vendored
14
src/app/core/cache/response.models.ts
vendored
@@ -14,6 +14,7 @@ import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { NormalizedAuthStatus } from '../auth/models/normalized-auth-status.model';
|
||||
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
||||
import { MetadataField } from '../metadata/metadata-field.model';
|
||||
import { ContentSource } from '../shared/content-source.model';
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
export class RestResponse {
|
||||
@@ -288,4 +289,17 @@ export class FilteredDiscoveryQueryResponse extends RestResponse {
|
||||
super(true, statusCode, statusText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A successful response containing exactly one MetadataSchema
|
||||
*/
|
||||
export class ContentSourceSuccessResponse extends RestResponse {
|
||||
constructor(
|
||||
public contentsource: ContentSource,
|
||||
public statusCode: number,
|
||||
public statusText: string,
|
||||
) {
|
||||
super(true, statusCode, statusText);
|
||||
}
|
||||
}
|
||||
/* tslint:enable:max-classes-per-file */
|
||||
|
@@ -117,6 +117,7 @@ import { MetadatafieldParsingService } from './data/metadatafield-parsing.servic
|
||||
import { NormalizedSubmissionUploadsModel } from './config/models/normalized-config-submission-uploads.model';
|
||||
import { NormalizedBrowseEntry } from './shared/normalized-browse-entry.model';
|
||||
import { BrowseDefinition } from './shared/browse-definition.model';
|
||||
import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service';
|
||||
|
||||
const IMPORTS = [
|
||||
CommonModule,
|
||||
@@ -203,6 +204,7 @@ const PROVIDERS = [
|
||||
TaskResponseParsingService,
|
||||
ClaimedTaskDataService,
|
||||
PoolTaskDataService,
|
||||
ContentSourceResponseParsingService,
|
||||
// register AuthInterceptor as HttpInterceptor
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { filter, map, take, tap } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
@@ -16,9 +16,12 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { FindAllOptions } from './request.models';
|
||||
import { ContentSourceRequest, FindAllOptions, RestRequest } from './request.models';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list';
|
||||
import { ContentSource } from '../shared/content-source.model';
|
||||
import { configureRequest, filterSuccessfulResponses, getRequestFromRequestHref } from '../shared/operators';
|
||||
import { ContentSourceSuccessResponse } from '../cache/response.models';
|
||||
|
||||
@Injectable()
|
||||
export class CollectionDataService extends ComColDataService<Collection> {
|
||||
@@ -57,4 +60,21 @@ export class CollectionDataService extends ComColDataService<Collection> {
|
||||
map((collections: RemoteData<PaginatedList<Collection>>) => collections.payload.totalElements > 0)
|
||||
);
|
||||
}
|
||||
|
||||
getHarvesterEndpoint(collectionId: string): Observable<string> {
|
||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||
map((href: string) => `${href}/${collectionId}/harvester`)
|
||||
);
|
||||
}
|
||||
|
||||
getContentSource(collectionId: string): Observable<ContentSource> {
|
||||
return this.getHarvesterEndpoint(collectionId).pipe(
|
||||
map((href: string) => new ContentSourceRequest(this.requestService.generateRequestId(), href)),
|
||||
configureRequest(this.requestService),
|
||||
map((request: RestRequest) => request.href),
|
||||
getRequestFromRequestHref(this.requestService),
|
||||
filterSuccessfulResponses(),
|
||||
map((response: ContentSourceSuccessResponse) => response.contentsource)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
19
src/app/core/data/content-source-response-parsing.service.ts
Normal file
19
src/app/core/data/content-source-response-parsing.service.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { ContentSource } from '../shared/content-source.model';
|
||||
|
||||
@Injectable()
|
||||
export class ContentSourceResponseParsingService implements ResponseParsingService {
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const payload = data.payload;
|
||||
|
||||
const deserialized = new DSpaceRESTv2Serializer(ContentSource).deserialize(payload);
|
||||
return new ContentSourceSuccessResponse(deserialized, data.statusCode, data.statusText);
|
||||
}
|
||||
|
||||
}
|
@@ -93,14 +93,16 @@ export class ObjectUpdatesService {
|
||||
const objectUpdates = this.getObjectEntry(url);
|
||||
return objectUpdates.pipe(map((objectEntry) => {
|
||||
const fieldUpdates: FieldUpdates = {};
|
||||
Object.keys(objectEntry.fieldStates).forEach((uuid) => {
|
||||
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
||||
if (isEmpty(fieldUpdate)) {
|
||||
const identifiable = initialFields.find((object: Identifiable) => object.uuid === uuid);
|
||||
fieldUpdate = { field: identifiable, changeType: undefined };
|
||||
}
|
||||
fieldUpdates[uuid] = fieldUpdate;
|
||||
});
|
||||
if (hasValue(objectEntry)) {
|
||||
Object.keys(objectEntry.fieldStates).forEach((uuid) => {
|
||||
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
||||
if (isEmpty(fieldUpdate)) {
|
||||
const identifiable = initialFields.find((object: Identifiable) => object.uuid === uuid);
|
||||
fieldUpdate = {field: identifiable, changeType: undefined};
|
||||
}
|
||||
fieldUpdates[uuid] = fieldUpdate;
|
||||
});
|
||||
}
|
||||
return fieldUpdates;
|
||||
}))
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import { MetadataschemaParsingService } from './metadataschema-parsing.service';
|
||||
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
import { TaskResponseParsingService } from '../tasks/task-response-parsing.service';
|
||||
import { ContentSourceResponseParsingService } from './content-source-response-parsing.service';
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
|
||||
@@ -358,6 +359,16 @@ export class CreateRequest extends PostRequest {
|
||||
}
|
||||
}
|
||||
|
||||
export class ContentSourceRequest extends GetRequest {
|
||||
constructor(uuid: string, href: string) {
|
||||
super(uuid, href);
|
||||
}
|
||||
|
||||
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||
return ContentSourceResponseParsingService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to delete an object based on its identifier
|
||||
*/
|
||||
|
@@ -1,41 +1,51 @@
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { autoserialize, autoserializeAs } from 'cerialize';
|
||||
|
||||
export enum ContentSourceHarvestType {
|
||||
None = 'NONE',
|
||||
Metadata = 'METADATA_ONLY',
|
||||
MetadataAndRef = 'METADATA_AND_REF',
|
||||
MetadataAndBitstreams = 'METADATA_AND_BITSTREAMS'
|
||||
}
|
||||
|
||||
/**
|
||||
* A model class that holds information about the Content Source of a Collection
|
||||
*/
|
||||
export class ContentSource {
|
||||
/**
|
||||
* Unique identifier
|
||||
* Unique identifier, this is necessary to store the ContentSource in FieldUpdates
|
||||
* Because the ContentSource coming from the REST API doesn't have a UUID, we're using the selflink
|
||||
*/
|
||||
@autoserializeAs('self')
|
||||
uuid: string;
|
||||
|
||||
/**
|
||||
* Does this collection harvest its content from an external source ?
|
||||
* OAI Provider / Source
|
||||
*/
|
||||
enabled = false;
|
||||
|
||||
/**
|
||||
* OAI Provider
|
||||
*/
|
||||
provider: string;
|
||||
@autoserializeAs('oai_source')
|
||||
oaiSource: string;
|
||||
|
||||
/**
|
||||
* OAI Specific set ID
|
||||
*/
|
||||
set: string;
|
||||
@autoserializeAs('oai_set_id')
|
||||
oaiSetId: string;
|
||||
|
||||
/**
|
||||
* Metadata Format
|
||||
* The ID of the metadata format used
|
||||
*/
|
||||
format = 'dc';
|
||||
@autoserializeAs('metadata_config_id')
|
||||
metadataConfigId = 'dc';
|
||||
|
||||
/**
|
||||
* Type of content being harvested
|
||||
* Defaults to 'NONE', meaning the collection doesn't harvest its content from an external source
|
||||
*/
|
||||
harvest = 3;
|
||||
@autoserializeAs('harvest_type')
|
||||
harvestType = ContentSourceHarvestType.None;
|
||||
|
||||
constructor() {
|
||||
// TODO: Remove this once the Content Source is fetched from the REST API and a custom generated UUID is not necessary anymore
|
||||
this.uuid = uuid();
|
||||
}
|
||||
/**
|
||||
* The REST link to itself
|
||||
*/
|
||||
@autoserialize
|
||||
self: string;
|
||||
}
|
||||
|
Reference in New Issue
Block a user