integrations: Add webhook code, API endpoint, and tests for Opbeat.

This commit is contained in:
fredfishgames 2018-01-15 16:50:12 +00:00 committed by showell
parent b0fb7aa6b2
commit 4e2b99a98b
11 changed files with 354 additions and 166 deletions

View File

@ -330,6 +330,13 @@ WEBHOOK_INTEGRATIONS = [
WebhookIntegration('librato', ['monitoring']),
WebhookIntegration('mention', ['marketing'], display_name='Mention'),
WebhookIntegration('newrelic', ['monitoring'], display_name='New Relic'),
WebhookIntegration(
'opbeat',
['monitoring'],
display_name='Opbeat',
stream_name='opbeat',
function='zerver.webhooks.opbeat.view.api_opbeat_webhook'
),
WebhookIntegration('opsgenie', ['meta-integration', 'monitoring'], display_name='OpsGenie'),
WebhookIntegration('pagerduty', ['monitoring']),
WebhookIntegration('papertrail', ['monitoring']),

View File

View File

@ -1,148 +0,0 @@
{
"id": "5df00003ea4e42458db48446692f6d37",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/activities/5df00003ea4e42458db48446692f6d37",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/#activity-5df00003ea4e42458db48446692f6d37",
"author": {
"id": "5802edc6e84b4843b23edff00c6d300a",
"legacy_id": 14883,
"first_name": "Ivche",
"last_name": "E",
"email": "ivchepro@gmail.com",
"avatar": {
"40": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=40",
"80": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=80",
"180": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=180",
"240": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=240",
"120": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=120"
},
"html_url": "https://opbeat.com/account/settings/",
"type_name": "user"
},
"created": "2017-12-10T18:14:23Z",
"occurred": "2017-12-10T18:14:23Z",
"title": "Ivche commented on E#2",
"summary": "comment",
"organization": {
"id": "f9a77c5e6b044c2686612539fe4a3a6f",
"name": "topkek",
"short_name": "topkek",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f",
"type_name": "organization"
},
"app": {
"id": "53daf84bfc",
"name": "Test-flask-app",
"short_name": "test-flask-app",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc",
"type_name": "app"
},
"subject_type": "comment",
"subject": {
"id": "ca45bf96cd674b3eaa914251f0a08773",
"created": "2017-12-10T18:14:23Z",
"text": "comment",
"html": "<p>comment</p>",
"author": {
"id": "5802edc6e84b4843b23edff00c6d300a",
"legacy_id": 14883,
"first_name": "Ivche",
"last_name": "E",
"email": "ivchepro@gmail.com",
"avatar": {
"40": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=40",
"80": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=80",
"180": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=180",
"240": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=240",
"120": "https://secure.gravatar.com/avatar/cf936cf5a05314e692830f4d17ec434e?d=https%3A%2F%2Fopbeat.com%2Fstatic%2Fimages%2Fcommon%2Favatars%2Favatar_default_user.png&size=120"
},
"html_url": "https://opbeat.com/account/settings/",
"type_name": "user"
},
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/#activity-5df00003ea4e42458db48446692f6d37",
"subject_type": "errorgroup",
"subject": {
"id": "eac027998bc44fb0b2f6269eb0ab0418",
"number": 2,
"created": "2017-12-10T17:52:48Z",
"first_seen": "2017-12-10T17:52:47Z",
"last_seen": "2017-12-10T18:07:55Z",
"times_seen": {
"this_release": 10,
"total": 10,
"24h": 10.0,
"72h": 10.0
},
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/",
"links": {
"activities": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/activities",
"undo-mark-as-fixed": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-mark-fixed",
"mark-as-temporarily-ignored": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/temporarily-ignore",
"comments": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/comments",
"mark-as-fixed": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/mark-fixed",
"assignable-users": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/assignable-users",
"undo-mark-as-ignored": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-ignore",
"mark-as-ignored": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/ignore",
"undo-mark-as-temporarily-ignored": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-temporarily-ignore",
"assign": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/assign"
},
"last_occurrence": {
"id": "24210da90e5b4d659965b2e3ebf360f4",
"created": "2017-12-10T18:07:55Z",
"culprit": "",
"message": "A warning occurred (42 apples)",
"logger": "__main__",
"client_supplied_id": "13a4410d11724b30af92cd6ef1d556e8",
"extra": {
"thread": "140621113497408",
"process": "6120",
"threadName": "MainThread",
"stack_info": "None",
"module": "app",
"funcName": "foo",
"processName": "MainProcess",
"pathname": "app.py",
"lineno": "17",
"message": "A warning occurred (42 apples)",
"filename": "app.py"
},
"type_name": "errorlog"
},
"resolved_state": "regressed",
"allowed_resolve_transitions": [
"mark-as-temporarily-ignored",
"mark-as-fixed",
"mark-as-ignored"
],
"is_alarm": false,
"num_comments": 4,
"is_expired": false,
"type_name": "errorgroup",
"first_error": {
"id": "24210da90e5b4d659965b2e3ebf360f4",
"created": "2017-12-10T18:07:55Z",
"culprit": "",
"message": "A warning occurred (42 apples)",
"logger": "__main__",
"client_supplied_id": "13a4410d11724b30af92cd6ef1d556e8",
"extra": {
"thread": "140621113497408",
"process": "6120",
"threadName": "MainThread",
"stack_info": "None",
"module": "app",
"funcName": "foo",
"processName": "MainProcess",
"pathname": "app.py",
"lineno": "17",
"message": "A warning occurred (42 apples)",
"filename": "app.py"
},
"type_name": "errorlog"
}
},
"type_name": "comment"
},
"action": "created",
"type_name": "activity"
}

View File

@ -1,11 +1,11 @@
{
"id": "bf991a45d9184b0ca6fb3d48d3db4c38",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/activities/bf991a45d9184b0ca6fb3d48d3db4c38",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/#activity-bf991a45d9184b0ca6fb3d48d3db4c38",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/#activity-bf991a45d9184b0ca6fb3d48d3db4c38",
"author": {
"id": "5802edc6e84b4843b23edff00c6d300a",
"legacy_id": 14883,
"first_name": "Ivche",
"first_name": "foo",
"last_name": "E",
"email": "ivchepro@gmail.com",
"avatar": {
@ -20,12 +20,12 @@
},
"created": "2017-12-10T18:15:07Z",
"occurred": "2017-12-10T18:15:07Z",
"title": "Ivche marked E#2 as fixed",
"summary": "Ivche marked the error group as fixed",
"title": "foo marked E#2 as fixed",
"summary": "foo marked the error group as fixed",
"organization": {
"id": "f9a77c5e6b044c2686612539fe4a3a6f",
"name": "topkek",
"short_name": "topkek",
"name": "test_org",
"short_name": "test_org",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f",
"type_name": "organization"
},
@ -50,7 +50,7 @@
"72h": 10.0
},
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/",
"links": {
"activities": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/activities",
"undo-mark-as-fixed": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-mark-fixed",

View File

@ -1,11 +1,11 @@
{
"id": "38a556dfc0b04a59a586359bbce1463d",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/activities/38a556dfc0b04a59a586359bbce1463d",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/#activity-38a556dfc0b04a59a586359bbce1463d",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/#activity-38a556dfc0b04a59a586359bbce1463d",
"author": {
"id": "5802edc6e84b4843b23edff00c6d300a",
"legacy_id": 14883,
"first_name": "Ivche",
"first_name": "foo",
"last_name": "E",
"email": "ivchepro@gmail.com",
"avatar": {
@ -20,12 +20,12 @@
},
"created": "2017-12-10T18:15:39Z",
"occurred": "2017-12-10T18:15:39Z",
"title": "Ivche reopened E#2",
"summary": "Ivche reopened the error group",
"title": "foo reopened E#2",
"summary": "foo reopened the error group",
"organization": {
"id": "f9a77c5e6b044c2686612539fe4a3a6f",
"name": "topkek",
"short_name": "topkek",
"name": "test_org",
"short_name": "test_org",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f",
"type_name": "organization"
},
@ -50,7 +50,7 @@
"72h": 10.0
},
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/",
"links": {
"activities": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/activities",
"undo-mark-as-fixed": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-mark-fixed",

View File

@ -0,0 +1,37 @@
{
"id": "47f1f10158d94cbf93a0b539abc64b0f",
"html_url": null,
"title": "foo",
"summary": "App foo created",
"organization": {
"id": "27a4c0633f5c4a24a15a8896754145c4",
"name": "bar",
"short_name": "bar",
"url": "https://opbeat.com/api/v2/organizations/27a4c0633f5c4a24a15a8896754145c4",
"type_name": "organization"
},
"app": {
"id": "bdb4751769",
"name": "foo",
"short_name": "foo",
"url": "https://opbeat.com/api/v2/organizations/27a4c0633f5c4a24a15a8896754145c4/apps/bdb4751769",
"type_name": "app"
},
"subject_type": "app",
"subject": {
"id": "bdb4751769",
"created": "2018-01-03T11:16:49Z",
"name": "foo",
"short_name": "foo",
"settings": null,
"url": "https://opbeat.com/api/v2/organizations/27a4c0633f5c4a24a15a8896754145c4/apps/bdb4751769",
"html_url": "/bar/foo/",
"has_unread_notifications": false,
"has_metrics_available": false,
"language": "nodejs",
"framework": "custom",
"type_name": "app"
},
"action": "created",
"type_name": "activity"
}

View File

@ -0,0 +1,47 @@
{
"id": "5df00003ea4e42458db48446692f6d37",
"html_url": "https://opbeat.com/foo/test-flask-app/errors/2/#activity-5df00003ea4e42458db48446692f6d37",
"author": {
"first_name": "foo",
"last_name": "bar"
},
"title": "foo commented on E#2",
"summary": "test comment",
"subject_type": "comment",
"subject": {
"id": "ca45bf96cd674b3eaa914251f0a08773",
"text": "test comment",
"author": {
"id": "5802edc6e84b4843b23edff00c6d300a",
"first_name": "foo",
"last_name": "barE"
},
"html_url": "https://opbeat.com/foo/test-flask-app/errors/2/#activity-5df00003ea4e42458db48446692f6d37",
"subject_type": "errorgroup",
"subject": {
"id": "eac027998bc44fb0b2f6269eb0ab0418",
"number": 2,
"html_url": "https://opbeat.com/foo/test-flask-app/errors/2/",
"last_occurrence": {
"id": "24210da90e5b4d659965b2e3ebf360f4",
"created": "2017-12-10T18:07:55Z",
"culprit": "",
"message": "A warning occurred (42 apples)",
"logger": "__main__",
"client_supplied_id": "13a4410d11724b30af92cd6ef1d556e8",
"extra": {
"module": "app",
"funcName": "foo",
"processName": "MainProcess",
"pathname": "app.py",
"lineno": "17",
"message": "A warning occurred (42 apples)"
},
"type_name": "errorlog"
}
},
"type_name": "comment"
},
"action": "created",
"type_name": "activity"
}

View File

@ -2,15 +2,15 @@
{
"id": "c0396f38323a4fa7b314f87d5ed9cdd2",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/activities/c0396f38323a4fa7b314f87d5ed9cdd2",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/#activity-c0396f38323a4fa7b314f87d5ed9cdd2",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/#activity-c0396f38323a4fa7b314f87d5ed9cdd2",
"created": "2017-12-10T18:07:55Z",
"occurred": "2017-12-10T18:07:55Z",
"title": "E#2 regressed",
"summary": "The error group regressed",
"organization": {
"id": "f9a77c5e6b044c2686612539fe4a3a6f",
"name": "topkek",
"short_name": "topkek",
"name": "test_org",
"short_name": "test_org",
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f",
"type_name": "organization"
},
@ -35,7 +35,7 @@
"72h": 10.0
},
"url": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418",
"html_url": "https://opbeat.com/topkek/test-flask-app/errors/2/",
"html_url": "https://opbeat.com/test_org/test-flask-app/errors/2/",
"links": {
"activities": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/activities",
"undo-mark-as-fixed": "https://opbeat.com/api/v2/organizations/f9a77c5e6b044c2686612539fe4a3a6f/apps/53daf84bfc/errorgroups/eac027998bc44fb0b2f6269eb0ab0418/actions/undo-mark-fixed",

View File

@ -0,0 +1,30 @@
{
"id": "47f1f10158d94cbf93a0b539abc64b0f",
"html_url": null,
"title": "test title",
"summary": "test summary",
"organization": {
"id": "27a4c0633f5c4a24a15a8896754145c4",
"name": "bar",
"short_name": "bar",
"url": "https://opbeat.com/api/v2/organizations/27a4c0633f5c4a24a15a8896754145c4",
"type_name": "organization"
},
"app": {
"id": "bdb4751769",
"name": "foo",
"short_name": "foo",
"url": "https://opbeat.com/api/v2/organizations/27a4c0633f5c4a24a15a8896754145c4/apps/bdb4751769",
"type_name": "app"
},
"subject_type": "foo",
"subject": {
"id": "bdb4751769",
"created": "2018-01-03T11:16:49Z",
"name": "foo",
"short_name": "foo",
"settings": null
},
"action": "created",
"type_name": "activity"
}

View File

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
from typing import Text
from zerver.lib.test_classes import WebhookTestCase
from zerver.webhooks.opbeat.view import get_value
class OpbeatHookTests(WebhookTestCase):
STREAM_NAME = 'opbeat'
URL_TEMPLATE = u"/api/v1/external/opbeat?api_key={api_key}"
FIXTURE_DIR_NAME = 'opbeat'
def test_comment(self) -> None:
expected_subject = "foo commented on E#2"
expected_message = '''
**[foo commented on E#2](https://opbeat.com/foo/test-flask-app/errors/2/#activity-5df00003ea4e42458db48446692f6d37)**
test comment
**[E#2](https://opbeat.com/foo/test-flask-app/errors/2/)**
>**Most recent Occurrence**
>in app.py
>A warning occurred (42 apples)'''
self.send_and_test_stream_message('new_comment', expected_subject, expected_message,
content_type="application/json")
def test_new_app(self) -> None:
expected_subject = "foo"
expected_message = '''
**foo**
App foo created
**[foo](https://opbeat.com/bar/foo/)**
>language: nodejs
>framework: custom'''
self.send_and_test_stream_message('new_app', expected_subject, expected_message,
content_type="application/json")
def test_get_empty_value(self) -> None:
self.assertEqual(get_value({'key': 'value'}, 'foo'), '')
def test_no_subject_type(self) -> None:
expected_subject = "test title"
expected_message = '''
**test title**
test summary'''
self.send_and_test_stream_message(
'unsupported_object',
expected_subject,
expected_message,
content_type='application/json'
)
def test_error_fixed(self) -> None:
expected_subject = 'foo marked E#2 as fixed'
expected_message = '''
**[foo marked E#2 as fixed](https://opbeat.com/test_org/test-flask-app/errors/2/#activity-bf991a45d9184b0ca6fb3d48d3db4c38)**
foo marked the error group as fixed
**[E#2](https://opbeat.com/test_org/test-flask-app/errors/2/)**
>**Most recent Occurrence**
>in app.py
>A warning occurred (42 apples)'''
self.send_and_test_stream_message(
'error_fixed', expected_subject, expected_message, content_type='application/json')
def test_error_reopened(self) -> None:
expected_subject = 'foo reopened E#2'
expected_message = '''
**[foo reopened E#2](https://opbeat.com/test_org/test-flask-app/errors/2/#activity-38a556dfc0b04a59a586359bbce1463d)**
foo reopened the error group
**[E#2](https://opbeat.com/test_org/test-flask-app/errors/2/)**
>**Most recent Occurrence**
>in app.py
>A warning occurred (42 apples)'''
self.send_and_test_stream_message(
'error_reopen', expected_subject, expected_message, content_type='application/json')
def test_error_regressed(self) -> None:
expected_subject = 'E#2 regressed'
expected_message = '''
**[E#2 regressed](https://opbeat.com/test_org/test-flask-app/errors/2/#activity-c0396f38323a4fa7b314f87d5ed9cdd2)**
The error group regressed
**[E#2](https://opbeat.com/test_org/test-flask-app/errors/2/)**
>**Most recent Occurrence**
>in app.py
>A warning occurred (42 apples)'''
self.send_and_test_stream_message(
'new_error', expected_subject, expected_message, content_type='application/json')

View File

@ -0,0 +1,120 @@
# Webhooks for external integrations.
from typing import Text, Dict, Any, List, Tuple, Union
from django.http import HttpRequest, HttpResponse
from zerver.decorator import api_key_only_webhook_view
from zerver.lib.actions import check_send_stream_message
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.models import UserProfile, get_client
subject_types = {
'app': [ # Object type name
['name'], # Title
['html_url'], # Automatically put into title
['language'], # Other properties.
['framework']
],
'base': [
['title'],
['html_url'],
['#summary'],
['subject']
],
'comment': [
[''],
['subject']
],
'errorgroup': [
['E#{}', 'number'],
['html_url'],
['last_occurrence:error']
],
'error': [
[''],
['">**Most recent Occurrence**'],
['in {}', 'extra/pathname'],
['!message']
]
} # type: Dict[str, List[List[str]]]
def get_value(_obj: Dict[str, Any], key: str) -> str:
for _key in key.lstrip('!').split('/'):
if _key in _obj.keys():
_obj = _obj[_key]
else:
return ''
return str(_obj)
def format_object(
obj: Dict[str, Any],
subject_type: str,
message: str
) -> str:
if subject_type not in subject_types.keys():
return message
keys = subject_types[subject_type][1:] # type: List[List[str]]
title = subject_types[subject_type][0]
if title[0] != '':
title_str = ''
if len(title) > 1:
title_str = title[0].format(get_value(obj, title[1]))
else:
title_str = obj[title[0]]
if obj['html_url'] is not None:
url = obj['html_url'] # type: str
if 'opbeat.com' not in url:
url = 'https://opbeat.com/' + url.lstrip('/')
message += '\n**[{}]({})**'.format(title_str, url)
else:
message += '\n**{}**'.format(title_str)
for key_list in keys:
if len(key_list) > 1:
value = key_list[0].format(get_value(obj, key_list[1]))
message += '\n>{}'.format(value)
else:
key = key_list[0]
key_raw = key.lstrip('!').lstrip('#').lstrip('"')
if key_raw != 'html_url' and key_raw != 'subject' and ':' not in key_raw:
value = get_value(obj, key_raw)
if key.startswith('!'):
message += '\n>{}'.format(value)
elif key.startswith('#'):
message += '\n{}'.format(value)
elif key.startswith('"'):
message += '\n{}'.format(key_raw)
else:
message += '\n>{}: {}'.format(key, value)
if key == 'subject':
message = format_object(
obj['subject'], obj['subject_type'], message + '\n')
if ':' in key:
value, value_type = key.split(':')
message = format_object(obj[value], value_type, message + '\n')
return message
@api_key_only_webhook_view("Opbeat")
@has_request_variables
def api_opbeat_webhook(
request: HttpRequest,
user_profile: UserProfile,
payload: Dict[str, Any]=REQ(argument_type='body'),
stream: str=REQ(default="opbeat")
) -> HttpResponse:
"""
This uses the subject name from opbeat to make the subject,
and the summary from Opbeat as the message body, with
details about the object mentioned.
"""
message_subject = payload['title']
message = format_object(payload, 'base', '')
check_send_stream_message(user_profile, get_client('ZulipOpbeatWebhook'),
stream, message_subject, message)
return json_success()