mirror of
https://github.com/caronc/apprise.git
synced 2025-01-21 05:19:01 +01:00
Support Slack URLs missing channel references (#108)
This commit is contained in:
parent
333926c359
commit
51a5ce344a
@ -57,7 +57,7 @@ The table below identifies the services this tool supports and some example serv
|
|||||||
| [Pushover](https://github.com/caronc/apprise/wiki/Notify_pushover) | pover:// | (TCP) 443 | pover://user@token<br />pover://user@token/DEVICE<br />pover://user@token/DEVICE1/DEVICE2/DEVICEN<br />**Note**: you must specify both your user_id and token
|
| [Pushover](https://github.com/caronc/apprise/wiki/Notify_pushover) | pover:// | (TCP) 443 | pover://user@token<br />pover://user@token/DEVICE<br />pover://user@token/DEVICE1/DEVICE2/DEVICEN<br />**Note**: you must specify both your user_id and token
|
||||||
| [Rocket.Chat](https://github.com/caronc/apprise/wiki/Notify_rocketchat) | rocket:// or rockets:// | (TCP) 80 or 443 | rocket://user:password@hostname/RoomID/Channel<br />rockets://user:password@hostname:443/Channel1/Channel1/RoomID<br />rocket://user:password@hostname/Channel
|
| [Rocket.Chat](https://github.com/caronc/apprise/wiki/Notify_rocketchat) | rocket:// or rockets:// | (TCP) 80 or 443 | rocket://user:password@hostname/RoomID/Channel<br />rockets://user:password@hostname:443/Channel1/Channel1/RoomID<br />rocket://user:password@hostname/Channel
|
||||||
| [Ryver](https://github.com/caronc/apprise/wiki/Notify_ryver) | ryver:// | (TCP) 443 | ryver://Organization/Token<br />ryver://botname@Organization/Token
|
| [Ryver](https://github.com/caronc/apprise/wiki/Notify_ryver) | ryver:// | (TCP) 443 | ryver://Organization/Token<br />ryver://botname@Organization/Token
|
||||||
| [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/Channel<br />slack://botname@TokenA/TokenB/TokenC/Channel<br />slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN
|
| [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/<br />slack://TokenA/TokenB/TokenC/Channel<br />slack://botname@TokenA/TokenB/TokenC/Channel<br />slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN
|
||||||
| [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID<br />tgram://bottoken/ChatID1/ChatID2/ChatIDN
|
| [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID<br />tgram://bottoken/ChatID1/ChatID2/ChatIDN
|
||||||
| [Twilio](https://github.com/caronc/apprise/wiki/Notify_twilio) | twilio:// | (TCP) 443 | twilio://AccountSid:AuthToken@FromPhoneNo<br/>twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo<br/>twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo1/ToPhoneNo2/ToPhoneNoN/<br/>twilio://AccountSid:AuthToken@ShortCode/ToPhoneNo<br/>twilio://AccountSid:AuthToken@ShortCode/ToPhoneNo1/ToPhoneNo2/ToPhoneNoN/
|
| [Twilio](https://github.com/caronc/apprise/wiki/Notify_twilio) | twilio:// | (TCP) 443 | twilio://AccountSid:AuthToken@FromPhoneNo<br/>twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo<br/>twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo1/ToPhoneNo2/ToPhoneNoN/<br/>twilio://AccountSid:AuthToken@ShortCode/ToPhoneNo<br/>twilio://AccountSid:AuthToken@ShortCode/ToPhoneNo1/ToPhoneNo2/ToPhoneNoN/
|
||||||
| [Twitter](https://github.com/caronc/apprise/wiki/Notify_twitter) | tweet:// | (TCP) 443 | tweet://user@CKey/CSecret/AKey/ASecret
|
| [Twitter](https://github.com/caronc/apprise/wiki/Notify_twitter) | tweet:// | (TCP) 443 | tweet://user@CKey/CSecret/AKey/ASecret
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
import re
|
import re
|
||||||
import six
|
|
||||||
import requests
|
import requests
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from time import time
|
from time import time
|
||||||
@ -46,6 +45,7 @@ from ..common import NotifyImageSize
|
|||||||
from ..common import NotifyType
|
from ..common import NotifyType
|
||||||
from ..common import NotifyFormat
|
from ..common import NotifyFormat
|
||||||
from ..utils import parse_bool
|
from ..utils import parse_bool
|
||||||
|
from ..utils import parse_list
|
||||||
|
|
||||||
# Token required as part of the API request
|
# Token required as part of the API request
|
||||||
# /AAAAAAAAA/........./........................
|
# /AAAAAAAAA/........./........................
|
||||||
@ -155,21 +155,13 @@ class NotifySlack(NotifyBase):
|
|||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'No user was specified; using %s.' % SLACK_DEFAULT_USER)
|
'No user was specified; using %s.' % SLACK_DEFAULT_USER)
|
||||||
|
|
||||||
if isinstance(targets, six.string_types):
|
# Build list of channels
|
||||||
self.channels = [x for x in filter(bool, CHANNEL_LIST_DELIM.split(
|
self.channels = parse_list(targets)
|
||||||
targets,
|
|
||||||
))]
|
|
||||||
|
|
||||||
elif isinstance(targets, (set, tuple, list)):
|
|
||||||
self.channels = targets
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.channels = list()
|
|
||||||
|
|
||||||
if len(self.channels) == 0:
|
if len(self.channels) == 0:
|
||||||
msg = 'No channel(s) were specified.'
|
# No problem; the webhook is smart enough to just notify the
|
||||||
self.logger.warning(msg)
|
# channel it was created for; adding 'None' is just used as
|
||||||
raise TypeError(msg)
|
# a flag lower to not set the channels
|
||||||
|
self.channels.append(None)
|
||||||
|
|
||||||
# Formatting requirements are defined here:
|
# Formatting requirements are defined here:
|
||||||
# https://api.slack.com/docs/message-formatting
|
# https://api.slack.com/docs/message-formatting
|
||||||
@ -218,35 +210,8 @@ class NotifySlack(NotifyBase):
|
|||||||
self.token_c,
|
self.token_c,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a copy of the channel list
|
|
||||||
channels = list(self.channels)
|
|
||||||
while len(channels):
|
|
||||||
channel = channels.pop(0)
|
|
||||||
if not IS_CHANNEL_RE.match(channel):
|
|
||||||
self.logger.warning(
|
|
||||||
"The specified channel '%s' is invalid; skipping." % (
|
|
||||||
channel,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# Mark our failure
|
|
||||||
has_error = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if len(channel) > 1 and channel[0] == '+':
|
|
||||||
# Treat as encoded id if prefixed with a +
|
|
||||||
_channel = channel[1:]
|
|
||||||
|
|
||||||
elif len(channel) > 1 and channel[0] == '@':
|
|
||||||
# Treat @ value 'as is'
|
|
||||||
_channel = channel
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Prefix with channel hash tag
|
|
||||||
_channel = '#%s' % channel
|
|
||||||
|
|
||||||
# prepare JSON Object
|
# prepare JSON Object
|
||||||
payload = {
|
payload = {
|
||||||
'channel': _channel,
|
|
||||||
'username': self.user if self.user else SLACK_DEFAULT_USER,
|
'username': self.user if self.user else SLACK_DEFAULT_USER,
|
||||||
# Use Markdown language
|
# Use Markdown language
|
||||||
'mrkdwn': (self.notify_format == NotifyFormat.MARKDOWN),
|
'mrkdwn': (self.notify_format == NotifyFormat.MARKDOWN),
|
||||||
@ -260,6 +225,34 @@ class NotifySlack(NotifyBase):
|
|||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Create a copy of the channel list
|
||||||
|
channels = list(self.channels)
|
||||||
|
while len(channels):
|
||||||
|
channel = channels.pop(0)
|
||||||
|
|
||||||
|
if channel is not None:
|
||||||
|
# Channel over-ride was specified
|
||||||
|
if not IS_CHANNEL_RE.match(channel):
|
||||||
|
self.logger.warning(
|
||||||
|
"The specified target {} is invalid;"
|
||||||
|
"skipping.".format(channel))
|
||||||
|
|
||||||
|
# Mark our failure
|
||||||
|
has_error = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(channel) > 1 and channel[0] == '+':
|
||||||
|
# Treat as encoded id if prefixed with a +
|
||||||
|
payload['channel'] = channel[1:]
|
||||||
|
|
||||||
|
elif len(channel) > 1 and channel[0] == '@':
|
||||||
|
# Treat @ value 'as is'
|
||||||
|
payload['channel'] = channel
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Prefix with channel hash tag
|
||||||
|
payload['channel'] = '#%s' % channel
|
||||||
|
|
||||||
# Acquire our to-be footer icon if configured to do so
|
# Acquire our to-be footer icon if configured to do so
|
||||||
image_url = None if not self.include_image \
|
image_url = None if not self.include_image \
|
||||||
else self.image_url(notify_type)
|
else self.image_url(notify_type)
|
||||||
@ -288,9 +281,10 @@ class NotifySlack(NotifyBase):
|
|||||||
r.status_code, SLACK_HTTP_ERROR_MAP)
|
r.status_code, SLACK_HTTP_ERROR_MAP)
|
||||||
|
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'Failed to send Slack notification to {}: '
|
'Failed to send Slack notification{}: '
|
||||||
'{}{}error={}.'.format(
|
'{}{}error={}.'.format(
|
||||||
channel,
|
' to {}'.format(channel)
|
||||||
|
if channel is not None else '',
|
||||||
status_str,
|
status_str,
|
||||||
', ' if status_str else '',
|
', ' if status_str else '',
|
||||||
r.status_code))
|
r.status_code))
|
||||||
@ -304,13 +298,16 @@ class NotifySlack(NotifyBase):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'Sent Slack notification to {}.'.format(channel))
|
'Sent Slack notification{}.'.format(
|
||||||
|
' to {}'.format(channel)
|
||||||
|
if channel is not None else ''))
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'A Connection error occured sending Slack:%s ' % (
|
'A Connection error occured sending Slack '
|
||||||
channel) + 'notification.'
|
'notification{}.'.format(
|
||||||
)
|
' to {}'.format(channel)
|
||||||
|
if channel is not None else ''))
|
||||||
self.logger.debug('Socket Exception: %s' % str(e))
|
self.logger.debug('Socket Exception: %s' % str(e))
|
||||||
|
|
||||||
# Mark our failure
|
# Mark our failure
|
||||||
|
@ -1671,8 +1671,8 @@ TEST_URLS = (
|
|||||||
'instance': plugins.NotifySlack,
|
'instance': plugins.NotifySlack,
|
||||||
}),
|
}),
|
||||||
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ', {
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ', {
|
||||||
# Missing a channel
|
# Missing a channel, falls back to webhook channel bindings
|
||||||
'instance': TypeError,
|
'instance': plugins.NotifySlack,
|
||||||
}),
|
}),
|
||||||
('slack://username@INVALID/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#cool', {
|
('slack://username@INVALID/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#cool', {
|
||||||
# invalid 1st Token
|
# invalid 1st Token
|
||||||
@ -3157,17 +3157,6 @@ def test_notify_slack_plugin(mock_post, mock_get):
|
|||||||
mock_post.return_value.status_code = requests.codes.ok
|
mock_post.return_value.status_code = requests.codes.ok
|
||||||
mock_get.return_value.status_code = requests.codes.ok
|
mock_get.return_value.status_code = requests.codes.ok
|
||||||
|
|
||||||
# Empty Channel list
|
|
||||||
try:
|
|
||||||
plugins.NotifySlack(
|
|
||||||
token_a=token_a, token_b=token_b, token_c=token_c,
|
|
||||||
targets=None)
|
|
||||||
assert False
|
|
||||||
|
|
||||||
except TypeError:
|
|
||||||
# we'll thrown because an empty list of channels was provided
|
|
||||||
assert True
|
|
||||||
|
|
||||||
# Missing first Token
|
# Missing first Token
|
||||||
try:
|
try:
|
||||||
plugins.NotifySlack(
|
plugins.NotifySlack(
|
||||||
|
Loading…
Reference in New Issue
Block a user