Skip to content

Commit

Permalink
Merge pull request #129 from nyaruka/inspect_with_validation
Browse files Browse the repository at this point in the history
🕵️‍♂️ The /flow/inspect endpoint should do optional validation
  • Loading branch information
rowanseymour authored May 28, 2019
2 parents 8f0384e + b36fc1d commit e5f3cf4
Show file tree
Hide file tree
Showing 18 changed files with 256 additions and 106 deletions.
21 changes: 16 additions & 5 deletions web/flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,18 @@ func handleValidate(ctx context.Context, s *web.Server, r *http.Request) (interf
return json.RawMessage(result), http.StatusOK, nil
}

// Inspects a flow.
// Inspects a flow, and returns metadata including the possible results generated by the flow,
// and dependencies in the flow. If `validate_with_org_id` is specified then the cloned flow
// will be validated against the assets of that org.
//
// {
// "flow": { "uuid": "468621a8-32e6-4cd2-afc1-04416f7151f0", "nodes": [...]}
// "flow": { "uuid": "468621a8-32e6-4cd2-afc1-04416f7151f0", "nodes": [...]},
// "validate_with_org_id": 1
// }
//
type inspectRequest struct {
Flow json.RawMessage `json:"flow" validate:"required"`
Flow json.RawMessage `json:"flow" validate:"required"`
ValidateWithOrgID models.OrgID `json:"validate_with_org_id"`
}

func handleInspect(ctx context.Context, s *web.Server, r *http.Request) (interface{}, int, error) {
Expand All @@ -112,12 +116,19 @@ func handleInspect(ctx context.Context, s *web.Server, r *http.Request) (interfa
return nil, http.StatusBadRequest, errors.Wrapf(err, "request failed validation")
}

// try to read the flow definition
flow, err := definition.ReadFlow(request.Flow)
flow, err := readFlow(request.Flow)
if err != nil {
return nil, http.StatusUnprocessableEntity, err
}

// if we have an org ID, do asset validation
if request.ValidateWithOrgID != models.NilOrgID {
status, err := validate(s.CTX, s.DB, request.ValidateWithOrgID, flow)
if err != nil {
return nil, status, err
}
}

return flow.Inspect(), http.StatusOK, nil
}

