From 70a6ea1ee6971ba6ae2a34e770f7c178160465c9 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Fri, 30 Nov 2018 10:30:01 -0700 Subject: [PATCH 1/3] [SHIBUI-925] Updated exception handling in overrides json schema validation to return an ErrorResponse object. Also fixed the method name of the handler. Updated controller to return an ErrorResponse object when a 409 is encountered. --- ...artyOverridesJsonSchemaValidatingControllerAdvice.groovy | 6 +++--- .../admin/ui/controller/EntityDescriptorController.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy index 934d7b1a7..e77097af6 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.jsonschema +import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation import mjson.Json import org.springframework.beans.factory.annotation.Autowired @@ -10,7 +11,6 @@ import org.springframework.http.ResponseEntity import org.springframework.http.converter.HttpMessageConverter import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler -import org.springframework.web.context.request.WebRequest import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter import javax.annotation.PostConstruct @@ -56,8 +56,8 @@ class RelyingPartyOverridesJsonSchemaValidatingControllerAdvice extends RequestB } @ExceptionHandler(JsonSchemaValidationFailedException) - final ResponseEntity handleUserNotFoundException(JsonSchemaValidationFailedException ex, WebRequest request) { - new ResponseEntity<>([errors: ex.errors], HttpStatus.BAD_REQUEST) + final ResponseEntity handleJsonSchemaValidationFailedException(JsonSchemaValidationFailedException ex) { + ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse("400", String.join('\n', ex.errors))) } @PostConstruct diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java index afde9d244..c3e76983e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java @@ -160,7 +160,7 @@ private ResponseEntity existingEntityDescriptorCheck(String entityId) { return ResponseEntity .status(HttpStatus.CONFLICT) .headers(headers) - .body(String.format("The entity descriptor with entity id [%s] already exists.", entityId)); + .body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()), String.format("The entity descriptor with entity id [%s] already exists.", entityId))); } //No existing entity descriptor, which is an OK condition indicated by returning a null conflict response return null; From 21265a41d4b0daf0cdbec3451e92582e83b64a3b Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 6 Dec 2018 08:52:54 -0700 Subject: [PATCH 2/3] SHIBUI-925 Implemented fix for error messages on upload --- .../domain/service/resolver.service.ts | 8 +++-- .../resolver/effect/collection.effects.ts | 33 +++++++++++++++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/ui/src/app/metadata/domain/service/resolver.service.ts b/ui/src/app/metadata/domain/service/resolver.service.ts index f0c9f4b3c..4012f9f23 100644 --- a/ui/src/app/metadata/domain/service/resolver.service.ts +++ b/ui/src/app/metadata/domain/service/resolver.service.ts @@ -45,7 +45,9 @@ export class ResolverService { return this.http.post(`${this.base}${this.endpoint}`, xml, { headers: new HttpHeaders().set('Content-Type', 'application/xml'), params: new HttpParams().set('spName', name) - }); + }).pipe(catchError(error => { + return throwError({ errorCode: error.status, errorMessage: `Unable to upload file ... ${error.error}` }); + })); } createFromUrl(name: string, url: string): Observable { @@ -53,7 +55,9 @@ export class ResolverService { return this.http.post(`${this.base}${this.endpoint}`, body, { headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'), params: new HttpParams().set('spName', name) - }); + }).pipe(catchError(error => { + return throwError({ errorCode: error.status, errorMessage: `Unable to upload file ... ${error.error}` }); + })); } preview(id: string): Observable { diff --git a/ui/src/app/metadata/resolver/effect/collection.effects.ts b/ui/src/app/metadata/resolver/effect/collection.effects.ts index d56110a7e..46d2d0712 100644 --- a/ui/src/app/metadata/resolver/effect/collection.effects.ts +++ b/ui/src/app/metadata/resolver/effect/collection.effects.ts @@ -1,15 +1,21 @@ import { Injectable } from '@angular/core'; import { Effect, Actions, ofType } from '@ngrx/effects'; import { Router } from '@angular/router'; - +import { Store } from '@ngrx/store'; import { of } from 'rxjs'; -import { map, catchError, switchMap, tap } from 'rxjs/operators'; +import { map, catchError, switchMap, tap, withLatestFrom } from 'rxjs/operators'; import * as providerActions from '../action/collection.action'; import * as draftActions from '../action/draft.action'; import { ResolverCollectionActionTypes } from '../action/collection.action'; import { ResolverService } from '../../domain/service/resolver.service'; import { removeNulls } from '../../../shared/util'; +import { AddNotification } from '../../../notification/action/notification.action'; +import { Notification, NotificationType } from '../../../notification/model/notification'; +import { I18nService } from '../../../i18n/service/i18n.service'; +import * as fromRoot from '../../../app.reducer'; +import * as fromI18n from '../../../i18n/reducer'; + /* istanbul ignore next */ @Injectable() @@ -112,11 +118,24 @@ export class ResolverCollectionEffects { ofType(ResolverCollectionActionTypes.ADD_RESOLVER_SUCCESS), map(action => action.payload), map(provider => { - console.log(provider); return new draftActions.RemoveDraftRequest(provider); }) ); + @Effect() + addResolverFailNotification$ = this.actions$.pipe( + ofType(ResolverCollectionActionTypes.ADD_RESOLVER_FAIL), + map(action => action.payload), + withLatestFrom(this.store.select(fromI18n.getMessages)), + map(([error, messages]) => new AddNotification( + new Notification( + NotificationType.Danger, + `${error.errorCode}: ${this.i18nService.translate(error.errorMessage, null, messages)}`, + 8000 + ) + )) + ); + @Effect() uploadResolverRequest$ = this.actions$.pipe( ofType(ResolverCollectionActionTypes.UPLOAD_RESOLVER_REQUEST), @@ -126,7 +145,7 @@ export class ResolverCollectionEffects { .upload(file.name, file.body) .pipe( map(p => new providerActions.AddResolverSuccess(p)), - catchError(() => of(new providerActions.AddResolverFail(file))) + catchError((error) => of(new providerActions.AddResolverFail(error))) ) ) ); @@ -140,7 +159,7 @@ export class ResolverCollectionEffects { .createFromUrl(file.name, file.url) .pipe( map(p => new providerActions.AddResolverSuccess(p)), - catchError(() => of(new providerActions.AddResolverFail(file))) + catchError((error) => of(new providerActions.AddResolverFail(error))) ) ) ); @@ -148,6 +167,8 @@ export class ResolverCollectionEffects { constructor( private descriptorService: ResolverService, private actions$: Actions, - private router: Router + private router: Router, + private store: Store, + private i18nService: I18nService ) { } } /* istanbul ignore next */ From 3590d8d0631f6ca26c005bd17a9557af4eeb98c6 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Thu, 6 Dec 2018 09:49:36 -0700 Subject: [PATCH 3/3] [SHIBUI-925] Updated a test to reflect the change in error messaging. --- .../admin/ui/controller/EntityDescriptorControllerTests.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy index 122a349ae..b38941b74 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy @@ -505,7 +505,7 @@ class EntityDescriptorControllerTests extends Specification { then: result.andExpect(status().isConflict()) - .andExpect(content().string("The entity descriptor with entity id [http://test.scaldingspoon.org/test1] already exists.")) + .andExpect(content().string("{\"errorCode\":\"409\",\"errorMessage\":\"The entity descriptor with entity id [http://test.scaldingspoon.org/test1] already exists.\"}")) } def "POST /EntityDescriptor handles x-www-form-urlencoded happily"() {