verbose error messages. make sure backend error messages during sync & source creation are propagated to the frontend.

This commit is contained in:
Jason Kulatunga 2024-01-20 21:59:17 -08:00
parent e3bbd8009a
commit efd2fb3655
No known key found for this signature in database
4 changed files with 43 additions and 17 deletions

6
.gitignore vendored
View File

@ -56,7 +56,6 @@ fabric.properties
/dist/ /dist/
vendor vendor
fasten.db
test.go test.go
/.couchdb /.couchdb
@ -64,3 +63,8 @@ config.dev.yaml
.cache/ .cache/
cache/ cache/
fasten-*.db fasten-*.db
fasten-*.db-shm
fasten-*.db-wal
fasten.db
fasten.db-shm
fasten.db-wal

View File

@ -25,8 +25,9 @@ func CreateReconnectSource(c *gin.Context) {
sourceCred := models.SourceCredential{} sourceCred := models.SourceCredential{}
if err := c.ShouldBindJSON(&sourceCred); err != nil { if err := c.ShouldBindJSON(&sourceCred); err != nil {
logger.Errorln("An error occurred while parsing posted source credential", err) err = fmt.Errorf("an error occurred while parsing posted source credential: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"success": false}) logger.Errorln(err)
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": err.Error()})
return return
} }
@ -88,7 +89,9 @@ func CreateReconnectSource(c *gin.Context) {
summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, &sourceCred) summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, &sourceCred)
if err != nil { 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 return
} }
@ -104,15 +107,18 @@ func SourceSync(c *gin.Context) {
sourceCred, err := databaseRepo.GetSource(c, c.Param("sourceId")) sourceCred, err := databaseRepo.GetSource(c, c.Param("sourceId"))
if err != nil { if err != nil {
logger.Errorln("An error occurred while retrieving source credential", err) err = fmt.Errorf("an error occurred while retrieving source credential: %w", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false}) logger.Errorln(err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
return return
} }
// after creating the source, we should do a bulk import (in the background) // after creating the source, we should do a bulk import (in the background)
summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, sourceCred) summary, err := BackgroundJobSyncResources(GetBackgroundContext(c), logger, databaseRepo, sourceCred)
if err != nil { 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 return
} }
@ -153,14 +159,16 @@ func CreateManualSource(c *gin.Context) {
} }
tempSourceClient, err := factory.GetSourceClient("", c, logger, &manualSourceCredential) tempSourceClient, err := factory.GetSourceClient("", c, logger, &manualSourceCredential)
if err != nil { if err != nil {
logger.Errorln("An error occurred while initializing hub client using manual source without credentials", err) err = fmt.Errorf("an error occurred while initializing hub client using manual source without credentials: %w", err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false}) logger.Errorln(err)
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
return return
} }
patientId, bundleType, err := tempSourceClient.ExtractPatientId(bundleFile) patientId, bundleType, err := tempSourceClient.ExtractPatientId(bundleFile)
if err != nil { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
return return
} }
@ -169,7 +177,8 @@ func CreateManualSource(c *gin.Context) {
//store the manualSourceCredential //store the manualSourceCredential
err = databaseRepo.CreateSource(c, &manualSourceCredential) err = databaseRepo.CreateSource(c, &manualSourceCredential)
if err != nil { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
return return
} }
@ -202,6 +211,7 @@ func CreateManualSource(c *gin.Context) {
}) })
if err != nil { 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()}) c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
return return
} }

View File

@ -216,7 +216,7 @@ export class MedicalSourcesConnectedComponent implements OnInit {
const toastNotification = new ToastNotification() const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error 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.autohide = false
toastNotification.link = { toastNotification.link = {
text: "View Details", text: "View Details",
@ -232,7 +232,7 @@ export class MedicalSourcesConnectedComponent implements OnInit {
const toastNotification = new ToastNotification() const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error 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 toastNotification.autohide = false
this.toastService.show(toastNotification) this.toastService.show(toastNotification)
console.error(err) console.error(err)
@ -332,11 +332,22 @@ export class MedicalSourcesConnectedComponent implements OnInit {
delete this.status[source.id] delete this.status[source.id]
delete this.status[source.brand_id] delete this.status[source.brand_id]
console.log("source sync response:", respData) 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) => { (err) => {
delete this.status[source.id] delete this.status[source.id]
delete this.status[source.brand_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) console.log(err)
} }
) )
} }
@ -376,7 +387,7 @@ export class MedicalSourcesConnectedComponent implements OnInit {
const toastNotification = new ToastNotification() const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error 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) this.toastService.show(toastNotification)
console.log(err) console.log(err)
}) })

View File

@ -176,12 +176,12 @@ export class LighthouseService {
* Scenario 1: No reuse of callback url * Scenario 1: No reuse of callback url
* origin_url - localhost:8080/sources/callback/aetna * origin_url - localhost:8080/sources/callback/aetna
* dest_url - https://.aetna.com/.../oauth2/authorize?redirect_uri=https://lighthouse.fastenhealth.com/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 * Scenario 2: Reused callback url
* origin_url - localhost:8080/sources/callback/healthybluela * origin_url - localhost:8080/sources/callback/healthybluela
* dest_url - https://patient360la.anthem.com/.../connect/authorize?redirect_uri=https://lighthouse.fastenhealth.com/callback/anthem * 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 }> { 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) const originUrlParts = new URL(window.location.href)
@ -192,6 +192,7 @@ export class LighthouseService {
if(!state){ if(!state){
throw new Error("No state found in destination url") throw new Error("No state found in destination url")
return
} }
if(environment.environment_desktop){ 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) const params = Oauth.validateAuthResponse(as, client, new URLSearchParams({"code": code, "state": expectedSourceStateInfo.state}), expectedSourceStateInfo.state)
if (Oauth.isOAuth2Error(params)) { if (Oauth.isOAuth2Error(params)) {
console.log('error', 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("ENDING--- Oauth.validateAuthResponse")
console.log("STARTING--- Oauth.authorizationCodeGrantRequest") console.log("STARTING--- Oauth.authorizationCodeGrantRequest")