mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 18:44:14 +00:00
64961: Edit bitstream metadata PATCH requests
This commit is contained in:
@@ -91,6 +91,8 @@
|
|||||||
"bitstream.edit.form.fileName.label": "Filename",
|
"bitstream.edit.form.fileName.label": "Filename",
|
||||||
"bitstream.edit.form.fileName.hint": "Change the filename for the bitstream. Note that this will change the display bitstream URL, but old links will still resolve as long as the sequence ID does not change.",
|
"bitstream.edit.form.fileName.hint": "Change the filename for the bitstream. Note that this will change the display bitstream URL, but old links will still resolve as long as the sequence ID does not change.",
|
||||||
"bitstream.edit.form.primaryBitstream.label": "Primary bitstream",
|
"bitstream.edit.form.primaryBitstream.label": "Primary bitstream",
|
||||||
|
"bitstream.edit.notifications.saved.content": "Your changes to this bitstream were saved.",
|
||||||
|
"bitstream.edit.notifications.saved.title": "Bitstream saved",
|
||||||
"browse.comcol.by.author": "By Author",
|
"browse.comcol.by.author": "By Author",
|
||||||
"browse.comcol.by.dateissued": "By Issue Date",
|
"browse.comcol.by.dateissued": "By Issue Date",
|
||||||
"browse.comcol.by.subject": "By Subject",
|
"browse.comcol.by.subject": "By Subject",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { map } from 'rxjs/operators';
|
import { map, tap } from 'rxjs/operators';
|
||||||
import { Subscription } from 'rxjs/internal/Subscription';
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
import {
|
import {
|
||||||
DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService,
|
DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService,
|
||||||
@@ -11,6 +11,11 @@ import {
|
|||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
|
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
|
||||||
|
import { getSucceededRemoteData } from '../../core/shared/operators';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-edit-bitstream-page',
|
selector: 'ds-edit-bitstream-page',
|
||||||
@@ -43,6 +48,11 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
HINT_KEY_SUFFIX = '.hint';
|
HINT_KEY_SUFFIX = '.hint';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string} Key prefix used to generate notification messages
|
||||||
|
*/
|
||||||
|
NOTIFICATIONS_PREFIX = 'bitstream.edit.notifications.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Dynamic Input Model for the file's name
|
* The Dynamic Input Model for the file's name
|
||||||
*/
|
*/
|
||||||
@@ -167,7 +177,9 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
constructor(private route: ActivatedRoute,
|
||||||
private formService: DynamicFormService,
|
private formService: DynamicFormService,
|
||||||
private translate: TranslateService) {
|
private translate: TranslateService,
|
||||||
|
private bitstreamService: BitstreamDataService,
|
||||||
|
private notificationsService: NotificationsService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -232,8 +244,32 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
|||||||
* Check for changes against the bitstream and send update requests to the REST API
|
* Check for changes against the bitstream and send update requests to the REST API
|
||||||
*/
|
*/
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
// TODO: Check for changes against the bitstream and send requests to the REST API accordingly
|
const updatedValues = this.formGroup.getRawValue();
|
||||||
console.log(this.formGroup.getRawValue());
|
const newBitstream = this.formToBitstream(updatedValues);
|
||||||
|
this.bitstreamService.update(newBitstream).pipe(
|
||||||
|
tap(() => this.bitstreamService.commitUpdates()),
|
||||||
|
getSucceededRemoteData()
|
||||||
|
).subscribe((bitstreamRD: RemoteData<Bitstream>) => {
|
||||||
|
this.bitstream = bitstreamRD.payload;
|
||||||
|
this.updateForm(this.bitstream);
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.translate.instant(this.NOTIFICATIONS_PREFIX + 'saved.title'),
|
||||||
|
this.translate.instant(this.NOTIFICATIONS_PREFIX + 'saved.content')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse form data to an updated bitstream object
|
||||||
|
* @param rawForm Raw form data
|
||||||
|
*/
|
||||||
|
formToBitstream(rawForm): Bitstream {
|
||||||
|
const newBitstream = cloneDeep(this.bitstream);
|
||||||
|
// TODO: Set bitstream to primary when supported
|
||||||
|
const primary = rawForm.fileNamePrimaryContainer.primaryBitstream;
|
||||||
|
newBitstream.name = rawForm.fileNamePrimaryContainer.fileName;
|
||||||
|
newBitstream.description = rawForm.descriptionContainer.description;
|
||||||
|
return newBitstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
19
src/app/core/cache/server-sync-buffer.effects.ts
vendored
19
src/app/core/cache/server-sync-buffer.effects.ts
vendored
@@ -15,7 +15,7 @@ import { Action, createSelector, MemoizedSelector, select, Store } from '@ngrx/s
|
|||||||
import { ServerSyncBufferEntry, ServerSyncBufferState } from './server-sync-buffer.reducer';
|
import { ServerSyncBufferEntry, ServerSyncBufferState } from './server-sync-buffer.reducer';
|
||||||
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
|
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
|
||||||
import { RequestService } from '../data/request.service';
|
import { RequestService } from '../data/request.service';
|
||||||
import { PutRequest } from '../data/request.models';
|
import { PatchRequest, PutRequest } from '../data/request.models';
|
||||||
import { ObjectCacheService } from './object-cache.service';
|
import { ObjectCacheService } from './object-cache.service';
|
||||||
import { ApplyPatchObjectCacheAction } from './object-cache.actions';
|
import { ApplyPatchObjectCacheAction } from './object-cache.actions';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
@@ -23,6 +23,8 @@ import { GenericConstructor } from '../shared/generic-constructor';
|
|||||||
import { hasValue, isNotEmpty, isNotUndefined } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty, isNotUndefined } from '../../shared/empty.util';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { RestRequestMethod } from '../data/rest-request-method';
|
import { RestRequestMethod } from '../data/rest-request-method';
|
||||||
|
import { ObjectCacheEntry } from './object-cache.reducer';
|
||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServerSyncBufferEffects {
|
export class ServerSyncBufferEffects {
|
||||||
@@ -96,15 +98,16 @@ export class ServerSyncBufferEffects {
|
|||||||
* @returns {Observable<Action>} ApplyPatchObjectCacheAction to be dispatched
|
* @returns {Observable<Action>} ApplyPatchObjectCacheAction to be dispatched
|
||||||
*/
|
*/
|
||||||
private applyPatch(href: string): Observable<Action> {
|
private applyPatch(href: string): Observable<Action> {
|
||||||
const patchObject = this.objectCache.getObjectBySelfLink(href).pipe(take(1));
|
const patchObject = this.objectCache.getBySelfLink(href).pipe(take(1));
|
||||||
|
|
||||||
return patchObject.pipe(
|
return patchObject.pipe(
|
||||||
map((object) => {
|
map((entry: ObjectCacheEntry) => {
|
||||||
const serializedObject = new DSpaceRESTv2Serializer(object.constructor as GenericConstructor<{}>).serialize(object);
|
if (isNotEmpty(entry.patches)) {
|
||||||
|
const flatPatch: Operation[] = [].concat(...entry.patches.map((patch) => patch.operations));
|
||||||
this.requestService.configure(new PutRequest(this.requestService.generateRequestId(), href, serializedObject));
|
this.requestService.configure(new PatchRequest(this.requestService.generateRequestId(), href, flatPatch));
|
||||||
|
return new ApplyPatchObjectCacheAction(href);
|
||||||
return new ApplyPatchObjectCacheAction(href)
|
}
|
||||||
|
// this.requestService.configure(new PutRequest(this.requestService.generateRequestId(), href, serializedObject));
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,9 @@ export class DSOChangeAnalyzer<T extends DSpaceObject> implements ChangeAnalyzer
|
|||||||
* The second object to compare
|
* The second object to compare
|
||||||
*/
|
*/
|
||||||
diff(object1: T | NormalizedDSpaceObject<T>, object2: T | NormalizedDSpaceObject<T>): Operation[] {
|
diff(object1: T | NormalizedDSpaceObject<T>, object2: T | NormalizedDSpaceObject<T>): Operation[] {
|
||||||
return compare(object1.metadata, object2.metadata).map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path }));
|
return compare(object1.metadata, object2.metadata)
|
||||||
|
// Filter out operations on UUIDs, as they should never change
|
||||||
|
.filter((operation: Operation) => !operation.path.endsWith('/uuid'))
|
||||||
|
.map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -94,7 +94,6 @@ 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 = {};
|
||||||
console.log(objectEntry);
|
|
||||||
Object.keys(ignoreStates ? objectEntry.fieldUpdates : objectEntry.fieldStates).forEach((uuid) => {
|
Object.keys(ignoreStates ? objectEntry.fieldUpdates : objectEntry.fieldStates).forEach((uuid) => {
|
||||||
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
let fieldUpdate = objectEntry.fieldUpdates[uuid];
|
||||||
if (isEmpty(fieldUpdate)) {
|
if (isEmpty(fieldUpdate)) {
|
||||||
|
@@ -4,19 +4,34 @@ import { Item } from './item.model';
|
|||||||
import { BitstreamFormat } from './bitstream-format.model';
|
import { BitstreamFormat } from './bitstream-format.model';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
|
import { hasValue, isUndefined } from '../../shared/empty.util';
|
||||||
|
|
||||||
export class Bitstream extends DSpaceObject {
|
export class Bitstream extends DSpaceObject {
|
||||||
static type = new ResourceType('bitstream');
|
static type = new ResourceType('bitstream');
|
||||||
|
|
||||||
|
private _description: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size of this bitstream in bytes
|
* The size of this bitstream in bytes
|
||||||
*/
|
*/
|
||||||
sizeBytes: number;
|
sizeBytes: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The description of this Bitstream
|
* Get the description of this Bitstream
|
||||||
*/
|
*/
|
||||||
description: string;
|
get description(): string {
|
||||||
|
return (isUndefined(this._description)) ? this.firstMetadataValue('dc.description') : this._description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the description of this Bitstream
|
||||||
|
*/
|
||||||
|
set description(description) {
|
||||||
|
if (hasValue(this.firstMetadata('dc.description'))) {
|
||||||
|
this.firstMetadata('dc.description').value = description;
|
||||||
|
}
|
||||||
|
this._description = description;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the Bundle this Bitstream is part of
|
* The name of the Bundle this Bitstream is part of
|
||||||
|
@@ -7,7 +7,7 @@ import {
|
|||||||
MetadatumViewModel
|
MetadatumViewModel
|
||||||
} from './metadata.models';
|
} from './metadata.models';
|
||||||
import { Metadata } from './metadata.utils';
|
import { Metadata } from './metadata.utils';
|
||||||
import { hasNoValue, isUndefined } from '../../shared/empty.util';
|
import { hasNoValue, hasValue, isUndefined } from '../../shared/empty.util';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
import { RemoteData } from '../data/remote-data';
|
import { RemoteData } from '../data/remote-data';
|
||||||
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||||
@@ -47,6 +47,9 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
|||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
*/
|
*/
|
||||||
set name(name) {
|
set name(name) {
|
||||||
|
if (hasValue(this.firstMetadata('dc.title'))) {
|
||||||
|
this.firstMetadata('dc.title').value = name;
|
||||||
|
}
|
||||||
this._name = name;
|
this._name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user