Skip to content

Commit

Permalink
Set up plumbing for org-level configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Popineau committed Jan 17, 2025
1 parent 101bd39 commit 1177382
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 16 deletions.
17 changes: 17 additions & 0 deletions models/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ type Organization struct {
// to a separate DB.
// TODO: clean this up when it's no longuer used.
UseMarbleDbSchemaAsDefault bool

OpenSanctionsConfig OrganizationOpenSanctionsConfig
}

// TODO: Add other organization-level configuration options
type OrganizationOpenSanctionsConfig struct {
Datasets []string
MatchThreshold int
MatchLimit int
}

func DefaultOrganizationOpenSanctionsConfig() OrganizationOpenSanctionsConfig {
return OrganizationOpenSanctionsConfig{
Datasets: []string{},
MatchThreshold: 70,
MatchLimit: 20,
}
}

type CreateOrganizationInput struct {
Expand Down
2 changes: 2 additions & 0 deletions repositories/dbmodels/db_organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ func AdaptOrganization(db DBOrganizationResult) (models.Organization, error) {
TransferCheckScenarioId: db.TransferCheckScenarioId,
UseMarbleDbSchemaAsDefault: db.UseMarbleDbSchemaAsDefault,
DefaultScenarioTimezone: db.DefaultScenarioTimezone,
// TODO: Actually get it from the database
OpenSanctionsConfig: models.DefaultOrganizationOpenSanctionsConfig(),
}, nil
}
34 changes: 27 additions & 7 deletions repositories/opensanctions_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ type openSanctionsRequestQuery struct {
Properties models.OpenSanctionCheckFilter `json:"properties"`
}

