mirror of https://github.com/zulip/zulip.git
webhooks: Add Clubhouse integration.
This commit is contained in:
parent
e7a172293f
commit
061e760d1e
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -282,6 +282,7 @@ WEBHOOK_INTEGRATIONS = [
|
|||
legacy=True
|
||||
),
|
||||
WebhookIntegration('circleci', ['continuous-integration'], display_name='CircleCI'),
|
||||
WebhookIntegration('clubhouse', ['project-management']),
|
||||
WebhookIntegration('codeship', ['continuous-integration', 'deployment']),
|
||||
WebhookIntegration('crashlytics', ['monitoring']),
|
||||
WebhookIntegration('dialogflow', ['customer-support'], display_name='Dialogflow'),
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
Get Zulip notifications for your Clubhouse Stories and Epics!
|
||||
|
||||
1. {!create-stream.md!}
|
||||
|
||||
1. {!create-bot-contruct-url-indented.md!}
|
||||
|
||||
1. Go to your Clubhouse Dashboard, and click on the settings icon in
|
||||
the top-right corner. Click on **Integrations**, and select **Webhooks**.
|
||||
Click **+ Add New Webhook**.
|
||||
|
||||
1. Set **Payload URL** to the URL constructed above, and click
|
||||
**Add New Webhook**.
|
||||
|
||||
{!congrats.md!}
|
||||
|
||||
![](/static/images/integrations/clubhouse/001.png)
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"id":"5b295f25-6212-40e3-912d-dee6ce7cb0c2",
|
||||
"changed_at":"2018-06-19T19:53:09.576Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"create",
|
||||
"name":"New Epic!",
|
||||
"follower_ids":[
|
||||
"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
],
|
||||
"requested_by_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"state":"to do",
|
||||
"description":"",
|
||||
"epic_state_id":500000002
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":500000002,
|
||||
"entity_type":"epic-state",
|
||||
"name":"to do",
|
||||
"type":"unstarted"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"id":"5b2962a4-6e8e-4a80-8a41-0e2be62064b5",
|
||||
"changed_at":"2018-06-19T20:08:04.359Z",
|
||||
"primary_id":23,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":23,
|
||||
"entity_type":"story",
|
||||
"action":"create",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/23",
|
||||
"description":"",
|
||||
"story_type":"feature",
|
||||
"name":"An epic story!",
|
||||
"epic_id":20,
|
||||
"requested_by_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"workflow_state_id":500000008,
|
||||
"object_story_link_ids":[
|
||||
500000023
|
||||
],
|
||||
"follower_ids":[
|
||||
"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
],
|
||||
"project_id":6
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add super cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"subject_story_link_ids":{
|
||||
"adds":[
|
||||
500000023
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":500000023,
|
||||
"entity_type":"story-link",
|
||||
"action":"create",
|
||||
"subject_id":11,
|
||||
"verb":"relates to",
|
||||
"object_id":23
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":6,
|
||||
"entity_type":"project",
|
||||
"name":"Backend"
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"name":"New Cool Epic!"
|
||||
},
|
||||
{
|
||||
"id":500000008,
|
||||
"entity_type":"workflow-state",
|
||||
"name":"Unscheduled",
|
||||
"type":"unstarted"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"id":"5b2960f1-0aed-46bc-8ef5-8c983f7ef3c1",
|
||||
"changed_at":"2018-06-19T20:00:49.707Z",
|
||||
"primary_id":21,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":21,
|
||||
"entity_type":"epic-comment",
|
||||
"action":"create",
|
||||
"text":"Added a comment on this Epic!",
|
||||
"author_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"comment_ids":{
|
||||
"adds":[
|
||||
21
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"id":"5b29602a-4906-48d7-a30a-c6feaa938eaa",
|
||||
"changed_at":"2018-06-19T19:57:30.443Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"Added a description!",
|
||||
"old":""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"id":"5b29605e-df5c-4d9a-b37c-d89c9d59400e",
|
||||
"changed_at":"2018-06-19T19:58:22.497Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"Changed a description!",
|
||||
"old":"Added a description!"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"id":"5b296195-5a9d-450f-9b1f-85fe8f4de79e",
|
||||
"changed_at":"2018-06-19T20:03:33.124Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"started_at":{
|
||||
"new":"2018-06-19T20:03:33Z"
|
||||
},
|
||||
"state":{
|
||||
"new":"in progress",
|
||||
"old":"to do"
|
||||
},
|
||||
"epic_state_id":{
|
||||
"new":500000003,
|
||||
"old":500000002
|
||||
},
|
||||
"started":{
|
||||
"new":true,
|
||||
"old":false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":500000003,
|
||||
"entity_type":"epic-state",
|
||||
"name":"in progress",
|
||||
"type":"started"
|
||||
},
|
||||
{
|
||||
"id":500000002,
|
||||
"entity_type":"epic-state",
|
||||
"name":"to do",
|
||||
"type":"unstarted"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"id":"5b295f9e-171b-4d5c-bb45-2b709eb0ad4f",
|
||||
"changed_at":"2018-06-19T19:55:10.245Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"name":{
|
||||
"new":"New Cool Epic!",
|
||||
"old":"New Epic!"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"id":"5b296099-86f1-493c-a2c7-ad3b6a8f2151",
|
||||
"changed_at":"2018-06-19T19:59:21.194Z",
|
||||
"primary_id":20,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":20,
|
||||
"entity_type":"epic",
|
||||
"action":"update",
|
||||
"name":"New Cool Epic!",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"",
|
||||
"old":"Changed a description!"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b2961f2-a2d0-449c-a4da-e9db7c69e10c",
|
||||
"changed_at":"2018-06-19T20:05:06.722Z",
|
||||
"primary_id":9,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":9,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Story 2",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/9",
|
||||
"changes":{
|
||||
"archived":{
|
||||
"new":true,
|
||||
"old":false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"id":"5b1fdcea-4b6a-4128-9f78-7e58214191fc",
|
||||
"changed_at":"2018-06-12T14:47:06.221Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"create",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"project_id":6,
|
||||
"description":"We should probably add this cool feature!",
|
||||
"workflow_state_id":500000008,
|
||||
"follower_ids":[
|
||||
"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
],
|
||||
"requested_by_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":6,
|
||||
"entity_type":"project",
|
||||
"name":"Backend"
|
||||
},
|
||||
{
|
||||
"id":500000008,
|
||||
"entity_type":"workflow-state",
|
||||
"name":"Unscheduled",
|
||||
"type":"unstarted"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b1fe806-f582-4b45-ac64-44cc7567a5d7",
|
||||
"changed_at":"2018-06-12T15:34:30.005Z",
|
||||
"primary_id":15,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":15,
|
||||
"entity_type":"story-task",
|
||||
"action":"update",
|
||||
"description":"A new task for this story",
|
||||
"story_id":11,
|
||||
"changes":{
|
||||
"complete":{
|
||||
"new":true,
|
||||
"old":false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b1fe66d-25b8-4838-9880-9a4169d369d7",
|
||||
"changed_at":"2018-06-12T15:27:41.816Z",
|
||||
"primary_id":14,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":14,
|
||||
"entity_type":"story-task",
|
||||
"action":"create",
|
||||
"description":"Added a new task",
|
||||
"complete":false
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"task_ids":{
|
||||
"adds":[
|
||||
14
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"id":"5b1fe779-e8d0-4a4d-a8d3-3d179da7b55e",
|
||||
"changed_at":"2018-06-12T15:32:09.246Z",
|
||||
"primary_id":14,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":14,
|
||||
"entity_type":"story-task",
|
||||
"action":"delete",
|
||||
"description":"Added a new task"
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"task_ids":{
|
||||
"removes":[
|
||||
14
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b1fe806-f582-4b45-ac64-44cc7567a5d7",
|
||||
"changed_at":"2018-06-12T15:34:30.005Z",
|
||||
"primary_id":15,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":15,
|
||||
"entity_type":"story-task",
|
||||
"action":"update",
|
||||
"description":"A new task for this story",
|
||||
"story_id":11,
|
||||
"changes":{
|
||||
"complete":{
|
||||
"new":false,
|
||||
"old":true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b2961f2-a2d0-449c-a4da-e9db7c69e10c",
|
||||
"changed_at":"2018-06-19T20:05:06.722Z",
|
||||
"primary_id":9,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":9,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Story 2",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/9",
|
||||
"changes":{
|
||||
"archived":{
|
||||
"new":false,
|
||||
"old":true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b1fdf0a-80c2-4c95-907b-899efa86374f",
|
||||
"changed_at":"2018-06-12T14:56:10.984Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"file_ids":{
|
||||
"adds":[
|
||||
13
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":13,
|
||||
"entity_type":"file",
|
||||
"name":"zuliprc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b1fdde6-c65d-4a20-a748-ec6d55bca140",
|
||||
"changed_at":"2018-06-12T14:51:18.822Z",
|
||||
"primary_id":12,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":12,
|
||||
"entity_type":"story-comment",
|
||||
"action":"create",
|
||||
"text":"Just leaving a comment here!",
|
||||
"author_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"comment_ids":{
|
||||
"adds":[
|
||||
12
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b1feaa3-b3ad-40ec-b6a7-732febad698f",
|
||||
"changed_at":"2018-06-12T15:45:39.951Z",
|
||||
"primary_id":9,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":9,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Story 2",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/9",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"Added a description.",
|
||||
"old":""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"id":"5b1fe052-2ebf-4efd-92f7-64ecdb555af7",
|
||||
"changed_at":"2018-06-12T15:01:38.093Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"feature",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"epic_id":{
|
||||
"new":7
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":7,
|
||||
"entity_type":"epic",
|
||||
"name":"Release 1.9"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"id":"5b1ff439-0a94-454d-9aa5-a1192f6a8603",
|
||||
"changed_at":"2018-06-12T16:26:33.129Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"estimate":{
|
||||
"new":4
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"id":"5b295c2c-f734-4a1a-a3a5-03c2594ef2d8",
|
||||
"changed_at":"2018-06-19T19:40:28.185Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"label_ids":{
|
||||
"adds":[
|
||||
18
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"entity_type":"label",
|
||||
"action":"create",
|
||||
"name":"mockup"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"id":"5b1fefb0-45f1-4e20-bacb-b8038867fa54",
|
||||
"changed_at":"2018-06-12T16:07:12.821Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"epic_id":{
|
||||
"new":17,
|
||||
"old":7
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":17,
|
||||
"entity_type":"epic",
|
||||
"name":"Clubhouse Fork"
|
||||
},
|
||||
{
|
||||
"id":7,
|
||||
"entity_type":"epic",
|
||||
"name":"Release 1.9"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b1ff494-3127-424b-bf77-bbdd17a5a59d",
|
||||
"changed_at":"2018-06-12T16:28:04.923Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"estimate":{
|
||||
"new":4,
|
||||
"old":1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"id":"5b1fed7e-3dc6-47e5-b6af-8820bf6e5554",
|
||||
"changed_at":"2018-06-12T15:57:50.741Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"project_id":{
|
||||
"new":16,
|
||||
"old":6
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":16,
|
||||
"entity_type":"project",
|
||||
"name":"Devops"
|
||||
},
|
||||
{
|
||||
"id":6,
|
||||
"entity_type":"project",
|
||||
"name":"Backend"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"id":"5b1fe334-1258-408e-85eb-8ecb6acdcc82",
|
||||
"changed_at":"2018-06-12T15:13:56.523Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"started":{
|
||||
"new":true,
|
||||
"old":false
|
||||
},
|
||||
"workflow_state_id":{
|
||||
"new":500000010,
|
||||
"old":500000008
|
||||
},
|
||||
"started_at":{
|
||||
"new":"2018-06-12T15:13:56Z"
|
||||
},
|
||||
"owner_ids":{
|
||||
"adds":[
|
||||
"5b1fda16-626f-487f-9ecf-f3a4abf42b8b"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":500000010,
|
||||
"entity_type":"workflow-state",
|
||||
"name":"Ready for Review",
|
||||
"type":"started"
|
||||
},
|
||||
{
|
||||
"id":500000008,
|
||||
"entity_type":"workflow-state",
|
||||
"name":"Unscheduled",
|
||||
"type":"unstarted"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b295e00-4bff-401e-ac41-23408c878ec9",
|
||||
"changed_at":"2018-06-19T19:48:16.817Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add super cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"name":{
|
||||
"new":"Add super cool feature!",
|
||||
"old":"Add cool feature!"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b1fe22b-b0b4-4bd4-b73f-c89eedfbfbbe",
|
||||
"changed_at":"2018-06-12T15:09:31.659Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"story_type":{
|
||||
"new":"bug",
|
||||
"old":"feature"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b1fe4a4-0402-4f06-af4c-0d676e8f0e23",
|
||||
"changed_at":"2018-06-12T15:20:04.324Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"We should probably add this cool feature! Just edited this. :)",
|
||||
"old":"We should probably add this cool feature!"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b295afb-47df-420b-953d-62ec73ab043d",
|
||||
"changed_at":"2018-06-19T19:35:23.772Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"file_ids":{
|
||||
"removes":[
|
||||
13
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":13,
|
||||
"entity_type":"file",
|
||||
"name":"zuliprc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id":"5b1ff306-741f-4084-a544-be7c0b078ebc",
|
||||
"changed_at":"2018-06-12T16:21:26.472Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"description":{
|
||||
"new":"",
|
||||
"old":"We should probably add this cool feature! Just edited this. :)"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"id":"5b1feccb-fb21-4c00-ab51-999728f8c2c1",
|
||||
"changed_at":"2018-06-12T15:54:51.986Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"epic_id":{
|
||||
"old":7
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":7,
|
||||
"entity_type":"epic",
|
||||
"name":"Release 1.9"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"id":"5b1ff466-e71a-48f6-9cf6-5fb021c65894",
|
||||
"changed_at":"2018-06-12T16:27:18.704Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"estimate":{
|
||||
"old":4
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"id":"5b295cc0-242a-4ecf-b75c-e2467c25513c",
|
||||
"changed_at":"2018-06-19T19:42:56.825Z",
|
||||
"primary_id":11,
|
||||
"version":"v1",
|
||||
"member_id":"5b1fda16-626f-487f-9ecf-f3a4abf42b8b",
|
||||
"actions":[
|
||||
{
|
||||
"id":11,
|
||||
"entity_type":"story",
|
||||
"action":"update",
|
||||
"name":"Add cool feature!",
|
||||
"story_type":"bug",
|
||||
"app_url":"https://app.clubhouse.io/zulip/story/11",
|
||||
"changes":{
|
||||
"label_ids":{
|
||||
"removes":[
|
||||
18
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"references":[
|
||||
{
|
||||
"id":18,
|
||||
"entity_type":"label",
|
||||
"name":"mockup"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
from mock import MagicMock, patch
|
||||
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
|
||||
class ClubhouseWebhookTest(WebhookTestCase):
|
||||
STREAM_NAME = 'clubhouse'
|
||||
URL_TEMPLATE = "/api/v1/external/clubhouse?stream={stream}&api_key={api_key}"
|
||||
FIXTURE_DIR_NAME = 'clubhouse'
|
||||
|
||||
def test_story_create(self) -> None:
|
||||
expected_message = u"New story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) of type **feature** was created."
|
||||
self.send_and_test_stream_message(
|
||||
'story_create', "Add cool feature!",
|
||||
expected_message
|
||||
)
|
||||
|
||||
def test_epic_story_create(self) -> None:
|
||||
expected_message = u"New story [An epic story!](https://app.clubhouse.io/zulip/story/23) was created and added to the epic **New Cool Epic!**."
|
||||
self.send_and_test_stream_message(
|
||||
'epic_create_story', "An epic story!",
|
||||
expected_message
|
||||
)
|
||||
|
||||
def test_story_archive(self) -> None:
|
||||
expected_message = u"The story [Story 2](https://app.clubhouse.io/zulip/story/9) was archived."
|
||||
self.send_and_test_stream_message('story_archive', "Story 2", expected_message)
|
||||
|
||||
def test_story_unarchive(self) -> None:
|
||||
expected_message = u"The story [Story 2](https://app.clubhouse.io/zulip/story/9) was unarchived."
|
||||
self.send_and_test_stream_message('story_unarchive', "Story 2", expected_message)
|
||||
|
||||
def test_epic_create(self) -> None:
|
||||
expected_message = u"New epic **New Epic!**(to do) was created."
|
||||
self.send_and_test_stream_message('epic_create', "New Epic!", expected_message)
|
||||
|
||||
def test_epic_update_add_comment(self) -> None:
|
||||
expected_message = u"New comment added to the epic **New Cool Epic!**:\n``` quote\nAdded a comment on this Epic!\n```"
|
||||
self.send_and_test_stream_message('epic_update_add_comment',
|
||||
"New Cool Epic!", expected_message)
|
||||
|
||||
def test_story_update_add_comment(self) -> None:
|
||||
expected_message = u"New comment added to the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11):\n``` quote\nJust leaving a comment here!\n```"
|
||||
self.send_and_test_stream_message('story_update_add_comment',
|
||||
"Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_epic_update_add_description(self) -> None:
|
||||
expected_message = u"New description added to the epic **New Cool Epic!**:\n``` quote\nAdded a description!\n```"
|
||||
self.send_and_test_stream_message('epic_update_add_description',
|
||||
"New Cool Epic!", expected_message)
|
||||
|
||||
def test_epic_update_remove_description(self) -> None:
|
||||
expected_message = u"Description for the epic **New Cool Epic!** was removed."
|
||||
self.send_and_test_stream_message('epic_update_remove_description',
|
||||
"New Cool Epic!", expected_message)
|
||||
|
||||
def test_epic_update_change_description(self) -> None:
|
||||
expected_message = u"Description for the epic **New Cool Epic!** was changed from:\n``` quote\nAdded a description!\n```\nto\n``` quote\nChanged a description!\n```"
|
||||
self.send_and_test_stream_message('epic_update_change_description',
|
||||
"New Cool Epic!", expected_message)
|
||||
|
||||
def test_story_update_add_description(self) -> None:
|
||||
expected_message = u"New description added to the story [Story 2](https://app.clubhouse.io/zulip/story/9):\n``` quote\nAdded a description.\n```"
|
||||
self.send_and_test_stream_message('story_update_add_description',
|
||||
"Story 2", expected_message)
|
||||
|
||||
def test_story_update_remove_description(self) -> None:
|
||||
expected_message = u"Description for the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was removed."
|
||||
self.send_and_test_stream_message('story_update_remove_description',
|
||||
"Add cool feature!", expected_message)
|
||||
|
||||
def test_story_update_change_description(self) -> None:
|
||||
expected_message = u"Description for the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was changed from:\n``` quote\nWe should probably add this cool feature!\n```\nto\n``` quote\nWe should probably add this cool feature! Just edited this. :)\n```"
|
||||
self.send_and_test_stream_message('story_update_description',
|
||||
"Add cool feature!", expected_message)
|
||||
|
||||
def test_epic_update_change_state(self) -> None:
|
||||
expected_message = u"State of the epic **New Cool Epic!** was changed from **to do** to **in progress**."
|
||||
self.send_and_test_stream_message('epic_update_change_state',
|
||||
"New Cool Epic!", expected_message)
|
||||
|
||||
def test_story_update_change_state(self) -> None:
|
||||
expected_message = u"State of the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was changed from **Unscheduled** to **Ready for Review**."
|
||||
self.send_and_test_stream_message('story_update_change_state',
|
||||
"Add cool feature!", expected_message)
|
||||
|
||||
def test_epic_update_change_name(self) -> None:
|
||||
expected_message = u"The name of the epic **New Cool Epic!** was changed from:\n``` quote\nNew Epic!\n```\nto\n``` quote\nNew Cool Epic!\n```"
|
||||
self.send_and_test_stream_message('epic_update_change_title', "New Cool Epic!",
|
||||
expected_message)
|
||||
|
||||
def test_story_update_change_name(self) -> None:
|
||||
expected_message = u"The name of the story [Add super cool feature!](https://app.clubhouse.io/zulip/story/11) was changed from:\n``` quote\nAdd cool feature!\n```\nto\n``` quote\nAdd super cool feature!\n```"
|
||||
self.send_and_test_stream_message('story_update_change_title', "Add super cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_task_created(self) -> None:
|
||||
expected_message = u"Task **Added a new task** was added to the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11)."
|
||||
self.send_and_test_stream_message('story_task_create', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_task_deleted(self) -> None:
|
||||
expected_message = u"Task **Added a new task** was removed from the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11)."
|
||||
self.send_and_test_stream_message('story_task_delete', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_task_completed(self) -> None:
|
||||
expected_message = u"Task **A new task for this story** ([Add cool feature!](https://app.clubhouse.io/zulip/story/11)) was completed. :tada:"
|
||||
self.send_and_test_stream_message('story_task_complete', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
@patch('zerver.lib.webhooks.common.check_send_webhook_message')
|
||||
def test_story_task_incomplete_ignore(
|
||||
self, check_send_webhook_message_mock: MagicMock) -> None:
|
||||
payload = self.get_body('story_task_not_complete')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_webhook_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_story_epic_changed(self) -> None:
|
||||
expected_message = (u"The story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was moved from **Release 1.9**"
|
||||
u" to **Clubhouse Fork**.")
|
||||
self.send_and_test_stream_message('story_update_change_epic', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_epic_added(self) -> None:
|
||||
expected_message = u"The story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was added to the epic **Release 1.9**."
|
||||
self.send_and_test_stream_message('story_update_add_epic', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_epic_removed(self) -> None:
|
||||
expected_message = u"The story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was removed from the epic **Release 1.9**."
|
||||
self.send_and_test_stream_message('story_update_remove_epic', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_estimate_changed(self) -> None:
|
||||
expected_message = u"The estimate for the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was set to 4 points."
|
||||
self.send_and_test_stream_message('story_update_change_estimate', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_estimate_added(self) -> None:
|
||||
expected_message = u"The estimate for the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was set to 4 points."
|
||||
self.send_and_test_stream_message('story_update_add_estimate', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_estimate_removed(self) -> None:
|
||||
expected_message = u"The estimate for the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was set to *Unestimated*."
|
||||
self.send_and_test_stream_message('story_update_remove_estimate', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_file_attachment_added(self) -> None:
|
||||
expected_message = u"A file attachment `zuliprc` was added to the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11)."
|
||||
self.send_and_test_stream_message('story_update_add_attachment', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
@patch('zerver.lib.webhooks.common.check_send_webhook_message')
|
||||
def test_story_file_attachment_removed_ignore(
|
||||
self, check_send_webhook_message_mock: MagicMock) -> None:
|
||||
payload = self.get_body('story_update_remove_attachment')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_webhook_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_story_label_added(self) -> None:
|
||||
expected_message = u"The label **mockup** was added to the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11)."
|
||||
self.send_and_test_stream_message('story_update_add_label', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
@patch('zerver.lib.webhooks.common.check_send_webhook_message')
|
||||
def test_story_label_removed_ignore(
|
||||
self, check_send_webhook_message_mock: MagicMock) -> None:
|
||||
payload = self.get_body('story_update_remove_label')
|
||||
result = self.client_post(self.url, payload, content_type="application/json")
|
||||
self.assertFalse(check_send_webhook_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_story_update_project(self) -> None:
|
||||
expected_message = u"The story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was moved from the **Backend** project to **Devops**."
|
||||
self.send_and_test_stream_message('story_update_change_project', "Add cool feature!",
|
||||
expected_message)
|
||||
|
||||
def test_story_update_type(self) -> None:
|
||||
expected_message = u"The type of the story [Add cool feature!](https://app.clubhouse.io/zulip/story/11) was changed from **feature** to **bug**."
|
||||
self.send_and_test_stream_message('story_update_change_type', "Add cool feature!",
|
||||
expected_message)
|
|
@ -0,0 +1,448 @@
|
|||
from functools import partial
|
||||
from typing import Any, Dict, Iterable, Optional
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
from zerver.decorator import api_key_only_webhook_view
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.lib.request import REQ, has_request_variables
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.models import UserProfile
|
||||
|
||||
|
||||
EPIC_NAME_TEMPLATE = "**{name}**"
|
||||
STORY_NAME_TEMPLATE = "[{name}]({app_url})"
|
||||
COMMENT_ADDED_TEMPLATE = "New comment added to the {entity} {name_template}:\n``` quote\n{text}\n```"
|
||||
NEW_DESC_ADDED_TEMPLATE = "New description added to the {entity} {name_template}:\n``` quote\n{new}\n```"
|
||||
DESC_CHANGED_TEMPLATE = ("Description for the {entity} {name_template} was changed from:\n"
|
||||
"``` quote\n{old}\n```\nto\n``` quote\n{new}\n```")
|
||||
DESC_REMOVED_TEMPLATE = "Description for the {entity} {name_template} was removed."
|
||||
STATE_CHANGED_TEMPLATE = "State of the {entity} {name_template} was changed from **{old}** to **{new}**."
|
||||
NAME_CHANGED_TEMPLATE = ("The name of the {entity} {name_template} was changed from:\n"
|
||||
"``` quote\n{old}\n```\nto\n``` quote\n{new}\n```")
|
||||
STORY_ARCHIVED_TEMPLATE = "The story {name_template} was {action}."
|
||||
STORY_TASK_TEMPLATE = "Task **{task_description}** was {action} the story {name_template}."
|
||||
STORY_TASK_COMPLETED_TEMPLATE = "Task **{task_description}** ({name_template}) was completed. :tada:"
|
||||
STORY_ADDED_REMOVED_EPIC_TEMPLATE = ("The story {story_name_template} was {action} the"
|
||||
" epic {epic_name_template}.")
|
||||
STORY_EPIC_CHANGED_TEMPLATE = ("The story {story_name_template} was moved from {old_epic_name_template}"
|
||||
" to {new_epic_name_template}.")
|
||||
STORY_ESTIMATE_TEMPLATE = "The estimate for the story {story_name_template} was set to {estimate}."
|
||||
FILE_ATTACHMENT_TEMPLATE = "A {type} attachment `{file_name}` was added to the story {name_template}."
|
||||
STORY_LABEL_TEMPLATE = "The label **{label_name}** was added to the story {name_template}."
|
||||
STORY_UPDATE_PROJECT_TEMPLATE = ("The story {name_template} was moved from"
|
||||
" the **{old}** project to **{new}**.")
|
||||
STORY_UPDATE_TYPE_TEMPLATE = ("The type of the story {name_template} was changed"
|
||||
" from **{old_type}** to **{new_type}**.")
|
||||
|
||||
|
||||
def get_action_with_primary_id(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
for action in payload["actions"]:
|
||||
if payload["primary_id"] == action["id"]:
|
||||
action_with_primary_id = action
|
||||
|
||||
return action_with_primary_id
|
||||
|
||||
def get_body_function_based_on_type(payload: Dict[str, Any]) -> Any:
|
||||
action = get_action_with_primary_id(payload)
|
||||
event = "{}_{}".format(action["entity_type"], action["action"])
|
||||
|
||||
changes = action.get("changes")
|
||||
if changes is not None:
|
||||
if changes.get("description") is not None:
|
||||
event = "{}_{}".format(event, "description")
|
||||
elif changes.get("state") is not None:
|
||||
event = "{}_{}".format(event, "state")
|
||||
elif changes.get("workflow_state_id") is not None:
|
||||
event = "{}_{}".format(event, "state")
|
||||
elif changes.get("name") is not None:
|
||||
event = "{}_{}".format(event, "name")
|
||||
elif changes.get("archived") is not None:
|
||||
event = "{}_{}".format(event, "archived")
|
||||
elif changes.get("complete") is not None:
|
||||
event = "{}_{}".format(event, "complete")
|
||||
elif changes.get("epic_id") is not None:
|
||||
event = "{}_{}".format(event, "epic")
|
||||
elif changes.get("estimate") is not None:
|
||||
event = "{}_{}".format(event, "estimate")
|
||||
elif changes.get("file_ids") is not None:
|
||||
event = "{}_{}".format(event, "attachment")
|
||||
elif changes.get("label_ids") is not None:
|
||||
event = "{}_{}".format(event, "label")
|
||||
elif changes.get("project_id") is not None:
|
||||
event = "{}_{}".format(event, "project")
|
||||
elif changes.get("story_type") is not None:
|
||||
event = "{}_{}".format(event, "type")
|
||||
|
||||
return EVENT_BODY_FUNCTION_MAPPER.get(event)
|
||||
|
||||
def get_topic_function_based_on_type(payload: Dict[str, Any]) -> Any:
|
||||
entity_type = get_action_with_primary_id(payload)["entity_type"]
|
||||
return EVENT_TOPIC_FUNCTION_MAPPER.get(entity_type)
|
||||
|
||||
def get_story_create_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
if action.get("epic_id") is None:
|
||||
message = "New story [{name}]({app_url}) of type **{story_type}** was created."
|
||||
kwargs = action
|
||||
else:
|
||||
message = "New story [{name}]({app_url}) was created and added to the epic **{epic_name}**."
|
||||
kwargs = {
|
||||
"name": action["name"],
|
||||
"app_url": action["app_url"],
|
||||
}
|
||||
epic_id = action["epic_id"]
|
||||
refs = payload["references"]
|
||||
for ref in refs:
|
||||
if ref["id"] == epic_id:
|
||||
kwargs["epic_name"] = ref["name"]
|
||||
|
||||
return message.format(**kwargs)
|
||||
|
||||
def get_epic_create_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
message = "New epic **{name}**({state}) was created."
|
||||
return message.format(**action)
|
||||
|
||||
def get_comment_added_body(payload: Dict[str, Any], entity: str) -> str:
|
||||
actions = payload["actions"]
|
||||
kwargs = {"entity": entity}
|
||||
for action in actions:
|
||||
if action["id"] == payload["primary_id"]:
|
||||
kwargs["text"] = action["text"]
|
||||
elif action["entity_type"] == entity:
|
||||
name_template = get_name_template(entity).format(
|
||||
name=action["name"],
|
||||
app_url=action.get("app_url")
|
||||
)
|
||||
kwargs["name_template"] = name_template
|
||||
|
||||
return COMMENT_ADDED_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_update_description_body(payload: Dict[str, Any], entity: str) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
desc = action["changes"]["description"]
|
||||
|
||||
kwargs = {
|
||||
"entity": entity,
|
||||
"new": desc["new"],
|
||||
"old": desc["old"],
|
||||
"name_template": get_name_template(entity).format(
|
||||
name=action["name"],
|
||||
app_url=action.get("app_url")
|
||||
)
|
||||
}
|
||||
|
||||
if kwargs["new"] and kwargs["old"]:
|
||||
body = DESC_CHANGED_TEMPLATE.format(**kwargs)
|
||||
elif kwargs["new"]:
|
||||
body = NEW_DESC_ADDED_TEMPLATE.format(**kwargs)
|
||||
else:
|
||||
body = DESC_REMOVED_TEMPLATE.format(**kwargs)
|
||||
|
||||
return body
|
||||
|
||||
def get_epic_update_state_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
state = action["changes"]["state"]
|
||||
kwargs = {
|
||||
"entity": "epic",
|
||||
"new": state["new"],
|
||||
"old": state["old"],
|
||||
"name_template": EPIC_NAME_TEMPLATE.format(name=action["name"])
|
||||
}
|
||||
|
||||
return STATE_CHANGED_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_state_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
workflow_state_id = action["changes"]["workflow_state_id"]
|
||||
references = payload["references"]
|
||||
|
||||
state = {}
|
||||
for ref in references:
|
||||
if ref["id"] == workflow_state_id["new"]:
|
||||
state["new"] = ref["name"]
|
||||
if ref["id"] == workflow_state_id["old"]:
|
||||
state["old"] = ref["name"]
|
||||
|
||||
kwargs = {
|
||||
"entity": "story",
|
||||
"new": state["new"],
|
||||
"old": state["old"],
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action.get("app_url"),
|
||||
)
|
||||
}
|
||||
|
||||
return STATE_CHANGED_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_update_name_body(payload: Dict[str, Any], entity: str) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
name = action["changes"]["name"]
|
||||
kwargs = {
|
||||
"entity": entity,
|
||||
"new": name["new"],
|
||||
"old": name["old"],
|
||||
"name_template": get_name_template(entity).format(
|
||||
name=action["name"],
|
||||
app_url=action.get("app_url")
|
||||
)
|
||||
}
|
||||
|
||||
return NAME_CHANGED_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_archived_body(payload: Dict[str, Any]) -> str:
|
||||
primary_action = get_action_with_primary_id(payload)
|
||||
archived = primary_action["changes"]["archived"]
|
||||
if archived["new"]:
|
||||
action = "archived"
|
||||
else:
|
||||
action = "unarchived"
|
||||
|
||||
kwargs = {
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=primary_action["name"],
|
||||
app_url=primary_action.get("app_url")
|
||||
),
|
||||
"action": action,
|
||||
}
|
||||
|
||||
return STORY_ARCHIVED_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_task_body(payload: Dict[str, Any], action: str) -> str:
|
||||
primary_action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"task_description": primary_action["description"],
|
||||
"action": action,
|
||||
}
|
||||
|
||||
for a in payload["actions"]:
|
||||
if a["entity_type"] == "story":
|
||||
kwargs["name_template"] = STORY_NAME_TEMPLATE.format(
|
||||
name=a["name"],
|
||||
app_url=a["app_url"],
|
||||
)
|
||||
|
||||
return STORY_TASK_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_task_completed_body(payload: Dict[str, Any]) -> Optional[str]:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"task_description": action["description"],
|
||||
}
|
||||
|
||||
story_id = action["story_id"]
|
||||
for ref in payload["references"]:
|
||||
if ref["id"] == story_id:
|
||||
kwargs["name_template"] = STORY_NAME_TEMPLATE.format(
|
||||
name=ref["name"],
|
||||
app_url=ref["app_url"],
|
||||
)
|
||||
|
||||
if action["changes"]["complete"]["new"]:
|
||||
return STORY_TASK_COMPLETED_TEMPLATE.format(**kwargs)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_story_update_epic_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"story_name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
),
|
||||
}
|
||||
|
||||
new_id = action["changes"]["epic_id"].get("new")
|
||||
old_id = action["changes"]["epic_id"].get("old")
|
||||
|
||||
for ref in payload["references"]:
|
||||
if ref["id"] == new_id:
|
||||
kwargs["new_epic_name_template"] = EPIC_NAME_TEMPLATE.format(
|
||||
name=ref["name"])
|
||||
|
||||
if ref["id"] == old_id:
|
||||
kwargs["old_epic_name_template"] = EPIC_NAME_TEMPLATE.format(
|
||||
name=ref["name"])
|
||||
|
||||
if new_id and old_id:
|
||||
return STORY_EPIC_CHANGED_TEMPLATE.format(**kwargs)
|
||||
elif new_id:
|
||||
kwargs["epic_name_template"] = kwargs["new_epic_name_template"]
|
||||
kwargs["action"] = "added to"
|
||||
else:
|
||||
kwargs["epic_name_template"] = kwargs["old_epic_name_template"]
|
||||
kwargs["action"] = "removed from"
|
||||
|
||||
return STORY_ADDED_REMOVED_EPIC_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_estimate_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"story_name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
),
|
||||
}
|
||||
|
||||
new = action["changes"]["estimate"].get("new")
|
||||
if new:
|
||||
kwargs["estimate"] = "{} points".format(new)
|
||||
else:
|
||||
kwargs["estimate"] = "*Unestimated*"
|
||||
|
||||
return STORY_ESTIMATE_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_attachment_body(payload: Dict[str, Any]) -> Optional[str]:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
)
|
||||
}
|
||||
file_ids_added = action["changes"]["file_ids"].get("adds")
|
||||
|
||||
# If this is a payload for when an attachment is removed, ignore it
|
||||
if not file_ids_added:
|
||||
return None
|
||||
|
||||
file_id = file_ids_added[0]
|
||||
for ref in payload["references"]:
|
||||
if ref["id"] == file_id:
|
||||
kwargs.update({
|
||||
"type": ref["entity_type"],
|
||||
"file_name": ref["name"],
|
||||
})
|
||||
|
||||
return FILE_ATTACHMENT_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_label_body(payload: Dict[str, Any]) -> Optional[str]:
|
||||
action = get_action_with_primary_id(payload)
|
||||
|
||||
kwargs = {
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
)
|
||||
}
|
||||
label_ids_added = action["changes"]["label_ids"].get("adds")
|
||||
|
||||
# If this is a payload for when a label is removed, ignore it
|
||||
if not label_ids_added:
|
||||
return None
|
||||
|
||||
label_id = label_ids_added[0]
|
||||
for action in payload["actions"]:
|
||||
if action["id"] == label_id:
|
||||
kwargs.update({"label_name": action["name"]})
|
||||
|
||||
return STORY_LABEL_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_project_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
kwargs = {
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
)
|
||||
}
|
||||
|
||||
new_project_id = action["changes"]["project_id"]["new"]
|
||||
old_project_id = action["changes"]["project_id"]["old"]
|
||||
for ref in payload["references"]:
|
||||
if ref["id"] == new_project_id:
|
||||
kwargs.update({"new": ref["name"]})
|
||||
if ref["id"] == old_project_id:
|
||||
kwargs.update({"old": ref["name"]})
|
||||
|
||||
return STORY_UPDATE_PROJECT_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_story_update_type_body(payload: Dict[str, Any]) -> str:
|
||||
action = get_action_with_primary_id(payload)
|
||||
kwargs = {
|
||||
"name_template": STORY_NAME_TEMPLATE.format(
|
||||
name=action["name"],
|
||||
app_url=action["app_url"]
|
||||
),
|
||||
"new_type": action["changes"]["story_type"]["new"],
|
||||
"old_type": action["changes"]["story_type"]["old"]
|
||||
}
|
||||
|
||||
return STORY_UPDATE_TYPE_TEMPLATE.format(**kwargs)
|
||||
|
||||
def get_entity_name(payload: Dict[str, Any], entity: Optional[str]=None) -> Optional[str]:
|
||||
name = get_action_with_primary_id(payload).get("name")
|
||||
|
||||
if name is None:
|
||||
for action in payload["actions"]:
|
||||
if action["entity_type"] == entity:
|
||||
name = action["name"]
|
||||
|
||||
if name is None:
|
||||
for ref in payload["references"]:
|
||||
if ref["entity_type"] == entity:
|
||||
name = ref["name"]
|
||||
|
||||
return name
|
||||
|
||||
def get_name_template(entity: str) -> str:
|
||||
if entity == "story":
|
||||
return STORY_NAME_TEMPLATE
|
||||
return EPIC_NAME_TEMPLATE
|
||||
|
||||
EVENT_BODY_FUNCTION_MAPPER = {
|
||||
"story_update_archived": get_story_update_archived_body,
|
||||
"story_create": get_story_create_body,
|
||||
"story-task_create": partial(get_story_task_body, action="added to"),
|
||||
"story-task_delete": partial(get_story_task_body, action="removed from"),
|
||||
"story-task_update_complete": get_story_task_completed_body,
|
||||
"story_update_epic": get_story_update_epic_body,
|
||||
"story_update_estimate": get_story_update_estimate_body,
|
||||
"story_update_attachment": get_story_update_attachment_body,
|
||||
"story_update_label": get_story_label_body,
|
||||
"story_update_project": get_story_update_project_body,
|
||||
"story_update_type": get_story_update_type_body,
|
||||
"epic_create": get_epic_create_body,
|
||||
"epic-comment_create": partial(get_comment_added_body, entity='epic'),
|
||||
"story-comment_create": partial(get_comment_added_body, entity='story'),
|
||||
"epic_update_description": partial(get_update_description_body, entity='epic'),
|
||||
"story_update_description": partial(get_update_description_body, entity='story'),
|
||||
"epic_update_state": get_epic_update_state_body,
|
||||
"story_update_state": get_story_update_state_body,
|
||||
"epic_update_name": partial(get_update_name_body, entity='epic'),
|
||||
"story_update_name": partial(get_update_name_body, entity='story'),
|
||||
}
|
||||
|
||||
EVENT_TOPIC_FUNCTION_MAPPER = {
|
||||
"story": partial(get_entity_name, entity='story'),
|
||||
"story-comment": partial(get_entity_name, entity='story'),
|
||||
"story-task": partial(get_entity_name, entity='story'),
|
||||
"epic": partial(get_entity_name, entity='epic'),
|
||||
"epic-comment": partial(get_entity_name, entity='epic'),
|
||||
}
|
||||
|
||||
@api_key_only_webhook_view('ClubHouse')
|
||||
@has_request_variables
|
||||
def api_clubhouse_webhook(
|
||||
request: HttpRequest, user_profile: UserProfile,
|
||||
payload: Dict[str, Any]=REQ(argument_type='body')
|
||||
) -> HttpResponse:
|
||||
|
||||
body_func = get_body_function_based_on_type(payload)
|
||||
topic_func = get_topic_function_based_on_type(payload)
|
||||
topic = topic_func(payload)
|
||||
body = body_func(payload)
|
||||
|
||||
if topic and body:
|
||||
check_send_webhook_message(request, user_profile, topic, body)
|
||||
|
||||
return json_success()
|
Loading…
Reference in New Issue