diff --git a/README.md b/README.md index c0df29a5..c74feb84 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,6 @@ The table below identifies the services this tool supports and some example serv | [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 | [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 | [Stride](https://github.com/caronc/apprise/wiki/Notify_stride) | stride:// | (TCP) 443 | stride://auth_token/cloud_id/convo_id -| [Super Toasty](https://github.com/caronc/apprise/wiki/Notify_toasty) | toasty:// | (TCP) 80 | toasty://user@DEVICE
toasty://user@DEVICE1/DEVICE2/DEVICEN
_Note: you must specify both your user_id and at least 1 device!_ | [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID
tgram://bottoken/ChatID1/ChatID2/ChatIDN | [Twitter](https://github.com/caronc/apprise/wiki/Notify_twitter) | tweet:// | (TCP) 443 | tweet://user@CKey/CSecret/AKey/ASecret | [XBMC](https://github.com/caronc/apprise/wiki/Notify_xbmc) | xbmc:// or xbmcs:// | (TCP) 8080 or 443 | xbmc://hostname
xbmc://user@hostname
xbmc://user:password@hostname:port diff --git a/apprise/plugins/NotifyToasty.py b/apprise/plugins/NotifyToasty.py deleted file mode 100644 index 0f16881a..00000000 --- a/apprise/plugins/NotifyToasty.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2019 Chris Caron -# All rights reserved. -# -# This code is licensed under the MIT License. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files(the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions : -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import re -import requests - -from .NotifyBase import NotifyBase -from .NotifyBase import HTTP_ERROR_MAP -from ..common import NotifyImageSize -from ..utils import compat_is_basestring - -# Used to break apart list of potential devices by their delimiter -# into a usable list. -DEVICES_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+') - - -class NotifyToasty(NotifyBase): - """ - A wrapper for Toasty Notifications - """ - - # The default descriptive name associated with the Notification - service_name = 'Toasty' - - # The services URL - service_url = 'http://supertoasty.com/' - - # The default protocol - protocol = 'toasty' - - # A URL that takes you to the setup/help of the specific protocol - setup_url = 'https://github.com/caronc/apprise/wiki/Notify_toasty' - - # Toasty uses the http protocol with JSON requests - notify_url = 'http://api.supertoasty.com/notify/' - - # Allows the user to specify the NotifyImageSize object - image_size = NotifyImageSize.XY_128 - - def __init__(self, devices, **kwargs): - """ - Initialize Toasty Object - """ - super(NotifyToasty, self).__init__(**kwargs) - - if compat_is_basestring(devices): - self.devices = [x for x in filter(bool, DEVICES_LIST_DELIM.split( - devices, - ))] - - elif isinstance(devices, (set, tuple, list)): - self.devices = devices - - else: - self.devices = list() - - if len(devices) == 0: - raise TypeError('You must specify at least 1 device.') - - if not self.user: - raise TypeError('You must specify a username.') - - def notify(self, title, body, notify_type, **kwargs): - """ - Perform Toasty Notification - """ - - headers = { - 'User-Agent': self.app_id, - 'Content-Type': 'multipart/form-data', - } - - # error tracking (used for function return) - has_error = False - - # Create a copy of the devices list - devices = list(self.devices) - while len(devices): - device = devices.pop(0) - - # prepare JSON Object - payload = { - 'sender': NotifyBase.quote(self.user), - 'title': NotifyBase.quote(title), - 'text': NotifyBase.quote(body), - } - - image_url = self.image_url(notify_type) - if image_url: - payload['image'] = image_url - - # URL to transmit content via - url = '%s%s' % (self.notify_url, device) - - self.logger.debug('Toasty POST URL: %s (cert_verify=%r)' % ( - url, self.verify_certificate, - )) - self.logger.debug('Toasty Payload: %s' % str(payload)) - try: - r = requests.get( - url, - data=payload, - headers=headers, - verify=self.verify_certificate, - ) - if r.status_code != requests.codes.ok: - # We had a problem - try: - self.logger.warning( - 'Failed to send Toasty:%s ' - 'notification: %s (error=%s).' % ( - device, - HTTP_ERROR_MAP[r.status_code], - r.status_code)) - - except KeyError: - self.logger.warning( - 'Failed to send Toasty:%s ' - 'notification (error=%s).' % ( - device, - r.status_code)) - - # self.logger.debug('Response Details: %s' % r.raw.read()) - - # Return; we're done - has_error = True - - else: - self.logger.info( - 'Sent Toasty notification to %s.' % device) - - except requests.RequestException as e: - self.logger.warning( - 'A Connection error occured sending Toasty:%s ' % ( - device) + 'notification.' - ) - self.logger.debug('Socket Exception: %s' % str(e)) - has_error = True - - if len(devices): - # Prevent thrashing requests - self.throttle() - - return not has_error - - @staticmethod - def parse_url(url): - """ - Parses the URL and returns enough arguments that can allow - us to substantiate this object. - - """ - results = NotifyBase.parse_url(url) - - if not results: - # We're done early as we couldn't load the results - return results - - # Apply our settings now - devices = NotifyBase.unquote(results['fullpath']) - - # Store our devices - results['devices'] = '%s/%s' % (results['host'], devices) - - return results diff --git a/apprise/plugins/__init__.py b/apprise/plugins/__init__.py index fdc8e2f9..74880fed 100644 --- a/apprise/plugins/__init__.py +++ b/apprise/plugins/__init__.py @@ -49,7 +49,6 @@ from .NotifyRocketChat import NotifyRocketChat from .NotifySlack import NotifySlack from .NotifyStride import NotifyStride from .NotifyTelegram import NotifyTelegram -from .NotifyToasty import NotifyToasty from .NotifyTwitter.NotifyTwitter import NotifyTwitter from .NotifyXBMC import NotifyXBMC from .NotifyXML import NotifyXML @@ -71,7 +70,7 @@ __all__ = [ 'NotifyJSON', 'NotifyMatrix', 'NotifyMatterMost', 'NotifyProwl', 'NotifyPushalot', 'NotifyPushed', 'NotifyPushBullet', 'NotifyPushjet', 'NotifyPushover', 'NotifyRocketChat', 'NotifySlack', 'NotifyStride', - 'NotifyToasty', 'NotifyTwitter', 'NotifyTelegram', 'NotifyXBMC', + 'NotifyTwitter', 'NotifyTelegram', 'NotifyXBMC', 'NotifyXML', 'NotifyWindows', # Reference diff --git a/test/test_rest_plugins.py b/test/test_rest_plugins.py index 266dc19b..56c100d6 100644 --- a/test/test_rest_plugins.py +++ b/test/test_rest_plugins.py @@ -1361,49 +1361,6 @@ TEST_URLS = ( 'test_requests_exceptions': True, }), - ################################## - # NotifyToasty (SuperToasty) - ################################## - ('toasty://', { - 'instance': None, - }), - # No username specified but contains a device - ('toasty://%s' % ('d' * 32), { - 'instance': TypeError, - }), - # User + 1 device - ('toasty://user@device', { - 'instance': plugins.NotifyToasty, - }), - # User + 3 devices - ('toasty://user@device0/device1/device2/', { - 'instance': plugins.NotifyToasty, - # don't include an image by default - 'include_image': False, - }), - # bad url - ('toasty://:@/', { - 'instance': None, - }), - ('toasty://user@device', { - 'instance': plugins.NotifyToasty, - # force a failure - 'response': False, - 'requests_response_code': requests.codes.internal_server_error, - }), - ('toasty://user@device', { - 'instance': plugins.NotifyToasty, - # throw a bizzare code forcing us to fail to look it up - 'response': False, - 'requests_response_code': 999, - }), - ('toasty://user@device', { - 'instance': plugins.NotifyToasty, - # Throws a series of connection and transfer exceptions when this flag - # is set and tests that we gracfully handle them - 'test_requests_exceptions': True, - }), - ################################## # NotifyKODI ################################## @@ -2710,54 +2667,6 @@ def test_notify_rocketchat_plugin(mock_post, mock_get): assert obj.logout() is False -@mock.patch('requests.get') -@mock.patch('requests.post') -def test_notify_toasty_plugin(mock_post, mock_get): - """ - API: NotifyToasty() Extra Checks - - """ - - # Support strings - devices = 'device1,device2,,,,' - - # User - user = 'l2g' - - # Prepare Mock - mock_get.return_value = requests.Request() - mock_post.return_value = requests.Request() - mock_post.return_value.status_code = requests.codes.ok - mock_get.return_value.status_code = requests.codes.ok - - try: - obj = plugins.NotifyToasty(user=user, devices=None) - # No devices specified - assert(False) - - except TypeError: - # Exception should be thrown about the fact no token was specified - assert(True) - - try: - obj = plugins.NotifyToasty(user=user, devices=set()) - # No devices specified - assert(False) - - except TypeError: - # Exception should be thrown about the fact no token was specified - assert(True) - - obj = plugins.NotifyToasty(user=user, devices=devices) - assert(isinstance(obj, plugins.NotifyToasty)) - assert(len(obj.devices) == 2) - - # Support the handling of an empty and invalid URL strings - assert(plugins.NotifyToasty.parse_url(None) is None) - assert(plugins.NotifyToasty.parse_url('') is None) - assert(plugins.NotifyToasty.parse_url(42) is None) - - @mock.patch('requests.get') @mock.patch('requests.post') def test_notify_telegram_plugin(mock_post, mock_get):