Files
zulip/zerver/lib/integrations.py
wizsid11 95789eb879 Add Slack webhook.
Adds a new webhook integration for Slack to receive messages
from one's Slack team's public channels.
Contains negative tests for broken, missing or invalid data.

Allows two different option for integration:
1. Receive notification on a single stream with different topics
for each of Slack's public channels.
2. Receive notification on different streams for each of Slack's
public channels.

Steps to choose between the two options is described in the documentation.

Fixes #3569.
2017-03-23 23:32:38 -07:00

228 lines
9.4 KiB
Python

from typing import Dict, List, Optional, TypeVar
from django.conf import settings
from django.conf.urls import url
from django.core.urlresolvers import LocaleRegexProvider
from django.utils.module_loading import import_string
"""This module declares all of the (documented) integrations available
in the Zulip server. The Integration class is used as part of
generating the documentation on the /integrations page, while the
WebhookIntegration class is also used to generate the URLs in
`zproject/urls.py` for webhook integrations.
To add a new non-webhook integration, add code to the INTEGRATIONS
dictionary below.
To add a new webhook integration, declare a WebhookIntegration in the
WEBHOOK_INTEGRATIONS list below (it will be automatically added to
INTEGRATIONS).
Over time, we expect this registry to grow additional convenience
features for writing and configuring integrations efficiently.
"""
class Integration(object):
DEFAULT_LOGO_STATIC_PATH = 'static/images/integrations/logos/{name}.png'
def __init__(self, name, client_name, logo=None, secondary_line_text=None, display_name=None, doc=None):
# type: (str, str, Optional[str], Optional[str], Optional[str], Optional[str]) -> None
self.name = name
self.client_name = client_name
self.secondary_line_text = secondary_line_text
self.doc = doc
if logo is None:
logo = self.DEFAULT_LOGO_STATIC_PATH.format(name=name)
self.logo = logo
if display_name is None:
display_name = name.title()
self.display_name = display_name
def is_enabled(self):
# type: () -> bool
return True
class EmailIntegration(Integration):
def is_enabled(self):
# type: () -> bool
return settings.EMAIL_GATEWAY_BOT != ""
class WebhookIntegration(Integration):
DEFAULT_FUNCTION_PATH = 'zerver.webhooks.{name}.view.api_{name}_webhook'
DEFAULT_URL = 'api/v1/external/{name}'
DEFAULT_CLIENT_NAME = 'Zulip{name}Webhook'
DEFAULT_DOC_PATH = '{name}/doc.html'
def __init__(self, name, client_name=None, logo=None, secondary_line_text=None,
function=None, url=None, display_name=None, doc=None):
# type: (str, Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> None
if client_name is None:
client_name = self.DEFAULT_CLIENT_NAME.format(name=name.title())
super(WebhookIntegration, self).__init__(name, client_name, logo, secondary_line_text, display_name)
if function is None:
function = self.DEFAULT_FUNCTION_PATH.format(name=name)
if isinstance(function, str):
function = import_string(function)
self.function = function
if url is None:
url = self.DEFAULT_URL.format(name=name)
self.url = url
if doc is None:
doc = self.DEFAULT_DOC_PATH.format(name=name)
self.doc = doc
@property
def url_object(self):
# type: () -> LocaleRegexProvider
return url(self.url, self.function)
class HubotLozenge(Integration):
GIT_URL_TEMPLATE = "https://github.com/hubot-scripts/hubot-{}"
def __init__(self, name, display_name=None, logo=None, logo_alt=None, git_url=None):
# type: (str, Optional[str], Optional[str], Optional[str], Optional[str]) -> None
if logo_alt is None:
logo_alt = "{} logo".format(name.title())
self.logo_alt = logo_alt
if git_url is None:
git_url = self.GIT_URL_TEMPLATE.format(name)
self.git_url = git_url
super(HubotLozenge, self).__init__(name, name, logo, display_name=display_name)
class GithubIntegration(WebhookIntegration):
"""
We need this class to don't creating url object for git integrations.
We want to have one generic url with dispatch function for github service and github webhook.
"""
@property
def url_object(self):
# type: () -> None
return
WEBHOOK_INTEGRATIONS = [
WebhookIntegration('airbrake'),
WebhookIntegration('appfollow', display_name='AppFollow'),
WebhookIntegration('beanstalk'),
WebhookIntegration('basecamp'),
WebhookIntegration('bitbucket2', logo='static/images/integrations/logos/bitbucket.png', display_name='Bitbucket'),
WebhookIntegration('bitbucket', secondary_line_text='(Enterprise)'),
WebhookIntegration('circleci', display_name='CircleCI'),
WebhookIntegration('codeship'),
WebhookIntegration('crashlytics'),
WebhookIntegration('delighted', display_name='Delighted'),
WebhookIntegration('deskdotcom', logo='static/images/integrations/logos/deskcom.png', display_name='Desk.com'),
WebhookIntegration('freshdesk'),
GithubIntegration(
'github',
function='zerver.webhooks.github.view.api_github_landing',
display_name='GitHub',
secondary_line_text='(deprecated)'
),
GithubIntegration(
'github_webhook',
display_name='GitHub',
logo='static/images/integrations/logos/github.png',
secondary_line_text='(webhook)',
function='zerver.webhooks.github_webhook.view.api_github_webhook'
),
WebhookIntegration('gitlab', display_name='GitLab'),
WebhookIntegration('gogs'),
WebhookIntegration('gosquared', display_name='GoSquared'),
WebhookIntegration('greenhouse', display_name='Greenhouse'),
WebhookIntegration('hellosign', display_name='HelloSign'),
WebhookIntegration('helloworld', display_name='Hello World'),
WebhookIntegration('heroku', display_name='Heroku'),
WebhookIntegration('homeassistant', display_name='Home Assistant'),
WebhookIntegration('ifttt', function='zerver.webhooks.ifttt.view.api_iftt_app_webhook', display_name='IFTTT'),
WebhookIntegration('jira', secondary_line_text='(hosted or v5.2+)', display_name='JIRA'),
WebhookIntegration('librato'),
WebhookIntegration('mention', display_name='Mention'),
WebhookIntegration('newrelic', display_name='New Relic'),
WebhookIntegration('pagerduty'),
WebhookIntegration('papertrail'),
WebhookIntegration('pingdom'),
WebhookIntegration('pivotal', display_name='Pivotal Tracker'),
WebhookIntegration('semaphore'),
WebhookIntegration('sentry'),
WebhookIntegration('slack'),
WebhookIntegration('solano', display_name='Solano Labs'),
WebhookIntegration('splunk', display_name='Splunk'),
WebhookIntegration('stash'),
WebhookIntegration('stripe', display_name='Stripe'),
WebhookIntegration('taiga'),
WebhookIntegration('teamcity'),
WebhookIntegration('transifex'),
WebhookIntegration('travis', display_name='Travis CI'),
WebhookIntegration('trello', secondary_line_text='(webhook)'),
WebhookIntegration('updown'),
WebhookIntegration(
'yo',
function='zerver.webhooks.yo.view.api_yo_app_webhook',
logo='static/images/integrations/logos/yo-app.png',
display_name='Yo App'
),
WebhookIntegration('wordpress', display_name='WordPress'),
WebhookIntegration('zapier'),
WebhookIntegration('zendesk')
] # type: List[WebhookIntegration]
INTEGRATIONS = {
'asana': Integration('asana', 'asana'),
'basecamp': Integration('basecamp', 'basecamp'),
'capistrano': Integration('capistrano', 'capistrano'),
'codebase': Integration('codebase', 'codebase'),
'email': EmailIntegration('email', 'email'),
'git': Integration('git', 'git'),
'google-calendar': Integration('google-calendar', 'google-calendar', display_name='Google Calendar'),
'hubot': Integration('hubot', 'hubot'),
'jenkins': Integration('jenkins', 'jenkins', secondary_line_text='(or Hudson)'),
'jira-plugin': Integration(
'jira-plugin',
'jira-plugin',
logo='static/images/integrations/logos/jira.png',
secondary_line_text='(locally installed)',
display_name='JIRA'
),
'mercurial': Integration('mercurial', 'mercurial', display_name='Mercurial (hg)'),
'nagios': Integration('nagios', 'nagios'),
'openshift': Integration('openshift', 'openshift', display_name='OpenShift'),
'perforce': Integration('perforce', 'perforce'),
'phabricator': Integration('phabricator', 'phabricator'),
'puppet': Integration('puppet', 'puppet'),
'redmine': Integration('redmine', 'redmine'),
'rss': Integration('rss', 'rss', display_name='RSS'),
'subversion': Integration('subversion', 'subversion'),
'trac': Integration('trac', 'trac'),
'trello-plugin': Integration(
'trello-plugin',
'trello-plugin',
logo='static/images/integrations/logos/trello.png',
secondary_line_text='(legacy)',
display_name='Trello'
),
'twitter': Integration('twitter', 'twitter'),
} # type: Dict[str, Integration]
HUBOT_LOZENGES = {
'assembla': HubotLozenge('assembla'),
'bonusly': HubotLozenge('bonusly'),
'chartbeat': HubotLozenge('chartbeat'),
'darksky': HubotLozenge('darksky', display_name='Dark Sky', logo_alt='Dark Sky logo'),
'hangouts': HubotLozenge('google-hangouts', display_name="Hangouts"),
'instagram': HubotLozenge('instagram'),
'mailchimp': HubotLozenge('mailchimp', display_name='MailChimp', logo_alt='MailChimp logo'),
'translate': HubotLozenge('google-translate', display_name="Translate", logo_alt='Google Translate logo'),
'youtube': HubotLozenge('youtube', display_name='YouTube', logo_alt='YouTube logo')
}
for integration in WEBHOOK_INTEGRATIONS:
INTEGRATIONS[integration.name] = integration