func (repo OpenSanctionsRepository) Search(ctx context.Context, cfg models.SanctionCheckConfig,
func (repo OpenSanctionsRepository) Search(ctx context.Context,
orgCfg models.OrganizationOpenSanctionsConfig, cfg models.SanctionCheckConfig,
query models.OpenSanctionsQuery,
) (models.SanctionCheckResult, error) {
req, err := repo.searchRequest(ctx, query)
req, err := repo.searchRequest(ctx, orgCfg, query)
if err != nil {
return models.SanctionCheckResult{}, err
}
Expand Down Expand Up @@ -61,7 +62,9 @@ func (repo OpenSanctionsRepository) Search(ctx context.Context, cfg models.Sanct
return httpmodels.AdaptOpenSanctionsResult(matches)
}

func (repo OpenSanctionsRepository) searchRequest(ctx context.Context, query models.OpenSanctionsQuery) (*http.Request, error) {
func (repo OpenSanctionsRepository) searchRequest(ctx context.Context,
orgCfg models.OrganizationOpenSanctionsConfig, query models.OpenSanctionsQuery,
) (*http.Request, error) {
q := openSanctionsRequest{
Queries: make(map[string]openSanctionsRequestQuery, len(query.Queries)),
}
Expand All @@ -81,14 +84,31 @@ func (repo OpenSanctionsRepository) searchRequest(ctx context.Context, query mod

requestUrl := fmt.Sprintf("%s/match/sanctions", repo.opensanctions.Host())

if len(repo.opensanctions.ApiKey()) > 0 {
qs := url.Values{}
qs.Set("api_key", repo.opensanctions.ApiKey())

if qs := repo.buildQueryString(orgCfg); len(qs) > 0 {
requestUrl = fmt.Sprintf("%s?%s", requestUrl, qs.Encode())
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestUrl, &body)

return req, err
}

func (repo OpenSanctionsRepository) buildQueryString(orgCfg models.OrganizationOpenSanctionsConfig) url.Values {
qs := url.Values{}

if len(repo.opensanctions.ApiKey()) > 0 {
qs.Set("api_key", repo.opensanctions.ApiKey())
}

if len(orgCfg.Datasets) > 0 {
qs["include_dataset"] = orgCfg.Datasets
}
if orgCfg.MatchLimit > 0 {
qs.Set("limit", fmt.Sprintf("%d", orgCfg.MatchLimit))
}
if orgCfg.MatchThreshold > 0 {
qs.Set("threshold", fmt.Sprintf("%.1f", float64(orgCfg.MatchThreshold)/100))
}

return qs
}
6 changes: 4 additions & 2 deletions usecases/evaluate_scenario/evaluate_scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ type ScenarioEvaluationParameters struct {
}

type EvalSanctionCheckUsecase interface {
Execute(context.Context, models.SanctionCheckConfig, models.OpenSanctionsQuery) (models.SanctionCheckResult, error)
Execute(context.Context, string, models.SanctionCheckConfig,
models.OpenSanctionsQuery) (models.SanctionCheckResult, error)
}

type SnoozesForDecisionReader interface {
Expand Down Expand Up @@ -133,7 +134,8 @@ func processScenarioIteration(ctx context.Context, params ScenarioEvaluationPara
"name": []string{"obama"},
}}

result, err := repositories.EvalSanctionCheckUsecase.Execute(ctx, *iteration.SanctionCheckConfig, query)
result, err := repositories.EvalSanctionCheckUsecase.Execute(ctx,
params.Scenario.OrganizationId, *iteration.SanctionCheckConfig, query)
if err != nil {
return models.ScenarioExecution{}, errors.Wrap(err, "could not perform sanction check")
}
Expand Down
22 changes: 17 additions & 5 deletions usecases/sanction_check_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,37 @@ import (
"context"

"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/repositories"
"github.com/checkmarble/marble-backend/usecases/executor_factory"
"github.com/pkg/errors"
)

type SanctionCheckProvider interface {
Search(context.Context, models.SanctionCheckConfig, models.OpenSanctionsQuery) (models.SanctionCheckResult, error)
Search(context.Context, models.OrganizationOpenSanctionsConfig, models.SanctionCheckConfig,
models.OpenSanctionsQuery) (models.SanctionCheckResult, error)
}

type SanctionCheckRepository interface {
InsertResults(context.Context, models.SanctionCheckResult) (models.SanctionCheckResult, error)
}

type SanctionCheckUsecase struct {
openSanctionsProvider SanctionCheckProvider
repository SanctionCheckRepository
organizationRepository repositories.OrganizationRepository
openSanctionsProvider SanctionCheckProvider
repository SanctionCheckRepository
executorFactory executor_factory.ExecutorFactory
}

func (uc SanctionCheckUsecase) Execute(ctx context.Context, cfg models.SanctionCheckConfig,
func (uc SanctionCheckUsecase) Execute(ctx context.Context, orgId string, cfg models.SanctionCheckConfig,
query models.OpenSanctionsQuery,
) (models.SanctionCheckResult, error) {
matches, err := uc.openSanctionsProvider.Search(ctx, cfg, query)
org, err := uc.organizationRepository.GetOrganizationById(ctx,
uc.executorFactory.NewExecutor(), orgId)
if err != nil {
return models.SanctionCheckResult{}, errors.Wrap(err, "could not retrieve organization")
}

matches, err := uc.openSanctionsProvider.Search(ctx, org.OpenSanctionsConfig, cfg, query)
if err != nil {
return models.SanctionCheckResult{}, err
}
Expand Down
6 changes: 4 additions & 2 deletions usecases/usecases_with_creds.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ func (usecases *UsecasesWithCreds) NewDecisionUsecase() DecisionUsecase {

func (usecases *UsecasesWithCreds) NewSanctionCheckUsecase() SanctionCheckUsecase {
return SanctionCheckUsecase{
openSanctionsProvider: usecases.Repositories.OpenSanctionsRepository,
repository: &usecases.Repositories.MarbleDbRepository,
organizationRepository: usecases.Repositories.OrganizationRepository,
openSanctionsProvider: usecases.Repositories.OpenSanctionsRepository,
repository: &usecases.Repositories.MarbleDbRepository,
executorFactory: usecases.NewExecutorFactory(),
}
}

Expand Down

0 comments on commit 1177382

Please sign in to comment.