From efd2fb36555330d80d6d77c699e02c2dca2f1a56 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 20 Jan 2024 21:59:17 -0800 Subject: [PATCH] verbose error messages. make sure backend error messages during sync & source creation are propagated to the frontend. --- .gitignore | 6 +++- backend/pkg/web/handler/source.go | 30 ++++++++++++------- .../medical-sources-connected.component.ts | 17 +++++++++-- .../src/app/services/lighthouse.service.ts | 7 +++-- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index c5d80bfe..c8df5ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,6 @@ fabric.properties /dist/ vendor -fasten.db test.go /.couchdb @@ -64,3 +63,8 @@ config.dev.yaml .cache/ cache/ fasten-*.db +fasten-*.db-shm +fasten-*.db-wal +fasten.db +fasten.db-shm +fasten.db-wal diff --git a/backend/pkg/web/handler/source.go b/backend/pkg/web/handler/source.go index 0d5a7bc6..eb738b3e 100644 --- a/backend/pkg/web/handler/source.go +++ b/backend/pkg/web/handler/source.go @@ -25,8 +25,9 @@ func CreateReconnectSource(c *gin.Context) { sourceCred := models.SourceCredential{} if err := c.ShouldBindJSON(&sourceCred); err != nil { - logger.Errorln("An error occurred while parsing posted source credential", err) - c.JSON(http.StatusBadRequest, gin.H{"success": false}) + err = fmt.Errorf("an error occurred while parsing posted source credential: %s", err) + logger.Errorln(err) + c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": err.Error()}) return } @@ -88,7 +89,9 @@ func CreateReconnectSource(c *gin.Context) { summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, &sourceCred) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + err := fmt.Errorf("an error occurred while starting initial sync: %w", err) + logger.Errorln(err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } @@ -104,15 +107,18 @@ func SourceSync(c *gin.Context) { sourceCred, err := databaseRepo.GetSource(c, c.Param("sourceId")) if err != nil { - logger.Errorln("An error occurred while retrieving source credential", err) - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + err = fmt.Errorf("an error occurred while retrieving source credential: %w", err) + logger.Errorln(err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } // after creating the source, we should do a bulk import (in the background) summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, sourceCred) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + err := fmt.Errorf("an error occurred while syncing resources: %w", err) + logger.Errorln(err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } @@ -153,14 +159,16 @@ func CreateManualSource(c *gin.Context) { } tempSourceClient, err := factory.GetSourceClient("", c, logger, &manualSourceCredential) if err != nil { - logger.Errorln("An error occurred while initializing hub client using manual source without credentials", err) - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + err = fmt.Errorf("an error occurred while initializing hub client using manual source without credentials: %w", err) + logger.Errorln(err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } patientId, bundleType, err := tempSourceClient.ExtractPatientId(bundleFile) if err != nil { - logger.Errorln("An error occurred while extracting patient id", err) + err = fmt.Errorf("an error occurred while extracting patient id: %w", err) + logger.Errorln(err) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } @@ -169,7 +177,8 @@ func CreateManualSource(c *gin.Context) { //store the manualSourceCredential err = databaseRepo.CreateSource(c, &manualSourceCredential) if err != nil { - logger.Errorln("An error occurred while creating manual source", err) + err = fmt.Errorf("an error occurred while creating manual source: %w", err) + logger.Errorln(err) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } @@ -202,6 +211,7 @@ func CreateManualSource(c *gin.Context) { }) if err != nil { + err = fmt.Errorf("an error occurred while storing manual source resources: %w", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } diff --git a/frontend/src/app/components/medical-sources-connected/medical-sources-connected.component.ts b/frontend/src/app/components/medical-sources-connected/medical-sources-connected.component.ts index 4c2cfe82..33cf601e 100644 --- a/frontend/src/app/components/medical-sources-connected/medical-sources-connected.component.ts +++ b/frontend/src/app/components/medical-sources-connected/medical-sources-connected.component.ts @@ -216,7 +216,7 @@ export class MedicalSourcesConnectedComponent implements OnInit { const toastNotification = new ToastNotification() toastNotification.type = ToastType.Error - toastNotification.message = `An error occurred while accessing external data source: '${this.extractErrorFromResponse(err)}'` + toastNotification.message = `An error occurred while finalizing external data source and starting sync: '${this.extractErrorFromResponse(err)}'` toastNotification.autohide = false toastNotification.link = { text: "View Details", @@ -232,7 +232,7 @@ export class MedicalSourcesConnectedComponent implements OnInit { const toastNotification = new ToastNotification() toastNotification.type = ToastType.Error - toastNotification.message = `An error occurred while accessing external data source: '${JSON.stringify(err)}'` + toastNotification.message = `An error occurred while accessing external data source: '${this.extractErrorFromResponse(err)}'` toastNotification.autohide = false this.toastService.show(toastNotification) console.error(err) @@ -332,11 +332,22 @@ export class MedicalSourcesConnectedComponent implements OnInit { delete this.status[source.id] delete this.status[source.brand_id] console.log("source sync response:", respData) + + const toastNotification = new ToastNotification() + toastNotification.type = ToastType.Success + toastNotification.message = `Successfully updated source: ${source.display}, ${respData} row(s) effected` + this.toastService.show(toastNotification) }, (err) => { delete this.status[source.id] delete this.status[source.brand_id] + + const toastNotification = new ToastNotification() + toastNotification.type = ToastType.Error + toastNotification.message = `An error occurred while updating source (${source.display}): ${this.extractErrorFromResponse(err)}` + this.toastService.show(toastNotification) console.log(err) + } ) } @@ -376,7 +387,7 @@ export class MedicalSourcesConnectedComponent implements OnInit { const toastNotification = new ToastNotification() toastNotification.type = ToastType.Error - toastNotification.message = `An error occurred while deleting source: ${sourceDisplayName}` + toastNotification.message = `An error occurred while deleting source (${sourceDisplayName}): ${this.extractErrorFromResponse(err)}` this.toastService.show(toastNotification) console.log(err) }) diff --git a/frontend/src/app/services/lighthouse.service.ts b/frontend/src/app/services/lighthouse.service.ts index 4b33b62a..e258e7e2 100644 --- a/frontend/src/app/services/lighthouse.service.ts +++ b/frontend/src/app/services/lighthouse.service.ts @@ -176,12 +176,12 @@ export class LighthouseService { * Scenario 1: No reuse of callback url * origin_url - localhost:8080/sources/callback/aetna * dest_url - https://.aetna.com/.../oauth2/authorize?redirect_uri=https://lighthouse.fastenhealth.com/callback/aetna - * redirect_url - lighthouse.fastenhealth.com/sandbox/redirect/aetna?origin_url=...&dest_url=... + * redirect_url - lighthouse.fastenhealth.com/sandbox/redirect/{STATE}?origin_url=...&dest_url=... * * Scenario 2: Reused callback url * origin_url - localhost:8080/sources/callback/healthybluela * dest_url - https://patient360la.anthem.com/.../connect/authorize?redirect_uri=https://lighthouse.fastenhealth.com/callback/anthem - * redirect_url - lighthouse.fastenhealth.com/sandbox/redirect/anthem?origin_url=...&dest_url=... + * redirect_url - lighthouse.fastenhealth.com/sandbox/redirect/{STATE}?origin_url=...&dest_url=... */ redirectWithOriginAndDestination(destUrl: string, redirectOpts: {platform_type: string, redirect_uri: string, brand_id: string, portal_id: string, id: string}): Observable<{ codeData:any, state:string }> { const originUrlParts = new URL(window.location.href) @@ -192,6 +192,7 @@ export class LighthouseService { if(!state){ throw new Error("No state found in destination url") + return } if(environment.environment_desktop){ @@ -271,7 +272,7 @@ export class LighthouseService { const params = Oauth.validateAuthResponse(as, client, new URLSearchParams({"code": code, "state": expectedSourceStateInfo.state}), expectedSourceStateInfo.state) if (Oauth.isOAuth2Error(params)) { console.log('error', params) - throw new Error() // Handle OAuth 2.0 redirect error + throw new Error('error when validating code & state before token exchange') // Handle OAuth 2.0 redirect error } console.log("ENDING--- Oauth.validateAuthResponse") console.log("STARTING--- Oauth.authorizationCodeGrantRequest")