Skip to content

Commit 86440db

Browse files
committed
Backfill stable rule IDs and make it non-optional.
1 parent 7d820a9 commit 86440db

18 files changed

+252
-148
lines changed

api/handle_workflows.go

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ func handleListWorkflowsForScenario(uc usecases.Usecases) func(c *gin.Context) {
1717
scenarioId := c.Param("scenarioId")
1818

1919
uc := usecasesWithCreds(ctx, uc)
20-
scenarioUsecase := uc.NewScenarioUsecase()
20+
workflowUsecase := uc.NewWorkflowUsecase()
2121

22-
rules, err := scenarioUsecase.ListWorkflowsForScenario(ctx, scenarioId)
22+
rules, err := workflowUsecase.ListWorkflowsForScenario(ctx, scenarioId)
2323
if presentError(ctx, c, err) {
2424
return
2525
}
@@ -40,14 +40,14 @@ func handleCreateWorkflowRule(uc usecases.Usecases) func(c *gin.Context) {
4040
}
4141

4242
uc := usecasesWithCreds(ctx, uc)
43-
scenarioUsecase := uc.NewScenarioUsecase()
43+
workflowUsecase := uc.NewWorkflowUsecase()
4444

4545
params := models.WorkflowRule{
4646
ScenarioId: payload.ScenarioId,
4747
Name: payload.Name,
4848
}
4949

50-
rule, err := scenarioUsecase.CreateWorkflowRule(ctx, params)
50+
rule, err := workflowUsecase.CreateWorkflowRule(ctx, params)
5151
if presentError(ctx, c, err) {
5252
return
5353
}
@@ -69,14 +69,14 @@ func handleUpdateWorkflowRule(uc usecases.Usecases) func(c *gin.Context) {
6969
}
7070

7171
uc := usecasesWithCreds(ctx, uc)
72-
scenarioUsecase := uc.NewScenarioUsecase()
72+
workflowUsecase := uc.NewWorkflowUsecase()
7373

7474
params := models.WorkflowRule{
7575
Id: ruleId,
7676
Name: payload.Name,
7777
}
7878

79-
rule, err := scenarioUsecase.UpdateWorkflowRule(ctx, params)
79+
rule, err := workflowUsecase.UpdateWorkflowRule(ctx, params)
8080
if presentError(ctx, c, err) {
8181
return
8282
}
@@ -91,9 +91,9 @@ func handleDeleteWorkflowRule(uc usecases.Usecases) func(c *gin.Context) {
9191
ruleId := c.Param("ruleId")
9292

9393
uc := usecasesWithCreds(ctx, uc)
94-
scenarioUsecase := uc.NewScenarioUsecase()
94+
workflowUsecase := uc.NewWorkflowUsecase()
9595

96-
if err := scenarioUsecase.DeleteWorkflowRule(ctx, ruleId); presentError(ctx, c, err) {
96+
if err := workflowUsecase.DeleteWorkflowRule(ctx, ruleId); presentError(ctx, c, err) {
9797
return
9898
}
9999

@@ -112,21 +112,17 @@ func handleCreateWorkflowCondition(uc usecases.Usecases) func(c *gin.Context) {
112112
c.Status(http.StatusBadRequest)
113113
return
114114
}
115-
if err := dto.ValidateWorkflowCondition(payload); presentError(ctx, c, err) {
116-
c.Status(http.StatusBadRequest)
117-
return
118-
}
119115

120116
uc := usecasesWithCreds(ctx, uc)
121-
scenarioUsecase := uc.NewScenarioUsecase()
117+
workflowUsecase := uc.NewWorkflowUsecase()
122118

123119
params := models.WorkflowCondition{
124120
RuleId: ruleId,
125121
Function: payload.Function,
126122
Params: payload.Params,
127123
}
128124

129-
condition, err := scenarioUsecase.CreateWorkflowCondition(ctx, params)
125+
condition, err := workflowUsecase.CreateWorkflowCondition(ctx, params)
130126
if presentError(ctx, c, err) {
131127
return
132128
}
@@ -147,13 +143,9 @@ func handleUpdateWorkflowCondition(uc usecases.Usecases) func(c *gin.Context) {
147143
c.Status(http.StatusBadRequest)
148144
return
149145
}
150-
if err := dto.ValidateWorkflowCondition(payload); presentError(ctx, c, err) {
151-
c.Status(http.StatusBadRequest)
152-
return
153-
}
154146

155147
uc := usecasesWithCreds(ctx, uc)
156-
scenarioUsecase := uc.NewScenarioUsecase()
148+
workflowUsecase := uc.NewWorkflowUsecase()
157149

158150
params := models.WorkflowCondition{
159151
Id: conditionId,
@@ -162,7 +154,7 @@ func handleUpdateWorkflowCondition(uc usecases.Usecases) func(c *gin.Context) {
162154
Params: payload.Params,
163155
}
164156

165-
condition, err := scenarioUsecase.UpdateWorkflowCondition(ctx, params)
157+
condition, err := workflowUsecase.UpdateWorkflowCondition(ctx, params)
166158
if presentError(ctx, c, err) {
167159
return
168160
}
@@ -178,9 +170,9 @@ func handleDeleteWorkflowCondition(uc usecases.Usecases) func(c *gin.Context) {
178170
conditionId := c.Param("conditionId")
179171

180172
uc := usecasesWithCreds(ctx, uc)
181-
scenarioUsecase := uc.NewScenarioUsecase()
173+
workflowUsecase := uc.NewWorkflowUsecase()
182174

183-
if err := scenarioUsecase.DeleteWorkflowCondition(ctx, ruleId, conditionId); presentError(ctx, c, err) {
175+
if err := workflowUsecase.DeleteWorkflowCondition(ctx, ruleId, conditionId); presentError(ctx, c, err) {
184176
return
185177
}
186178

@@ -204,15 +196,15 @@ func handleCreateWorkflowAction(uc usecases.Usecases) func(c *gin.Context) {
204196
}
205197

206198
uc := usecasesWithCreds(ctx, uc)
207-
scenarioUsecase := uc.NewScenarioUsecase()
199+
workflowUsecase := uc.NewWorkflowUsecase()
208200

209201
params := models.WorkflowAction{
210202
RuleId: ruleId,
211203
Action: payload.Action,
212204
Params: payload.Params,
213205
}
214206

215-
action, err := scenarioUsecase.CreateWorkflowAction(ctx, params)
207+
action, err := workflowUsecase.CreateWorkflowAction(ctx, params)
216208
if presentError(ctx, c, err) {
217209
return
218210
}
@@ -238,7 +230,7 @@ func handleUpdateWorkflowAction(uc usecases.Usecases) func(c *gin.Context) {
238230
}
239231

240232
uc := usecasesWithCreds(ctx, uc)
241-
scenarioUsecase := uc.NewScenarioUsecase()
233+
workflowUsecase := uc.NewWorkflowUsecase()
242234

243235
params := models.WorkflowAction{
244236
Id: actionId,
@@ -247,7 +239,7 @@ func handleUpdateWorkflowAction(uc usecases.Usecases) func(c *gin.Context) {
247239
Params: payload.Params,
248240
}
249241

250-
action, err := scenarioUsecase.UpdateWorkflowAction(ctx, params)
242+
action, err := workflowUsecase.UpdateWorkflowAction(ctx, params)
251243
if presentError(ctx, c, err) {
252244
return
253245
}
@@ -262,9 +254,9 @@ func handleDeleteWorkflowAction(uc usecases.Usecases) func(c *gin.Context) {
262254
actionId := c.Param("actionId")
263255

264256
uc := usecasesWithCreds(ctx, uc)
265-
scenarioUsecase := uc.NewScenarioUsecase()
257+
workflowUsecase := uc.NewWorkflowUsecase()
266258

267-
if err := scenarioUsecase.DeleteWorkflowAction(ctx, ruleId, actionId); presentError(ctx, c, err) {
259+
if err := workflowUsecase.DeleteWorkflowAction(ctx, ruleId, actionId); presentError(ctx, c, err) {
268260
return
269261
}
270262

@@ -284,9 +276,9 @@ func handleReorderWorkflowRules(uc usecases.Usecases) func(c *gin.Context) {
284276
}
285277

286278
uc := usecasesWithCreds(ctx, uc)
287-
scenarioUsecase := uc.NewScenarioUsecase()
279+
workflowUsecase := uc.NewWorkflowUsecase()
288280

289-
if err := scenarioUsecase.ReorderWorkflowRules(ctx, scenarioId, ids); presentError(ctx, c, err) {
281+
if err := workflowUsecase.ReorderWorkflowRules(ctx, scenarioId, ids); presentError(ctx, c, err) {
290282
return
291283
}
292284

dto/workflows.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ type WorkflowConditionRuleHitParams struct {
3939
RuleId string `json:"rule_id" binding:"required,uuid"`
4040
}
4141

42+
type WorkflowConditionScreeningHitParams struct {
43+
ScreeningId string `json:"screening_id" binding:"required,uuid"`
44+
}
45+
4246
type WorkflowConditionEvaluatesParams struct {
4347
Expression NodeDto `json:"expression" binding:"required"`
4448
}
@@ -92,23 +96,6 @@ func AdaptWorkflowAction(m models.WorkflowAction) WorkflowActionDto {
9296
}
9397
}
9498

95-
func ValidateWorkflowCondition(cond PostWorkflowConditionDto) error {
96-
switch cond.Function {
97-
case models.WorkflowConditionAlways, models.WorkflowConditionNever:
98-
if cond.Params != nil {
99-
return errors.Wrapf(models.BadParameterError, "workflow condition %s does not take parameters", cond.Function)
100-
}
101-
case models.WorkflowConditionOutcomeIn:
102-
if err := json.Unmarshal(cond.Params, new([]string)); err != nil {
103-
return errors.Join(models.BadParameterError, json.Unmarshal(cond.Params, new([]string)))
104-
}
105-
default:
106-
return errors.Wrapf(models.BadParameterError, "unknown workflow condition type: %s", cond.Function)
107-
}
108-
109-
return nil
110-
}
111-
11299
func ValidateWorkflowAction(cond PostWorkflowActionDto) error {
113100
switch cond.Action {
114101
case models.WorkflowCreateCase, models.WorkflowAddToCaseIfPossible:

integration_test/batch_ingestion_and_execution_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99
"time"
1010

11+
"github.com/google/uuid"
1112
"github.com/riverqueue/river"
1213
"github.com/segmentio/analytics-go/v3"
1314
"github.com/stretchr/testify/assert"
@@ -186,6 +187,7 @@ func getRulesForBatchTest() []models.CreateRuleInput {
186187
ScoreModifier: 100,
187188
Name: "Rule that hits",
188189
Description: "Rule that hits",
190+
StableRuleId: uuid.NewString(),
189191
},
190192
}
191193
}

integration_test/scenario_flow_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ func setupScenarioAndPublish(
281281
) (scenarioId, scenarioIterationId string) {
282282
// Create a new empty scenario
283283
scenarioUsecase := usecasesWithCreds.NewScenarioUsecase()
284+
workflowUsecase := usecasesWithCreds.NewWorkflowUsecase()
284285
scenario, err := scenarioUsecase.CreateScenario(ctx, models.CreateScenarioInput{
285286
Name: "Test scenario",
286287
Description: "Test scenario description",
@@ -406,15 +407,15 @@ func setupScenarioAndPublish(
406407
}
407408
fmt.Printf("Updated scenario iteration %+v\n", scenarioIteration)
408409

409-
rule, err := scenarioUsecase.CreateWorkflowRule(ctx, models.WorkflowRule{
410+
rule, err := workflowUsecase.CreateWorkflowRule(ctx, models.WorkflowRule{
410411
ScenarioId: scenarioId,
411412
Name: "First rule",
412413
})
413414
if err != nil {
414415
assert.FailNow(t, "Could not create workflow rule", err)
415416
}
416417

417-
_, err = scenarioUsecase.CreateWorkflowCondition(ctx, models.WorkflowCondition{
418+
_, err = workflowUsecase.CreateWorkflowCondition(ctx, models.WorkflowCondition{
418419
RuleId: rule.Id,
419420
Function: models.WorkflowConditionOutcomeIn,
420421
Params: []byte(`["decline", "review"]`),
@@ -423,7 +424,7 @@ func setupScenarioAndPublish(
423424
assert.FailNow(t, "Could not create workflow condition", err)
424425
}
425426

426-
_, err = scenarioUsecase.CreateWorkflowAction(ctx, models.WorkflowAction{
427+
_, err = workflowUsecase.CreateWorkflowAction(ctx, models.WorkflowAction{
427428
RuleId: rule.Id,
428429
Action: models.WorkflowAddToCaseIfPossible,
429430
Params: fmt.Appendf(nil, `{"inbox_id": "%s"}`, inboxId),
@@ -707,6 +708,7 @@ func getRulesForFullApiTest() []models.CreateRuleInput {
707708
ScoreModifier: 100,
708709
Name: "Check on account name",
709710
Description: "Check on account name",
711+
StableRuleId: uuid.NewString(),
710712
},
711713
{
712714
FormulaAstExpression: &ast.Node{
@@ -746,6 +748,7 @@ func getRulesForFullApiTest() []models.CreateRuleInput {
746748
ScoreModifier: 10,
747749
Name: "Check on aggregated value",
748750
Description: "Check on aggregated value",
751+
StableRuleId: uuid.NewString(),
749752
},
750753
{
751754
FormulaAstExpression: &ast.Node{
@@ -767,6 +770,7 @@ func getRulesForFullApiTest() []models.CreateRuleInput {
767770
ScoreModifier: 1,
768771
Name: "Fuzzy match on name",
769772
Description: "Fuzzy match on name",
773+
StableRuleId: uuid.NewString(),
770774
},
771775
}
772776
}

models/rule.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type Rule struct {
2222
CreatedAt time.Time
2323
RuleGroup string
2424
SnoozeGroupId *string
25-
StableRuleId *string
25+
StableRuleId string
2626
}
2727

2828
type CreateRuleInput struct {
@@ -36,7 +36,7 @@ type CreateRuleInput struct {
3636
ScoreModifier int
3737
RuleGroup string
3838
SnoozeGroupId *string
39-
StableRuleId *string
39+
StableRuleId string
4040
}
4141

4242
type UpdateRuleInput struct {

models/screening.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ type Screening struct {
116116
}
117117

118118
type ScreeningConfigRef struct {
119-
Name string
119+
Id string
120+
StableId string
121+
Name string
120122
}
121123
type ScreeningWithMatches struct {
122124
Screening
@@ -143,7 +145,12 @@ type ScreeningRawSearchResponseWithMatches struct {
143145
func (s ScreeningRawSearchResponseWithMatches) AdaptScreeningFromSearchResponse(query OpenSanctionsQuery) ScreeningWithMatches {
144146
screening := ScreeningWithMatches{
145147
Screening: Screening{
146-
ScreeningConfigId: query.Config.Id,
148+
ScreeningConfigId: query.Config.Id,
149+
Config: ScreeningConfigRef{
150+
Id: query.Config.Id,
151+
StableId: query.Config.StableId,
152+
Name: query.Config.Name,
153+
},
147154
Datasets: query.Config.Datasets,
148155
OrgConfig: query.OrgConfig,
149156
SearchInput: s.SearchInput,

models/workflows.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ type WorkflowRule struct {
2929
type WorkflowConditionType string
3030

3131
const (
32-
WorkflowConditionUnknown WorkflowConditionType = "unknown"
33-
WorkflowConditionAlways = "always"
34-
WorkflowConditionNever = "never"
35-
WorkflowConditionOutcomeIn = "outcome_in"
36-
WorkflowConditionRuleHit = "rule_hit"
37-
WorkflowPayloadEvaluates = "payload_evaluates"
32+
WorkflowConditionUnknown WorkflowConditionType = "unknown"
33+
WorkflowConditionAlways = "always"
34+
WorkflowConditionNever = "never"
35+
WorkflowConditionOutcomeIn = "outcome_in"
36+
WorkflowConditionRuleHit = "rule_hit"
37+
WorkflowConditionScreeningHit = "screening_hit"
38+
WorkflowPayloadEvaluates = "payload_evaluates"
3839
)
3940

4041
var (
@@ -58,6 +59,8 @@ func WorkflowConditionFromString(s string) WorkflowConditionType {
5859
return WorkflowConditionRuleHit
5960
case WorkflowPayloadEvaluates:
6061
return WorkflowPayloadEvaluates
62+
case WorkflowConditionScreeningHit:
63+
return WorkflowConditionScreeningHit
6164
default:
6265
return WorkflowConditionUnknown
6366
}

repositories/dbmodels/db_rule.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type DBRule struct {
2727
DeletedAt pgtype.Time `db:"deleted_at"`
2828
RuleGroup string `db:"rule_group"`
2929
SnoozeGroupId *string `db:"snooze_group_id"`
30-
StableRuleId *string `db:"stable_rule_id"`
30+
StableRuleId string `db:"stable_rule_id"`
3131
}
3232

3333
func AdaptRule(db DBRule) (models.Rule, error) {
@@ -81,7 +81,7 @@ type DBCreateRuleInput struct {
8181
FormulaAstExpression *[]byte `db:"formula_ast_expression"`
8282
RuleGroup string `db:"rule_group"`
8383
SnoozeGroupId *string `db:"snooze_group_id"`
84-
StableRuleId *string `db:"stable_rule_id"`
84+
StableRuleId string `db:"stable_rule_id"`
8585
}
8686

8787
func AdaptDBCreateRuleInput(rule models.CreateRuleInput) (DBCreateRuleInput, error) {

repositories/migrations/20250620211400_create_workflows.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ begin
7474
end loop;
7575
end $$;
7676

77+
update scenario_iteration_rules
78+
set stable_rule_id = gen_random_uuid()
79+
where stable_rule_id is null;
80+
81+
alter table scenario_iteration_rules
82+
alter column stable_rule_id set not null;
83+
7784
-- +goose StatementEnd
7885

7986
-- +goose Down

0 commit comments

Comments
 (0)