forked from GithubBackups/healthchecks
Add the SLACK_ENABLED setting
This commit is contained in:
parent
67ff8a9bee
commit
52435a9a0c
@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Add experimental Dockerfile and docker-compose.yml
|
- Add experimental Dockerfile and docker-compose.yml
|
||||||
- Add rate limiting for Pushover notifications (6 notifications / user / minute)
|
- Add rate limiting for Pushover notifications (6 notifications / user / minute)
|
||||||
- Add the WEBHOOKS_ENABLED setting (#471)
|
- Add the WEBHOOKS_ENABLED setting (#471)
|
||||||
|
- Add the SLACK_ENABLED setting (#471)
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
- Fix unwanted HTML escaping in SMS and WhatsApp notifications
|
- Fix unwanted HTML escaping in SMS and WhatsApp notifications
|
||||||
|
@ -45,6 +45,7 @@ SITE_NAME=Mychecks
|
|||||||
SITE_ROOT=http://localhost:8000
|
SITE_ROOT=http://localhost:8000
|
||||||
SLACK_CLIENT_ID=
|
SLACK_CLIENT_ID=
|
||||||
SLACK_CLIENT_SECRET=
|
SLACK_CLIENT_SECRET=
|
||||||
|
SLACK_ENABLED=True
|
||||||
TELEGRAM_BOT_NAME=ExampleBot
|
TELEGRAM_BOT_NAME=ExampleBot
|
||||||
TELEGRAM_TOKEN=
|
TELEGRAM_TOKEN=
|
||||||
TRELLO_APP_KEY=
|
TRELLO_APP_KEY=
|
||||||
|
@ -8,7 +8,6 @@ from django.core import mail
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from hc.api.models import Channel, Check, Notification, TokenBucket
|
from hc.api.models import Channel, Check, Notification, TokenBucket
|
||||||
from hc.test import BaseTestCase
|
from hc.test import BaseTestCase
|
||||||
from requests.exceptions import Timeout
|
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
|
||||||
@ -72,63 +71,6 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
self.assertFalse(mock_post.called)
|
self.assertFalse(mock_post.called)
|
||||||
self.assertEqual(Notification.objects.count(), 0)
|
self.assertEqual(Notification.objects.count(), 0)
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
|
||||||
def test_slack(self, mock_post):
|
|
||||||
self._setup_data("slack", "123")
|
|
||||||
mock_post.return_value.status_code = 200
|
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
|
||||||
assert Notification.objects.count() == 1
|
|
||||||
|
|
||||||
args, kwargs = mock_post.call_args
|
|
||||||
payload = kwargs["json"]
|
|
||||||
attachment = payload["attachments"][0]
|
|
||||||
fields = {f["title"]: f["value"] for f in attachment["fields"]}
|
|
||||||
self.assertEqual(fields["Last Ping"], "an hour ago")
|
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
|
||||||
def test_slack_with_complex_value(self, mock_post):
|
|
||||||
v = json.dumps({"incoming_webhook": {"url": "123"}})
|
|
||||||
self._setup_data("slack", v)
|
|
||||||
mock_post.return_value.status_code = 200
|
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
|
||||||
assert Notification.objects.count() == 1
|
|
||||||
|
|
||||||
args, kwargs = mock_post.call_args
|
|
||||||
self.assertEqual(args[1], "123")
|
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
|
||||||
def test_slack_handles_500(self, mock_post):
|
|
||||||
self._setup_data("slack", "123")
|
|
||||||
mock_post.return_value.status_code = 500
|
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
|
||||||
|
|
||||||
n = Notification.objects.get()
|
|
||||||
self.assertEqual(n.error, "Received status code 500")
|
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request", side_effect=Timeout)
|
|
||||||
def test_slack_handles_timeout(self, mock_post):
|
|
||||||
self._setup_data("slack", "123")
|
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
|
||||||
|
|
||||||
n = Notification.objects.get()
|
|
||||||
self.assertEqual(n.error, "Connection timed out")
|
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
|
||||||
def test_slack_with_tabs_in_schedule(self, mock_post):
|
|
||||||
self._setup_data("slack", "123")
|
|
||||||
self.check.kind = "cron"
|
|
||||||
self.check.schedule = "*\t* * * *"
|
|
||||||
self.check.save()
|
|
||||||
mock_post.return_value.status_code = 200
|
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
|
||||||
self.assertEqual(Notification.objects.count(), 1)
|
|
||||||
self.assertTrue(mock_post.called)
|
|
||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
@patch("hc.api.transports.requests.request")
|
||||||
def test_hipchat(self, mock_post):
|
def test_hipchat(self, mock_post):
|
||||||
self._setup_data("hipchat", "123")
|
self._setup_data("hipchat", "123")
|
||||||
|
91
hc/api/tests/test_notify_slack.py
Normal file
91
hc/api/tests/test_notify_slack.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import timedelta as td
|
||||||
|
import json
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from hc.api.models import Channel, Check, Notification
|
||||||
|
from hc.test import BaseTestCase
|
||||||
|
from requests.exceptions import Timeout
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
|
||||||
|
class NotifyTestCase(BaseTestCase):
|
||||||
|
def _setup_data(self, value, status="down", email_verified=True):
|
||||||
|
self.check = Check(project=self.project)
|
||||||
|
self.check.status = status
|
||||||
|
self.check.last_ping = now() - td(minutes=61)
|
||||||
|
self.check.save()
|
||||||
|
|
||||||
|
self.channel = Channel(project=self.project)
|
||||||
|
self.channel.kind = "slack"
|
||||||
|
self.channel.value = value
|
||||||
|
self.channel.email_verified = email_verified
|
||||||
|
self.channel.save()
|
||||||
|
self.channel.checks.add(self.check)
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request")
|
||||||
|
def test_slack(self, mock_post):
|
||||||
|
self._setup_data("123")
|
||||||
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
assert Notification.objects.count() == 1
|
||||||
|
|
||||||
|
args, kwargs = mock_post.call_args
|
||||||
|
payload = kwargs["json"]
|
||||||
|
attachment = payload["attachments"][0]
|
||||||
|
fields = {f["title"]: f["value"] for f in attachment["fields"]}
|
||||||
|
self.assertEqual(fields["Last Ping"], "an hour ago")
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request")
|
||||||
|
def test_slack_with_complex_value(self, mock_post):
|
||||||
|
v = json.dumps({"incoming_webhook": {"url": "123"}})
|
||||||
|
self._setup_data(v)
|
||||||
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
assert Notification.objects.count() == 1
|
||||||
|
|
||||||
|
args, kwargs = mock_post.call_args
|
||||||
|
self.assertEqual(args[1], "123")
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request")
|
||||||
|
def test_slack_handles_500(self, mock_post):
|
||||||
|
self._setup_data("123")
|
||||||
|
mock_post.return_value.status_code = 500
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
|
||||||
|
n = Notification.objects.get()
|
||||||
|
self.assertEqual(n.error, "Received status code 500")
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request", side_effect=Timeout)
|
||||||
|
def test_slack_handles_timeout(self, mock_post):
|
||||||
|
self._setup_data("123")
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
|
||||||
|
n = Notification.objects.get()
|
||||||
|
self.assertEqual(n.error, "Connection timed out")
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request")
|
||||||
|
def test_slack_with_tabs_in_schedule(self, mock_post):
|
||||||
|
self._setup_data("123")
|
||||||
|
self.check.kind = "cron"
|
||||||
|
self.check.schedule = "*\t* * * *"
|
||||||
|
self.check.save()
|
||||||
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
self.assertEqual(Notification.objects.count(), 1)
|
||||||
|
self.assertTrue(mock_post.called)
|
||||||
|
|
||||||
|
@override_settings(SLACK_ENABLED=False)
|
||||||
|
def test_it_requires_slack_enabled(self):
|
||||||
|
self._setup_data("123")
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
|
||||||
|
n = Notification.objects.get()
|
||||||
|
self.assertEqual(n.error, "Slack notifications are not enabled.")
|
@ -263,6 +263,9 @@ class Webhook(HttpTransport):
|
|||||||
|
|
||||||
class Slack(HttpTransport):
|
class Slack(HttpTransport):
|
||||||
def notify(self, check):
|
def notify(self, check):
|
||||||
|
if not settings.SLACK_ENABLED:
|
||||||
|
return "Slack notifications are not enabled."
|
||||||
|
|
||||||
text = tmpl("slack_message.json", check=check)
|
text = tmpl("slack_message.json", check=check)
|
||||||
payload = json.loads(text)
|
payload = json.loads(text)
|
||||||
return self.post(self.channel.slack_webhook_url, json=payload)
|
return self.post(self.channel.slack_webhook_url, json=payload)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from django.test.utils import override_settings
|
||||||
from hc.api.models import Channel
|
from hc.api.models import Channel
|
||||||
from hc.test import BaseTestCase
|
from hc.test import BaseTestCase
|
||||||
|
|
||||||
@ -38,3 +39,9 @@ class AddSlackTestCase(BaseTestCase):
|
|||||||
self.client.login(username="bob@example.org", password="password")
|
self.client.login(username="bob@example.org", password="password")
|
||||||
r = self.client.get(self.url)
|
r = self.client.get(self.url)
|
||||||
self.assertEqual(r.status_code, 403)
|
self.assertEqual(r.status_code, 403)
|
||||||
|
|
||||||
|
@override_settings(SLACK_ENABLED=False)
|
||||||
|
def test_it_handles_disabled_integration(self):
|
||||||
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
r = self.client.get(self.url)
|
||||||
|
self.assertEqual(r.status_code, 404)
|
||||||
|
@ -34,3 +34,9 @@ class AddSlackBtnTestCase(BaseTestCase):
|
|||||||
self.client.login(username="bob@example.org", password="password")
|
self.client.login(username="bob@example.org", password="password")
|
||||||
r = self.client.get(self.url)
|
r = self.client.get(self.url)
|
||||||
self.assertEqual(r.status_code, 403)
|
self.assertEqual(r.status_code, 403)
|
||||||
|
|
||||||
|
@override_settings(SLACK_ENABLED=False)
|
||||||
|
def test_it_handles_disabled_integration(self):
|
||||||
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
r = self.client.get(self.url)
|
||||||
|
self.assertEqual(r.status_code, 404)
|
||||||
|
@ -81,3 +81,9 @@ class AddSlackCompleteTestCase(BaseTestCase):
|
|||||||
self.client.login(username="bob@example.org", password="password")
|
self.client.login(username="bob@example.org", password="password")
|
||||||
r = self.client.get("/integrations/add_slack_btn/?code=12345678&state=foo")
|
r = self.client.get("/integrations/add_slack_btn/?code=12345678&state=foo")
|
||||||
self.assertEqual(r.status_code, 403)
|
self.assertEqual(r.status_code, 403)
|
||||||
|
|
||||||
|
@override_settings(SLACK_ENABLED=False)
|
||||||
|
def test_it_requires_slack_enabled(self):
|
||||||
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
r = self.client.get("/integrations/add_slack_btn/?code=12345678&state=foo")
|
||||||
|
self.assertEqual(r.status_code, 404)
|
||||||
|
@ -300,6 +300,7 @@ def index(request):
|
|||||||
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
|
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
|
||||||
"enable_shell": settings.SHELL_ENABLED is True,
|
"enable_shell": settings.SHELL_ENABLED is True,
|
||||||
"enable_signal": settings.SIGNAL_CLI_ENABLED is True,
|
"enable_signal": settings.SIGNAL_CLI_ENABLED is True,
|
||||||
|
"enable_slack": settings.SLACK_ENABLED is True,
|
||||||
"enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
|
"enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
|
||||||
"enable_sms": settings.TWILIO_AUTH is not None,
|
"enable_sms": settings.TWILIO_AUTH is not None,
|
||||||
"enable_telegram": settings.TELEGRAM_TOKEN is not None,
|
"enable_telegram": settings.TELEGRAM_TOKEN is not None,
|
||||||
@ -767,6 +768,7 @@ def channels(request, code):
|
|||||||
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
|
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
|
||||||
"enable_shell": settings.SHELL_ENABLED is True,
|
"enable_shell": settings.SHELL_ENABLED is True,
|
||||||
"enable_signal": settings.SIGNAL_CLI_ENABLED is True,
|
"enable_signal": settings.SIGNAL_CLI_ENABLED is True,
|
||||||
|
"enable_slack": settings.SLACK_ENABLED is True,
|
||||||
"enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
|
"enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
|
||||||
"enable_sms": settings.TWILIO_AUTH is not None,
|
"enable_sms": settings.TWILIO_AUTH is not None,
|
||||||
"enable_telegram": settings.TELEGRAM_TOKEN is not None,
|
"enable_telegram": settings.TELEGRAM_TOKEN is not None,
|
||||||
@ -1112,6 +1114,7 @@ def add_pagertree(request, code):
|
|||||||
return render(request, "integrations/add_pagertree.html", ctx)
|
return render(request, "integrations/add_pagertree.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@require_setting("SLACK_ENABLED")
|
||||||
@login_required
|
@login_required
|
||||||
def add_slack(request, code):
|
def add_slack(request, code):
|
||||||
project = _get_rw_project_for_user(request, code)
|
project = _get_rw_project_for_user(request, code)
|
||||||
@ -1136,12 +1139,14 @@ def add_slack(request, code):
|
|||||||
return render(request, "integrations/add_slack.html", ctx)
|
return render(request, "integrations/add_slack.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@require_setting("SLACK_ENABLED")
|
||||||
@require_setting("SLACK_CLIENT_ID")
|
@require_setting("SLACK_CLIENT_ID")
|
||||||
def slack_help(request):
|
def slack_help(request):
|
||||||
ctx = {"page": "channels"}
|
ctx = {"page": "channels"}
|
||||||
return render(request, "integrations/add_slack_btn.html", ctx)
|
return render(request, "integrations/add_slack_btn.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@require_setting("SLACK_ENABLED")
|
||||||
@require_setting("SLACK_CLIENT_ID")
|
@require_setting("SLACK_CLIENT_ID")
|
||||||
@login_required
|
@login_required
|
||||||
def add_slack_btn(request, code):
|
def add_slack_btn(request, code):
|
||||||
@ -1166,6 +1171,7 @@ def add_slack_btn(request, code):
|
|||||||
return render(request, "integrations/add_slack_btn.html", ctx)
|
return render(request, "integrations/add_slack_btn.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@require_setting("SLACK_ENABLED")
|
||||||
@require_setting("SLACK_CLIENT_ID")
|
@require_setting("SLACK_CLIENT_ID")
|
||||||
@login_required
|
@login_required
|
||||||
def add_slack_complete(request):
|
def add_slack_complete(request):
|
||||||
|
@ -221,6 +221,7 @@ SIGNAL_CLI_ENABLED = envbool("SIGNAL_CLI_ENABLED", "False")
|
|||||||
# Slack integration
|
# Slack integration
|
||||||
SLACK_CLIENT_ID = os.getenv("SLACK_CLIENT_ID")
|
SLACK_CLIENT_ID = os.getenv("SLACK_CLIENT_ID")
|
||||||
SLACK_CLIENT_SECRET = os.getenv("SLACK_CLIENT_SECRET")
|
SLACK_CLIENT_SECRET = os.getenv("SLACK_CLIENT_SECRET")
|
||||||
|
SLACK_ENABLED = envbool("SLACK_ENABLED", "True")
|
||||||
|
|
||||||
# Telegram integration -- override in local_settings.py
|
# Telegram integration -- override in local_settings.py
|
||||||
TELEGRAM_BOT_NAME = os.getenv("TELEGRAM_BOT_NAME", "ExampleBot")
|
TELEGRAM_BOT_NAME = os.getenv("TELEGRAM_BOT_NAME", "ExampleBot")
|
||||||
|
@ -267,10 +267,14 @@ its web UI and documentation.</p>
|
|||||||
it needs to construct absolute URLs.</p>
|
it needs to construct absolute URLs.</p>
|
||||||
<h2 id="SLACK_CLIENT_ID"><code>SLACK_CLIENT_ID</code></h2>
|
<h2 id="SLACK_CLIENT_ID"><code>SLACK_CLIENT_ID</code></h2>
|
||||||
<p>Default: <code>None</code></p>
|
<p>Default: <code>None</code></p>
|
||||||
<p>The Slack Client ID, required by the Slack integration.</p>
|
<p>The Slack Client ID, used by the Slack integration.</p>
|
||||||
<p>Go to <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>
|
<p>The Slack integration can work with or without the Slack Client ID. If
|
||||||
to create a <em>Slack app</em>, and look up its <em>Client ID</em> and <em>Client Secret</em>.</p>
|
the Slack Client ID is not set, in the "Integrations - Add Slack" page,
|
||||||
<p>When setting up the Slack app, make sure to:</p>
|
Healthchecks will ask the user to provide a webhook URL for posting notifications.</p>
|
||||||
|
<p>If the Slack Client <em>is</em> set, Healthchecks will use the OAuth2 flow
|
||||||
|
to get the webhook URL from Slack. The OAuth2 flow is more user-friendly.
|
||||||
|
To set it up, go to <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>
|
||||||
|
and create a <em>Slack app</em>. When setting up the Slack app, make sure to:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Add the <a href="https://api.slack.com/scopes/incoming-webhook">incoming-webhook</a>
|
<li>Add the <a href="https://api.slack.com/scopes/incoming-webhook">incoming-webhook</a>
|
||||||
scope to the Bot Token Scopes.</li>
|
scope to the Bot Token Scopes.</li>
|
||||||
@ -280,8 +284,11 @@ to create a <em>Slack app</em>, and look up its <em>Client ID</em> and <em>Clien
|
|||||||
</ul>
|
</ul>
|
||||||
<h2 id="SLACK_CLIENT_SECRET"><code>SLACK_CLIENT_SECRET</code></h2>
|
<h2 id="SLACK_CLIENT_SECRET"><code>SLACK_CLIENT_SECRET</code></h2>
|
||||||
<p>Default: <code>None</code></p>
|
<p>Default: <code>None</code></p>
|
||||||
<p>The Slack Client Secret, required by the Slack integration.
|
<p>The Slack Client Secret, required if <code>SLACK_CLIENT_ID</code> is set.
|
||||||
Look it up at <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>.</p>
|
Look it up at <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>.</p>
|
||||||
|
<h2 id="SLACK_ENABLED"><code>SLACK_ENABLED</code></h2>
|
||||||
|
<p>Default: <code>True</code></p>
|
||||||
|
<p>A boolean that turns on/off the Slack integration. Enabled by default.</p>
|
||||||
<h2 id="TELEGRAM_BOT_NAME"><code>TELEGRAM_BOT_NAME</code></h2>
|
<h2 id="TELEGRAM_BOT_NAME"><code>TELEGRAM_BOT_NAME</code></h2>
|
||||||
<p>Default: <code>ExampleBot</code></p>
|
<p>Default: <code>ExampleBot</code></p>
|
||||||
<p>The <a href="https://telegram.org/">Telegram</a> bot name, required by the Telegram integration.</p>
|
<p>The <a href="https://telegram.org/">Telegram</a> bot name, required by the Telegram integration.</p>
|
||||||
|
@ -427,12 +427,16 @@ it needs to construct absolute URLs.
|
|||||||
|
|
||||||
Default: `None`
|
Default: `None`
|
||||||
|
|
||||||
The Slack Client ID, required by the Slack integration.
|
The Slack Client ID, used by the Slack integration.
|
||||||
|
|
||||||
Go to [https://api.slack.com/apps/](https://api.slack.com/apps/)
|
The Slack integration can work with or without the Slack Client ID. If
|
||||||
to create a _Slack app_, and look up its _Client ID_ and _Client Secret_.
|
the Slack Client ID is not set, in the "Integrations - Add Slack" page,
|
||||||
|
Healthchecks will ask the user to provide a webhook URL for posting notifications.
|
||||||
|
|
||||||
When setting up the Slack app, make sure to:
|
If the Slack Client _is_ set, Healthchecks will use the OAuth2 flow
|
||||||
|
to get the webhook URL from Slack. The OAuth2 flow is more user-friendly.
|
||||||
|
To set it up, go to [https://api.slack.com/apps/](https://api.slack.com/apps/)
|
||||||
|
and create a _Slack app_. When setting up the Slack app, make sure to:
|
||||||
|
|
||||||
* Add the [incoming-webhook](https://api.slack.com/scopes/incoming-webhook)
|
* Add the [incoming-webhook](https://api.slack.com/scopes/incoming-webhook)
|
||||||
scope to the Bot Token Scopes.
|
scope to the Bot Token Scopes.
|
||||||
@ -444,9 +448,15 @@ When setting up the Slack app, make sure to:
|
|||||||
|
|
||||||
Default: `None`
|
Default: `None`
|
||||||
|
|
||||||
The Slack Client Secret, required by the Slack integration.
|
The Slack Client Secret. Required if `SLACK_CLIENT_ID` is set.
|
||||||
Look it up at [https://api.slack.com/apps/](https://api.slack.com/apps/).
|
Look it up at [https://api.slack.com/apps/](https://api.slack.com/apps/).
|
||||||
|
|
||||||
|
## `SLACK_ENABLED` {: #SLACK_ENABLED }
|
||||||
|
|
||||||
|
Default: `True`
|
||||||
|
|
||||||
|
A boolean that turns on/off the Slack integration. Enabled by default.
|
||||||
|
|
||||||
## `TELEGRAM_BOT_NAME` {: #TELEGRAM_BOT_NAME }
|
## `TELEGRAM_BOT_NAME` {: #TELEGRAM_BOT_NAME }
|
||||||
|
|
||||||
Default: `ExampleBot`
|
Default: `ExampleBot`
|
||||||
|
@ -186,6 +186,7 @@
|
|||||||
{% if rw %}
|
{% if rw %}
|
||||||
<h1 class="ai-title">Add More</h1>
|
<h1 class="ai-title">Add More</h1>
|
||||||
<ul class="add-integration">
|
<ul class="add-integration">
|
||||||
|
{% if enable_slack %}
|
||||||
<li>
|
<li>
|
||||||
<img src="{% static 'img/integrations/slack.png' %}"
|
<img src="{% static 'img/integrations/slack.png' %}"
|
||||||
class="icon" alt="Slack icon" />
|
class="icon" alt="Slack icon" />
|
||||||
@ -198,6 +199,8 @@
|
|||||||
<a href="{% url 'hc-add-slack' project.code %}" class="btn btn-primary">Add Integration</a>
|
<a href="{% url 'hc-add-slack' project.code %}" class="btn btn-primary">Add Integration</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<img src="{% static 'img/integrations/email.png' %}"
|
<img src="{% static 'img/integrations/email.png' %}"
|
||||||
class="icon" alt="Email icon" />
|
class="icon" alt="Email icon" />
|
||||||
|
@ -393,6 +393,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enable_slack %}
|
||||||
<div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
|
<div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
|
||||||
{% if enable_slack_btn %}
|
{% if enable_slack_btn %}
|
||||||
<a href="{% url 'hc-slack-help' %}" class="integration">
|
<a href="{% url 'hc-slack-help' %}" class="integration">
|
||||||
@ -412,6 +413,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if enable_apprise %}
|
{% if enable_apprise %}
|
||||||
<div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
|
<div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
<div class="row ai-step">
|
<div class="row ai-step">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<span class="step-no"></span>
|
<span class="step-no"></span>
|
||||||
<p>Copy the displayed <strong>WebHook URL</strong> and paste it down below.</p>
|
<p>Copy the displayed <strong>Webhook URL</strong> and paste it down below.</p>
|
||||||
<p>Save the integration, and it's done!</p>
|
<p>Save the integration, and it's done!</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
@ -57,7 +57,7 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group {{ form.value.css_classes }}">
|
<div class="form-group {{ form.value.css_classes }}">
|
||||||
<label for="callback-url" class="col-sm-2 control-label">
|
<label for="callback-url" class="col-sm-2 control-label">
|
||||||
Callback URL
|
Webhook URL
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input
|
<input
|
||||||
|
Loading…
x
Reference in New Issue
Block a user