diff --git a/README.md b/README.md
index 4a82a582..4be81b7a 100644
--- a/README.md
+++ b/README.md
@@ -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
pover://user@token/DEVICE
pover://user@token/DEVICE1/DEVICE2/DEVICEN
**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
rockets://user:password@hostname:443/Channel1/Channel1/RoomID
rocket://user:password@hostname/Channel
| [Ryver](https://github.com/caronc/apprise/wiki/Notify_ryver) | ryver:// | (TCP) 443 | ryver://Organization/Token
ryver://botname@Organization/Token
-| [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/Channel
slack://botname@TokenA/TokenB/TokenC/Channel
slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN
+| [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/
slack://TokenA/TokenB/TokenC/Channel
slack://botname@TokenA/TokenB/TokenC/Channel
slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN
| [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID
tgram://bottoken/ChatID1/ChatID2/ChatIDN
| [Twilio](https://github.com/caronc/apprise/wiki/Notify_twilio) | twilio:// | (TCP) 443 | twilio://AccountSid:AuthToken@FromPhoneNo
twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo
twilio://AccountSid:AuthToken@FromPhoneNo/ToPhoneNo1/ToPhoneNo2/ToPhoneNoN/
twilio://AccountSid:AuthToken@ShortCode/ToPhoneNo
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
diff --git a/apprise/plugins/NotifySlack.py b/apprise/plugins/NotifySlack.py
index 77c81023..0aad4657 100644
--- a/apprise/plugins/NotifySlack.py
+++ b/apprise/plugins/NotifySlack.py
@@ -36,7 +36,6 @@
#
#
import re
-import six
import requests
from json import dumps
from time import time
@@ -46,6 +45,7 @@ from ..common import NotifyImageSize
from ..common import NotifyType
from ..common import NotifyFormat
from ..utils import parse_bool
+from ..utils import parse_list
# Token required as part of the API request
# /AAAAAAAAA/........./........................
@@ -155,21 +155,13 @@ class NotifySlack(NotifyBase):
self.logger.warning(
'No user was specified; using %s.' % SLACK_DEFAULT_USER)
- if isinstance(targets, six.string_types):
- self.channels = [x for x in filter(bool, CHANNEL_LIST_DELIM.split(
- targets,
- ))]
-
- elif isinstance(targets, (set, tuple, list)):
- self.channels = targets
-
- else:
- self.channels = list()
-
+ # Build list of channels
+ self.channels = parse_list(targets)
if len(self.channels) == 0:
- msg = 'No channel(s) were specified.'
- self.logger.warning(msg)
- raise TypeError(msg)
+ # No problem; the webhook is smart enough to just notify the
+ # channel it was created for; adding 'None' is just used as
+ # a flag lower to not set the channels
+ self.channels.append(None)
# Formatting requirements are defined here:
# https://api.slack.com/docs/message-formatting
@@ -218,47 +210,48 @@ class NotifySlack(NotifyBase):
self.token_c,
)
+ # prepare JSON Object
+ payload = {
+ 'username': self.user if self.user else SLACK_DEFAULT_USER,
+ # Use Markdown language
+ 'mrkdwn': (self.notify_format == NotifyFormat.MARKDOWN),
+ 'attachments': [{
+ 'title': title,
+ 'text': body,
+ 'color': self.color(notify_type),
+ # Time
+ 'ts': time(),
+ 'footer': self.app_id,
+ }],
+ }
+
# 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:]
+ 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))
- elif len(channel) > 1 and channel[0] == '@':
- # Treat @ value 'as is'
- _channel = channel
+ # Mark our failure
+ has_error = True
+ continue
- else:
- # Prefix with channel hash tag
- _channel = '#%s' % channel
+ if len(channel) > 1 and channel[0] == '+':
+ # Treat as encoded id if prefixed with a +
+ payload['channel'] = channel[1:]
- # prepare JSON Object
- payload = {
- 'channel': _channel,
- 'username': self.user if self.user else SLACK_DEFAULT_USER,
- # Use Markdown language
- 'mrkdwn': (self.notify_format == NotifyFormat.MARKDOWN),
- 'attachments': [{
- 'title': title,
- 'text': body,
- 'color': self.color(notify_type),
- # Time
- 'ts': time(),
- 'footer': self.app_id,
- }],
- }
+ 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
image_url = None if not self.include_image \
@@ -288,9 +281,10 @@ class NotifySlack(NotifyBase):
r.status_code, SLACK_HTTP_ERROR_MAP)
self.logger.warning(
- 'Failed to send Slack notification to {}: '
+ 'Failed to send Slack notification{}: '
'{}{}error={}.'.format(
- channel,
+ ' to {}'.format(channel)
+ if channel is not None else '',
status_str,
', ' if status_str else '',
r.status_code))
@@ -304,13 +298,16 @@ class NotifySlack(NotifyBase):
else:
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:
self.logger.warning(
- 'A Connection error occured sending Slack:%s ' % (
- channel) + 'notification.'
- )
+ 'A Connection error occured sending Slack '
+ 'notification{}.'.format(
+ ' to {}'.format(channel)
+ if channel is not None else ''))
self.logger.debug('Socket Exception: %s' % str(e))
# Mark our failure
diff --git a/test/test_rest_plugins.py b/test/test_rest_plugins.py
index 7d5194a1..ef1c77a1 100644
--- a/test/test_rest_plugins.py
+++ b/test/test_rest_plugins.py
@@ -1671,8 +1671,8 @@ TEST_URLS = (
'instance': plugins.NotifySlack,
}),
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ', {
- # Missing a channel
- 'instance': TypeError,
+ # Missing a channel, falls back to webhook channel bindings
+ 'instance': plugins.NotifySlack,
}),
('slack://username@INVALID/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#cool', {
# 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_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
try:
plugins.NotifySlack(