markdown support

pull/5/head
Chris Caron 2018-02-19 20:59:19 -05:00
parent e6106de81b
commit 602b9bab6f
9 changed files with 133 additions and 27 deletions

View File

@ -21,8 +21,10 @@
import re import re
import logging import logging
from markdown import markdown
from .common import NotifyType from .common import NotifyType
from .common import NotifyFormat
from .utils import parse_list from .utils import parse_list
from .utils import compat_is_basestring from .utils import compat_is_basestring
@ -217,9 +219,14 @@ class Apprise(object):
""" """
self.servers[:] = [] self.servers[:] = []
def notify(self, title, body, notify_type=NotifyType.INFO): def notify(self, title, body, notify_type=NotifyType.INFO,
body_format=None):
""" """
Send a notification to all of the plugins previously loaded Send a notification to all of the plugins previously loaded.
If the body_format specified is NotifyFormat.MARKDOWN, it will
be converted to HTML if the Notification type expects this.
""" """
# Initialize our return result # Initialize our return result
@ -228,12 +235,28 @@ class Apprise(object):
if not (title or body): if not (title or body):
return False return False
# Tracks conversions
conversion_map = dict()
# Iterate over our loaded plugins # Iterate over our loaded plugins
for server in self.servers: for server in self.servers:
if server.notify_format not in conversion_map:
if body_format == NotifyFormat.MARKDOWN and \
server.notify_format == NotifyFormat.HTML:
# Apply Markdown
conversion_map[server.notify_format] = markdown(body)
else:
# Store entry directly
conversion_map[server.notify_format] = body
try: try:
# Send notification # Send notification
if not server.notify( if not server.notify(
title=title, body=body, notify_type=notify_type): title=title,
body=conversion_map[server.notify_format],
notify_type=notify_type):
# Toggle our return status flag # Toggle our return status flag
status = False status = False

View File

@ -24,9 +24,10 @@ __copywrite__ = 'Copyright 2017 Chris Caron <lead2gold@gmail.com>'
from .common import NotifyType from .common import NotifyType
from .common import NOTIFY_TYPES from .common import NOTIFY_TYPES
from .common import NOTIFY_IMAGE_SIZES
from .common import NotifyImageSize from .common import NotifyImageSize
from .plugins.NotifyBase import NotifyFormat from .common import NOTIFY_IMAGE_SIZES
from .common import NotifyFormat
from .common import NOTIFY_FORMATS
from .plugins.NotifyBase import NotifyBase from .plugins.NotifyBase import NotifyBase
from .Apprise import Apprise from .Apprise import Apprise
@ -43,5 +44,5 @@ __all__ = [
# Reference # Reference
'NotifyType', 'NotifyImageSize', 'NotifyFormat', 'NOTIFY_TYPES', 'NotifyType', 'NotifyImageSize', 'NotifyFormat', 'NOTIFY_TYPES',
'NOTIFY_IMAGE_SIZES', 'NOTIFY_IMAGE_SIZES', 'NOTIFY_FORMATS',
] ]

View File

@ -53,3 +53,20 @@ NOTIFY_IMAGE_SIZES = (
NotifyImageSize.XY_128, NotifyImageSize.XY_128,
NotifyImageSize.XY_256, NotifyImageSize.XY_256,
) )
class NotifyFormat(object):
"""
A list of pre-defined text message formats that can be passed via the
apprise library.
"""
TEXT = 'text'
HTML = 'html'
MARKDOWN = 'markdown'
NOTIFY_FORMATS = (
NotifyFormat.TEXT,
NotifyFormat.HTML,
NotifyFormat.MARKDOWN,
)

View File

