marketing updates.

make sure the oauth endpoints are configurable.
This commit is contained in:
Jason Kulatunga 2022-09-19 20:21:22 -07:00
parent 080379eabe
commit 342cfa740b
19 changed files with 127 additions and 78 deletions

View File

@ -25,6 +25,6 @@ const (
SourceTypeTrinity SourceType = "trinity"
SourceTypeUCSF SourceType = "ucsf"
SourceTypeUnitedHealthcare SourceType = "unitedhealthcare"
SourceTypeVeteransHealthAdministration SourceType = "va"
SourceTypeVeteransHealthAdministration SourceType = "bluebutton"
SourceTypeVerity SourceType = "verity"
)

View File

@ -6,6 +6,7 @@ import (
"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/fastenhealth/gofhir-models/fhir401"
"github.com/sirupsen/logrus"
"net/http"
)
@ -21,17 +22,25 @@ func NewClient(ctx context.Context, appConfig config.Interface, globalLogger log
}, updatedSource, err
}
func (c AetnaClient) GetPatientBundle(patientId string) (fhir401.Bundle, error) {
bundle := fhir401.Bundle{}
err := c.GetRequest("Patient", &bundle)
return bundle, err
}
func (c AetnaClient) SyncAll(db database.DatabaseRepository) error {
bundle, err := c.GetPatientBundle(c.Source.PatientId)
if err != nil {
c.Logger.Infof("An error occured while getting patient bundle %s", c.Source.PatientId)
c.Logger.Infof("An error occurred while getting patient bundle %s", c.Source.PatientId)
return err
}
wrappedResourceModels, err := c.ProcessBundle(bundle)
if err != nil {
c.Logger.Infof("An error occured while processing patient bundle %s", c.Source.PatientId)
c.Logger.Infof("An error occurred while processing patient bundle %s", c.Source.PatientId)
return err
}
//todo, create the resources in dependency order
@ -39,7 +48,7 @@ func (c AetnaClient) SyncAll(db database.DatabaseRepository) error {
for _, apiModel := range wrappedResourceModels {
err = db.UpsertResource(context.Background(), apiModel)
if err != nil {
c.Logger.Info("An error occured while upserting resource")
c.Logger.Info("An error occurred while upserting resource")
return err
}
}

View File

@ -40,8 +40,8 @@ func NewBaseClient(ctx context.Context, appConfig config.Interface, globalLogger
ClientID: source.ClientId,
ClientSecret: "",
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("%s/authorize", source.OauthEndpointBaseUrl),
TokenURL: fmt.Sprintf("%s/token", source.OauthEndpointBaseUrl),
AuthURL: source.OauthAuthorizationEndpoint,
TokenURL: source.OauthTokenEndpointAuthMethods,
},
//RedirectURL: "",
//Scopes: nil,

View File

@ -29,7 +29,10 @@ func (c CignaClient) SyncAll(db database.DatabaseRepository) error {
}
wrappedResourceModels, err := c.ProcessBundle(bundle)
if err != nil {
c.Logger.Infof("An error occurred while processing patient bundle %s", c.Source.PatientId)
return err
}
//todo, create the resources in dependency order
for _, apiModel := range wrappedResourceModels {

View File

@ -29,7 +29,10 @@ func (c LogicaClient) SyncAll(db database.DatabaseRepository) error {
}
wrappedResourceModels, err := c.ProcessBundle(bundle)
if err != nil {
c.Logger.Infof("An error occurred while processing patient bundle %s", c.Source.PatientId)
return err
}
//todo, create the resources in dependency order
for _, apiModel := range wrappedResourceModels {

View File

@ -13,17 +13,23 @@ type Source struct {
SourceType pkg.SourceType `json:"source_type" gorm:"uniqueIndex:idx_user_source_patient"`
PatientId string `json:"patient_id" gorm:"uniqueIndex:idx_user_source_patient"`
OauthEndpointBaseUrl string `json:"oauth_endpoint_base_url"`
ApiEndpointBaseUrl string `json:"api_endpoint_base_url"`
ClientId string `json:"client_id"`
RedirectUri string `json:"redirect_uri"`
Scopes string `json:"scopes"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
IdToken string `json:"id_token"`
ExpiresAt int64 `json:"expires_at"`
CodeChallenge string `json:"code_challenge"`
CodeVerifier string `json:"code_verifier"`
//oauth endpoints
OauthAuthorizationEndpoint string `json:"oauth_authorization_endpoint"`
OauthTokenEndpoint string `json:"oauth_token_endpoint"`
OauthRegistrationEndpoint string `json:"oauth_registration_endpoint"`
OauthIntrospectionEndpoint string `json:"oauth_introspection_endpoint"`
OauthTokenEndpointAuthMethods string `json:"oauth_token_endpoint_auth_methods_supported"`
ApiEndpointBaseUrl string `json:"api_endpoint_base_url"`
ClientId string `json:"client_id"`
RedirectUri string `json:"redirect_uri"`
Scopes string `json:"scopes"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
IdToken string `json:"id_token"`
ExpiresAt int64 `json:"expires_at"`
CodeChallenge string `json:"code_challenge"`
CodeVerifier string `json:"code_verifier"`
}
/*

View File

@ -13,27 +13,27 @@ func GetMetadataSource(c *gin.Context) {
string(pkg.SourceTypeLogica): {Display: "Logica (Sandbox)", SourceType: pkg.SourceTypeLogica, Category: []string{"Sandbox"}, Supported: true},
// enabled
string(pkg.SourceTypeAetna): {Display: "Aetna", SourceType: pkg.SourceTypeAetna, Category: []string{"Insurance"}, Supported: true},
string(pkg.SourceTypeCigna): {Display: "Cigna", SourceType: pkg.SourceTypeCigna, Category: []string{"Insurance", "Hospital"}, Supported: true},
string(pkg.SourceTypeAetna): {Display: "Aetna", SourceType: pkg.SourceTypeAetna, Category: []string{"Insurance"}, Supported: true},
string(pkg.SourceTypeCigna): {Display: "Cigna", SourceType: pkg.SourceTypeCigna, Category: []string{"Insurance", "Hospital"}, Supported: true},
string(pkg.SourceTypeVeteransHealthAdministration): {Display: "Veterans Health (BlueButton)", SourceType: pkg.SourceTypeVeteransHealthAdministration, Category: []string{"Hospital"}, Supported: true},
// pending
string(pkg.SourceTypeAnthem): {Display: "Anthem", SourceType: pkg.SourceTypeAnthem, Category: []string{"Insurance"}},
string(pkg.SourceTypeCedarSinai): {Display: "Cedar Sinai", SourceType: pkg.SourceTypeCedarSinai, Category: []string{"Hospital"}},
string(pkg.SourceTypeCommonSpirit): {Display: "Common Spirit", SourceType: pkg.SourceTypeCommonSpirit, Category: []string{"Hospital"}},
string(pkg.SourceTypeDeltaDental): {Display: "Delta Dental", SourceType: pkg.SourceTypeDeltaDental, Category: []string{"Insurance"}},
string(pkg.SourceTypeDignityHealth): {Display: "Dignity Health", SourceType: pkg.SourceTypeDignityHealth, Category: []string{"Hospital"}},
string(pkg.SourceTypeHCAHealthcare): {Display: "HCA Healthcare", SourceType: pkg.SourceTypeHCAHealthcare, Category: []string{"Insurance"}},
string(pkg.SourceTypeHumana): {Display: "Humana", SourceType: pkg.SourceTypeHumana, Category: []string{"Insurance"}},
string(pkg.SourceTypeKaiser): {Display: "Kaiser", SourceType: pkg.SourceTypeKaiser, Category: []string{"Hospital", "Insurance"}},
string(pkg.SourceTypeMetlife): {Display: "Metlife", SourceType: pkg.SourceTypeMetlife, Category: []string{"Insurance"}},
string(pkg.SourceTypeProvidence): {Display: "Providence", SourceType: pkg.SourceTypeProvidence, Category: []string{"Hospital"}},
string(pkg.SourceTypeStanford): {Display: "Stanford Healthcare", SourceType: pkg.SourceTypeStanford, Category: []string{"Hospital"}},
string(pkg.SourceTypeSutter): {Display: "Sutter", SourceType: pkg.SourceTypeSutter, Category: []string{"Hospital"}},
string(pkg.SourceTypeTrinity): {Display: "Trinity", SourceType: pkg.SourceTypeTrinity, Category: []string{"Hospital"}},
string(pkg.SourceTypeUCSF): {Display: "UCSF", SourceType: pkg.SourceTypeUCSF, Category: []string{"Hospital"}},
string(pkg.SourceTypeUnitedHealthcare): {Display: "United Healthcare", SourceType: pkg.SourceTypeUnitedHealthcare, Category: []string{"Insurance"}},
string(pkg.SourceTypeVeteransHealthAdministration): {Display: "Veterans Health (VA)", SourceType: pkg.SourceTypeVeteransHealthAdministration, Category: []string{"Hospital"}},
string(pkg.SourceTypeVerity): {Display: "Verity", SourceType: pkg.SourceTypeVerity, Category: []string{"Hospital"}},
string(pkg.SourceTypeAnthem): {Display: "Anthem", SourceType: pkg.SourceTypeAnthem, Category: []string{"Insurance"}},
string(pkg.SourceTypeCedarSinai): {Display: "Cedar Sinai", SourceType: pkg.SourceTypeCedarSinai, Category: []string{"Hospital"}},
string(pkg.SourceTypeCommonSpirit): {Display: "Common Spirit", SourceType: pkg.SourceTypeCommonSpirit, Category: []string{"Hospital"}},
string(pkg.SourceTypeDeltaDental): {Display: "Delta Dental", SourceType: pkg.SourceTypeDeltaDental, Category: []string{"Insurance"}},
string(pkg.SourceTypeDignityHealth): {Display: "Dignity Health", SourceType: pkg.SourceTypeDignityHealth, Category: []string{"Hospital"}},
string(pkg.SourceTypeHCAHealthcare): {Display: "HCA Healthcare", SourceType: pkg.SourceTypeHCAHealthcare, Category: []string{"Insurance"}},
string(pkg.SourceTypeHumana): {Display: "Humana", SourceType: pkg.SourceTypeHumana, Category: []string{"Insurance"}},
string(pkg.SourceTypeKaiser): {Display: "Kaiser", SourceType: pkg.SourceTypeKaiser, Category: []string{"Hospital", "Insurance"}},
string(pkg.SourceTypeMetlife): {Display: "Metlife", SourceType: pkg.SourceTypeMetlife, Category: []string{"Insurance"}},
string(pkg.SourceTypeProvidence): {Display: "Providence", SourceType: pkg.SourceTypeProvidence, Category: []string{"Hospital"}},
string(pkg.SourceTypeStanford): {Display: "Stanford Healthcare", SourceType: pkg.SourceTypeStanford, Category: []string{"Hospital"}},
string(pkg.SourceTypeSutter): {Display: "Sutter", SourceType: pkg.SourceTypeSutter, Category: []string{"Hospital"}},
string(pkg.SourceTypeTrinity): {Display: "Trinity", SourceType: pkg.SourceTypeTrinity, Category: []string{"Hospital"}},
string(pkg.SourceTypeUCSF): {Display: "UCSF", SourceType: pkg.SourceTypeUCSF, Category: []string{"Hospital"}},
string(pkg.SourceTypeUnitedHealthcare): {Display: "United Healthcare", SourceType: pkg.SourceTypeUnitedHealthcare, Category: []string{"Insurance"}},
string(pkg.SourceTypeVerity): {Display: "Verity", SourceType: pkg.SourceTypeVerity, Category: []string{"Hospital"}},
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": metadataSource})

View File

@ -1,26 +1,27 @@
<div class="az-content-left az-content-left-components">
<div class="component-item">
<label>UI Elements</label>
<label>Connected</label>
<nav class="nav flex-column">
<a routerLink="/ui-elements/buttons" routerLinkActive="active" class="nav-link">Buttons</a>
<a routerLink="/ui-elements/dropdown" routerLinkActive="active" class="nav-link">Dropdown</a>
<a routerLink="/ui-elements/icons" routerLinkActive="active" class="nav-link">Icons</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Active Sources</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Manual</a>
</nav>
<label>Categories</label>
<nav class="nav flex-column">
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Hospital Networks/Clinics</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Pharmacies</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Insurers</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Laboratoreies</a>
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Wearables</a>
</nav>
<label>Forms</label>
<label>Industry</label>
<nav class="nav flex-column">
<a routerLink="/form/form-elements" routerLinkActive="active" class="nav-link">Form Elements</a>
<a routerLink="/charts/chartjs" routerLinkActive="active" class="nav-link">Medical</a>
<a routerLink="/charts/chartjs" routerLinkActive="active" class="nav-link">Dental</a>
<a routerLink="/charts/chartjs" routerLinkActive="active" class="nav-link">Vision</a>
<a routerLink="/charts/chartjs" routerLinkActive="active" class="nav-link">Mental</a>
</nav>
<label>Charts</label>
<nav class="nav flex-column">
<a routerLink="/charts/chartjs" routerLinkActive="active" class="nav-link">ChartJS</a>
</nav>
<label>Tables</label>
<nav class="nav flex-column">
<a routerLink="/tables/basic-tables" routerLinkActive="active" class="nav-link">Basic Tables</a>
</nav>
</div><!-- component-item -->
</div><!-- az-content-left -->
</div><!-- az-content-left -->

View File

@ -1,8 +1,8 @@
<div class="az-footer ht-40">
<div class="container ht-100p pd-t-0-f">
<div class="d-sm-flex justify-content-center justify-content-sm-between py-2 w-100">
<span class="text-muted text-center text-sm-left d-block d-sm-inline-block">Copyright © Fasten Health 2020</span>
<span class="float-none float-sm-right d-block mt-1 mt-sm-0 text-center">Free <a href="https://www.bootstrapdash.com/angular-admin-templates/" target="_blank"> angular admin template </a> from <a href="https://www.bootstrapdash.com/" target="_blank">bootstrapdash.com </a></span>
<span class="text-muted text-center text-sm-left d-block d-sm-inline-block">Copyright © Fasten 2022</span>
<span class="float-none float-sm-right d-block mt-1 mt-sm-0 text-center">Open Source personal electronic medical record system. <a href="https://www.fastenhealth.com/" target="_blank">It's your health. Own it.</a></span>
</div>
</div><!-- container -->
</div><!-- az-footer -->

View File

@ -4,7 +4,12 @@ export class Source {
source_type: string
patient_id: string
oauth_endpoint_base_url: string
oauth_authorization_endpoint: string
oauth_token_endpoint: string
oauth_registration_endpoint: string
oauth_introspection_endpoint: string
oauth_token_endpoint_auth_methods_supported: string
api_endpoint_base_url: string
client_id: string
redirect_uri: string

View File

@ -1,5 +1,10 @@
export class LighthouseSource {
oauth_endpoint_base_url: string
oauth_authorization_endpoint: string
oauth_token_endpoint: string
oauth_registration_endpoint: string
oauth_introspection_endpoint: string
oauth_token_endpoint_auth_methods_supported: string
api_endpoint_base_url: string
response_type: string
client_id: string

View File

@ -3,17 +3,20 @@
<div>
<i class="typcn typcn-chart-bar-outline"></i>
<h1 class="az-logo">fasten</h1>
<h5>Responsive Modern Dashboard &amp; Admin Template</h5>
<p>We are excited to launch our new company and product Azia. After being featured in too many magazines to mention and having created an online stir, we know that BootstrapDash is going to be big. We also hope to win Startup Fictional Business of the Year this year.</p>
<p>Browse our site and see for yourself why you need Azia.</p>
<a routerLink="/" class="btn btn-outline-indigo">Learn More</a>
<h5>Access, aggregate and track your medical records.</h5>
<p>Import your medical, dental and vision history from your various health providers.
Your data is always stored safely and securely on your computer.
</p>
<p>Build one consolidated health record of your full health history, supports multiple users, create accounts for your whole family
</p>
<a href="https://www.fastenhealth.com/" class="btn btn-outline-indigo">Learn More</a>
</div>
</div><!-- az-column-signup-left -->
<div class="az-column-signup">
<h1 class="az-logo">fasten</h1>
<div class="az-signup-header">
<h2>Get Started</h2>
<h4>It's free to signup and only takes a minute.</h4>
<h2>It's your health. Own it.</h2>
<h4>Create an account, and get started.</h4>
<form (ngSubmit)="signupSubmit()" #userForm="ngForm">
<div class="form-group">

View File

@ -26,10 +26,6 @@
<div class="az-dashboard-nav">
<nav class="nav">
<a class="nav-link active" routerLink="/">Overview</a>
<a class="nav-link" routerLink="/">Audiences</a>
<a class="nav-link" routerLink="/">Demographics</a>
<a class="nav-link" routerLink="/">More</a>
</nav>
<nav class="nav">
@ -144,7 +140,7 @@
<div class="table-responsive">
<table class="table mg-b-0">
<tbody>
<tr *ngFor="let source of sources" (click)="selectSource(source)" class="alert" role="alert">
<tr *ngFor="let source of sources" (click)="selectSource(source)" class="alert cursor-pointer" role="alert">
<td class="align-middle">
<div class="media">
<img [src]="'assets/sources/'+source.source_type+'.png'"

View File

@ -10,7 +10,7 @@
<div class="row">
<div *ngFor="let sourceData of connectedSourceList" (click)="connect($event, sourceData['source_type'])" class="col-sm-3 mg-b-20 px-3">
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0">
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0 cursor-pointer">
<div class="card-body">
<img [src]="'assets/sources/'+sourceData['source_type']+'.png'" alt="client" class="img-fluid">
</div>
@ -44,7 +44,7 @@
<div *ngFor="let sourceData of availableSourceList" (click)="connect($event, sourceData['source_type'])" class="col-sm-3 mg-b-20 px-3">
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0">
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0 cursor-pointer">
<div class="card-body">
<img [src]="'assets/sources/'+sourceData['source_type']+'.png'" [alt]="metadataSources[sourceData['source_type']].display" class="img-fluid">

View File

@ -99,11 +99,17 @@ export class MedicalSourcesComponent implements OnInit {
token_endpoint_auth_method: 'none',
}
//check if the oauth_token_endpoint_auth_methods_supported field is set
if(connectData.oauth_token_endpoint_auth_methods_supported){
let auth_methods = connectData.oauth_token_endpoint_auth_methods_supported.split(",")
client.token_endpoint_auth_method = auth_methods[0]
}
const as = {
issuer: `${authorizationUrl.protocol}//${authorizationUrl.host}`,
authorization_endpoint: `${connectData.oauth_endpoint_base_url}/authorize`,
token_endpoint: `${connectData.oauth_endpoint_base_url}/token`,
introspection_endpoint: `${connectData.oauth_endpoint_base_url}/introspect`,
authorization_endpoint: connectData.oauth_authorization_endpoint,
token_endpoint: connectData.oauth_token_endpoint,
introspection_endpoint: connectData.oauth_introspection_endpoint,
}
console.log("STARTING--- Oauth.validateAuthResponse")
@ -137,11 +143,15 @@ export class MedicalSourcesComponent implements OnInit {
//Create FHIR Client
const sourceCredential: Source = {
source_type: sourceType,
oauth_endpoint_base_url: connectData.oauth_endpoint_base_url,
oauth_authorization_endpoint: connectData.oauth_authorization_endpoint,
oauth_token_endpoint: connectData.oauth_token_endpoint,
oauth_registration_endpoint: connectData.oauth_registration_endpoint,
oauth_introspection_endpoint: connectData.oauth_introspection_endpoint,
oauth_token_endpoint_auth_methods_supported: connectData.oauth_token_endpoint_auth_methods_supported,
api_endpoint_base_url: connectData.api_endpoint_base_url,
client_id: connectData.client_id,
redirect_uri: connectData.redirect_uri,
scopes: connectData.scopes.join(' '),
scopes: connectData.scopes ? connectData.scopes.join(' ') : undefined,
patient_id: payload.patient,
access_token: payload.access_token,
refresh_token: payload.refresh_token,

View File

@ -26,14 +26,16 @@ export class LighthouseService {
generatePKCESourceAuthorizeUrl(codeVerifier: string, codeChallenge: string, codeChallengeMethod: string, state: string, lighthouseSource: LighthouseSource): URL {
// generate the authorization url
const authorizationUrl = new URL(`${lighthouseSource.oauth_endpoint_base_url}/authorize`);
const authorizationUrl = new URL(lighthouseSource.oauth_authorization_endpoint);
authorizationUrl.searchParams.set('client_id', lighthouseSource.client_id);
authorizationUrl.searchParams.set('code_challenge', codeChallenge);
authorizationUrl.searchParams.set('code_challenge_method', codeChallengeMethod);
authorizationUrl.searchParams.set('redirect_uri', lighthouseSource.redirect_uri);
authorizationUrl.searchParams.set('response_type', 'code');
authorizationUrl.searchParams.set('scope', lighthouseSource.scopes.join(' '));
authorizationUrl.searchParams.set('state', state);
if(lighthouseSource.scopes && lighthouseSource.scopes.length){
authorizationUrl.searchParams.set('scope', lighthouseSource.scopes.join(' '));
}
if (lighthouseSource.aud) {
authorizationUrl.searchParams.set('aud', lighthouseSource.aud);
}

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -1,3 +1,9 @@
//Custom
.cursor-pointer {
cursor: pointer;
}
/* You can add global styles to this file, and also import other style files */
/*
* Azia v1.0.0 (https://www.bootstrapdash.com/demo/azia/v1.0/)