Merge pull request #57 from caronc/52-telegram-code-block-support

telegram markdown support added; refs #52
pull/58/head
Chris Caron 2019-02-06 00:03:20 -05:00 committed by GitHub
commit 042c5ed2da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 46 deletions

View File

@ -159,9 +159,9 @@ class NotifyBase(object):
self.user = kwargs.get('user') self.user = kwargs.get('user')
self.password = kwargs.get('password') self.password = kwargs.get('password')
if 'notify_format' in kwargs: if 'format' in kwargs:
# Store the specified notify_format if specified # Store the specified format if specified
notify_format = kwargs.get('notify_format') notify_format = kwargs.get('format', '')
if notify_format.lower() not in NOTIFY_FORMATS: if notify_format.lower() not in NOTIFY_FORMATS:
self.logger.error( self.logger.error(
'Invalid notification format %s' % notify_format, 'Invalid notification format %s' % notify_format,

View File

@ -227,6 +227,9 @@ class NotifyEmail(NotifyBase):
# A URL that takes you to the setup/help of the specific protocol # A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_email' setup_url = 'https://github.com/caronc/apprise/wiki/Notify_email'
# Default Notify Format
notify_format = NotifyFormat.HTML
# Default Non-Encryption Port # Default Non-Encryption Port
default_port = 25 default_port = 25
@ -433,20 +436,10 @@ class NotifyEmail(NotifyBase):
# Apply our settings now # Apply our settings now
# Default Format is HTML
results['notify_format'] = NotifyFormat.HTML
results['secure_mode'] = NotifyEmail.default_secure_mode
to_addr = '' to_addr = ''
from_addr = '' from_addr = ''
smtp_host = '' smtp_host = ''
if 'format' in results['qsd'] and len(results['qsd']['format']):
# Extract email format (Text/Html)
format = NotifyBase.unquote(results['qsd']['format']).lower()
if len(format) > 0 and format[0] == 't':
results['notify_format'] = NotifyFormat.TEXT
# Attempt to detect 'from' email address # Attempt to detect 'from' email address
if 'from' in results['qsd'] and len(results['qsd']['from']): if 'from' in results['qsd'] and len(results['qsd']['from']):
from_addr = NotifyBase.unquote(results['qsd']['from']) from_addr = NotifyBase.unquote(results['qsd']['from'])

View File

@ -62,6 +62,7 @@ from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyImageSize from ..common import NotifyImageSize
from ..utils import compat_is_basestring from ..utils import compat_is_basestring
from ..utils import parse_bool from ..utils import parse_bool
from ..common import NotifyFormat
TELEGRAM_IMAGE_XY = NotifyImageSize.XY_256 TELEGRAM_IMAGE_XY = NotifyImageSize.XY_256
@ -262,7 +263,7 @@ class NotifyTelegram(NotifyBase):
# Try to get the error message if we can: # Try to get the error message if we can:
error_msg = loads(r.content)['description'] error_msg = loads(r.content)['description']
except: except Exception:
error_msg = None error_msg = None
try: try:
@ -356,25 +357,51 @@ class NotifyTelegram(NotifyBase):
payload = {} payload = {}
# Prepare Email Message
if self.notify_format == NotifyFormat.MARKDOWN:
payload['parse_mode'] = 'MARKDOWN'
else:
# Either TEXT or HTML; if TEXT we'll make it HTML
payload['parse_mode'] = 'HTML'
# HTML Spaces ( ) and tabs ( ) aren't supported
# See https://core.telegram.org/bots/api#html-style
body = re.sub(' ?', ' ', body, re.I)
# Tabs become 3 spaces
body = re.sub(' ?', ' ', body, re.I)
if title:
# HTML Spaces ( ) and tabs ( ) aren't supported # HTML Spaces ( ) and tabs ( ) aren't supported
# See https://core.telegram.org/bots/api#html-style # See https://core.telegram.org/bots/api#html-style
title = re.sub(' ?', ' ', title, re.I) title = re.sub(' ?', ' ', title, re.I)
body = re.sub(' ?', ' ', body, re.I)
# Tabs become 3 spaces # Tabs become 3 spaces
title = re.sub(' ?', ' ', title, re.I) title = re.sub(' ?', ' ', title, re.I)
body = re.sub(' ?', ' ', body, re.I)
# HTML # HTML
title = NotifyBase.escape_html(title, whitespace=False) title = NotifyBase.escape_html(title, whitespace=False)
body = NotifyBase.escape_html(body, whitespace=False) body = NotifyBase.escape_html(body, whitespace=False)
payload['parse_mode'] = 'HTML' # Assign the body
payload['text'] = body
if title and self.notify_format == NotifyFormat.TEXT:
# Text HTML Formatting
payload['text'] = '<b>%s</b>\r\n%s' % ( payload['text'] = '<b>%s</b>\r\n%s' % (
title, title,
body, body,
) )
elif title:
# Already HTML; trust developer has wrapped
# the title appropriately
payload['text'] = '%s\r\n%s' % (
title,
body,
)
# Create a copy of the chat_ids list # Create a copy of the chat_ids list
chat_ids = list(self.chat_ids) chat_ids = list(self.chat_ids)
while len(chat_ids): while len(chat_ids):
@ -426,7 +453,7 @@ class NotifyTelegram(NotifyBase):
# Try to get the error message if we can: # Try to get the error message if we can:
error_msg = loads(r.content)['description'] error_msg = loads(r.content)['description']
except: except Exception:
error_msg = None error_msg = None
try: try:

View File

@ -35,7 +35,6 @@ from apprise import NotifyBase
from apprise import NotifyType from apprise import NotifyType
from apprise import NotifyFormat from apprise import NotifyFormat
from apprise import NotifyImageSize from apprise import NotifyImageSize
from apprise import plugins
from apprise import __version__ from apprise import __version__
from apprise.Apprise import __load_matrix from apprise.Apprise import __load_matrix
import pytest import pytest
@ -243,27 +242,35 @@ def test_apprise_notify_formats(tmpdir):
assert(len(a) == 0) assert(len(a) == 0)
class TextNotification(NotifyBase): class TextNotification(NotifyBase):
# set our default notification format
notify_format = NotifyFormat.TEXT
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(TextNotification, self).__init__( super(TextNotification, self).__init__()
notify_format=NotifyFormat.TEXT)
def notify(self, **kwargs): def notify(self, **kwargs):
# Pretend everything is okay # Pretend everything is okay
return True return True
class HtmlNotification(NotifyBase): class HtmlNotification(NotifyBase):
# set our default notification format
notify_format = NotifyFormat.HTML
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(HtmlNotification, self).__init__( super(HtmlNotification, self).__init__()
notify_format=NotifyFormat.HTML)
def notify(self, **kwargs): def notify(self, **kwargs):
# Pretend everything is okay # Pretend everything is okay
return True return True
class MarkDownNotification(NotifyBase): class MarkDownNotification(NotifyBase):
# set our default notification format
notify_format = NotifyFormat.MARKDOWN
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(MarkDownNotification, self).__init__( super(MarkDownNotification, self).__init__()
notify_format=NotifyFormat.MARKDOWN)
def notify(self, **kwargs): def notify(self, **kwargs):
# Pretend everything is okay # Pretend everything is okay
@ -339,7 +346,7 @@ def test_apprise_asset(tmpdir):
# The exception we expect since dict is not supported # The exception we expect since dict is not supported
assert(True) assert(True)
except: except Exception:
# Any other exception is not good # Any other exception is not good
assert(False) assert(False)

View File

@ -26,6 +26,8 @@
from apprise import plugins from apprise import plugins
from apprise import NotifyType from apprise import NotifyType
from apprise import Apprise from apprise import Apprise
from apprise.plugins import NotifyEmailBase
import smtplib import smtplib
import mock import mock
import re import re
@ -287,8 +289,6 @@ def test_webbase_lookup(mock_smtp, mock_smtpssl):
""" """
from apprise.plugins import NotifyEmailBase
# Insert a test email at the head of our table # Insert a test email at the head of our table
NotifyEmailBase.WEBBASE_LOOKUP_TABLE = ( NotifyEmailBase.WEBBASE_LOOKUP_TABLE = (
( (
@ -324,8 +324,6 @@ def test_smtplib_init_fail(mock_smtplib):
""" """
from apprise.plugins import NotifyEmailBase
obj = Apprise.instantiate( obj = Apprise.instantiate(
'mailto://user:pass@gmail.com', suppress_exceptions=False) 'mailto://user:pass@gmail.com', suppress_exceptions=False)
assert(isinstance(obj, plugins.NotifyEmail)) assert(isinstance(obj, plugins.NotifyEmail))
@ -362,8 +360,7 @@ def test_smtplib_send_okay(mock_smtplib):
""" """
from apprise.plugins import NotifyEmailBase # Defaults to HTML
obj = Apprise.instantiate( obj = Apprise.instantiate(
'mailto://user:pass@gmail.com', suppress_exceptions=False) 'mailto://user:pass@gmail.com', suppress_exceptions=False)
assert(isinstance(obj, plugins.NotifyEmail)) assert(isinstance(obj, plugins.NotifyEmail))
@ -374,4 +371,13 @@ def test_smtplib_send_okay(mock_smtplib):
mock_smtplib.sendmail.return_value = True mock_smtplib.sendmail.return_value = True
mock_smtplib.quit.return_value = True mock_smtplib.quit.return_value = True
obj.notify(title='test', body='body', notify_type=NotifyType.INFO) assert(obj.notify(
title='test', body='body', notify_type=NotifyType.INFO) is True)
# Set Text
obj = Apprise.instantiate(
'mailto://user:pass@gmail.com?format=text', suppress_exceptions=False)
assert(isinstance(obj, plugins.NotifyEmail))
assert(obj.notify(
title='test', body='body', notify_type=NotifyType.INFO) is True)

View File

@ -38,7 +38,7 @@ def test_notify_base():
# invalid types throw exceptions # invalid types throw exceptions
try: try:
nb = NotifyBase(notify_format='invalid') nb = NotifyBase(**{'format': 'invalid'})
# We should never reach here as an exception should be thrown # We should never reach here as an exception should be thrown
assert(False) assert(False)

View File

@ -140,6 +140,15 @@ TEST_URLS = (
'instance': plugins.NotifyDiscord, 'instance': plugins.NotifyDiscord,
'requests_response_code': requests.codes.no_content, 'requests_response_code': requests.codes.no_content,
}), }),
# different format support
('discord://%s/%s?format=markdown' % ('i' * 24, 't' * 64), {
'instance': plugins.NotifyDiscord,
'requests_response_code': requests.codes.no_content,
}),
('discord://%s/%s?format=text' % ('i' * 24, 't' * 64), {
'instance': plugins.NotifyDiscord,
'requests_response_code': requests.codes.no_content,
}),
# Test without image set # Test without image set
('discord://%s/%s' % ('i' * 24, 't' * 64), { ('discord://%s/%s' % ('i' * 24, 't' * 64), {
'instance': plugins.NotifyDiscord, 'instance': plugins.NotifyDiscord,
@ -1155,6 +1164,16 @@ TEST_URLS = (
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=', { ('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=', {
'instance': plugins.NotifyTelegram, 'instance': plugins.NotifyTelegram,
}), }),
# Testing valid formats
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=markdown', {
'instance': plugins.NotifyTelegram,
}),
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=html', {
'instance': plugins.NotifyTelegram,
}),
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=text', {
'instance': plugins.NotifyTelegram,
}),
# Simple Message without image # Simple Message without image
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', { ('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
'instance': plugins.NotifyTelegram, 'instance': plugins.NotifyTelegram,
@ -1486,6 +1505,9 @@ def test_rest_plugins(mock_post, mock_get):
assert(hasattr(key, obj)) assert(hasattr(key, obj))
assert(getattr(key, obj) == val) assert(getattr(key, obj) == val)
#
# Stage 1: with title defined
#
try: try:
if test_requests_exceptions is False: if test_requests_exceptions is False:
# check that we're as expected # check that we're as expected
@ -1521,6 +1543,44 @@ def test_rest_plugins(mock_post, mock_get):
# Check that we were expecting this exception to happen # Check that we were expecting this exception to happen
assert isinstance(e, response) assert isinstance(e, response)
#
# Stage 1: without title defined
#
try:
if test_requests_exceptions is False:
# check that we're as expected
assert obj.notify(
title='', body='body',
notify_type=notify_type) == response
else:
for _exception in REQUEST_EXCEPTIONS:
mock_post.side_effect = _exception
mock_get.side_effect = _exception
try:
assert obj.notify(
title='', body='body',
notify_type=NotifyType.INFO) is False
except AssertionError:
# Don't mess with these entries
raise
except Exception as e:
# We can't handle this exception type
print('%s / %s' % (url, str(e)))
assert False
except AssertionError:
# Don't mess with these entries
print('%s AssertionError' % url)
raise
except Exception as e:
# Check that we were expecting this exception to happen
assert isinstance(e, response)
except AssertionError: except AssertionError:
# Don't mess with these entries # Don't mess with these entries
print('%s AssertionError' % url) print('%s AssertionError' % url)