@ -36,6 +36,8 @@ from ..utils import parse_bool
from ..utils import is_hostname from ..utils import is_hostname
from ..common import NOTIFY_IMAGE_SIZES from ..common import NOTIFY_IMAGE_SIZES
from ..common import NOTIFY_TYPES from ..common import NOTIFY_TYPES
from ..common import NotifyFormat
from ..common import NOTIFY_FORMATS
from ..AppriseAsset import AppriseAsset from ..AppriseAsset import AppriseAsset
@ -60,24 +62,11 @@ HTTP_ERROR_MAP = {
} }
# HTML New Line Delimiter # HTML New Line Delimiter
NOTIFY_NEWLINE = '\n' NOTIFY_NEWLINE = '\r\n'
# Used to break a path list into parts # Used to break a path list into parts
PATHSPLIT_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+') PATHSPLIT_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+')
class NotifyFormat(object):
TEXT = 'text'
HTML = 'html'
MARKDOWN = 'markdown'
NOTIFY_FORMATS = (
NotifyFormat.TEXT,
NotifyFormat.HTML,
NotifyFormat.MARKDOWN,
)
# Regular expression retrieved from: # Regular expression retrieved from:
# http://www.regular-expressions.info/email.html # http://www.regular-expressions.info/email.html
IS_EMAIL_RE = re.compile( IS_EMAIL_RE = re.compile(
@ -327,7 +316,7 @@ class NotifyBase(object):
return is_hostname(hostname) return is_hostname(hostname)
@staticmethod @staticmethod
def parse_url(url, verify_host=True): def parse_url(url, verify_host=True, default_format=NotifyFormat.TEXT):
""" """
Parses the URL and returns it broken apart into a dictionary. Parses the URL and returns it broken apart into a dictionary.
@ -343,10 +332,10 @@ class NotifyBase(object):
results['secure'] = (results['schema'][-1] == 's') results['secure'] = (results['schema'][-1] == 's')
# Our default notification format # Our default notification format
results['notify_format'] = NotifyFormat.TEXT results['notify_format'] = default_format
# Support SSL Certificate 'verify' keyword. Default to being enabled # Support SSL Certificate 'verify' keyword. Default to being enabled
results['verify'] = True results['verify'] = verify_host
if 'verify' in results['qsd']: if 'verify' in results['qsd']:
results['verify'] = parse_bool( results['verify'] = parse_bool(

View File

@ -25,7 +25,7 @@ from socket import error as SocketError
from email.mime.text import MIMEText from email.mime.text import MIMEText
from .NotifyBase import NotifyBase from .NotifyBase import NotifyBase
from .NotifyBase import NotifyFormat from ..common import NotifyFormat
class WebBaseLogin(object): class WebBaseLogin(object):

View File

@ -20,8 +20,8 @@ import re
import requests import requests
from .NotifyBase import NotifyBase from .NotifyBase import NotifyBase
from .NotifyBase import NotifyFormat
from .NotifyBase import HTTP_ERROR_MAP from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyFormat
# Extend HTTP Error Messages # Extend HTTP Error Messages
NMA_HTTP_ERROR_MAP = HTTP_ERROR_MAP.copy() NMA_HTTP_ERROR_MAP = HTTP_ERROR_MAP.copy()

View File

@ -47,8 +47,8 @@ from json import loads
from json import dumps from json import dumps
from .NotifyBase import NotifyBase from .NotifyBase import NotifyBase
from .NotifyBase import NotifyFormat
from .NotifyBase import HTTP_ERROR_MAP from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyFormat
from ..common import NotifyImageSize from ..common import NotifyImageSize
from ..utils import compat_is_basestring from ..utils import compat_is_basestring

View File

@ -5,3 +5,4 @@ oauthlib
urllib3 urllib3
six six
click >= 5.0 click >= 5.0
markdown

View File

@ -25,6 +25,7 @@ from apprise import AppriseAsset
from apprise.Apprise import SCHEMA_MAP from apprise.Apprise import SCHEMA_MAP
from apprise import NotifyBase from apprise import NotifyBase
from apprise import NotifyType from apprise import NotifyType
from apprise import NotifyFormat
from apprise import NotifyImageSize from apprise import NotifyImageSize
from apprise.Apprise import __load_matrix from apprise.Apprise import __load_matrix
@ -107,7 +108,8 @@ def test_apprise():
class GoodNotification(NotifyBase): class GoodNotification(NotifyBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(GoodNotification, self).__init__() super(GoodNotification, self).__init__(
notify_format=NotifyFormat.HTML)
def notify(self, **kwargs): def notify(self, **kwargs):
# Pretend everything is okay # Pretend everything is okay
@ -205,6 +207,79 @@ def test_apprise():
assert(len(a) == 0) assert(len(a) == 0)
def test_apprise_notify_formats(tmpdir):
"""
API: Apprise() TextFormat tests
"""
# Caling load matix a second time which is an internal function causes it
# to skip over content already loaded into our matrix and thefore accesses
# other if/else parts of the code that aren't otherwise called
__load_matrix()
a = Apprise()
# no items
assert(len(a) == 0)
class TextNotification(NotifyBase):
def __init__(self, **kwargs):
super(TextNotification, self).__init__(
notify_format=NotifyFormat.TEXT)
def notify(self, **kwargs):
# Pretend everything is okay
return True
class HtmlNotification(NotifyBase):
def __init__(self, **kwargs):
super(HtmlNotification, self).__init__(
notify_format=NotifyFormat.HTML)
def notify(self, **kwargs):
# Pretend everything is okay
return True
class MarkDownNotification(NotifyBase):
def __init__(self, **kwargs):
super(MarkDownNotification, self).__init__(
notify_format=NotifyFormat.MARKDOWN)
def notify(self, **kwargs):
# Pretend everything is okay
return True
# Store our notifications into our schema map
SCHEMA_MAP['text'] = TextNotification
SCHEMA_MAP['html'] = HtmlNotification
SCHEMA_MAP['markdown'] = MarkDownNotification
# Test Markdown; the above calls the markdown because our good://
# defined plugin above was defined to default to HTML which triggers
# a markdown to take place if the body_format specified on the notify
# call
assert(a.add('html://localhost') is True)
assert(a.add('html://another.server') is True)
assert(a.add('html://and.another') is True)
assert(a.add('text://localhost') is True)
assert(a.add('text://another.server') is True)
assert(a.add('text://and.another') is True)
assert(a.add('markdown://localhost') is True)
assert(a.add('markdown://another.server') is True)
assert(a.add('markdown://and.another') is True)
assert(len(a) == 9)
assert(a.notify(title="markdown", body="## Testing Markdown",
body_format=NotifyFormat.MARKDOWN) is True)
assert(a.notify(title="text", body="Testing Text",
body_format=NotifyFormat.TEXT) is True)
assert(a.notify(title="html", body="<b>HTML</b>",
body_format=NotifyFormat.HTML) is True)
def test_apprise_asset(tmpdir): def test_apprise_asset(tmpdir):
""" """
API: AppriseAsset() object API: AppriseAsset() object