diff --git a/core/search/queries.go b/core/search/queries.go index 35ba64fc5..52fb1d956 100644 --- a/core/search/queries.go +++ b/core/search/queries.go @@ -14,10 +14,10 @@ import ( // Exclusions are preset exclusion conditions type Exclusions struct { - NonActive bool `json:"non_active"` // contacts who are blocked, stopped or archived - InAFlow bool `json:"in_a_flow"` // contacts who are currently in a flow (including this one) - StartedPreviously bool `json:"started_previously"` // contacts who have been in this flow in the last 90 days - NotSeenRecently bool `json:"not_seen_recently"` // contacts who have not been seen for more than 90 days + NonActive bool `json:"non_active"` // contacts who are blocked, stopped or archived + InAFlow bool `json:"in_a_flow"` // contacts who are currently in a flow (including this one) + StartedPreviously bool `json:"started_previously"` // contacts who have been in this flow in the last 90 days + NotSeenSinceDays int `json:"not_seen_since_days"` // contacts who have not been seen for more than this number of days } // BuildStartQuery builds a start query for the given flow and start options @@ -51,8 +51,8 @@ func BuildStartQuery(env envs.Environment, flow *models.Flow, groups []*models.G if excs.StartedPreviously { exclusions = append(exclusions, fmt.Sprintf("history != \"%s\"", flow.Name())) } - if excs.NotSeenRecently { - seenSince := dates.Now().Add(-time.Hour * 24 * 90) + if excs.NotSeenSinceDays > 0 { + seenSince := dates.Now().Add(-time.Hour * time.Duration(24*excs.NotSeenSinceDays)) exclusions = append(exclusions, fmt.Sprintf("last_seen_on > %s", formatQueryDate(env, seenSince))) } diff --git a/core/search/queries_test.go b/core/search/queries_test.go index a068d9080..d30f9b000 100644 --- a/core/search/queries_test.go +++ b/core/search/queries_test.go @@ -51,7 +51,7 @@ func TestBuildStartQuery(t *testing.T) { NonActive: true, InAFlow: true, StartedPreviously: true, - NotSeenRecently: true, + NotSeenSinceDays: 90, }, expected: `(group = "Doctors" OR uuid = "6393abc0-283d-4c9b-a1b3-641a035c34bf" OR tel = "+1234567890") AND status = "active" AND flow = "" AND history != "Favorites" AND last_seen_on > 20-01-2022`, }, @@ -73,9 +73,9 @@ func TestBuildStartQuery(t *testing.T) { NonActive: true, InAFlow: true, StartedPreviously: true, - NotSeenRecently: true, + NotSeenSinceDays: 30, }, - expected: `gender = M AND status = "active" AND flow = "" AND history != "Favorites" AND last_seen_on > 20-01-2022`, + expected: `gender = M AND status = "active" AND flow = "" AND history != "Favorites" AND last_seen_on > 21-03-2022`, }, } diff --git a/web/flow/start.go b/web/flow/start.go index adc7bf15e..300d20132 100644 --- a/web/flow/start.go +++ b/web/flow/start.go @@ -25,11 +25,13 @@ func init() { // { // "org_id": 1, // "flow_id": 2, -// "group_uuids": ["5fa925e4-edd8-4e2a-ab24-b3dbb5932ddd", "2912b95f-5b89-4d39-a2a8-5292602f357f"], -// "contact_uuids": ["e5bb9e6f-7703-4ba1-afba-0b12791de38b"], -// "urns": ["tel:+1234567890"], -// "user_query": "", -// "exclusions": { +// "include": { +// "group_uuids": ["5fa925e4-edd8-4e2a-ab24-b3dbb5932ddd", "2912b95f-5b89-4d39-a2a8-5292602f357f"], +// "contact_uuids": ["e5bb9e6f-7703-4ba1-afba-0b12791de38b"], +// "urns": ["tel:+1234567890"], +// "user_query": "" +// }, +// "exclude": { // "non_active": false, // "in_a_flow": false, // "started_previously": true, @@ -51,14 +53,16 @@ func init() { // } // type previewStartRequest struct { - OrgID models.OrgID `json:"org_id" validate:"required"` - FlowID models.FlowID `json:"flow_id" validate:"required"` - GroupUUIDs []assets.GroupUUID `json:"group_uuids"` - ContactUUIDs []flows.ContactUUID `json:"contact_uuids"` - URNs []urns.URN `json:"urns"` - Query string `json:"query"` - Exclusions search.Exclusions `json:"exclusions"` - SampleSize int `json:"sample_size" validate:"required"` + OrgID models.OrgID `json:"org_id" validate:"required"` + FlowID models.FlowID `json:"flow_id" validate:"required"` + Include struct { + GroupUUIDs []assets.GroupUUID `json:"group_uuids"` + ContactUUIDs []flows.ContactUUID `json:"contact_uuids"` + URNs []urns.URN `json:"urns"` + Query string `json:"query"` + } `json:"include" validate:"required"` + Exclude search.Exclusions `json:"exclude"` + SampleSize int `json:"sample_size" validate:"required"` } type previewStartResponse struct { @@ -84,15 +88,15 @@ func handlePreviewStart(ctx context.Context, rt *runtime.Runtime, r *http.Reques return nil, http.StatusInternalServerError, errors.Wrapf(err, "unable to load flow") } - groups := make([]*models.Group, 0, len(request.GroupUUIDs)) - for _, groupUUID := range request.GroupUUIDs { + groups := make([]*models.Group, 0, len(request.Include.GroupUUIDs)) + for _, groupUUID := range request.Include.GroupUUIDs { g := oa.GroupByUUID(groupUUID) if g != nil { groups = append(groups, g) } } - query := search.BuildStartQuery(oa.Env(), flow, groups, request.ContactUUIDs, request.URNs, request.Query, request.Exclusions) + query := search.BuildStartQuery(oa.Env(), flow, groups, request.Include.ContactUUIDs, request.Include.URNs, request.Include.Query, request.Exclude) if query == "" { return &previewStartResponse{SampleIDs: []models.ContactID{}}, http.StatusOK, nil } diff --git a/web/flow/testdata/preview_start.json b/web/flow/testdata/preview_start.json index 7ecd305ad..95b711618 100644 --- a/web/flow/testdata/preview_start.json +++ b/web/flow/testdata/preview_start.json @@ -25,6 +25,7 @@ "body": { "org_id": 1, "flow_id": 10001, + "include": {}, "sample_size": 3 }, "status": 200, @@ -41,19 +42,21 @@ "body": { "org_id": 1, "flow_id": 10001, - "group_uuids": [ - "c153e265-f7c9-4539-9dbc-9b358714b638", - "5e9d8fab-5e7e-4f51-b533-261af5dea70d" - ], - "contact_uuids": [ - "5a8345c1-514a-4d1b-aee5-6f39b2f53cfa", - "bd2aab59-5e28-4db4-b6e8-bbdb75fd7a0a" - ], - "urns": [ - "tel:+1234567890", - "facebook:9876543210" - ], - "query": "", + "include": { + "group_uuids": [ + "c153e265-f7c9-4539-9dbc-9b358714b638", + "5e9d8fab-5e7e-4f51-b533-261af5dea70d" + ], + "contact_uuids": [ + "5a8345c1-514a-4d1b-aee5-6f39b2f53cfa", + "bd2aab59-5e28-4db4-b6e8-bbdb75fd7a0a" + ], + "urns": [ + "tel:+1234567890", + "facebook:9876543210" + ], + "query": "" + }, "sample_size": 3 }, "status": 200, @@ -94,10 +97,12 @@ "body": { "org_id": 1, "flow_id": 10001, - "group_ids": [], - "contact_ids": [], - "urns": [], - "query": "gender = M", + "include": { + "group_ids": [], + "contact_ids": [], + "urns": [], + "query": "gender = M" + }, "sample_size": 3 }, "status": 200, @@ -128,24 +133,26 @@ "body": { "org_id": 1, "flow_id": 10001, - "group_uuids": [ - "c153e265-f7c9-4539-9dbc-9b358714b638", - "5e9d8fab-5e7e-4f51-b533-261af5dea70d" - ], - "contact_uuids": [ - "5a8345c1-514a-4d1b-aee5-6f39b2f53cfa", - "bd2aab59-5e28-4db4-b6e8-bbdb75fd7a0a" - ], - "urns": [ - "tel:+1234567890", - "facebook:9876543210" - ], - "query": "", - "exclusions": { + "include": { + "group_uuids": [ + "c153e265-f7c9-4539-9dbc-9b358714b638", + "5e9d8fab-5e7e-4f51-b533-261af5dea70d" + ], + "contact_uuids": [ + "5a8345c1-514a-4d1b-aee5-6f39b2f53cfa", + "bd2aab59-5e28-4db4-b6e8-bbdb75fd7a0a" + ], + "urns": [ + "tel:+1234567890", + "facebook:9876543210" + ], + "query": "" + }, + "exclude": { "non_active": true, "in_a_flow": true, "started_previously": true, - "not_seen_recently": true + "not_seen_since_days": 90 }, "sample_size": 3 }, @@ -191,12 +198,14 @@ "body": { "org_id": 1, "flow_id": 10001, - "query": "gender = M", - "exclusions": { + "include": { + "query": "gender = M" + }, + "exclude": { "non_active": true, "in_a_flow": true, "started_previously": true, - "not_seen_recently": true + "not_seen_since_days": 90 }, "sample_size": 3 },