support logica service.
update dashboard. moved RAW API endpoint outside of the secure block.
This commit is contained in:
parent
02dcbcc507
commit
cc485a0615
|
@ -13,4 +13,5 @@ const (
|
|||
SourceTypeHumana SourceType = "humana"
|
||||
SourceTypeKaiser SourceType = "kaiser"
|
||||
SourceTypeUnitedHealthcare SourceType = "unitedhealthcare"
|
||||
SourceTypeLogica SourceType = "logica"
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ type DatabaseRepository interface {
|
|||
GetResource(context.Context, string) (*models.ResourceFhir, error)
|
||||
GetResourceBySourceId(context.Context, string, string) (*models.ResourceFhir, error)
|
||||
ListResources(context.Context, models.ListResourceQueryOptions) ([]models.ResourceFhir, error)
|
||||
GetPatientForSources(ctx context.Context) ([]models.ResourceFhir, error)
|
||||
//UpsertProfile(context.Context, *models.Profile) error
|
||||
//UpsertOrganziation(context.Context, *models.Organization) error
|
||||
|
||||
|
|
|
@ -138,9 +138,16 @@ func (sr *sqliteRepository) GetSummary(ctx context.Context) (*models.Summary, er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// we want the main Patient for each source
|
||||
patients, err := sr.GetPatientForSources(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summary := &models.Summary{
|
||||
Sources: sources,
|
||||
ResourceTypeCounts: resourceCountResults,
|
||||
Patients: patients,
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
|
@ -237,6 +244,29 @@ func (sr *sqliteRepository) GetResource(ctx context.Context, resourceId string)
|
|||
return &wrappedResourceModel, results.Error
|
||||
}
|
||||
|
||||
// Get the patient for each source (for the current user)
|
||||
func (sr *sqliteRepository) GetPatientForSources(ctx context.Context) ([]models.ResourceFhir, error) {
|
||||
|
||||
//SELECT * FROM resource_fhirs WHERE user_id = "" and source_resource_type = "Patient" GROUP BY source_id
|
||||
|
||||
//var sourceCred models.Source
|
||||
//results := sr.gormClient.WithContext(ctx).
|
||||
// Where(models.Source{UserID: sr.GetCurrentUser(ctx).ID, ModelBase: models.ModelBase{ID: sourceUUID}}).
|
||||
// First(&sourceCred)
|
||||
|
||||
var wrappedResourceModels []models.ResourceFhir
|
||||
results := sr.gormClient.WithContext(ctx).
|
||||
Model(models.ResourceFhir{}).
|
||||
Group("source_id").
|
||||
Where(models.OriginBase{
|
||||
UserID: sr.GetCurrentUser(ctx).ID,
|
||||
SourceResourceType: "Patient",
|
||||
}).
|
||||
Find(&wrappedResourceModels)
|
||||
|
||||
return wrappedResourceModels, results.Error
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Source
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/aetna"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/cigna"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/logica"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/manual"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -27,6 +28,8 @@ func NewClient(sourceType pkg.SourceType, ctx context.Context, appConfig config.
|
|||
sourceClient, updatedSource, err = cigna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||
case pkg.SourceTypeCigna:
|
||||
sourceClient, updatedSource, err = cigna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||
case pkg.SourceTypeLogica:
|
||||
sourceClient, updatedSource, err = logica.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||
case pkg.SourceTypeManual:
|
||||
sourceClient, updatedSource, err = manual.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package logica
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type LogicaClient struct {
|
||||
*base.FHIR401Client
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, appConfig config.Interface, globalLogger logrus.FieldLogger, source models.Source, testHttpClient ...*http.Client) (base.Client, *models.Source, error) {
|
||||
baseClient, updatedSource, err := base.NewFHIR401Client(ctx, appConfig, globalLogger, source, testHttpClient...)
|
||||
return LogicaClient{
|
||||
baseClient,
|
||||
}, updatedSource, err
|
||||
}
|
||||
|
||||
func (c LogicaClient) SyncAll(db database.DatabaseRepository) error {
|
||||
|
||||
bundle, err := c.GetPatientBundle(c.Source.PatientId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wrappedResourceModels, err := c.ProcessBundle(bundle)
|
||||
|
||||
//todo, create the resources in dependency order
|
||||
|
||||
for _, apiModel := range wrappedResourceModels {
|
||||
err = db.UpsertResource(context.Background(), apiModel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -2,5 +2,6 @@ package models
|
|||
|
||||
type Summary struct {
|
||||
Sources []Source `json:"sources,omitempty"`
|
||||
Patients []ResourceFhir `json:"patients,omitempty"`
|
||||
ResourceTypeCounts []map[string]interface{} `json:"resource_type_counts,omitempty"`
|
||||
}
|
||||
|
|
|
@ -148,38 +148,34 @@ func RawRequestSource(c *gin.Context) {
|
|||
logger := c.MustGet("LOGGER").(*logrus.Entry)
|
||||
databaseRepo := c.MustGet("REPOSITORY").(database.DatabaseRepository)
|
||||
|
||||
sources, err := databaseRepo.GetSources(c)
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while storing source credential", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
return
|
||||
}
|
||||
//!!!!!!INSECURE!!!!!!S
|
||||
//We're setting the username to a user provided value, this is insecure, but required for calling databaseRepo fns
|
||||
c.Set("AUTH_USERNAME", c.Param("username"))
|
||||
|
||||
var foundSource *models.Source
|
||||
for _, source := range sources {
|
||||
if source.SourceType == pkg.SourceType(c.Param("sourceType")) {
|
||||
foundSource = &source
|
||||
break
|
||||
}
|
||||
foundSource, err := databaseRepo.GetSource(c, c.Param("sourceId"))
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while finding source credential", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if foundSource == nil {
|
||||
logger.Errorf("Did not source credentials for %s", c.Param("sourceType"))
|
||||
c.JSON(http.StatusNotFound, gin.H{"success": false})
|
||||
c.JSON(http.StatusNotFound, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
client, updatedSource, err := hub.NewClient(pkg.SourceType(c.Param("sourceType")), c, nil, logger, *foundSource)
|
||||
client, updatedSource, err := hub.NewClient(foundSource.SourceType, c, nil, logger, *foundSource)
|
||||
if err != nil {
|
||||
logger.Errorf("Could not initialize source client", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
if updatedSource != nil {
|
||||
err := databaseRepo.CreateSource(c, updatedSource)
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while updating source credential", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +184,7 @@ func RawRequestSource(c *gin.Context) {
|
|||
err = client.GetRequest(strings.TrimSuffix(c.Param("path"), "/"), &resp)
|
||||
if err != nil {
|
||||
logger.Errorf("Error making raw request", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": resp})
|
||||
|
|
|
@ -52,12 +52,17 @@ func (ae *AppEngine) Setup(logger *logrus.Entry) *gin.Engine {
|
|||
secure.GET("/source", handler.ListSource)
|
||||
secure.GET("/source/:sourceId", handler.GetSource)
|
||||
secure.GET("/source/:sourceId/summary", handler.GetSourceSummary)
|
||||
//in debug mode, this endpoint lets us request data directly from the source api
|
||||
secure.GET("/source/raw/:sourceType/*path", handler.RawRequestSource)
|
||||
|
||||
secure.GET("/resource/fhir", handler.ListResourceFhir) //
|
||||
secure.GET("/resource/fhir/:resourceId", handler.GetResourceFhir)
|
||||
}
|
||||
|
||||
if ae.Config.GetString("log.level") == "DEBUG" {
|
||||
//in debug mode, this endpoint lets us request data directly from the source api
|
||||
ae.Logger.Warningf("***INSECURE*** ***INSECURE*** DEBUG mode enables developer functionality, including unauthenticated raw api requests")
|
||||
|
||||
//http://localhost:9090/api/raw/test@test.com/436d7277-ad56-41ce-9823-44e353d1b3f6/Patient/smart-1288992
|
||||
api.GET("/raw/:username/:sourceId/*path", handler.RawRequestSource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import {Source} from './source';
|
||||
import {ResourceTypeCounts} from './source-summary';
|
||||
import {ResourceFhir} from './resource_fhir';
|
||||
|
||||
export class Summary {
|
||||
sources: Source[]
|
||||
patients: ResourceFhir[]
|
||||
resource_type_counts: ResourceTypeCounts[]
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<canvas baseChart [chartType]="'doughnut'" [datasets]="sessionsChartTwoData" [labels]="sessionsChartTwoLabels" [options]="sessionsChartTwoOptions" height="45"></canvas>
|
||||
</div>
|
||||
<div>
|
||||
<label>Updated</label>
|
||||
<label>Updates</label>
|
||||
<h4>19</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -154,8 +154,7 @@
|
|||
<div class="media-body">
|
||||
<h5>{{source.source_type}}</h5>
|
||||
<p>
|
||||
GeeksforGeeks is a computer science portal.
|
||||
It is a best programming platform.
|
||||
{{getPatientSummary(patientForSource[source.id]?.payload)}}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,7 @@ import {Source} from '../../models/fasten/source';
|
|||
import {Router} from '@angular/router';
|
||||
import {Summary} from '../../models/fasten/summary';
|
||||
import {ResourceTypeCounts} from '../../models/fasten/source-summary';
|
||||
import {ResourceFhir} from '../../models/fasten/resource_fhir';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
|
@ -16,6 +17,7 @@ export class DashboardComponent implements OnInit {
|
|||
sources: Source[] = []
|
||||
encounterCount: number = 0
|
||||
recordsCount: number = 0
|
||||
patientForSource: {[name: string]: ResourceFhir} = {}
|
||||
|
||||
constructor(private fastenApi: FastenApiService, private router: Router) { }
|
||||
|
||||
|
@ -33,9 +35,11 @@ export class DashboardComponent implements OnInit {
|
|||
this.encounterCount = resourceTypeInfo.count
|
||||
}
|
||||
})
|
||||
})
|
||||
// this.fastenApi.getResources('Patient')
|
||||
|
||||
summary.patients.forEach((resourceFhir) => {
|
||||
this.patientForSource[resourceFhir.source_id] = resourceFhir
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
selectSource(selectedSource: Source){
|
||||
|
@ -44,6 +48,12 @@ export class DashboardComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
getPatientSummary(patient: any) {
|
||||
if(patient && patient.name && patient.name[0]){
|
||||
return `${patient.name[0].family}, ${patient.name[0].given.join(' ')}`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pageViewChartData = [{
|
||||
label: 'This week',
|
||||
|
|
|
@ -5,7 +5,7 @@ import {LighthouseSource} from '../../models/lighthouse/lighthouse-source';
|
|||
import * as Oauth from '@panva/oauth4webapi';
|
||||
import {AuthorizeClaim} from '../../models/lighthouse/authorize-claim';
|
||||
import {Source} from '../../models/fasten/source';
|
||||
import {getAccessTokenExpiration} from 'fhirclient/lib/lib';
|
||||
import {getAccessTokenExpiration, jwtDecode} from 'fhirclient/lib/lib';
|
||||
import BrowserAdapter from 'fhirclient/lib/adapters/BrowserAdapter';
|
||||
import {Observable, of, throwError} from 'rxjs';
|
||||
import {concatMap, delay, retryWhen} from 'rxjs/operators';
|
||||
|
@ -34,6 +34,7 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
"humana": {"display": "Humana"},
|
||||
"kaiser": {"display": "Kaiser"},
|
||||
"unitedhealthcare": {"display": "United Healthcare"},
|
||||
"logica": {"display": "Logica Sandbox"},
|
||||
}
|
||||
|
||||
connectedSourceList = []
|
||||
|
@ -103,7 +104,7 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
issuer: `${authorizationUrl.protocol}//${authorizationUrl.host}`,
|
||||
authorization_endpoint: `${connectData.oauth_endpoint_base_url}/authorize`,
|
||||
token_endpoint: `${connectData.oauth_endpoint_base_url}/token`,
|
||||
introspect_endpoint: `${connectData.oauth_endpoint_base_url}/introspect`,
|
||||
introspection_endpoint: `${connectData.oauth_endpoint_base_url}/introspect`,
|
||||
}
|
||||
|
||||
console.log("STARTING--- Oauth.validateAuthResponse")
|
||||
|
@ -125,6 +126,15 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
console.log("ENDING--- Oauth.authorizationCodeGrantRequest", payload)
|
||||
|
||||
|
||||
//If payload.patient is not set, make sure we extract the patient ID from the id_token or make an introspection req
|
||||
if(!payload.patient){
|
||||
//
|
||||
console.log("NO PATIENT ID present, decoding jwt to extract patient")
|
||||
//const introspectionResp = await Oauth.introspectionRequest(as, client, payload.access_token)
|
||||
//console.log(introspectionResp)
|
||||
payload.patient = jwtDecode(payload.id_token, new BrowserAdapter())["profile"].replace(/^(Patient\/)/,'')
|
||||
}
|
||||
|
||||
//Create FHIR Client
|
||||
const sourceCredential: Source = {
|
||||
source_type: sourceType,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Loading…
Reference in New Issue