Expand Down
8 changes: 6 additions & 2 deletions web/flow/flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ func TestServer(t *testing.T) {
{URL: "/mr/flow/validate", Method: "POST", BodyFile: "validate_invalid_legacy.json", Status: 422, ResponseFile: "validate_invalid_legacy.response.json"},
{URL: "/mr/flow/validate", Method: "POST", BodyFile: "validate_valid.json", Status: 200, ResponseFile: "validate_valid.response.json"},
{URL: "/mr/flow/validate", Method: "POST", BodyFile: "validate_invalid.json", Status: 422, ResponseFile: "validate_invalid.response.json"},
{URL: "/mr/flow/validate", Method: "POST", BodyFile: "validate_valid_without_assets.json", Status: 200, ResponseFile: "validate_valid_without_assets.response.json"},
{URL: "/mr/flow/validate", Method: "POST", BodyFile: "validate_legacy_single_msg.json", Status: 200, ResponseFile: "validate_legacy_single_msg.response.json"},

{URL: "/mr/flow/inspect", Method: "GET", Status: 405, Response: `{"error": "illegal method: GET"}`},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_valid_legacy.json", Status: 200, ResponseFile: "inspect_valid_legacy.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_invalid_legacy.json", Status: 422, ResponseFile: "inspect_invalid_legacy.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_valid.json", Status: 200, ResponseFile: "inspect_valid.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_invalid.json", Status: 422, ResponseFile: "inspect_invalid.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_valid_without_org.json", Status: 200, ResponseFile: "inspect_valid_without_org.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_invalid_without_org.json", Status: 200, ResponseFile: "inspect_invalid_without_org.response.json"},
{URL: "/mr/flow/inspect", Method: "POST", BodyFile: "inspect_legacy_single_msg.json", Status: 200, ResponseFile: "inspect_legacy_single_msg.response.json"},

{URL: "/mr/flow/clone", Method: "GET", Status: 405, Response: `{"error": "illegal method: GET"}`},
{URL: "/mr/flow/clone", Method: "POST", BodyFile: "clone_valid.json", Status: 200, ResponsePattern: `"uuid": "1cf84575-ee14-4253-88b6-e3675c04a066"`},
Expand Down
36 changes: 36 additions & 0 deletions web/flow/testdata/inspect_invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"validate_with_org_id": 1,
"flow": {
"uuid": "8f107d42-7416-4cf2-9a51-9490361ad517",
"name": "Invalid Flow",
"spec_version": "13.0.0",
"language": "eng",
"type": "messaging",
"revision": 106,
"expire_after_minutes": 10080,
"localization": {},
"nodes": [
{
"uuid": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"actions": [
{
"type": "add_contact_groups",
"uuid": "23337aa9-0d3d-4e70-876e-9a2633d1e5e4",
"groups": [
{
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d",
"name": "Testers"
}
]
}
],
"exits": [
{
"uuid": "d3f3f024-a90e-43a5-bd5a-7056f5bea699",
"destination_uuid": "55fbef81-4151-4589-9f0a-8e5c44f6b5a3"
}
]
}
]
}
}
3 changes: 3 additions & 0 deletions web/flow/testdata/inspect_invalid.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"error": "invalid node[uuid=6fde1a09-3997-47dd-aff0-92e8aff3a642]: destination 55fbef81-4151-4589-9f0a-8e5c44f6b5a3 of exit[uuid=d3f3f024-a90e-43a5-bd5a-7056f5bea699] isn't a known node"
}
48 changes: 48 additions & 0 deletions web/flow/testdata/inspect_invalid_legacy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"validate_with_org_id": 1,
"flow": {
"entry": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"action_sets": [
{
"uuid": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"x": 107,
"y": 0,
"destination": null,
"actions": [
{
"type": "add_group",
"uuid": "23337aa9-0d3d-4e70-876e-9a2633d1e5e4",
"groups": [
{
"uuid": "1465eb20-066d-4933-a8b4-62fe7b19fd39",
"name": "I Don't Exist"
}
]
},
{
"type": "reply",
"uuid": "05a5cb7c-bb8a-4ad9-af90-ef9887cc370e",
"msg": {
"eng": "Your birthdate is @contact.birthdate"
},
"media": {},
"quick_replies": [],
"send_all": false
}
],
"exit_uuid": "d3f3f024-a90e-43a5-bd5a-7056f5bea699"
}
],
"rule_sets": [],
"base_language": "eng",
"flow_type": "M",
"version": "11.12",
"metadata": {
"expires": 10080,
"saved_on": "2019-03-04T17:37:06.873734Z",
"uuid": "8f107d42-7416-4cf2-9a51-9490361ad517",
"name": "Valid Legacy Flow",
"revision": 106
}
}
}
3 changes: 3 additions & 0 deletions web/flow/testdata/inspect_invalid_legacy.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"error": "missing dependencies: field[key=birthdate,name=],group[uuid=1465eb20-066d-4933-a8b4-62fe7b19fd39,name=I Don't Exist]"
}
39 changes: 39 additions & 0 deletions web/flow/testdata/inspect_invalid_without_org.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"flow": {
"uuid": "8f107d42-7416-4cf2-9a51-9490361ad517",
"name": "Valid Flow",
"spec_version": "13.0.0",
"language": "eng",
"type": "messaging",
"revision": 106,
"expire_after_minutes": 10080,
"localization": {},
"nodes": [
{
"uuid": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"actions": [
{
"type": "add_contact_groups",
"uuid": "23337aa9-0d3d-4e70-876e-9a2633d1e5e4",
"groups": [
{
"uuid": "e484d7b8-aada-4b63-b498-4ba4fbcafbc7",
"name": "No such group"
}
]
},
{
"type": "send_msg",
"uuid": "05a5cb7c-bb8a-4ad9-af90-ef9887cc370e",
"text": "Your birthdate is @contact.fields.birthdate"
}
],
"exits": [
{
"uuid": "d3f3f024-a90e-43a5-bd5a-7056f5bea699"
}
]
}
]
}
}
18 changes: 18 additions & 0 deletions web/flow/testdata/inspect_invalid_without_org.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"dependencies": {
"fields": [
{
"key": "birthdate",
"name": ""
}
],
"groups": [
{
"name": "No such group",
"uuid": "e484d7b8-aada-4b63-b498-4ba4fbcafbc7"
}
]
},
"results": [],
"waiting_exits": []
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"org_id": 1,
"validate_with_org_id": 1,
"flow": {
"version": "11.12",
"entry": "59329bcc-393e-4b36-af14-27b4c9454d0c",
Expand Down
5 changes: 5 additions & 0 deletions web/flow/testdata/inspect_legacy_single_msg.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {},
"results": [],
"waiting_exits": []
}
2 changes: 1 addition & 1 deletion web/flow/testdata/inspect_valid.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"uuid": "23337aa9-0d3d-4e70-876e-9a2633d1e5e4",
"groups": [
{
"uuid": "ebe441b4-c581-4b03-b544-5695cfe29bc1",
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d",
"name": "Testers"
}
]
Expand Down
4 changes: 2 additions & 2 deletions web/flow/testdata/inspect_valid.response.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"dependencies": {
"groups": [
{
"name": "Testers",
"uuid": "ebe441b4-c581-4b03-b544-5695cfe29bc1"
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d",
"name": "Testers"
}
]
},
Expand Down
48 changes: 48 additions & 0 deletions web/flow/testdata/inspect_valid_legacy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"validate_with_org_id": 1,
"flow": {
"entry": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"action_sets": [
{
"uuid": "6fde1a09-3997-47dd-aff0-92e8aff3a642",
"x": 107,
"y": 0,
"destination": null,
"actions": [
{
"type": "add_group",
"uuid": "23337aa9-0d3d-4e70-876e-9a2633d1e5e4",
"groups": [
{
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d",
"name": "Testers"
}
]
},
{
"type": "reply",
"uuid": "05a5cb7c-bb8a-4ad9-af90-ef9887cc370e",
"msg": {
"eng": "Your birthdate is soon"
},
"media": {},
"quick_replies": [],
"send_all": false
}
],
"exit_uuid": "d3f3f024-a90e-43a5-bd5a-7056f5bea699"
}
],
"rule_sets": [],
"base_language": "eng",
"flow_type": "M",
"version": "11.12",
"metadata": {
"expires": 10080,
"saved_on": "2019-03-04T17:37:06.873734Z",
"uuid": "8f107d42-7416-4cf2-9a51-9490361ad517",
"name": "Valid Legacy Flow",
"revision": 106
}
}
}
12 changes: 12 additions & 0 deletions web/flow/testdata/inspect_valid_legacy.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"dependencies": {
"groups": [
{
"name": "Testers",
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d"
}
]
},
"results": [],
"waiting_exits": []
}
18 changes: 18 additions & 0 deletions web/flow/testdata/inspect_valid_without_org.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"dependencies": {
"fields": [
{
"key": "birthdate",
"name": ""
}
],
"groups": [
{
"name": "Testers",
"uuid": "5e9d8fab-5e7e-4f51-b533-261af5dea70d"
}
]
},
"results": [],
"waiting_exits": []
}
42 changes: 0 additions & 42 deletions web/flow/testdata/validate_legacy_single_msg.response.json

This file was deleted.

Loading

0 comments on commit e5f3cf4

Please sign in to comment.