From 1b9bc2f7a3fc6f03e18a1ffe15fc8be297f88ba5 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 20 Aug 2019 17:28:28 +0200 Subject: [PATCH] 64503: Content Source PUT request on form submit --- resources/i18n/en.json | 2 + .../collection-source.component.ts | 13 +++- src/app/core/data/collection-data.service.ts | 67 +++++++++++++++++-- src/app/core/data/request.models.ts | 10 +++ src/app/core/shared/content-source.model.ts | 6 +- 5 files changed, 87 insertions(+), 11 deletions(-) diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 41a4bc3f29..0fb6fd4229 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -131,6 +131,8 @@ "collection.page.browse.recent.head": "Recent Submissions", "collection.page.license": "License", "collection.page.news": "News", + "collection.source.update.notifications.error.content": "The provided settings have been tested and didn't work.", + "collection.source.update.notifications.error.title": "Server Error", "community.create.head": "Create a Community", "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", "community.delete.cancel": "Cancel", diff --git a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts index 932092a4a4..92dba10ce8 100644 --- a/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts +++ b/src/app/+collection-page/edit-collection-page/collection-source/collection-source.component.ts @@ -331,9 +331,16 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem * Submit the edited Content Source to the REST API, re-initialize the field update and display a notification */ onSubmit() { - // TODO: Fetch field update and send to REST API - this.initializeOriginalContentSource(); - this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved')); + this.collectionRD$.pipe( + getSucceededRemoteData(), + map((col) => col.payload.uuid), + switchMap((uuid) => this.collectionService.updateContentSource(uuid, this.contentSource)), + take(1) + ).subscribe((contentSource: ContentSource) => { + this.contentSource = contentSource; + this.initializeOriginalContentSource(); + this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved')); + }); } /** diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts index 1a59498a72..a858469466 100644 --- a/src/app/core/data/collection-data.service.ts +++ b/src/app/core/data/collection-data.service.ts @@ -12,21 +12,33 @@ import { CommunityDataService } from './community-data.service'; import { RequestService } from './request.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } 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 { ContentSourceRequest, FindAllOptions, RestRequest } from './request.models'; +import { ContentSourceRequest, FindAllOptions, RestRequest, UpdateContentSourceRequest } 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'; +import { + configureRequest, + filterSuccessfulResponses, + getRequestFromRequestHref, + getResponseFromEntry +} from '../shared/operators'; +import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; +import { TranslateService } from '@ngx-translate/core'; @Injectable() export class CollectionDataService extends ComColDataService { protected linkPath = 'collections'; protected forceBypassCache = false; + protected errorTitle = 'collection.source.update.notifications.error.title'; + protected contentSourceError = 'collection.source.update.notifications.error.content'; constructor( protected requestService: RequestService, @@ -38,7 +50,8 @@ export class CollectionDataService extends ComColDataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DSOChangeAnalyzer + protected comparator: DSOChangeAnalyzer, + protected translate: TranslateService ) { super(); } @@ -77,4 +90,48 @@ export class CollectionDataService extends ComColDataService { map((response: ContentSourceSuccessResponse) => response.contentsource) ); } + + updateContentSource(collectionId: string, contentSource: ContentSource): Observable { + const requestId = this.requestService.generateRequestId(); + const serializedContentSource = new DSpaceRESTv2Serializer(ContentSource).serialize(contentSource); + const request$ = this.getHarvesterEndpoint(collectionId).pipe( + take(1), + map((href: string) => { + const options: HttpOptions = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Content-Type', 'application/json'); + options.headers = headers; + return new UpdateContentSourceRequest(requestId, href, JSON.stringify(serializedContentSource), options); + }) + ); + + // Execute the post/put request + request$.pipe( + configureRequest(this.requestService) + ).subscribe(); + + // Return updated ContentSource + return this.requestService.getByUUID(requestId).pipe( + getResponseFromEntry(), + map((response: RestResponse) => { + if (!response.isSuccessful) { + if (hasValue((response as any).errorMessage)) { + if (response.statusCode === 422) { + this.notificationsService.error(this.translate.instant(this.errorTitle), this.translate.instant(this.contentSourceError), new NotificationOptions(-1)); + } else { + this.notificationsService.error(this.translate.instant(this.errorTitle), (response as any).errorMessage, new NotificationOptions(-1)); + } + } + } else { + return response; + } + }), + isNotEmptyOperator(), + map((response: ContentSourceSuccessResponse) => { + if (isNotEmpty(response.contentsource)) { + return response.contentsource; + } + }) + ); + } } diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index eab7af5751..f25b084af7 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -369,6 +369,16 @@ export class ContentSourceRequest extends GetRequest { } } +export class UpdateContentSourceRequest extends PutRequest { + constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) { + super(uuid, href, body, options); + } + + getResponseParser(): GenericConstructor { + return ContentSourceResponseParsingService; + } +} + /** * Request to delete an object based on its identifier */ diff --git a/src/app/core/shared/content-source.model.ts b/src/app/core/shared/content-source.model.ts index 68db549adb..76df1f10ce 100644 --- a/src/app/core/shared/content-source.model.ts +++ b/src/app/core/shared/content-source.model.ts @@ -1,4 +1,4 @@ -import { autoserialize, autoserializeAs } from 'cerialize'; +import { autoserialize, autoserializeAs, deserializeAs, deserialize } from 'cerialize'; export enum ContentSourceHarvestType { None = 'NONE', @@ -15,7 +15,7 @@ export class ContentSource { * 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') + @deserializeAs('self') uuid: string; /** @@ -46,6 +46,6 @@ export class ContentSource { /** * The REST link to itself */ - @autoserialize + @deserialize self: string; }