mirror of https://github.com/caronc/apprise
more unit tests; 90% coverage
parent
f8c3d35f8c
commit
cc79763b3f
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -41,12 +41,14 @@ class NotifyImageSize(object):
|
|||
A list of pre-defined image sizes to make it easier to work with defined
|
||||
plugins.
|
||||
"""
|
||||
XY_32 = '32x32'
|
||||
XY_72 = '72x72'
|
||||
XY_128 = '128x128'
|
||||
XY_256 = '256x256'
|
||||
|
||||
|
||||
NOTIFY_IMAGE_SIZES = (
|
||||
NotifyImageSize.XY_32,
|
||||
NotifyImageSize.XY_72,
|
||||
NotifyImageSize.XY_128,
|
||||
NotifyImageSize.XY_256,
|
||||
|
|
|
@ -183,13 +183,9 @@ class NotifyMyAndroid(NotifyBase):
|
|||
|
||||
if 'format' in results['qsd'] and len(results['qsd']['format']):
|
||||
# Extract email format (Text/Html)
|
||||
try:
|
||||
format = NotifyBase.unquote(results['qsd']['format']).lower()
|
||||
if len(format) > 0 and format[0] == 't':
|
||||
results['notify_format'] = NotifyFormat.TEXT
|
||||
|
||||
except AttributeError:
|
||||
pass
|
||||
format = NotifyBase.unquote(results['qsd']['format']).lower()
|
||||
if len(format) > 0 and format[0] == 't':
|
||||
results['notify_format'] = NotifyFormat.TEXT
|
||||
|
||||
if 'priority' in results['qsd'] and len(results['qsd']['priority']):
|
||||
_map = {
|
||||
|
|
|
@ -31,7 +31,7 @@ VALIDATE_PROVIDERKEY = re.compile(r'[A-Za-z0-9]{40}')
|
|||
|
||||
# Priorities
|
||||
class ProwlPriority(object):
|
||||
VERY_LOW = -2
|
||||
LOW = -2
|
||||
MODERATE = -1
|
||||
NORMAL = 0
|
||||
HIGH = 1
|
||||
|
@ -39,7 +39,7 @@ class ProwlPriority(object):
|
|||
|
||||
|
||||
PROWL_PRIORITIES = (
|
||||
ProwlPriority.VERY_LOW,
|
||||
ProwlPriority.LOW,
|
||||
ProwlPriority.MODERATE,
|
||||
ProwlPriority.NORMAL,
|
||||
ProwlPriority.HIGH,
|
||||
|
@ -65,8 +65,7 @@ class NotifyProwl(NotifyBase):
|
|||
# Prowl uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.prowlapp.com/publicapi/add'
|
||||
|
||||
def __init__(self, apikey, providerkey=None, priority=ProwlPriority.NORMAL,
|
||||
**kwargs):
|
||||
def __init__(self, apikey, providerkey=None, priority=None, **kwargs):
|
||||
"""
|
||||
Initialize Prowl Object
|
||||
"""
|
||||
|
@ -146,7 +145,7 @@ class NotifyProwl(NotifyBase):
|
|||
PROWL_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Prowl notification '
|
||||
'(error=%s).' % (
|
||||
|
@ -159,7 +158,7 @@ class NotifyProwl(NotifyBase):
|
|||
else:
|
||||
self.logger.info('Sent Prowl notification.')
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Prowl notification.')
|
||||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
|
@ -186,15 +185,33 @@ class NotifyProwl(NotifyBase):
|
|||
|
||||
# optionally find the provider key
|
||||
try:
|
||||
providerkey = filter(
|
||||
bool, NotifyBase.split_path(results['fullpath']))[0]
|
||||
|
||||
if not providerkey:
|
||||
providerkey = None
|
||||
providerkey = [x for x in filter(
|
||||
bool, NotifyBase.split_path(results['fullpath']))][0]
|
||||
|
||||
except (AttributeError, IndexError):
|
||||
providerkey = None
|
||||
|
||||
if 'priority' in results['qsd'] and len(results['qsd']['priority']):
|
||||
_map = {
|
||||
'l': ProwlPriority.LOW,
|
||||
'-2': ProwlPriority.LOW,
|
||||
'm': ProwlPriority.MODERATE,
|
||||
'-1': ProwlPriority.MODERATE,
|
||||
'n': ProwlPriority.NORMAL,
|
||||
'0': ProwlPriority.NORMAL,
|
||||
'h': ProwlPriority.HIGH,
|
||||
'1': ProwlPriority.HIGH,
|
||||
'e': ProwlPriority.EMERGENCY,
|
||||
'2': ProwlPriority.EMERGENCY,
|
||||
}
|
||||
try:
|
||||
results['priority'] = \
|
||||
_map[results['qsd']['priority'][0].lower()]
|
||||
|
||||
except KeyError:
|
||||
# No priority was set
|
||||
pass
|
||||
|
||||
results['apikey'] = results['host']
|
||||
results['providerkey'] = providerkey
|
||||
|
||||
|
|
|
@ -60,11 +60,10 @@ class NotifyPushBullet(NotifyBase):
|
|||
|
||||
self.accesstoken = accesstoken
|
||||
if compat_is_basestring(recipients):
|
||||
self.recipients = filter(bool, RECIPIENTS_LIST_DELIM.split(
|
||||
recipients,
|
||||
))
|
||||
self.recipients = [x for x in filter(
|
||||
bool, RECIPIENTS_LIST_DELIM.split(recipients))]
|
||||
|
||||
elif isinstance(recipients, (tuple, list)):
|
||||
elif isinstance(recipients, (set, tuple, list)):
|
||||
self.recipients = recipients
|
||||
|
||||
else:
|
||||
|
@ -138,7 +137,7 @@ class NotifyPushBullet(NotifyBase):
|
|||
PUSHBULLET_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send PushBullet notification '
|
||||
'(error=%s).' % r.status_code)
|
||||
|
@ -148,7 +147,7 @@ class NotifyPushBullet(NotifyBase):
|
|||
# Return; we're done
|
||||
has_error = True
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending PushBullet '
|
||||
'notification.'
|
||||
|
@ -176,11 +175,7 @@ class NotifyPushBullet(NotifyBase):
|
|||
return results
|
||||
|
||||
# Apply our settings now
|
||||
try:
|
||||
recipients = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
except AttributeError:
|
||||
recipients = ''
|
||||
recipients = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
results['accesstoken'] = results['host']
|
||||
results['recipients'] = recipients
|
||||
|
|
|
@ -43,10 +43,7 @@ class NotifyPushalot(NotifyBase):
|
|||
A wrapper for Pushalot Notifications
|
||||
"""
|
||||
|
||||
# The default protocol
|
||||
protocol = 'palot'
|
||||
|
||||
# The default secure protocol
|
||||
# The default protocol is always secured
|
||||
secure_protocol = 'palot'
|
||||
|
||||
# Pushalot uses the http protocol with JSON requests
|
||||
|
@ -117,7 +114,7 @@ class NotifyPushalot(NotifyBase):
|
|||
PUSHALOT_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Pushalot notification '
|
||||
'(error=%s).' % r.status_code)
|
||||
|
@ -128,7 +125,7 @@ class NotifyPushalot(NotifyBase):
|
|||
else:
|
||||
self.logger.info('Sent Pushalot notification.')
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Pushalot notification.')
|
||||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
|
|
|
@ -27,18 +27,18 @@ from .NotifyBase import HTTP_ERROR_MAP
|
|||
PUSHOVER_SEND_TO_ALL = 'ALL_DEVICES'
|
||||
|
||||
# Used to validate API Key
|
||||
VALIDATE_TOKEN = re.compile(r'[A-Za-z0-9]{30}')
|
||||
VALIDATE_TOKEN = re.compile(r'^[a-z0-9]{30}$', re.I)
|
||||
|
||||
# Used to detect a User and/or Group
|
||||
VALIDATE_USERGROUP = re.compile(r'[A-Za-z0-9]{30}')
|
||||
VALIDATE_USERGROUP = re.compile(r'^[a-z0-9]{30}$', re.I)
|
||||
|
||||
# Used to detect a User and/or Group
|
||||
VALIDATE_DEVICE = re.compile(r'[A-Za-z0-9_]{1,25}')
|
||||
VALIDATE_DEVICE = re.compile(r'^[a-z0-9_]{1,25}$', re.I)
|
||||
|
||||
|
||||
# Priorities
|
||||
class PushoverPriority(object):
|
||||
VERY_LOW = -2
|
||||
LOW = -2
|
||||
MODERATE = -1
|
||||
NORMAL = 0
|
||||
HIGH = 1
|
||||
|
@ -46,7 +46,7 @@ class PushoverPriority(object):
|
|||
|
||||
|
||||
PUSHOVER_PRIORITIES = (
|
||||
PushoverPriority.VERY_LOW,
|
||||
PushoverPriority.LOW,
|
||||
PushoverPriority.MODERATE,
|
||||
PushoverPriority.NORMAL,
|
||||
PushoverPriority.HIGH,
|
||||
|
@ -68,24 +68,29 @@ class NotifyPushover(NotifyBase):
|
|||
A wrapper for Pushover Notifications
|
||||
"""
|
||||
|
||||
# The default protocol
|
||||
protocol = 'pover'
|
||||
|
||||
# The default secure protocol
|
||||
# All pushover requests are secure
|
||||
secure_protocol = 'pover'
|
||||
|
||||
# Pushover uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.pushover.net/1/messages.json'
|
||||
|
||||
def __init__(self, token, devices=None,
|
||||
priority=PushoverPriority.NORMAL, **kwargs):
|
||||
def __init__(self, token, devices=None, priority=None, **kwargs):
|
||||
"""
|
||||
Initialize Pushover Object
|
||||
"""
|
||||
super(NotifyPushover, self).__init__(
|
||||
title_maxlen=250, body_maxlen=512, **kwargs)
|
||||
|
||||
if not VALIDATE_TOKEN.match(token.strip()):
|
||||
try:
|
||||
# The token associated with the account
|
||||
self.token = token.strip()
|
||||
|
||||
except AttributeError:
|
||||
# Token was None
|
||||
self.logger.warning('No API Token was specified.')
|
||||
raise TypeError('No API Token was specified.')
|
||||
|
||||
if not VALIDATE_TOKEN.match(self.token):
|
||||
self.logger.warning(
|
||||
'The API Token specified (%s) is invalid.' % token,
|
||||
)
|
||||
|
@ -93,13 +98,10 @@ class NotifyPushover(NotifyBase):
|
|||
'The API Token specified (%s) is invalid.' % token,
|
||||
)
|
||||
|
||||
# The token associated with the account
|
||||
self.token = token.strip()
|
||||
|
||||
if compat_is_basestring(devices):
|
||||
self.devices = filter(bool, DEVICE_LIST_DELIM.split(
|
||||
self.devices = [x for x in filter(bool, DEVICE_LIST_DELIM.split(
|
||||
devices,
|
||||
))
|
||||
))]
|
||||
|
||||
elif isinstance(devices, (set, tuple, list)):
|
||||
self.devices = devices
|
||||
|
@ -121,10 +123,6 @@ class NotifyPushover(NotifyBase):
|
|||
self.logger.warning('No user was specified.')
|
||||
raise TypeError('No user was specified.')
|
||||
|
||||
if not self.token:
|
||||
self.logger.warning('No token was specified.')
|
||||
raise TypeError('No token was specified.')
|
||||
|
||||
if not VALIDATE_USERGROUP.match(self.user):
|
||||
self.logger.warning(
|
||||
'The user/group specified (%s) is invalid.' % self.user,
|
||||
|
@ -152,6 +150,13 @@ class NotifyPushover(NotifyBase):
|
|||
while len(devices):
|
||||
device = devices.pop(0)
|
||||
|
||||
if VALIDATE_DEVICE.match(device) is None:
|
||||
self.logger.warning(
|
||||
'The device specified (%s) is invalid.' % device,
|
||||
)
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
# prepare JSON Object
|
||||
payload = {
|
||||
'token': self.token,
|
||||
|
@ -159,18 +164,9 @@ class NotifyPushover(NotifyBase):
|
|||
'priority': str(self.priority),
|
||||
'title': title,
|
||||
'message': body,
|
||||
'device': device,
|
||||
}
|
||||
|
||||
if device != PUSHOVER_SEND_TO_ALL:
|
||||
if not VALIDATE_DEVICE.match(device):
|
||||
self.logger.warning(
|
||||
'The device specified (%s) is invalid.' % device,
|
||||
)
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
payload['device'] = device
|
||||
|
||||
self.logger.debug('Pushover POST URL: %s (cert_verify=%r)' % (
|
||||
self.notify_url, self.verify_certificate,
|
||||
))
|
||||
|
@ -193,7 +189,7 @@ class NotifyPushover(NotifyBase):
|
|||
PUSHOVER_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Pushover:%s '
|
||||
'notification (error=%s).' % (
|
||||
|
@ -205,7 +201,7 @@ class NotifyPushover(NotifyBase):
|
|||
# Return; we're done
|
||||
has_error = True
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Pushover:%s ' % (
|
||||
device) + 'notification.'
|
||||
|
@ -217,7 +213,7 @@ class NotifyPushover(NotifyBase):
|
|||
# Prevent thrashing requests
|
||||
self.throttle()
|
||||
|
||||
return has_error
|
||||
return not has_error
|
||||
|
||||
@staticmethod
|
||||
def parse_url(url):
|
||||
|
@ -233,11 +229,28 @@ class NotifyPushover(NotifyBase):
|
|||
return results
|
||||
|
||||
# Apply our settings now
|
||||
try:
|
||||
devices = NotifyBase.unquote(results['fullpath'])
|
||||
devices = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
except AttributeError:
|
||||
devices = ''
|
||||
if 'priority' in results['qsd'] and len(results['qsd']['priority']):
|
||||
_map = {
|
||||
'l': PushoverPriority.LOW,
|
||||
'-2': PushoverPriority.LOW,
|
||||
'm': PushoverPriority.MODERATE,
|
||||
'-1': PushoverPriority.MODERATE,
|
||||
'n': PushoverPriority.NORMAL,
|
||||
'0': PushoverPriority.NORMAL,
|
||||
'h': PushoverPriority.HIGH,
|
||||
'1': PushoverPriority.HIGH,
|
||||
'e': PushoverPriority.EMERGENCY,
|
||||
'2': PushoverPriority.EMERGENCY,
|
||||
}
|
||||
try:
|
||||
results['priority'] = \
|
||||
_map[results['qsd']['priority'][0].lower()]
|
||||
|
||||
except KeyError:
|
||||
# No priority was set
|
||||
pass
|
||||
|
||||
results['token'] = results['host']
|
||||
results['devices'] = devices
|
||||
|
|
|
@ -173,7 +173,7 @@ class NotifyRocketChat(NotifyBase):
|
|||
'%s (error=%s).' % (
|
||||
RC_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Rocket.Chat notification ' +
|
||||
'(error=%s).' % (
|
||||
|
@ -186,7 +186,7 @@ class NotifyRocketChat(NotifyBase):
|
|||
self.logger.debug('Rocket.Chat Server Response: %s.' % r.text)
|
||||
self.logger.info('Sent Rocket.Chat notification.')
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Rocket.Chat ' +
|
||||
'notification.')
|
||||
|
@ -277,6 +277,7 @@ class NotifyRocketChat(NotifyBase):
|
|||
'%s (error=%s).' % (
|
||||
RC_HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
self.logger.warning(
|
||||
'Failed to log off Rocket.Chat server ' +
|
||||
|
@ -316,10 +317,6 @@ class NotifyRocketChat(NotifyBase):
|
|||
return results
|
||||
|
||||
# Apply our settings now
|
||||
try:
|
||||
results['recipients'] = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
except AttributeError:
|
||||
return None
|
||||
results['recipients'] = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
return results
|
||||
|
|
|
@ -49,13 +49,13 @@ from json import dumps
|
|||
from .NotifyBase import NotifyBase
|
||||
from .NotifyBase import NotifyFormat
|
||||
from .NotifyBase import HTTP_ERROR_MAP
|
||||
|
||||
from ..common import NotifyImageSize
|
||||
from ..utils import compat_is_basestring
|
||||
|
||||
# Token required as part of the API request
|
||||
# allow the word 'bot' infront
|
||||
VALIDATE_BOT_TOKEN = re.compile(
|
||||
r'(bot)?(?P<key>[0-9]+:[A-Za-z0-9_-]+)/*$',
|
||||
r'^(bot)?(?P<key>[0-9]+:[a-z0-9_-]+)/*$',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
@ -63,7 +63,7 @@ VALIDATE_BOT_TOKEN = re.compile(
|
|||
# If the Chat ID is positive, then it's addressed to a single person
|
||||
# If the Chat ID is negative, then it's targeting a group
|
||||
IS_CHAT_ID_RE = re.compile(
|
||||
r'(@*(?P<idno>-?[0-9]{1,32})|(?P<name>[a-z_-][a-z0-9_-]*))',
|
||||
r'^(@*(?P<idno>-?[0-9]{1,32})|(?P<name>[a-z_-][a-z0-9_-]+))$',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
@ -71,7 +71,7 @@ IS_CHAT_ID_RE = re.compile(
|
|||
# The stickers/images are kind of big and consume a lot of space
|
||||
# It's not as appealing as just having the post not contain
|
||||
# an image at all.
|
||||
TELEGRAM_IMAGE_XY = None
|
||||
TELEGRAM_IMAGE_XY = NotifyImageSize.XY_32
|
||||
|
||||
# Used to break path apart into list of chat identifiers
|
||||
CHAT_ID_LIST_DELIM = re.compile(r'[ \t\r\n,#\\/]+')
|
||||
|
@ -88,32 +88,37 @@ class NotifyTelegram(NotifyBase):
|
|||
# Telegram uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.telegram.org/bot'
|
||||
|
||||
def __init__(self, bot_token, chat_ids, **kwargs):
|
||||
def __init__(self, bot_token, chat_ids, notify_format=NotifyFormat.HTML,
|
||||
**kwargs):
|
||||
"""
|
||||
Initialize Telegram Object
|
||||
"""
|
||||
super(NotifyTelegram, self).__init__(
|
||||
title_maxlen=250, body_maxlen=4096,
|
||||
image_size=TELEGRAM_IMAGE_XY, **kwargs)
|
||||
image_size=TELEGRAM_IMAGE_XY, notify_format=notify_format,
|
||||
**kwargs)
|
||||
|
||||
if bot_token is None:
|
||||
raise TypeError(
|
||||
'The Bot Token specified is invalid.'
|
||||
)
|
||||
try:
|
||||
self.bot_token = bot_token.strip()
|
||||
|
||||
result = VALIDATE_BOT_TOKEN.match(bot_token.strip())
|
||||
except AttributeError:
|
||||
# Token was None
|
||||
self.logger.warning('No Bot Token was specified.')
|
||||
raise TypeError('No Bot Token was specified.')
|
||||
|
||||
result = VALIDATE_BOT_TOKEN.match(self.bot_token)
|
||||
if not result:
|
||||
raise TypeError(
|
||||
'The Bot Token specified (%s) is invalid.' % bot_token,
|
||||
)
|
||||
|
||||
# Store our API Key
|
||||
# Store our Bot Token
|
||||
self.bot_token = result.group('key')
|
||||
|
||||
if compat_is_basestring(chat_ids):
|
||||
self.chat_ids = filter(bool, CHAT_ID_LIST_DELIM.split(
|
||||
self.chat_ids = [x for x in filter(bool, CHAT_ID_LIST_DELIM.split(
|
||||
chat_ids,
|
||||
))
|
||||
))]
|
||||
|
||||
elif isinstance(chat_ids, (set, tuple, list)):
|
||||
self.chat_ids = list(chat_ids)
|
||||
|
@ -125,51 +130,54 @@ class NotifyTelegram(NotifyBase):
|
|||
# Treat this as a channel too
|
||||
self.chat_ids.append(self.user)
|
||||
|
||||
# Bot's can't send messages to themselves which is fair enough
|
||||
# but if or when they can, this code will allow a default fallback
|
||||
# solution if no chat_id and/or channel is specified
|
||||
# if len(self.chat_ids) == 0:
|
||||
#
|
||||
# chat_id = self._get_chat_id()
|
||||
# if chat_id is not None:
|
||||
# self.logger.warning(
|
||||
# 'No chat_id or @channel was specified; ' +\
|
||||
# 'using detected bot_chat_id (%d).' % chat_id,
|
||||
# )
|
||||
# self.chat_ids.append(str(chat_id))
|
||||
|
||||
if len(self.chat_ids) == 0:
|
||||
self.logger.warning('No chat_id(s) were specified.')
|
||||
raise TypeError('No chat_id(s) were specified.')
|
||||
|
||||
def _get_chat_id(self):
|
||||
def notify_image(self, chat_id, notify_type, **kwargs):
|
||||
"""
|
||||
This function retrieves the chat id belonging to the key specified
|
||||
"""
|
||||
headers = {
|
||||
'User-Agent': self.app_id,
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
Sends the notification image based on the specified chat id
|
||||
|
||||
"""
|
||||
image_content = self.image_raw(notify_type)
|
||||
if image_content is None:
|
||||
# Nothing to do
|
||||
return True
|
||||
|
||||
# prepare our image URL
|
||||
url = '%s%s/%s' % (
|
||||
self.notify_url,
|
||||
self.bot_token,
|
||||
'getMe'
|
||||
'sendPhoto'
|
||||
)
|
||||
|
||||
self.logger.debug('Telegram (Detection) GET URL: %s' % url)
|
||||
# Set up our upload
|
||||
files = {'photo': ('%s.png' % notify_type, image_content)}
|
||||
|
||||
payload = {
|
||||
'chat_id': chat_id,
|
||||
'disable_notification': True,
|
||||
}
|
||||
|
||||
self.logger.debug(
|
||||
'Telegram (image) POST URL: %s (cert_verify=%r)' % (
|
||||
url, self.verify_certificate))
|
||||
|
||||
self.logger.debug(
|
||||
'Telegram (image) Payload: %s' % str(payload))
|
||||
|
||||
chat_id = None
|
||||
try:
|
||||
r = requests.post(url, headers=headers)
|
||||
if r.status_code == requests.codes.ok:
|
||||
# Extract our chat ID
|
||||
result = loads(r.text)
|
||||
if result.get('ok', False) is True:
|
||||
chat_id = result['result'].get('id')
|
||||
if chat_id <= 0:
|
||||
chat_id = None
|
||||
else:
|
||||
r = requests.post(
|
||||
url,
|
||||
data=payload,
|
||||
headers={
|
||||
'User-Agent': self.app_id,
|
||||
},
|
||||
files=files,
|
||||
verify=self.verify_certificate,
|
||||
)
|
||||
|
||||
if r.status_code != requests.codes.ok:
|
||||
# We had a problem
|
||||
try:
|
||||
# Try to get the error message if we can:
|
||||
|
@ -181,28 +189,38 @@ class NotifyTelegram(NotifyBase):
|
|||
try:
|
||||
if error_msg:
|
||||
self.logger.warning(
|
||||
'Failed to lookup Telegram chat_id from '
|
||||
'apikey: (%s) %s.' % (r.status_code, error_msg))
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification: (%s) %s.' % (
|
||||
payload['chat_id'],
|
||||
r.status_code, error_msg))
|
||||
|
||||
else:
|
||||
self.logger.warning(
|
||||
'Failed to lookup Telegram chat_id from '
|
||||
'apikey: %s (error=%s).' % (
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification: %s (error=%s).' % (
|
||||
payload['chat_id'],
|
||||
HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to lookup Telegram chat_id from '
|
||||
'apikey: (error=%s).' % r.status_code)
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification (error=%s).' % (
|
||||
payload['chat_id'],
|
||||
r.status_code))
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
return False
|
||||
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured looking up Telegram chat_id '
|
||||
'from apikey.')
|
||||
'A Connection error occured sending Telegram:%s ' % (
|
||||
payload['chat_id']) + 'notification.'
|
||||
)
|
||||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
return False
|
||||
|
||||
return chat_id
|
||||
# We were successful
|
||||
return True
|
||||
|
||||
def notify(self, title, body, notify_type, **kwargs):
|
||||
"""
|
||||
|
@ -217,19 +235,6 @@ class NotifyTelegram(NotifyBase):
|
|||
# error tracking (used for function return)
|
||||
has_error = False
|
||||
|
||||
image_url = None
|
||||
image_content = self.image_raw(notify_type)
|
||||
if image_content is not None:
|
||||
# prepare our image URL
|
||||
image_url = '%s%s/%s' % (
|
||||
self.notify_url,
|
||||
self.bot_token,
|
||||
'sendPhoto'
|
||||
)
|
||||
|
||||
# Set up our upload
|
||||
files = {'photo': ('%s.png' % notify_type, image_content)}
|
||||
|
||||
url = '%s%s/%s' % (
|
||||
self.notify_url,
|
||||
self.bot_token,
|
||||
|
@ -263,6 +268,7 @@ class NotifyTelegram(NotifyBase):
|
|||
chat_id,
|
||||
)
|
||||
)
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
if chat_id.group('name') is not None:
|
||||
|
@ -273,72 +279,19 @@ class NotifyTelegram(NotifyBase):
|
|||
# ID
|
||||
payload['chat_id'] = chat_id.group('idno')
|
||||
|
||||
if image_url is not None:
|
||||
image_payload = {
|
||||
'chat_id': payload['chat_id'],
|
||||
'disable_notification': True,
|
||||
}
|
||||
if not self.notify_image(
|
||||
chat_id=payload['chat_id'], notify_type=notify_type):
|
||||
# Uh oh... The image failed to post if we get here
|
||||
|
||||
self.logger.debug(
|
||||
'Telegram (image) POST URL: %s (cert_verify=%r)' % (
|
||||
image_url, self.verify_certificate))
|
||||
if len(chat_ids) > 0:
|
||||
# Prevent thrashing requests
|
||||
self.throttle()
|
||||
|
||||
self.logger.debug(
|
||||
'Telegram (image) Payload: %s' % str(image_payload))
|
||||
# Flag our error
|
||||
has_error = True
|
||||
|
||||
try:
|
||||
r = requests.post(
|
||||
image_url,
|
||||
data=image_payload,
|
||||
headers={
|
||||
'User-Agent': self.app_id,
|
||||
},
|
||||
files=files,
|
||||
verify=self.verify_certificate,
|
||||
)
|
||||
if r.status_code != requests.codes.ok:
|
||||
# We had a problem
|
||||
|
||||
try:
|
||||
# Try to get the error message if we can:
|
||||
error_msg = loads(r.text)['description']
|
||||
except:
|
||||
error_msg = None
|
||||
|
||||
try:
|
||||
if error_msg:
|
||||
self.logger.warning(
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification: (%s) %s.' % (
|
||||
payload['chat_id'],
|
||||
r.status_code, error_msg))
|
||||
|
||||
else:
|
||||
self.logger.warning(
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification: %s (error=%s).' % (
|
||||
payload['chat_id'],
|
||||
HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
self.logger.warning(
|
||||
'Failed to send Telegram Image:%s '
|
||||
'notification (error=%s).' % (
|
||||
payload['chat_id'],
|
||||
r.status_code))
|
||||
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Telegram:%s ' % (
|
||||
payload['chat_id']) + 'notification.'
|
||||
)
|
||||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
has_error = True
|
||||
continue
|
||||
# Move along
|
||||
continue
|
||||
|
||||
self.logger.debug('Telegram POST URL: %s' % url)
|
||||
self.logger.debug('Telegram POST URL: %s (cert_verify=%r)' % (
|
||||
|
@ -353,12 +306,14 @@ class NotifyTelegram(NotifyBase):
|
|||
headers=headers,
|
||||
verify=self.verify_certificate,
|
||||
)
|
||||
|
||||
if r.status_code != requests.codes.ok:
|
||||
# We had a problem
|
||||
|
||||
try:
|
||||
# Try to get the error message if we can:
|
||||
error_msg = loads(r.text)['description']
|
||||
|
||||
except:
|
||||
error_msg = None
|
||||
|
||||
|
@ -378,7 +333,7 @@ class NotifyTelegram(NotifyBase):
|
|||
HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Telegram:%s '
|
||||
'notification (error=%s).' % (
|
||||
|
@ -386,10 +341,10 @@ class NotifyTelegram(NotifyBase):
|
|||
|
||||
# self.logger.debug('Response Details: %s' % r.raw.read())
|
||||
|
||||
# Return; we're done
|
||||
# Flag our error
|
||||
has_error = True
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Telegram:%s ' % (
|
||||
payload['chat_id']) + 'notification.'
|
||||
|
@ -397,11 +352,12 @@ class NotifyTelegram(NotifyBase):
|
|||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
has_error = True
|
||||
|
||||
if len(chat_ids):
|
||||
# Prevent thrashing requests
|
||||
self.throttle()
|
||||
finally:
|
||||
if len(chat_ids):
|
||||
# Prevent thrashing requests
|
||||
self.throttle()
|
||||
|
||||
return has_error
|
||||
return not has_error
|
||||
|
||||
@staticmethod
|
||||
def parse_url(url):
|
||||
|
@ -410,14 +366,6 @@ class NotifyTelegram(NotifyBase):
|
|||
us to substantiate this object.
|
||||
|
||||
"""
|
||||
# super() is formatted slightly different when dealing with
|
||||
# static method inheritance
|
||||
results = NotifyBase.parse_url(url)
|
||||
|
||||
if results:
|
||||
# We're done early
|
||||
return results
|
||||
|
||||
# This is a dirty hack; but it's the only work around to
|
||||
# tgram:// messages since the bot_token has a colon in it.
|
||||
# It invalidates an normal URL.
|
||||
|
@ -427,11 +375,16 @@ class NotifyTelegram(NotifyBase):
|
|||
# alternative is to ask users to actually change the colon
|
||||
# into a slash (which will work too), but it's more likely
|
||||
# to cause confusion... So this is the next best thing
|
||||
tgram = re.match(
|
||||
r'(?P<protocol>%s://)(bot)?(?P<prefix>([a-z0-9_-]+)'
|
||||
r'(:[a-z0-9_-]+)?@)?(?P<btoken_a>[0-9]+):+'
|
||||
r'(?P<remaining>.*)$' % 'tgram',
|
||||
url, re.I)
|
||||
try:
|
||||
tgram = re.match(
|
||||
r'(?P<protocol>%s://)(bot)?(?P<prefix>([a-z0-9_-]+)'
|
||||
r'(:[a-z0-9_-]+)?@)?(?P<btoken_a>[0-9]+):+'
|
||||
r'(?P<remaining>.*)$' % NotifyTelegram.secure_protocol,
|
||||
url, re.I)
|
||||
|
||||
except (TypeError, AttributeError):
|
||||
# url is bad; force tgram to be None
|
||||
tgram = None
|
||||
|
||||
if not tgram:
|
||||
# Content is simply not parseable
|
||||
|
@ -439,7 +392,7 @@ class NotifyTelegram(NotifyBase):
|
|||
|
||||
if tgram.group('prefix'):
|
||||
# Try again
|
||||
result = NotifyBase.parse_url(
|
||||
results = NotifyBase.parse_url(
|
||||
'%s%s%s/%s' % (
|
||||
tgram.group('protocol'),
|
||||
tgram.group('prefix'),
|
||||
|
@ -450,7 +403,7 @@ class NotifyTelegram(NotifyBase):
|
|||
|
||||
else:
|
||||
# Try again
|
||||
result = NotifyBase.parse_url(
|
||||
results = NotifyBase.parse_url(
|
||||
'%s%s/%s' % (
|
||||
tgram.group('protocol'),
|
||||
tgram.group('btoken_a'),
|
||||
|
@ -459,30 +412,22 @@ class NotifyTelegram(NotifyBase):
|
|||
)
|
||||
|
||||
# The first token is stored in the hostnamee
|
||||
bot_token_a = result['host']
|
||||
bot_token_a = results['host']
|
||||
|
||||
# Now fetch the remaining tokens
|
||||
try:
|
||||
bot_token_b = filter(
|
||||
bool, NotifyBase.split_path(result['fullpath']))[0]
|
||||
bot_token_b = [x for x in filter(
|
||||
bool, NotifyBase.split_path(results['fullpath']))][0]
|
||||
|
||||
bot_token = '%s:%s' % (bot_token_a, bot_token_b)
|
||||
bot_token = '%s:%s' % (bot_token_a, bot_token_b)
|
||||
|
||||
except (AttributeError, IndexError):
|
||||
# Force a bad value that will get caught in parsing later
|
||||
bot_token = None
|
||||
chat_ids = ','.join(
|
||||
[x for x in filter(
|
||||
bool, NotifyBase.split_path(results['fullpath']))][1:])
|
||||
|
||||
try:
|
||||
chat_ids = ','.join(
|
||||
filter(bool, NotifyBase.split_path(result['fullpath']))[1:])
|
||||
# Store our bot token
|
||||
results['bot_token'] = bot_token
|
||||
|
||||
except (AttributeError, IndexError):
|
||||
# Force some bad values that will get caught
|
||||
# in parsing later
|
||||
chat_ids = None
|
||||
# Store our chat ids
|
||||
results['chat_ids'] = chat_ids
|
||||
|
||||
# Return our results
|
||||
return result + {
|
||||
'bot_token': bot_token,
|
||||
'chat_ids': chat_ids,
|
||||
}.items()
|
||||
return results
|
||||
|
|
|
@ -52,14 +52,17 @@ class NotifyToasty(NotifyBase):
|
|||
**kwargs)
|
||||
|
||||
if compat_is_basestring(devices):
|
||||
self.devices = filter(bool, DEVICES_LIST_DELIM.split(
|
||||
self.devices = [x for x in filter(bool, DEVICES_LIST_DELIM.split(
|
||||
devices,
|
||||
))
|
||||
))]
|
||||
|
||||
elif isinstance(devices, (tuple, list)):
|
||||
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:
|
||||
|
@ -118,7 +121,7 @@ class NotifyToasty(NotifyBase):
|
|||
HTTP_ERROR_MAP[r.status_code],
|
||||
r.status_code))
|
||||
|
||||
except IndexError:
|
||||
except KeyError:
|
||||
self.logger.warning(
|
||||
'Failed to send Toasty:%s '
|
||||
'notification (error=%s).' % (
|
||||
|
@ -130,7 +133,7 @@ class NotifyToasty(NotifyBase):
|
|||
# Return; we're done
|
||||
has_error = True
|
||||
|
||||
except requests.ConnectionError as e:
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occured sending Toasty:%s ' % (
|
||||
device) + 'notification.'
|
||||
|
@ -142,7 +145,7 @@ class NotifyToasty(NotifyBase):
|
|||
# Prevent thrashing requests
|
||||
self.throttle()
|
||||
|
||||
return has_error
|
||||
return not has_error
|
||||
|
||||
@staticmethod
|
||||
def parse_url(url):
|
||||
|
@ -158,11 +161,7 @@ class NotifyToasty(NotifyBase):
|
|||
return results
|
||||
|
||||
# Apply our settings now
|
||||
try:
|
||||
devices = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
except AttributeError:
|
||||
devices = ''
|
||||
devices = NotifyBase.unquote(results['fullpath'])
|
||||
|
||||
# Store our devices
|
||||
results['devices'] = '%s/%s' % (results['host'], devices)
|
||||
|
|
|
@ -20,10 +20,10 @@ from apprise import plugins
|
|||
from apprise import NotifyType
|
||||
from apprise import Apprise
|
||||
from apprise import AppriseAsset
|
||||
from json import dumps
|
||||
import requests
|
||||
import mock
|
||||
|
||||
|
||||
TEST_URLS = (
|
||||
##################################
|
||||
# NotifyBoxcar
|
||||
|
@ -176,7 +176,6 @@ TEST_URLS = (
|
|||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
# apikey = a
|
||||
('join://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyJoin,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
|
@ -380,8 +379,6 @@ TEST_URLS = (
|
|||
}),
|
||||
# Invalid APIKey
|
||||
('nma://%s' % ('a' * 24), {
|
||||
'instance': None,
|
||||
# Missing a channel
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIKey
|
||||
|
@ -390,6 +387,42 @@ TEST_URLS = (
|
|||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# APIKey + priority setting
|
||||
('nma://%s?priority=high' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# APIKey + invalid priority setting
|
||||
('nma://%s?priority=invalid' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# APIKey + priority setting (empty)
|
||||
('nma://%s?priority=' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# APIKey + Invalid DevAPI Key
|
||||
('nma://%s/%s' % ('a' * 48, 'b' * 24), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIKey + DevAPI Key
|
||||
('nma://%s/%s' % ('a' * 48, 'b' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# Testing valid format
|
||||
('nma://%s?format=text' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# Testing valid format
|
||||
('nma://%s?format=html' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# Testing invalid format (fall's back to html)
|
||||
('nma://%s?format=invalid' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# Testing empty format (falls back to html)
|
||||
('nma://%s?format=' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
}),
|
||||
# APIKey + with image
|
||||
('nma://%s' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
|
@ -410,7 +443,6 @@ TEST_URLS = (
|
|||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
# apikey = a
|
||||
('nma://%s' % ('a' * 48), {
|
||||
'instance': plugins.NotifyMyAndroid,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
|
@ -418,6 +450,262 @@ TEST_URLS = (
|
|||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyProwl
|
||||
##################################
|
||||
('prowl://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# APIkey; no device
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# Invalid APIKey
|
||||
('prowl://%s' % ('a' * 24), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIKey
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# APIKey + priority setting
|
||||
('prowl://%s?priority=high' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# APIKey + invalid priority setting
|
||||
('prowl://%s?priority=invalid' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# APIKey + priority setting (empty)
|
||||
('prowl://%s?priority=' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# APIKey + Invalid Provider Key
|
||||
('prowl://%s/%s' % ('a' * 40, 'b' * 24), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIKey + No Provider Key (empty)
|
||||
('prowl://%s///' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# APIKey + Provider Key
|
||||
('prowl://%s/%s' % ('a' * 40, 'b' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# APIKey + with image
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
}),
|
||||
# bad url
|
||||
('prowl://:@/', {
|
||||
'instance': None,
|
||||
}),
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
# force a failure
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('prowl://%s' % ('a' * 40), {
|
||||
'instance': plugins.NotifyProwl,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyPushalot
|
||||
##################################
|
||||
('palot://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# AuthToken
|
||||
('palot://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushalot,
|
||||
}),
|
||||
# AuthToken, no image
|
||||
('palot://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushalot,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# Invalid AuthToken
|
||||
('palot://%s' % ('a' * 24), {
|
||||
'instance': None,
|
||||
# Missing a channel
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# AuthToken + bad url
|
||||
('palot://:@/', {
|
||||
'instance': None,
|
||||
}),
|
||||
('palot://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushalot,
|
||||
# force a failure
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('palot://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushalot,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('palot://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushalot,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyPushBullet
|
||||
##################################
|
||||
('pbul://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# APIkey
|
||||
('pbul://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + channel
|
||||
('pbul://%s/#channel/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + 2 channels
|
||||
('pbul://%s/#channel1/#channel2' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + device
|
||||
('pbul://%s/device/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + 2 devices
|
||||
('pbul://%s/device1/device2/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + email
|
||||
('pbul://%s/user@example.com/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + 2 emails
|
||||
('pbul://%s/user@example.com/abc@def.com/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + Combo
|
||||
('pbul://%s/device/#channel/user@example.com/' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
}),
|
||||
# APIKey + bad url
|
||||
('pbul://:@/', {
|
||||
'instance': None,
|
||||
}),
|
||||
('pbul://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
# force a failure
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('pbul://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('pbul://%s' % ('a' * 32), {
|
||||
'instance': plugins.NotifyPushBullet,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyPushover
|
||||
##################################
|
||||
('pover://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# APIkey; no user
|
||||
('pover://%s' % ('a' * 30), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIkey; invalid user
|
||||
('pover://%s@%s' % ('u' * 20, 'a' * 30), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# Invalid APIKey; valid User
|
||||
('pover://%s@%s' % ('u' * 30, 'a' * 24), {
|
||||
'exception': TypeError,
|
||||
}),
|
||||
# APIKey + Valid User
|
||||
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# APIKey + Valid User + 1 Device
|
||||
('pover://%s@%s/DEVICE' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
}),
|
||||
# APIKey + Valid User + 2 Devices
|
||||
('pover://%s@%s/DEVICE1/DEVICE2/' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
}),
|
||||
# APIKey + Valid User + invalid device
|
||||
('pover://%s@%s/%s/' % ('u' * 30, 'a' * 30, 'd' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# Notify will return False since there is a bad device in our list
|
||||
'response': False,
|
||||
}),
|
||||
# APIKey + Valid User + device + invalid device
|
||||
('pover://%s@%s/DEVICE1/%s/' % ('u' * 30, 'a' * 30, 'd' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# Notify will return False since there is a bad device in our list
|
||||
'response': False,
|
||||
}),
|
||||
# APIKey + priority setting
|
||||
('pover://%s@%s?priority=high' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
}),
|
||||
# APIKey + invalid priority setting
|
||||
('pover://%s@%s?priority=invalid' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
}),
|
||||
# APIKey + priority setting (empty)
|
||||
('pover://%s@%s?priority=' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
}),
|
||||
# bad url
|
||||
('pover://:@/', {
|
||||
'instance': None,
|
||||
}),
|
||||
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# force a failure
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
||||
'instance': plugins.NotifyPushover,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifySlack
|
||||
##################################
|
||||
|
@ -486,6 +774,173 @@ TEST_URLS = (
|
|||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyTelegram
|
||||
##################################
|
||||
('tgram://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# Simple Message
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Simple Message (no images)
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# Simple Message with multiple chat names
|
||||
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Simple Message with an invalid chat ID
|
||||
('tgram://123456789:abcdefg_hijklmnop/%$/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# Notify will fail
|
||||
'response': False,
|
||||
}),
|
||||
# Simple Message with multiple chat ids
|
||||
('tgram://123456789:abcdefg_hijklmnop/id1/id2/23423/-30/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Simple Message with multiple chat ids (no images)
|
||||
('tgram://123456789:abcdefg_hijklmnop/id1/id2/23423/-30/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# Support bot keyword prefix
|
||||
('tgram://bottest@123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Testing valid format
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=text', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Testing valid format
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=html', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Testing invalid format (fall's back to text)
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=invalid', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Testing empty format (falls back to text)
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
}),
|
||||
# Simple Message without image
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# don't include an image by default
|
||||
'include_image': False,
|
||||
}),
|
||||
# Invalid Bot Token
|
||||
('tgram://alpha:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': None,
|
||||
}),
|
||||
# AuthToken + bad url
|
||||
('tgram://:@/', {
|
||||
'instance': None,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# force a failure
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# force a failure without an image specified
|
||||
'include_image': False,
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# force a failure with multiple chat_ids
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# force a failure without an image specified
|
||||
'include_image': False,
|
||||
'response': False,
|
||||
'requests_response_code': requests.codes.internal_server_error,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# throw a bizzare code forcing us to fail to look it up without
|
||||
# having an image included
|
||||
'include_image': False,
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
||||
'instance': plugins.NotifyTelegram,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them without images set
|
||||
'include_image': False,
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
|
||||
##################################
|
||||
# NotifyToasty (SuperToasty)
|
||||
##################################
|
||||
('toasty://', {
|
||||
'instance': None,
|
||||
}),
|
||||
# No username specified but contains a device
|
||||
('toasty://%s' % ('d' * 32), {
|
||||
'exception': 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
|
||||
##################################
|
||||
|
@ -696,6 +1151,9 @@ def test_rest_plugins(mock_post, mock_get):
|
|||
|
||||
assert(isinstance(obj, instance))
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
obj.throttle_attempt = 0
|
||||
|
||||
if self:
|
||||
# Iterate over our expected entries inside of our object
|
||||
for key, val in self.items():
|
||||
|
@ -711,9 +1169,9 @@ def test_rest_plugins(mock_post, mock_get):
|
|||
notify_type=notify_type) == response
|
||||
|
||||
else:
|
||||
for exception in test_requests_exceptions:
|
||||
mock_post.side_effect = exception
|
||||
mock_get.side_effect = exception
|
||||
for _exception in test_requests_exceptions:
|
||||
mock_post.side_effect = _exception
|
||||
mock_get.side_effect = _exception
|
||||
try:
|
||||
assert obj.notify(
|
||||
title='test', body='body',
|
||||
|
@ -805,6 +1263,10 @@ def test_notify_boxcar_plugin(mock_post, mock_get):
|
|||
|
||||
# Test notifications without a body or a title
|
||||
p = plugins.NotifyBoxcar(access=access, secret=secret, recipients=None)
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
p.throttle_attempt = 0
|
||||
|
||||
p.notify(body=None, title=None, notify_type=NotifyType.INFO) is True
|
||||
|
||||
|
||||
|
@ -835,6 +1297,9 @@ def test_notify_join_plugin(mock_post, mock_get):
|
|||
mock_post.return_value.status_code = requests.codes.created
|
||||
mock_get.return_value.status_code = requests.codes.created
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
p.throttle_attempt = 0
|
||||
|
||||
# Test notifications without a body or a title; nothing to send
|
||||
# so we return False
|
||||
p.notify(body=None, title=None, notify_type=NotifyType.INFO) is False
|
||||
|
@ -859,6 +1324,8 @@ def test_notify_slack_plugin(mock_post, mock_get):
|
|||
obj = plugins.NotifySlack(
|
||||
token_a=token_a, token_b=token_b, token_c=token_c, channels=channels)
|
||||
assert(len(obj.channels) == 4)
|
||||
|
||||
# Prepare Mock
|
||||
mock_get.return_value = requests.Request()
|
||||
mock_post.return_value = requests.Request()
|
||||
mock_post.return_value.status_code = requests.codes.ok
|
||||
|
@ -880,6 +1347,271 @@ def test_notify_slack_plugin(mock_post, mock_get):
|
|||
token_a=token_a, token_b=token_b, token_c=token_c, channels=channels,
|
||||
include_image=True)
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
obj.throttle_attempt = 0
|
||||
|
||||
# This call includes an image with it's payload:
|
||||
assert obj.notify(title='title', body='body',
|
||||
notify_type=NotifyType.INFO) is True
|
||||
|
||||
|
||||
@mock.patch('requests.get')
|
||||
@mock.patch('requests.post')
|
||||
def test_notify_pushbullet_plugin(mock_post, mock_get):
|
||||
"""
|
||||
API: NotifyPushBullet() Extra Checks
|
||||
|
||||
"""
|
||||
|
||||
# Initialize some generic (but valid) tokens
|
||||
accesstoken = 'a' * 32
|
||||
|
||||
# Support strings
|
||||
recipients = '#chan1,#chan2,device,user@example.com,,,'
|
||||
|
||||
# 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
|
||||
|
||||
obj = plugins.NotifyPushBullet(
|
||||
accesstoken=accesstoken, recipients=recipients)
|
||||
assert(isinstance(obj, plugins.NotifyPushBullet))
|
||||
assert(len(obj.recipients) == 4)
|
||||
|
||||
obj = plugins.NotifyPushBullet(accesstoken=accesstoken)
|
||||
assert(isinstance(obj, plugins.NotifyPushBullet))
|
||||
# Default is to send to all devices, so there will be a
|
||||
# recipient here
|
||||
assert(len(obj.recipients) == 1)
|
||||
|
||||
obj = plugins.NotifyPushBullet(accesstoken=accesstoken, recipients=set())
|
||||
assert(isinstance(obj, plugins.NotifyPushBullet))
|
||||
# Default is to send to all devices, so there will be a
|
||||
# recipient here
|
||||
assert(len(obj.recipients) == 1)
|
||||
|
||||
# Support the handling of an empty and invalid URL strings
|
||||
assert(plugins.NotifyPushBullet.parse_url(None) is None)
|
||||
assert(plugins.NotifyPushBullet.parse_url('') is None)
|
||||
assert(plugins.NotifyPushBullet.parse_url(42) is None)
|
||||
|
||||
|
||||
@mock.patch('requests.get')
|
||||
@mock.patch('requests.post')
|
||||
def test_notify_pushover_plugin(mock_post, mock_get):
|
||||
"""
|
||||
API: NotifyPushover() Extra Checks
|
||||
|
||||
"""
|
||||
|
||||
# Initialize some generic (but valid) tokens
|
||||
token = 'a' * 30
|
||||
user = 'u' * 30
|
||||
|
||||
invalid_device = 'd' * 35
|
||||
|
||||
# Support strings
|
||||
devices = 'device1,device2,,,,%s' % invalid_device
|
||||
|
||||
# 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.NotifyPushover(user=user, token=None)
|
||||
# No token specified
|
||||
assert(False)
|
||||
|
||||
except TypeError:
|
||||
# Exception should be thrown about the fact no token was specified
|
||||
assert(True)
|
||||
|
||||
obj = plugins.NotifyPushover(user=user, token=token, devices=devices)
|
||||
assert(isinstance(obj, plugins.NotifyPushover))
|
||||
assert(len(obj.devices) == 3)
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
obj.throttle_attempt = 0
|
||||
|
||||
# This call fails because there is 1 invalid device
|
||||
assert obj.notify(title='title', body='body',
|
||||
notify_type=NotifyType.INFO) is False
|
||||
|
||||
obj = plugins.NotifyPushover(user=user, token=token)
|
||||
assert(isinstance(obj, plugins.NotifyPushover))
|
||||
# Default is to send to all devices, so there will be a
|
||||
# device defined here
|
||||
assert(len(obj.devices) == 1)
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
obj.throttle_attempt = 0
|
||||
|
||||
# This call succeeds because all of the devices are valid
|
||||
assert obj.notify(title='title', body='body',
|
||||
notify_type=NotifyType.INFO) is True
|
||||
|
||||
obj = plugins.NotifyPushover(user=user, token=token, devices=set())
|
||||
assert(isinstance(obj, plugins.NotifyPushover))
|
||||
# Default is to send to all devices, so there will be a
|
||||
# device defined here
|
||||
assert(len(obj.devices) == 1)
|
||||
|
||||
# Support the handling of an empty and invalid URL strings
|
||||
assert(plugins.NotifyPushover.parse_url(None) is None)
|
||||
assert(plugins.NotifyPushover.parse_url('') is None)
|
||||
assert(plugins.NotifyPushover.parse_url(42) is None)
|
||||
|
||||
|
||||
@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):
|
||||
"""
|
||||
API: NotifyTelegram() Extra Checks
|
||||
|
||||
"""
|
||||
# Bot Token
|
||||
bot_token = '123456789:abcdefg_hijklmnop'
|
||||
invalid_bot_token = 'abcd:123'
|
||||
|
||||
# Chat ID
|
||||
chat_ids = 'l2g, lead2gold'
|
||||
|
||||
# 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.NotifyTelegram(bot_token=None, chat_ids=chat_ids)
|
||||
# invalid bot token (None)
|
||||
assert(False)
|
||||
|
||||
except TypeError:
|
||||
# Exception should be thrown about the fact no token was specified
|
||||
assert(True)
|
||||
|
||||
try:
|
||||
obj = plugins.NotifyTelegram(
|
||||
bot_token=invalid_bot_token, chat_ids=chat_ids)
|
||||
# invalid bot token
|
||||
assert(False)
|
||||
|
||||
except TypeError:
|
||||
# Exception should be thrown about the fact an invalid token was
|
||||
# specified
|
||||
assert(True)
|
||||
|
||||
try:
|
||||
obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids=None)
|
||||
# No chat_ids specified
|
||||
assert(False)
|
||||
|
||||
except TypeError:
|
||||
# Exception should be thrown about the fact no token was specified
|
||||
assert(True)
|
||||
|
||||
try:
|
||||
obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids=set())
|
||||
# No chat_ids specified
|
||||
assert(False)
|
||||
|
||||
except TypeError:
|
||||
# Exception should be thrown about the fact no token was specified
|
||||
assert(True)
|
||||
|
||||
obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids=chat_ids)
|
||||
assert(isinstance(obj, plugins.NotifyTelegram))
|
||||
assert(len(obj.chat_ids) == 2)
|
||||
|
||||
# Support the handling of an empty and invalid URL strings
|
||||
assert(plugins.NotifyTelegram.parse_url(None) is None)
|
||||
assert(plugins.NotifyTelegram.parse_url('') is None)
|
||||
assert(plugins.NotifyTelegram.parse_url(42) is None)
|
||||
|
||||
# Prepare Mock to fail
|
||||
response = mock.Mock()
|
||||
response.status_code = requests.codes.internal_server_error
|
||||
|
||||
# a error response
|
||||
response.text = dumps({
|
||||
'description': 'test',
|
||||
})
|
||||
mock_get.return_value = response
|
||||
mock_post.return_value = response
|
||||
|
||||
# No image asset
|
||||
nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids=chat_ids)
|
||||
nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)
|
||||
|
||||
# Disable throttling to speed up unit tests
|
||||
nimg_obj.throttle_attempt = 0
|
||||
obj.throttle_attempt = 0
|
||||
|
||||
# This tests erroneous messages involving multiple chat ids
|
||||
assert obj.notify(
|
||||
title='title', body='body', notify_type=NotifyType.INFO) is False
|
||||
assert nimg_obj.notify(
|
||||
title='title', body='body', notify_type=NotifyType.INFO) is False
|
||||
|
||||
# This tests erroneous messages involving a single chat id
|
||||
obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids='l2g')
|
||||
nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, chat_ids='l2g')
|
||||
nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)
|
||||
|
||||
assert obj.notify(
|
||||
title='title', body='body', notify_type=NotifyType.INFO) is False
|
||||
assert nimg_obj.notify(
|
||||
title='title', body='body', notify_type=NotifyType.INFO) is False
|
||||
|
|
Loading…
Reference in New Issue