Skip to content

Commit

Permalink
Merge pull request #52 from fastenhealth/resource_type_allow_list
Browse files Browse the repository at this point in the history
adding support for a resource type allow list
  • Loading branch information
AnalogJ authored Sep 20, 2024
2 parents e893d2a + 572b3c8 commit e0b77b2
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 25 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ FROM golang:1.21
WORKDIR /go/src/github.com/fastenhealth/fasten-sources
COPY . .

RUN go mod tidy && go mod vendor && go build -o /usr/bin/oauth_cli ./testutils/oauth_cli.go
RUN go mod tidy && go mod vendor && go build -o /usr/bin/test-smart-client ./tools/test-smart-client/main.go

CMD ["/usr/bin/oauth_cli"]
CMD ["/usr/bin/test-smart-client"]

EXPOSE 9999
18 changes: 13 additions & 5 deletions clients/internal/base/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ type SourceClientBase struct {
EndpointDefinition *definitionsModels.LighthouseSourceDefinition
Headers map[string]string

UsCoreResources []string
FhirVersion string
ResourceTypesUsCore []string
FhirVersion string

SourceClientOptions *models.SourceClientOptions

Expand Down Expand Up @@ -69,7 +69,7 @@ func NewBaseClient(env pkg.FastenLighthouseEnvType, ctx context.Context, globalL
Headers: map[string]string{},

// https://build.fhir.org/ig/HL7/US-Core/
UsCoreResources: []string{
ResourceTypesUsCore: []string{
"AllergyIntolerance",
//"Binary",
"CarePlan",
Expand Down Expand Up @@ -113,8 +113,16 @@ func NewBaseClient(env pkg.FastenLighthouseEnvType, ctx context.Context, globalL
return client, nil
}

func (c *SourceClientBase) GetUsCoreResources() []string {
return c.UsCoreResources
func (c *SourceClientBase) GetResourceTypesUsCore() []string {
return c.ResourceTypesUsCore
}

func (c *SourceClientBase) GetResourceTypesAllowList() []string {
if c.SourceClientOptions == nil {
return []string{}
} else {
return c.SourceClientOptions.ResourceTypesAllowList
}
}

func (c *SourceClientBase) GetSourceCredential() models.SourceCredential {
Expand Down
10 changes: 9 additions & 1 deletion clients/internal/base/fhir401_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ func (c *SourceClientFHIR401) SyncAllByResourceName(db models.DatabaseRepository
}

//process any pending resources
lookupResourceReferences, syncErrors = c.ProcessPendingResources(db, &summary, lookupResourceReferences, syncErrors)
//if we have a populated whitelist, skip this -- we don't care about references to other resources, just the ones we queried. This is a naiive solution to prevent requesting unnecessary records. This should be improved.
if len(c.GetResourceTypesAllowList()) == 0 {
lookupResourceReferences, syncErrors = c.ProcessPendingResources(db, &summary, lookupResourceReferences, syncErrors)
}

checkpointErrorData := map[string]interface{}{}
if len(syncErrors) > 0 {
Expand Down Expand Up @@ -469,6 +472,11 @@ func (c *SourceClientFHIR401) ProcessResource(db models.DatabaseRepository, reso
c.Logger.Warnf("Skipping contained resource missing id: (%s/%s#%s index: %d)", currentResourceType, *currentResourceId, containedResourceType, cndx)
continue
}
if len(c.GetResourceTypesAllowList()) > 0 && !lo.Contains(c.GetResourceTypesAllowList(), containedResourceType) {
c.Logger.Warnf("Skipping contained resource not in allow list: (%s/%s#%s index: %d)", currentResourceType, *currentResourceId, containedResourceType, cndx)
continue
}

normalizedContainedResourceId := normalizeContainedResourceId(currentResourceType, *currentResourceId, *containedResourceId)

//generate a unique id for this contained resource by base64 url encoding this string
Expand Down
13 changes: 10 additions & 3 deletions clients/internal/dynamic_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,16 @@ func (c dynamicSourceClient) SyncAll(db models.DatabaseRepository) (models.Upser
//Operation-PatientEverything is not supported - https://build.fhir.org/operation-patient-everything.html
//Manually processing individual resources

supportedResources := c.GetUsCoreResources()
if c.EndpointDefinition.ClientSupportedResources != nil {
supportedResources = append(supportedResources, c.EndpointDefinition.ClientSupportedResources...)
var supportedResources []string
if len(c.GetResourceTypesAllowList()) > 0 {
supportedResources = c.GetResourceTypesAllowList()
supportedResources = append(supportedResources, "Patient") //always ensure the patient is included
} else {
//no override provided, attempt to sync all resources
supportedResources = c.GetResourceTypesUsCore()
if c.EndpointDefinition.ClientSupportedResources != nil {
supportedResources = append(supportedResources, c.EndpointDefinition.ClientSupportedResources...)
}
}
return c.SyncAllByResourceName(db, supportedResources)
} else if len(c.EndpointDefinition.CustomOpPatientEverything) > 0 {
Expand Down
14 changes: 14 additions & 0 deletions clients/internal/dynamic_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package internal

import (
"github.com/fastenhealth/fasten-sources/clients/models"
"github.com/stretchr/testify/require"
"testing"
)

func TestGetDynamicSourceClient_ImplementsInterface(t *testing.T) {
t.Parallel()

//assert
require.Implements(t, (*models.SourceClient)(nil), &dynamicSourceClient{}, "should implement the models.SourceClient interface")
}
14 changes: 14 additions & 0 deletions clients/internal/fasten/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fasten

import (
"github.com/fastenhealth/fasten-sources/clients/models"
"github.com/stretchr/testify/require"
"testing"
)

func TestGetSourceClientFasten_ImplementsInterface(t *testing.T) {
t.Parallel()

//assert
require.Implements(t, (*models.SourceClient)(nil), &FastenClient{}, "should implement the models.SourceClient interface")
}
8 changes: 8 additions & 0 deletions clients/internal/manual/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (m ManualClient) GetUsCoreResources() []string {
panic("implement me")
}

func (m ManualClient) GetResourceTypesUsCore() []string {
return []string{}
}

func (m ManualClient) GetResourceTypesAllowList() []string {
return []string{}
}

func (m ManualClient) SyncAllByResourceName(db models.DatabaseRepository, resourceNames []string) (models.UpsertSummary, error) {
//TODO implement me
panic("implement me")
Expand Down
8 changes: 8 additions & 0 deletions clients/internal/manual/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package manual

import (
"context"
"github.com/fastenhealth/fasten-sources/clients/models"
mock_models "github.com/fastenhealth/fasten-sources/clients/models/mock"
"github.com/fastenhealth/fasten-sources/pkg"
"github.com/golang/mock/gomock"
Expand All @@ -11,6 +12,13 @@ import (
"testing"
)

func TestGetSourceClientManual_ImplementsInterface(t *testing.T) {
t.Parallel()

//assert
require.Implements(t, (*models.SourceClient)(nil), &ManualClient{}, "should implement the models.SourceClient interface")
}

func TestGetSourceClientManual_ExtractPatientId_Bundle(t *testing.T) {
t.Parallel()
//setup
Expand Down
40 changes: 27 additions & 13 deletions clients/models/mock/mock_source_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion clients/models/source_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (

//go:generate mockgen -source=source_client.go -destination=mock/mock_source_client.go
type SourceClient interface {
GetUsCoreResources() []string
GetResourceTypesUsCore() []string
GetResourceTypesAllowList() []string
GetRequest(resourceSubpath string, decodeModelPtr interface{}) (string, error)
GetResourceBundle(relativeResourcePath string) (interface{}, error)
SyncAll(db DatabaseRepository) (UpsertSummary, error)
Expand Down
8 changes: 8 additions & 0 deletions clients/models/source_client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type SourceClientOptions struct {
RedirectURL string
Scopes []string

ResourceTypesAllowList []string //list of resource types that are allowed to be fetched from this source. Default empty (USCDI Core List)

SourceClientRefreshOptions []func(*SourceClientRefreshOptions)

Context context.Context
Expand Down Expand Up @@ -65,6 +67,12 @@ func WithScopes(scopes []string) func(*SourceClientOptions) {
}
}

func WithResourceTypeAllowList(resourceTypeAllowList []string) func(*SourceClientOptions) {
return func(s *SourceClientOptions) {
s.ResourceTypesAllowList = resourceTypeAllowList
}
}

func WithSourceClientRefreshOptions(options ...func(*SourceClientRefreshOptions)) func(*SourceClientOptions) {
return func(s *SourceClientOptions) {
s.SourceClientRefreshOptions = options
Expand Down

0 comments on commit e0b77b2

Please sign in to comment.