zulip/zerver/lib/integrations.py

829 lines
32 KiB
Python
Raw Normal View History

import os
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import URLResolver, path
from django.utils.functional import Promise
2016-10-27 14:52:33 +02:00
from django.utils.module_loading import import_string
from django.utils.translation import gettext as gettext_lazy
from zerver.lib.storage import static_path
"""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).
To add a new integration category, add to the CATEGORIES dict.
Over time, we expect this registry to grow additional convenience
features for writing and configuring integrations efficiently.
"""
OptionValidator = Callable[[str, str], Optional[str]]
CATEGORIES: Dict[str, Promise] = {
"meta-integration": gettext_lazy("Integration frameworks"),
"continuous-integration": gettext_lazy("Continuous integration"),
"customer-support": gettext_lazy("Customer support"),
"deployment": gettext_lazy("Deployment"),
2021-03-28 00:11:00 +01:00
"entertainment": gettext_lazy("Entertainment"),
"communication": gettext_lazy("Communication"),
"financial": gettext_lazy("Financial"),
"hr": gettext_lazy("HR"),
"marketing": gettext_lazy("Marketing"),
"misc": gettext_lazy("Miscellaneous"),
"monitoring": gettext_lazy("Monitoring tools"),
"project-management": gettext_lazy("Project management"),
"productivity": gettext_lazy("Productivity"),
"version-control": gettext_lazy("Version control"),
"bots": gettext_lazy("Interactive bots"),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
}
class Integration:
DEFAULT_LOGO_STATIC_PATH_PNG = "images/integrations/logos/{name}.png"
DEFAULT_LOGO_STATIC_PATH_SVG = "images/integrations/logos/{name}.svg"
DEFAULT_BOT_AVATAR_PATH = "images/integrations/bot_avatars/{name}.png"
def __init__(
self,
name: str,
client_name: str,
categories: List[str],
logo: Optional[str] = None,
secondary_line_text: Optional[str] = None,
display_name: Optional[str] = None,
doc: Optional[str] = None,
stream_name: Optional[str] = None,
legacy: bool = False,
config_options: Sequence[Tuple[str, str, OptionValidator]] = [],
) -> None:
self.name = name
self.client_name = client_name
self.secondary_line_text = secondary_line_text
self.legacy = legacy
self.doc = doc
# Note: Currently only incoming webhook type bots use this list for
# defining how the bot's BotConfigData should be. Embedded bots follow
# a different approach.
self.config_options = config_options
for category in categories:
if category not in CATEGORIES:
raise KeyError( # nocoverage
"INTEGRATIONS: "
+ name
+ " - category '"
+ category
+ "' is not a key in CATEGORIES.",
)
self.categories = list(map((lambda c: CATEGORIES[c]), categories))
self.logo_path = logo if logo is not None else self.get_logo_path()
self.logo_url = self.get_logo_url()
if display_name is None:
display_name = name.title()
self.display_name = display_name
if stream_name is None:
stream_name = self.name
self.stream_name = stream_name
def is_enabled(self) -> bool:
return True
def get_logo_path(self) -> Optional[str]:
logo_file_path_svg = self.DEFAULT_LOGO_STATIC_PATH_SVG.format(name=self.name)
logo_file_path_png = self.DEFAULT_LOGO_STATIC_PATH_PNG.format(name=self.name)
if os.path.isfile(static_path(logo_file_path_svg)):
return logo_file_path_svg
elif os.path.isfile(static_path(logo_file_path_png)):
return logo_file_path_png
return None
def get_bot_avatar_path(self) -> Optional[str]:
if self.logo_path is not None:
name = os.path.splitext(os.path.basename(self.logo_path))[0]
return self.DEFAULT_BOT_AVATAR_PATH.format(name=name)
return None
def get_logo_url(self) -> Optional[str]:
if self.logo_path is not None:
return staticfiles_storage.url(self.logo_path)
return None
class BotIntegration(Integration):
DEFAULT_LOGO_STATIC_PATH_PNG = "generated/bots/{name}/logo.png"
DEFAULT_LOGO_STATIC_PATH_SVG = "generated/bots/{name}/logo.svg"
ZULIP_LOGO_STATIC_PATH_PNG = "images/logo/zulip-icon-128x128.png"
DEFAULT_DOC_PATH = "{name}/doc.md"
def __init__(
self,
name: str,
categories: List[str],
logo: Optional[str] = None,
secondary_line_text: Optional[str] = None,
display_name: Optional[str] = None,
doc: Optional[str] = None,
) -> None:
super().__init__(
name,
client_name=name,
categories=categories,
secondary_line_text=secondary_line_text,
)
if logo is None:
self.logo_url = self.get_logo_url()
if self.logo_url is None:
# TODO: Add a test for this by initializing one in a test.
logo = staticfiles_storage.url(self.ZULIP_LOGO_STATIC_PATH_PNG) # nocoverage
else:
self.logo_url = staticfiles_storage.url(logo)
if display_name is None:
display_name = f"{name.title()} Bot" # nocoverage
else:
display_name = f"{display_name} Bot"
self.display_name = display_name
if doc is None:
doc = self.DEFAULT_DOC_PATH.format(name=name)
self.doc = doc
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.{ext}"
def __init__(
self,
name: str,
categories: List[str],
client_name: Optional[str] = None,
logo: Optional[str] = None,
secondary_line_text: Optional[str] = None,
function: Optional[str] = None,
url: Optional[str] = None,
display_name: Optional[str] = None,
doc: Optional[str] = None,
stream_name: Optional[str] = None,
legacy: bool = False,
config_options: Sequence[Tuple[str, str, OptionValidator]] = [],
) -> None:
if client_name is None:
client_name = self.DEFAULT_CLIENT_NAME.format(name=name.title())
super().__init__(
name,
client_name,
categories,
logo=logo,
secondary_line_text=secondary_line_text,
display_name=display_name,
stream_name=stream_name,
legacy=legacy,
config_options=config_options,
)
if function is None:
function = self.DEFAULT_FUNCTION_PATH.format(name=name)
2016-10-27 14:52:33 +02:00
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, ext="md")
self.doc = doc
@property
def url_object(self) -> URLResolver:
assert self.function is not None
return path(self.url, self.function)
def split_fixture_path(path: str) -> Tuple[str, str]:
path, fixture_name = os.path.split(path)
fixture_name, _ = os.path.splitext(fixture_name)
integration_name = os.path.split(os.path.dirname(path))[-1]
return integration_name, fixture_name
@dataclass
class BaseScreenshotConfig:
fixture_name: str
image_name: str = "001.png"
image_dir: Optional[str] = None
bot_name: Optional[str] = None
@dataclass
class ScreenshotConfig(BaseScreenshotConfig):
payload_as_query_param: bool = False
payload_param_name: str = "payload"
extra_params: Dict[str, str] = field(default_factory=dict)
use_basic_auth: bool = False
custom_headers: Dict[str, str] = field(default_factory=dict)
def get_fixture_and_image_paths(
integration: Integration, screenshot_config: BaseScreenshotConfig
) -> Tuple[str, str]:
if isinstance(integration, WebhookIntegration):
fixture_dir = os.path.join("zerver", "webhooks", integration.name, "fixtures")
else:
fixture_dir = os.path.join("zerver", "integration_fixtures", integration.name)
fixture_path = os.path.join(fixture_dir, screenshot_config.fixture_name)
image_dir = screenshot_config.image_dir or integration.name
image_name = screenshot_config.image_name
image_path = os.path.join("static/images/integrations", image_dir, image_name)
return fixture_path, image_path
class HubotIntegration(Integration):
GIT_URL_TEMPLATE = "https://github.com/hubot-scripts/hubot-{}"
def __init__(
self,
name: str,
categories: List[str],
display_name: Optional[str] = None,
logo: Optional[str] = None,
logo_alt: Optional[str] = None,
git_url: Optional[str] = None,
legacy: bool = False,
) -> None:
if logo_alt is None:
logo_alt = f"{name.title()} logo"
self.logo_alt = logo_alt
if git_url is None:
git_url = self.GIT_URL_TEMPLATE.format(name)
self.hubot_docs_url = git_url
super().__init__(
name,
name,
categories,
logo=logo,
display_name=display_name,
doc="zerver/integrations/hubot_common.md",
legacy=legacy,
)
class EmbeddedBotIntegration(Integration):
"""
This class acts as a registry for bots verified as safe
and valid such that these are capable of being deployed on the server.
"""
DEFAULT_CLIENT_NAME = "Zulip{name}EmbeddedBot"
def __init__(self, name: str, *args: Any, **kwargs: Any) -> None:
assert kwargs.get("client_name") is None
client_name = self.DEFAULT_CLIENT_NAME.format(name=name.title())
super().__init__(name, client_name, *args, **kwargs)
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
EMBEDDED_BOTS: List[EmbeddedBotIntegration] = [
EmbeddedBotIntegration("converter", []),
EmbeddedBotIntegration("encrypt", []),
EmbeddedBotIntegration("helloworld", []),
EmbeddedBotIntegration("virtual_fs", []),
EmbeddedBotIntegration("giphy", []),
EmbeddedBotIntegration("followup", []),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
]
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [
WebhookIntegration("airbrake", ["monitoring"]),
WebhookIntegration(
"alertmanager",
["monitoring"],
display_name="Prometheus Alertmanager",
logo="images/integrations/logos/prometheus.svg",
),
WebhookIntegration("ansibletower", ["deployment"], display_name="Ansible Tower"),
WebhookIntegration("appfollow", ["customer-support"], display_name="AppFollow"),
WebhookIntegration("appveyor", ["continuous-integration"], display_name="AppVeyor"),
WebhookIntegration("beanstalk", ["version-control"], stream_name="commits"),
WebhookIntegration("basecamp", ["project-management"]),
WebhookIntegration("beeminder", ["misc"], display_name="Beeminder"),
WebhookIntegration(
"bitbucket3",
["version-control"],
logo="images/integrations/logos/bitbucket.svg",
display_name="Bitbucket Server",
stream_name="bitbucket",
),
WebhookIntegration(
"bitbucket2",
["version-control"],
logo="images/integrations/logos/bitbucket.svg",
display_name="Bitbucket",
stream_name="bitbucket",
),
WebhookIntegration(
"bitbucket",
["version-control"],
display_name="Bitbucket",
secondary_line_text="(Enterprise)",
stream_name="commits",
legacy=True,
),
WebhookIntegration("buildbot", ["continuous-integration"], display_name="Buildbot"),
WebhookIntegration("canarytoken", ["monitoring"], display_name="Thinkst Canarytokens"),
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"),
WebhookIntegration("delighted", ["customer-support", "marketing"], display_name="Delighted"),
WebhookIntegration(
"deskdotcom",
["customer-support"],
logo="images/integrations/logos/deskcom.png",
display_name="Desk.com",
stream_name="desk",
),
WebhookIntegration("dropbox", ["productivity"], display_name="Dropbox"),
WebhookIntegration("errbit", ["monitoring"], display_name="Errbit"),
WebhookIntegration("flock", ["customer-support"], display_name="Flock"),
WebhookIntegration("freshdesk", ["customer-support"]),
WebhookIntegration("freshping", ["monitoring"], display_name="Freshping"),
WebhookIntegration(
"freshstatus", ["monitoring", "customer-support"], display_name="Freshstatus"
),
WebhookIntegration("front", ["customer-support"], display_name="Front"),
WebhookIntegration("gitea", ["version-control"], stream_name="commits"),
WebhookIntegration(
"github",
["version-control"],
display_name="GitHub",
logo="images/integrations/logos/github.svg",
function="zerver.webhooks.github.view.api_github_webhook",
stream_name="github",
),
WebhookIntegration("gitlab", ["version-control"], display_name="GitLab"),
WebhookIntegration("gocd", ["continuous-integration"], display_name="GoCD"),
WebhookIntegration("gogs", ["version-control"], stream_name="commits"),
WebhookIntegration("gosquared", ["marketing"], display_name="GoSquared"),
WebhookIntegration("grafana", ["monitoring"], display_name="Grafana"),
WebhookIntegration("greenhouse", ["hr"], display_name="Greenhouse"),
WebhookIntegration("groove", ["customer-support"], display_name="Groove"),
WebhookIntegration("harbor", ["deployment", "productivity"], display_name="Harbor"),
WebhookIntegration("hellosign", ["productivity", "hr"], display_name="HelloSign"),
WebhookIntegration("helloworld", ["misc"], display_name="Hello World"),
WebhookIntegration("heroku", ["deployment"], display_name="Heroku"),
WebhookIntegration("homeassistant", ["misc"], display_name="Home Assistant"),
WebhookIntegration(
"ifttt",
["meta-integration"],
function="zerver.webhooks.ifttt.view.api_iftt_app_webhook",
display_name="IFTTT",
),
WebhookIntegration("insping", ["monitoring"], display_name="Insping"),
WebhookIntegration("intercom", ["customer-support"], display_name="Intercom"),
WebhookIntegration("jira", ["project-management"], display_name="Jira"),
WebhookIntegration("jotform", ["misc"], display_name="Jotform"),
WebhookIntegration("json", ["misc"], display_name="JSON formatter"),
WebhookIntegration("librato", ["monitoring"]),
2021-03-28 00:11:00 +01:00
WebhookIntegration("lidarr", ["entertainment"]),
WebhookIntegration("mention", ["marketing"], display_name="Mention"),
WebhookIntegration("netlify", ["continuous-integration", "deployment"], display_name="Netlify"),
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("opencollective", ["communication"], display_name="Open Collective"),
WebhookIntegration("opsgenie", ["meta-integration", "monitoring"]),
WebhookIntegration("pagerduty", ["monitoring"], display_name="PagerDuty"),
WebhookIntegration("papertrail", ["monitoring"]),
WebhookIntegration("pingdom", ["monitoring"]),
WebhookIntegration("pivotal", ["project-management"], display_name="Pivotal Tracker"),
2021-03-27 18:40:42 +01:00
WebhookIntegration("radarr", ["entertainment"], display_name="Radarr"),
WebhookIntegration("raygun", ["monitoring"], display_name="Raygun"),
WebhookIntegration("reviewboard", ["version-control"], display_name="Review Board"),
WebhookIntegration("semaphore", ["continuous-integration", "deployment"]),
WebhookIntegration("sentry", ["monitoring"]),
WebhookIntegration(
"slack_incoming",
["communication", "meta-integration"],
display_name="Slack-compatible webhook",
logo="images/integrations/logos/slack.svg",
),
WebhookIntegration("slack", ["communication"]),
WebhookIntegration("solano", ["continuous-integration"], display_name="Solano Labs"),
WebhookIntegration("sonarqube", ["continuous-integration"], display_name="SonarQube"),
2021-03-27 03:56:36 +01:00
WebhookIntegration("sonarr", ["entertainment"], display_name="Sonarr"),
WebhookIntegration("splunk", ["monitoring"], display_name="Splunk"),
WebhookIntegration("statuspage", ["customer-support"], display_name="Statuspage"),
WebhookIntegration("stripe", ["financial"], display_name="Stripe"),
WebhookIntegration("taiga", ["project-management"]),
WebhookIntegration("teamcity", ["continuous-integration"]),
WebhookIntegration("thinkst", ["monitoring"]),
WebhookIntegration("transifex", ["misc"]),
WebhookIntegration("travis", ["continuous-integration"], display_name="Travis CI"),
WebhookIntegration("trello", ["project-management"]),
WebhookIntegration("updown", ["monitoring"]),
WebhookIntegration("uptimerobot", ["monitoring"], display_name="UptimeRobot"),
WebhookIntegration(
"yo",
["communication"],
function="zerver.webhooks.yo.view.api_yo_app_webhook",
display_name="Yo",
),
WebhookIntegration("wordpress", ["marketing"], display_name="WordPress"),
WebhookIntegration("zapier", ["meta-integration"]),
WebhookIntegration("zendesk", ["customer-support"]),
WebhookIntegration("zabbix", ["monitoring"], display_name="Zabbix"),
WebhookIntegration("gci", ["misc"], display_name="Google Code-in", stream_name="gci"),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
]
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
INTEGRATIONS: Dict[str, Integration] = {
"asana": Integration(
"asana", "asana", ["project-management"], doc="zerver/integrations/asana.md"
),
"big-blue-button": Integration(
"big-blue-button",
"big-blue-button",
["communication"],
logo="images/integrations/logos/bigbluebutton.svg",
display_name="BigBlueButton",
doc="zerver/integrations/big-blue-button.md",
),
"capistrano": Integration(
"capistrano",
"capistrano",
["deployment"],
display_name="Capistrano",
doc="zerver/integrations/capistrano.md",
),
"codebase": Integration(
"codebase", "codebase", ["version-control"], doc="zerver/integrations/codebase.md"
),
"discourse": Integration(
"discourse", "discourse", ["communication"], doc="zerver/integrations/discourse.md"
),
"email": Integration("email", "email", ["communication"], doc="zerver/integrations/email.md"),
"errbot": Integration(
"errbot", "errbot", ["meta-integration", "bots"], doc="zerver/integrations/errbot.md"
),
"giphy": Integration(
"giphy",
"giphy",
display_name="GIPHY",
categories=["misc"],
doc="zerver/integrations/giphy.md",
logo="images/GIPHY_big_logo.png",
),
"git": Integration(
"git", "git", ["version-control"], stream_name="commits", doc="zerver/integrations/git.md"
),
"github-actions": Integration(
"github-actions",
"github-actions",
["continuous-integration"],
display_name="GitHub Actions",
doc="zerver/integrations/github-actions.md",
),
"google-calendar": Integration(
"google-calendar",
"google-calendar",
["productivity"],
display_name="Google Calendar",
doc="zerver/integrations/google-calendar.md",
),
"hubot": Integration(
"hubot", "hubot", ["meta-integration", "bots"], doc="zerver/integrations/hubot.md"
),
"irc": Integration(
"irc", "irc", ["communication"], display_name="IRC", doc="zerver/integrations/irc.md"
),
"jenkins": Integration(
"jenkins",
"jenkins",
["continuous-integration"],
secondary_line_text="(or Hudson)",
doc="zerver/integrations/jenkins.md",
),
"jira-plugin": Integration(
"jira-plugin",
"jira-plugin",
["project-management"],
logo="images/integrations/logos/jira.svg",
secondary_line_text="(locally installed)",
display_name="Jira",
doc="zerver/integrations/jira-plugin.md",
stream_name="jira",
legacy=True,
),
"jitsi": Integration(
"jitsi",
"jitsi",
["communication"],
logo="images/integrations/logos/jitsi.svg",
display_name="Jitsi Meet",
doc="zerver/integrations/jitsi.md",
),
"matrix": Integration(
"matrix", "matrix", ["communication"], doc="zerver/integrations/matrix.md"
),
"mercurial": Integration(
"mercurial",
"mercurial",
["version-control"],
display_name="Mercurial (hg)",
doc="zerver/integrations/mercurial.md",
stream_name="commits",
),
"nagios": Integration("nagios", "nagios", ["monitoring"], doc="zerver/integrations/nagios.md"),
"openshift": Integration(
"openshift",
"openshift",
["deployment"],
display_name="OpenShift",
doc="zerver/integrations/openshift.md",
stream_name="deployments",
),
"perforce": Integration(
"perforce", "perforce", ["version-control"], doc="zerver/integrations/perforce.md"
),
"phabricator": Integration(
"phabricator", "phabricator", ["version-control"], doc="zerver/integrations/phabricator.md"
),
"puppet": Integration("puppet", "puppet", ["deployment"], doc="zerver/integrations/puppet.md"),
"redmine": Integration(
"redmine", "redmine", ["project-management"], doc="zerver/integrations/redmine.md"
),
"rss": Integration(
"rss", "rss", ["communication"], display_name="RSS", doc="zerver/integrations/rss.md"
),
"svn": Integration("svn", "svn", ["version-control"], doc="zerver/integrations/svn.md"),
"trac": Integration("trac", "trac", ["project-management"], doc="zerver/integrations/trac.md"),
"trello-plugin": Integration(
"trello-plugin",
"trello-plugin",
["project-management"],
logo="images/integrations/logos/trello.svg",
secondary_line_text="(legacy)",
display_name="Trello",
doc="zerver/integrations/trello-plugin.md",
stream_name="trello",
legacy=True,
),
"twitter": Integration(
"twitter",
"twitter",
["customer-support", "marketing"],
# _ needed to get around adblock plus
logo="images/integrations/logos/twitte_r.svg",
doc="zerver/integrations/twitter.md",
),
"zoom": Integration(
"zoom",
"zoom",
["communication"],
logo="images/integrations/logos/zoom.svg",
display_name="Zoom",
doc="zerver/integrations/zoom.md",
),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
}
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
BOT_INTEGRATIONS: List[BotIntegration] = [
BotIntegration("github_detail", ["version-control", "bots"], display_name="GitHub Detail"),
BotIntegration(
"xkcd", ["bots", "misc"], display_name="xkcd", logo="images/integrations/logos/xkcd.png"
),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
]
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
HUBOT_INTEGRATIONS: List[HubotIntegration] = [
HubotIntegration(
"assembla",
["version-control", "project-management"],
display_name="Assembla",
logo_alt="Assembla",
),
HubotIntegration("bonusly", ["hr"]),
HubotIntegration("chartbeat", ["marketing"], display_name="Chartbeat"),
HubotIntegration("darksky", ["misc"], display_name="Dark Sky", logo_alt="Dark Sky logo"),
HubotIntegration(
"instagram",
["misc"],
display_name="Instagram",
# _ needed to get around adblock plus
logo="images/integrations/logos/instagra_m.svg",
),
HubotIntegration("mailchimp", ["communication", "marketing"], display_name="Mailchimp"),
HubotIntegration(
"google-translate",
["misc"],
display_name="Google Translate",
logo_alt="Google Translate logo",
),
HubotIntegration(
"youtube",
["misc"],
display_name="YouTube",
# _ needed to get around adblock plus
logo="images/integrations/logos/youtub_e.svg",
),
python: Convert assignment type annotations to Python 3.6 style. This commit was split by tabbott; this piece covers the vast majority of files in Zulip, but excludes scripts/, tools/, and puppet/ to help ensure we at least show the right error messages for Xenial systems. We can likely further refine the remaining pieces with some testing. Generated by com2ann, with whitespace fixes and various manual fixes for runtime issues: - invoiced_through: Optional[LicenseLedger] = models.ForeignKey( + invoiced_through: Optional["LicenseLedger"] = models.ForeignKey( -_apns_client: Optional[APNsClient] = None +_apns_client: Optional["APNsClient"] = None - notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) + signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) - author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) + author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE) - bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) - default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) + default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE) -descriptors_by_handler_id: Dict[int, ClientDescriptor] = {} +descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {} -worker_classes: Dict[str, Type[QueueProcessingWorker]] = {} -queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {} +worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {} +queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {} -AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None +AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
]
for hubot_integration in HUBOT_INTEGRATIONS:
INTEGRATIONS[hubot_integration.name] = hubot_integration
for webhook_integration in WEBHOOK_INTEGRATIONS:
INTEGRATIONS[webhook_integration.name] = webhook_integration
for bot_integration in BOT_INTEGRATIONS:
INTEGRATIONS[bot_integration.name] = bot_integration
# Add integrations that don't have automated screenshots here
NO_SCREENSHOT_WEBHOOKS = {
"beeminder", # FIXME: fixture's goal.losedate needs to be modified dynamically
"ifttt", # Docs don't have a screenshot
"slack_incoming", # Docs don't have a screenshot
"zapier", # Docs don't have a screenshot
}
DOC_SCREENSHOT_CONFIG: Dict[str, List[BaseScreenshotConfig]] = {
"airbrake": [ScreenshotConfig("error_message.json")],
"alertmanager": [
ScreenshotConfig("alert.json", extra_params={"name": "topic", "desc": "description"})
],
"ansibletower": [ScreenshotConfig("job_successful_multiple_hosts.json")],
"appfollow": [ScreenshotConfig("review.json")],
"appveyor": [ScreenshotConfig("appveyor_build_success.json")],
"basecamp": [ScreenshotConfig("doc_active.json")],
"beanstalk": [
ScreenshotConfig("git_multiple.json", use_basic_auth=True, payload_as_query_param=True)
],
# 'beeminder': [ScreenshotConfig('derail_worried.json')],
"bitbucket": [
ScreenshotConfig("push.json", "002.png", use_basic_auth=True, payload_as_query_param=True)
],
"bitbucket2": [
ScreenshotConfig("issue_created.json", "003.png", "bitbucket", bot_name="Bitbucket Bot")
],
"bitbucket3": [
ScreenshotConfig(
"repo_push_update_single_branch.json",
"004.png",
"bitbucket",
bot_name="Bitbucket Server Bot",
)
],
"buildbot": [ScreenshotConfig("started.json")],
"canarytoken": [ScreenshotConfig("canarytoken_real.json")],
"circleci": [
ScreenshotConfig(
"github_bionic_production_build_success_multiple_parties.json", image_name="001.png"
),
ScreenshotConfig("bitbucket_private_repo_pull_request_failure.json", image_name="002.png"),
],
"clubhouse": [ScreenshotConfig("story_create.json")],
"codeship": [ScreenshotConfig("error_build.json")],
"crashlytics": [ScreenshotConfig("issue_message.json")],
"delighted": [ScreenshotConfig("survey_response_updated_promoter.json")],
"deskdotcom": [ScreenshotConfig("static_text.txt", "009.png", "desk", use_basic_auth=True)],
"dialogflow": [ScreenshotConfig("weather_app.json", extra_params={"email": "iago@zulip.com"})],
"dropbox": [ScreenshotConfig("file_updated.json")],
"errbit": [ScreenshotConfig("error_message.json")],
"flock": [ScreenshotConfig("messages.json")],
"freshdesk": [
ScreenshotConfig("ticket_created.json", image_name="004.png", use_basic_auth=True)
],
"freshping": [ScreenshotConfig("freshping_check_unreachable.json")],
"freshstatus": [ScreenshotConfig("freshstatus_incident_open.json")],
"front": [ScreenshotConfig("inbound_message.json")],
"gci": [ScreenshotConfig("task_abandoned_by_student.json")],
"gitea": [ScreenshotConfig("pull_request__merged.json")],
"github": [ScreenshotConfig("push__1_commit.json")],
"gitlab": [ScreenshotConfig("push_hook__push_local_branch_without_commits.json")],
"gocd": [ScreenshotConfig("pipeline.json")],
"gogs": [ScreenshotConfig("pull_request__opened.json")],
"gosquared": [ScreenshotConfig("traffic_spike.json", image_name="000.png")],
"grafana": [ScreenshotConfig("alert.json")],
"greenhouse": [ScreenshotConfig("candidate_stage_change.json", image_name="000.png")],
"groove": [ScreenshotConfig("ticket_started.json")],
"harbor": [ScreenshotConfig("scanning_completed.json")],
"hellosign": [
ScreenshotConfig(
"signatures_signed_by_one_signatory.json",
payload_as_query_param=True,
payload_param_name="json",
)
],
"helloworld": [ScreenshotConfig("hello.json")],
"heroku": [ScreenshotConfig("deploy.txt")],
"homeassistant": [ScreenshotConfig("reqwithtitle.json", image_name="003.png")],
"insping": [ScreenshotConfig("website_state_available.json")],
"intercom": [ScreenshotConfig("conversation_admin_replied.json")],
"jira": [ScreenshotConfig("created_v1.json")],
"jotform": [ScreenshotConfig("response.json")],
"json": [ScreenshotConfig("json_github_push__1_commit.json")],
"librato": [ScreenshotConfig("three_conditions_alert.json", payload_as_query_param=True)],
2021-03-28 00:11:00 +01:00
"lidarr": [ScreenshotConfig("lidarr_tracks_grabbed.json")],
"mention": [ScreenshotConfig("webfeeds.json")],
"nagios": [BaseScreenshotConfig("service_notify.json")],
"netlify": [ScreenshotConfig("deploy_building.json")],
"newrelic": [
ScreenshotConfig("incident_opened.json", "001.png"),
ScreenshotConfig("incident_acknowledged.json", "002.png"),
ScreenshotConfig("incident_closed.json", "003.png"),
],
"opbeat": [ScreenshotConfig("error_reopen.json")],
"opencollective": [ScreenshotConfig("one_time_donation.json")],
"opsgenie": [ScreenshotConfig("addrecipient.json", image_name="000.png")],
"pagerduty": [ScreenshotConfig("trigger_v2.json")],
"papertrail": [ScreenshotConfig("short_post.json", payload_as_query_param=True)],
"pingdom": [ScreenshotConfig("http_up_to_down.json", image_name="002.png")],
"pivotal": [ScreenshotConfig("v5_type_changed.json")],
2021-03-27 18:40:42 +01:00
"radarr": [ScreenshotConfig("radarr_movie_grabbed.json")],
"raygun": [ScreenshotConfig("new_error.json")],
"reviewboard": [ScreenshotConfig("review_request_published.json")],
"semaphore": [ScreenshotConfig("pull_request.json")],
"sentry": [
ScreenshotConfig("event_for_exception_python.json"),
ScreenshotConfig("issue_assigned_to_team.json", "002.png"),
],
"slack": [ScreenshotConfig("message_info.txt")],
"solano": [ScreenshotConfig("build_001.json")],
"sonarqube": [ScreenshotConfig("error.json")],
2021-03-27 03:56:36 +01:00
"sonarr": [ScreenshotConfig("sonarr_episode_grabbed.json")],
"splunk": [ScreenshotConfig("search_one_result.json")],
"statuspage": [ScreenshotConfig("incident_created.json")],
"stripe": [ScreenshotConfig("charge_succeeded__card.json")],
"taiga": [ScreenshotConfig("userstory_changed_status.json")],
"teamcity": [ScreenshotConfig("success.json"), ScreenshotConfig("personal.json", "002.png")],
"thinkst": [ScreenshotConfig("canary_consolidated_port_scan.json")],
"transifex": [
ScreenshotConfig(
"",
extra_params={
"project": "Zulip Mobile",
"language": "en",
"resource": "file",
"reviewed": "100",
},
)
],
"travis": [ScreenshotConfig("build.json", payload_as_query_param=True)],
"trello": [ScreenshotConfig("adding_comment_to_card.json")],
"updown": [ScreenshotConfig("check_multiple_events.json")],
"uptimerobot": [ScreenshotConfig("uptimerobot_monitor_up.json")],
"wordpress": [ScreenshotConfig("publish_post.txt", "wordpress_post_created.png")],
"yo": [
ScreenshotConfig(
"",
"002.png",
"yo-app",
extra_params={"email": "iago@zulip.com", "username": "Cordelia"},
)
],
"zabbix": [ScreenshotConfig("zabbix_alert.json")],
"zendesk": [
ScreenshotConfig(
"",
"007.png",
use_basic_auth=True,
extra_params={
"ticket_title": "Test ticket",
"ticket_id": "4",
"message": "Test message",
},
)
],
}