mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +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.roles.title": "Collection Edit - Roles",
|
||||||
"collection.edit.tabs.source.external": "This collection harvests its content from an external source",
|
"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.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.harvestType": "Content being harvested",
|
||||||
"collection.edit.tabs.source.form.harvest": "Content being harvested",
|
|
||||||
"collection.edit.tabs.source.form.head": "Configure an external source",
|
"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.metadataConfigId": "Metadata Format",
|
||||||
"collection.edit.tabs.source.form.options.format.dim": "DSpace Intermediate Metadata",
|
"collection.edit.tabs.source.form.oaiSetId": "OAI specific set id",
|
||||||
"collection.edit.tabs.source.form.options.format.qdc": "Qualified Dublin Core",
|
"collection.edit.tabs.source.form.oaiSource": "OAI Provider",
|
||||||
"collection.edit.tabs.source.form.options.harvest.1": "Harvest metadata only",
|
"collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Harvest metadata and bitstreams (requires ORE support)",
|
||||||
"collection.edit.tabs.source.form.options.harvest.2": "Harvest metadata and references to 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.harvest.3": "Harvest metadata and bitstreams (requires ORE support)",
|
"collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Harvest metadata only",
|
||||||
"collection.edit.tabs.source.form.provider": "OAI Provider",
|
"collection.edit.tabs.source.form.options.metadataConfigId.dc": "Simple Dublin Core",
|
||||||
"collection.edit.tabs.source.form.set": "OAI specific set id",
|
"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.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.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
|
||||||
"collection.edit.tabs.source.notifications.discarded.title": "Changed discarded",
|
"collection.edit.tabs.source.notifications.discarded.title": "Changed discarded",
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
<div class="container-fluid">
|
<ng-container *ngIf="contentSource">
|
||||||
|
<div class="container-fluid">
|
||||||
<div class="d-inline-block float-right">
|
<div class="d-inline-block float-right">
|
||||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
[disabled]="!(hasChanges() | async)"
|
[disabled]="!(hasChanges() | async)"
|
||||||
@@ -19,12 +20,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
||||||
<div class="form-check mb-4">
|
<div class="form-check mb-4">
|
||||||
<input type="checkbox" class="form-check-input" id="externalSourceCheck" [checked]="contentSource.enabled" (change)="changeExternalSource()">
|
<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>
|
<label class="form-check-label" for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label>
|
||||||
</div>
|
</div>
|
||||||
<h4 *ngIf="contentSource.enabled">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
<h4 *ngIf="(contentSource.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<ds-form *ngIf="formGroup && contentSource.enabled"
|
<ds-form *ngIf="formGroup && (contentSource.harvestType !== harvestTypeNone)"
|
||||||
[formId]="'collection-source-form-id'"
|
[formId]="'collection-source-form-id'"
|
||||||
[formGroup]="formGroup"
|
[formGroup]="formGroup"
|
||||||
[formModel]="formModel"
|
[formModel]="formModel"
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
(dfChange)="onChange($event)"
|
(dfChange)="onChange($event)"
|
||||||
(submitForm)="onSubmit()"
|
(submitForm)="onSubmit()"
|
||||||
(cancel)="onCancel()"></ds-form>
|
(cancel)="onCancel()"></ds-form>
|
||||||
<div class="container-fluid" *ngIf="contentSource.enabled">
|
<div class="container-fluid" *ngIf="(contentSource.harvestType !== harvestTypeNone)">
|
||||||
<div class="d-inline-block float-right">
|
<div class="d-inline-block float-right">
|
||||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
[disabled]="!(hasChanges() | async)"
|
[disabled]="!(hasChanges() | async)"
|
||||||
@@ -52,4 +53,5 @@
|
|||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
@@ -1,8 +1,13 @@
|
|||||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component';
|
import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component';
|
||||||
import {
|
import {
|
||||||
DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService,
|
DynamicFormControlModel,
|
||||||
DynamicInputModel, DynamicOptionControlModel, DynamicRadioGroupModel,
|
DynamicFormGroupModel,
|
||||||
|
DynamicFormLayout,
|
||||||
|
DynamicFormService,
|
||||||
|
DynamicInputModel,
|
||||||
|
DynamicOptionControlModel,
|
||||||
|
DynamicRadioGroupModel,
|
||||||
DynamicSelectModel,
|
DynamicSelectModel,
|
||||||
DynamicTextAreaModel
|
DynamicTextAreaModel
|
||||||
} from '@ng-dynamic-forms/core';
|
} 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 { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
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 { Observable } from 'rxjs/internal/Observable';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { Collection } from '../../../core/shared/collection.model';
|
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 { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { Subscription } from 'rxjs/internal/Subscription';
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
|
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
|
* 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
|
* The Dynamic Input Model for the OAI Provider
|
||||||
*/
|
*/
|
||||||
providerModel = new DynamicInputModel({
|
oaiSourceModel = new DynamicInputModel({
|
||||||
id: 'provider',
|
id: 'oaiSource',
|
||||||
name: 'provider',
|
name: 'oaiSource',
|
||||||
required: true,
|
required: true,
|
||||||
validators: {
|
validators: {
|
||||||
required: null
|
required: null
|
||||||
@@ -79,17 +86,17 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
/**
|
/**
|
||||||
* The Dynamic Input Model for the OAI Set
|
* The Dynamic Input Model for the OAI Set
|
||||||
*/
|
*/
|
||||||
setModel = new DynamicInputModel({
|
oaiSetIdModel = new DynamicInputModel({
|
||||||
id: 'set',
|
id: 'oaiSetId',
|
||||||
name: 'set'
|
name: 'oaiSetId'
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Dynamic Input Model for the Metadata Format used
|
* The Dynamic Input Model for the Metadata Format used
|
||||||
*/
|
*/
|
||||||
formatModel = new DynamicSelectModel({
|
metadataConfigIdModel = new DynamicSelectModel({
|
||||||
id: 'format',
|
id: 'metadataConfigId',
|
||||||
name: 'format',
|
name: 'metadataConfigId',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
value: 'dc'
|
value: 'dc'
|
||||||
@@ -100,24 +107,25 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
{
|
{
|
||||||
value: 'dim'
|
value: 'dim'
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
value: 'dc'
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Dynamic Input Model for the type of harvesting
|
* The Dynamic Input Model for the type of harvesting
|
||||||
*/
|
*/
|
||||||
harvestModel = new DynamicRadioGroupModel<number>({
|
harvestTypeModel = new DynamicRadioGroupModel<string>({
|
||||||
id: 'harvest',
|
id: 'harvestType',
|
||||||
name: 'harvest',
|
name: 'harvestType',
|
||||||
options: [
|
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
|
* 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
|
* 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[] = [
|
formModel: DynamicFormControlModel[] = [
|
||||||
new DynamicFormGroupModel({
|
new DynamicFormGroupModel({
|
||||||
id: 'providerContainer',
|
id: 'oaiSourceContainer',
|
||||||
group: [
|
group: [
|
||||||
this.providerModel
|
this.oaiSourceModel
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
new DynamicFormGroupModel({
|
new DynamicFormGroupModel({
|
||||||
id: 'setContainer',
|
id: 'oaiSetContainer',
|
||||||
group: [
|
group: [
|
||||||
this.setModel,
|
this.oaiSetIdModel,
|
||||||
this.formatModel
|
this.metadataConfigIdModel
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
new DynamicFormGroupModel({
|
new DynamicFormGroupModel({
|
||||||
id: 'harvestContainer',
|
id: 'harvestTypeContainer',
|
||||||
group: [
|
group: [
|
||||||
this.harvestModel
|
this.harvestTypeModel
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
@@ -157,38 +165,38 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
* Layout used for structuring the form inputs
|
* Layout used for structuring the form inputs
|
||||||
*/
|
*/
|
||||||
formLayout: DynamicFormLayout = {
|
formLayout: DynamicFormLayout = {
|
||||||
provider: {
|
oaiSource: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'col-12 d-inline-block'
|
host: 'col-12 d-inline-block'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set: {
|
oaiSetId: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'col col-sm-6 d-inline-block'
|
host: 'col col-sm-6 d-inline-block'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
format: {
|
metadataConfigId: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'col col-sm-6 d-inline-block'
|
host: 'col col-sm-6 d-inline-block'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
harvest: {
|
harvestType: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'col-12',
|
host: 'col-12',
|
||||||
option: 'btn-outline-secondary'
|
option: 'btn-outline-secondary'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setContainer: {
|
oaiSetContainer: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'row'
|
host: 'row'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
providerContainer: {
|
oaiSourceContainer: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'row'
|
host: 'row'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
harvestContainer: {
|
harvestTypeContainer: {
|
||||||
grid: {
|
grid: {
|
||||||
host: 'row'
|
host: 'row'
|
||||||
}
|
}
|
||||||
@@ -205,6 +213,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
*/
|
*/
|
||||||
updateSub: Subscription;
|
updateSub: Subscription;
|
||||||
|
|
||||||
|
harvestTypeNone = ContentSourceHarvestType.None;
|
||||||
|
|
||||||
public constructor(public objectUpdatesService: ObjectUpdatesService,
|
public constructor(public objectUpdatesService: ObjectUpdatesService,
|
||||||
public notificationsService: NotificationsService,
|
public notificationsService: NotificationsService,
|
||||||
protected location: Location,
|
protected location: Location,
|
||||||
@@ -212,7 +222,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,) {
|
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
|
protected collectionService: CollectionDataService) {
|
||||||
super(objectUpdatesService, notificationsService, translate);
|
super(objectUpdatesService, notificationsService, translate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,16 +240,21 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||||
this.collectionRD$ = this.route.parent.data.pipe(first(), map((data) => data.dso));
|
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.collectionRD$.pipe(
|
||||||
this.contentSource = new ContentSource();
|
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.updateFieldTranslations();
|
||||||
this.translate.onLangChange
|
this.translate.onLangChange
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.updateFieldTranslations();
|
this.updateFieldTranslations();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.initializeOriginalContentSource();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,15 +270,15 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
if (update) {
|
if (update) {
|
||||||
const field = update.field as ContentSource;
|
const field = update.field as ContentSource;
|
||||||
this.formGroup.patchValue({
|
this.formGroup.patchValue({
|
||||||
providerContainer: {
|
oaiSourceContainer: {
|
||||||
provider: field.provider
|
oaiSource: field.oaiSource
|
||||||
},
|
},
|
||||||
setContainer: {
|
oaiSetContainer: {
|
||||||
set: field.set,
|
oaiSetId: field.oaiSetId,
|
||||||
format: field.format
|
metadataConfigId: field.metadataConfigId
|
||||||
},
|
},
|
||||||
harvestContainer: {
|
harvestTypeContainer: {
|
||||||
harvest: field.harvest
|
harvestType: field.harvestType
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.contentSource = cloneDeep(field);
|
this.contentSource = cloneDeep(field);
|
||||||
@@ -307,7 +323,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onChange(event) {
|
onChange(event) {
|
||||||
this.updateContentSourceField(event.model);
|
this.updateContentSourceField(event.model, true);
|
||||||
this.saveFieldUpdate();
|
this.saveFieldUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,24 +347,28 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
* Is the current form valid to be submitted ?
|
* Is the current form valid to be submitted ?
|
||||||
*/
|
*/
|
||||||
isValid(): boolean {
|
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
|
* Switch the external source on or off and fire a field update
|
||||||
*/
|
*/
|
||||||
changeExternalSource() {
|
changeExternalSource() {
|
||||||
this.contentSource.enabled = !this.contentSource.enabled;
|
if (this.contentSource.harvestType === ContentSourceHarvestType.None) {
|
||||||
this.updateContentSource();
|
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
|
* Loop over all inputs and update the Content Source with their value
|
||||||
*/
|
*/
|
||||||
updateContentSource() {
|
updateContentSource(updateHarvestType: boolean) {
|
||||||
this.inputModels.forEach(
|
this.inputModels.forEach(
|
||||||
(fieldModel: DynamicInputModel) => {
|
(fieldModel: DynamicInputModel) => {
|
||||||
this.updateContentSourceField(fieldModel)
|
this.updateContentSourceField(fieldModel, updateHarvestType)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.saveFieldUpdate();
|
this.saveFieldUpdate();
|
||||||
@@ -358,8 +378,8 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
* Update the Content Source with the value from a DynamicInputModel
|
* Update the Content Source with the value from a DynamicInputModel
|
||||||
* @param fieldModel
|
* @param fieldModel
|
||||||
*/
|
*/
|
||||||
updateContentSourceField(fieldModel: DynamicInputModel) {
|
updateContentSourceField(fieldModel: DynamicInputModel, updateHarvestType: boolean) {
|
||||||
if (hasValue(fieldModel.value)) {
|
if (hasValue(fieldModel.value) && !(fieldModel.id === this.harvestTypeModel.id && !updateHarvestType)) {
|
||||||
this.contentSource[fieldModel.id] = fieldModel.value;
|
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 { NormalizedAuthStatus } from '../auth/models/normalized-auth-status.model';
|
||||||
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
||||||
import { MetadataField } from '../metadata/metadata-field.model';
|
import { MetadataField } from '../metadata/metadata-field.model';
|
||||||
|
import { ContentSource } from '../shared/content-source.model';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
export class RestResponse {
|
export class RestResponse {
|
||||||
@@ -288,4 +289,17 @@ export class FilteredDiscoveryQueryResponse extends RestResponse {
|
|||||||
super(true, statusCode, statusText);
|
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 */
|
/* 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 { NormalizedSubmissionUploadsModel } from './config/models/normalized-config-submission-uploads.model';
|
||||||
import { NormalizedBrowseEntry } from './shared/normalized-browse-entry.model';
|
import { NormalizedBrowseEntry } from './shared/normalized-browse-entry.model';
|
||||||
import { BrowseDefinition } from './shared/browse-definition.model';
|
import { BrowseDefinition } from './shared/browse-definition.model';
|
||||||
|
import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -203,6 +204,7 @@ const PROVIDERS = [
|
|||||||
TaskResponseParsingService,
|
TaskResponseParsingService,
|
||||||
ClaimedTaskDataService,
|
ClaimedTaskDataService,
|
||||||
PoolTaskDataService,
|
PoolTaskDataService,
|
||||||
|
ContentSourceResponseParsingService,
|
||||||
// register AuthInterceptor as HttpInterceptor
|
// register AuthInterceptor as HttpInterceptor
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
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 { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
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 { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FindAllOptions } from './request.models';
|
import { ContentSourceRequest, FindAllOptions, RestRequest } from './request.models';
|
||||||
import { RemoteData } from './remote-data';
|
import { RemoteData } from './remote-data';
|
||||||
import { PaginatedList } from './paginated-list';
|
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()
|
@Injectable()
|
||||||
export class CollectionDataService extends ComColDataService<Collection> {
|
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)
|
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);
|
const objectUpdates = this.getObjectEntry(url);
|
||||||
return objectUpdates.pipe(map((objectEntry) => {
|
return objectUpdates.pipe(map((objectEntry) => {
|
||||||
const fieldUpdates: FieldUpdates = {};
|
const fieldUpdates: FieldUpdates = {};
|
||||||
|
if (hasValue(objectEntry)) {
|
||||||
Object.keys(objectEntry.fieldStates).forEach((uuid) => {
|
Object.keys(objectEntry.fieldStates).forEach((uuid) => {
|
||||||
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
||||||
if (isEmpty(fieldUpdate)) {
|
if (isEmpty(fieldUpdate)) {
|
||||||
const identifiable = initialFields.find((object: Identifiable) => object.uuid === uuid);
|
const identifiable = initialFields.find((object: Identifiable) => object.uuid === uuid);
|
||||||
fieldUpdate = { field: identifiable, changeType: undefined };
|
fieldUpdate = {field: identifiable, changeType: undefined};
|
||||||
}
|
}
|
||||||
fieldUpdates[uuid] = fieldUpdate;
|
fieldUpdates[uuid] = fieldUpdate;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
return fieldUpdates;
|
return fieldUpdates;
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ import { MetadataschemaParsingService } from './metadataschema-parsing.service';
|
|||||||
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
||||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||||
import { TaskResponseParsingService } from '../tasks/task-response-parsing.service';
|
import { TaskResponseParsingService } from '../tasks/task-response-parsing.service';
|
||||||
|
import { ContentSourceResponseParsingService } from './content-source-response-parsing.service';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* 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
|
* 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
|
* A model class that holds information about the Content Source of a Collection
|
||||||
*/
|
*/
|
||||||
export class ContentSource {
|
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;
|
uuid: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this collection harvest its content from an external source ?
|
* OAI Provider / Source
|
||||||
*/
|
*/
|
||||||
enabled = false;
|
@autoserializeAs('oai_source')
|
||||||
|
oaiSource: string;
|
||||||
/**
|
|
||||||
* OAI Provider
|
|
||||||
*/
|
|
||||||
provider: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OAI Specific set ID
|
* 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
|
* 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
|
* The REST link to itself
|
||||||
this.uuid = uuid();
|
*/
|
||||||
}
|
@autoserialize
|
||||||
|
self: string;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user