From 1cdebd061787d1fc1f852dad5208a4f81cfdb54d Mon Sep 17 00:00:00 2001 From: Halali Date: Thu, 28 Feb 2019 11:46:11 +0100 Subject: [PATCH 1/2] Update Apprise to 0.7.3 --- libs/apprise/Apprise.py | 151 +++++++++-- libs/apprise/AppriseAsset.py | 31 ++- libs/apprise/__init__.py | 39 +-- libs/apprise/cli.py | 32 ++- libs/apprise/common.py | 29 ++- libs/apprise/plugins/NotifyBase.py | 65 ++++- libs/apprise/plugins/NotifyBoxcar.py | 29 ++- libs/apprise/plugins/NotifyDiscord.py | 81 +++--- libs/apprise/plugins/NotifyEmail.py | 178 ++++++++++--- libs/apprise/plugins/NotifyEmby.py | 29 ++- libs/apprise/plugins/NotifyFaast.py | 28 +- .../plugins/NotifyGrowl/NotifyGrowl.py | 29 ++- libs/apprise/plugins/NotifyGrowl/__init__.py | 29 ++- .../plugins/NotifyGrowl/gntp/config.py | 6 +- libs/apprise/plugins/NotifyGrowl/gntp/shim.py | 6 +- libs/apprise/plugins/NotifyIFTTT.py | 29 ++- libs/apprise/plugins/NotifyJSON.py | 32 ++- libs/apprise/plugins/NotifyJoin.py | 29 ++- libs/apprise/plugins/NotifyMatterMost.py | 29 ++- libs/apprise/plugins/NotifyProwl.py | 29 ++- libs/apprise/plugins/NotifyPushBullet.py | 29 ++- libs/apprise/plugins/NotifyPushalot.py | 161 ------------ .../plugins/NotifyPushjet/NotifyPushjet.py | 79 ++++-- .../apprise/plugins/NotifyPushjet/__init__.py | 29 ++- .../plugins/NotifyPushjet/pushjet/pushjet.py | 26 +- libs/apprise/plugins/NotifyPushover.py | 29 ++- libs/apprise/plugins/NotifyRocketChat.py | 49 ++-- libs/apprise/plugins/NotifySlack.py | 29 ++- libs/apprise/plugins/NotifyStride.py | 246 ------------------ libs/apprise/plugins/NotifyTelegram.py | 90 +++++-- libs/apprise/plugins/NotifyToasty.py | 180 ------------- .../plugins/NotifyTwitter/NotifyTwitter.py | 29 ++- .../apprise/plugins/NotifyTwitter/__init__.py | 29 ++- libs/apprise/plugins/NotifyWindows.py | 30 ++- libs/apprise/plugins/NotifyXBMC.py | 29 ++- libs/apprise/plugins/NotifyXML.py | 32 ++- libs/apprise/plugins/__init__.py | 51 ++-- libs/apprise/utils.py | 32 ++- 38 files changed, 1014 insertions(+), 1075 deletions(-) delete mode 100644 libs/apprise/plugins/NotifyPushalot.py delete mode 100644 libs/apprise/plugins/NotifyStride.py delete mode 100644 libs/apprise/plugins/NotifyToasty.py diff --git a/libs/apprise/Apprise.py b/libs/apprise/Apprise.py index 73adf6299..576f1d546 100644 --- a/libs/apprise/Apprise.py +++ b/libs/apprise/Apprise.py @@ -1,23 +1,27 @@ # -*- coding: utf-8 -*- # -# Apprise Core +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with apprise. If not, see . +# 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 logging @@ -27,6 +31,7 @@ from .common import NotifyType from .common import NotifyFormat from .utils import parse_list from .utils import compat_is_basestring +from .utils import GET_SCHEMA_RE from .AppriseAsset import AppriseAsset @@ -39,9 +44,6 @@ logger = logging.getLogger(__name__) # Build a list of supported plugins SCHEMA_MAP = {} -# Used for attempting to acquire the schema if the URL can't be parsed. -GET_SCHEMA_RE = re.compile(r'\s*(?P[a-z0-9]{3,9})://.*$', re.I) - # Load our Lookup Matrix def __load_matrix(): @@ -55,7 +57,7 @@ def __load_matrix(): # Get our plugin plugin = getattr(plugins, entry) - if not hasattr(plugin, 'app_id'): # pragma: no branch + if not hasattr(plugin, 'app_id'): # pragma: no branch # Filter out non-notification modules continue @@ -119,7 +121,7 @@ class Apprise(object): self.add(servers) @staticmethod - def instantiate(url, asset=None, suppress_exceptions=True): + def instantiate(url, asset=None, tag=None, suppress_exceptions=True): """ Returns the instance of a instantiated plugin based on the provided Server URL. If the url fails to be parsed, then None is returned. @@ -160,6 +162,9 @@ class Apprise(object): logger.error('Could not parse URL: %s' % url) return None + # Build a list of tags to associate with the newly added notifications + results['tag'] = set(parse_list(tag)) + if suppress_exceptions: try: # Attempt to create an instance of our plugin using the parsed @@ -182,10 +187,16 @@ class Apprise(object): return plugin - def add(self, servers, asset=None): + def add(self, servers, asset=None, tag=None): """ Adds one or more server URLs into our list. + You can override the global asset if you wish by including it with the + server(s) that you add. + + The tag allows you to associate 1 or more tag values to the server(s) + being added. tagging a service allows you to exclusively access them + when calling the notify() function. """ # Initialize our return status @@ -200,12 +211,13 @@ class Apprise(object): self.servers.append(servers) return True + # build our server listings servers = parse_list(servers) for _server in servers: # Instantiate ourselves an object, this function throws or # returns None if it fails - instance = Apprise.instantiate(_server, asset=asset) + instance = Apprise.instantiate(_server, asset=asset, tag=tag) if not instance: return_status = False logging.error( @@ -227,13 +239,18 @@ class Apprise(object): self.servers[:] = [] def notify(self, title, body, notify_type=NotifyType.INFO, - body_format=None): + body_format=None, tag=None): """ 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. + if the tag is specified (either a string or a set/list/tuple + of strings), then only the notifications flagged with that + tagged value are notified. By default all added services + are notified (tag=None) + """ # Initialize our return result @@ -245,8 +262,63 @@ class Apprise(object): # Tracks conversions conversion_map = dict() + # Build our tag setup + # - top level entries are treated as an 'or' + # - second level (or more) entries are treated as 'and' + # + # examples: + # tag="tagA, tagB" = tagA or tagB + # tag=['tagA', 'tagB'] = tagA or tagB + # tag=[('tagA', 'tagC'), 'tagB'] = (tagA and tagC) or tagB + # tag=[('tagB', 'tagC')] = tagB and tagC + # Iterate over our loaded plugins for server in self.servers: + + if tag is not None: + + if isinstance(tag, (list, tuple, set)): + # using the tags detected; determine if we'll allow the + # notification to be sent or not + matched = False + + # Every entry here will be or'ed with the next + for entry in tag: + if isinstance(entry, (list, tuple, set)): + + # treat these entries as though all elements found + # must exist in the notification service + tags = set(parse_list(entry)) + + if len(tags.intersection( + server.tags)) == len(tags): + # our set contains all of the entries found + # in our notification server object + matched = True + break + + elif entry in server: + # our entr(ies) match what was found in our server + # object. + matched = True + break + + # else: keep looking + + if not matched: + # We did not meet any of our and'ed criteria + continue + + elif tag not in server: + # one or more tags were defined and they didn't match the + # entry in the current service; move along... + continue + + # else: our content was found inside the server, so we're good + + # If our code reaches here, we either did not define a tag (it was + # set to None), or we did define a tag and the logic above + # determined we need to notify the service it's associated with if server.notify_format not in conversion_map: if body_format == NotifyFormat.MARKDOWN and \ server.notify_format == NotifyFormat.HTML: @@ -254,6 +326,39 @@ class Apprise(object): # Apply Markdown conversion_map[server.notify_format] = markdown(body) + elif body_format == NotifyFormat.TEXT and \ + server.notify_format == NotifyFormat.HTML: + + # Basic TEXT to HTML format map; supports keys only + re_map = { + # Support Ampersand + r'&': '&', + + # Spaces to   for formatting purposes since + # multiple spaces are treated as one an this may not + # be the callers intention + r' ': ' ', + + # Tab support + r'\t': '   ', + + # Greater than and Less than Characters + r'>': '>', + r'<': '<', + } + + # Compile our map + re_table = re.compile( + r'(' + '|'.join(map(re.escape, re_map.keys())) + r')', + re.IGNORECASE, + ) + + # Execute our map against our body in addition to swapping + # out new lines and replacing them with
+ conversion_map[server.notify_format] = \ + re.sub(r'\r*\n', '
\r\n', + re_table.sub(lambda x: re_map[x.group()], body)) + else: # Store entry directly conversion_map[server.notify_format] = body @@ -302,7 +407,7 @@ class Apprise(object): # Get our plugin plugin = getattr(plugins, entry) - if not hasattr(plugin, 'app_id'): # pragma: no branch + if not hasattr(plugin, 'app_id'): # pragma: no branch # Filter out non-notification modules continue diff --git a/libs/apprise/AppriseAsset.py b/libs/apprise/AppriseAsset.py index ee845f726..61bd75f33 100644 --- a/libs/apprise/AppriseAsset.py +++ b/libs/apprise/AppriseAsset.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Apprise Asset +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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 @@ -227,7 +234,7 @@ class AppriseAsset(object): 'app_desc': self.app_desc, 'default_extension': self.default_extension, 'theme': self.theme, - 'image_path_mask': self.image_url_mask, + 'image_path_mask': self.image_path_mask, 'image_url_mask': self.image_url_mask, 'image_url_logo': self.image_url_logo, } diff --git a/libs/apprise/__init__.py b/libs/apprise/__init__.py index d25dd04af..cf9e034e3 100644 --- a/libs/apprise/__init__.py +++ b/libs/apprise/__init__.py @@ -1,26 +1,35 @@ # -*- coding: utf-8 -*- # -# base class for easier library inclusion +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017-2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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. __title__ = 'apprise' -__version__ = '0.5.0' -__author__ = 'Chris Caron ' -__license__ = 'GPLv3' -__copywrite__ = 'Copyright 2017-2018 Chris Caron ' +__version__ = '0.7.3' +__author__ = 'Chris Caron' +__license__ = 'MIT' +__copywrite__ = 'Copyright 2019 Chris Caron ' +__email__ = 'lead2gold@gmail.com' +__status__ = 'Production' from .common import NotifyType from .common import NOTIFY_TYPES diff --git a/libs/apprise/cli.py b/libs/apprise/cli.py index d22229fb1..974dd8bb7 100644 --- a/libs/apprise/cli.py +++ b/libs/apprise/cli.py @@ -1,24 +1,28 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Apprise CLI Tool +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017-2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with apprise. If not, see . +# 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 click import logging diff --git a/libs/apprise/common.py b/libs/apprise/common.py index be7a389c5..834c19287 100644 --- a/libs/apprise/common.py +++ b/libs/apprise/common.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Base Notify Wrapper +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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. class NotifyType(object): diff --git a/libs/apprise/plugins/NotifyBase.py b/libs/apprise/plugins/NotifyBase.py index 0a8a3687b..a8471f837 100644 --- a/libs/apprise/plugins/NotifyBase.py +++ b/libs/apprise/plugins/NotifyBase.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Base Notify Wrapper +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017-2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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 logging @@ -33,6 +40,7 @@ except ImportError: from ..utils import parse_url from ..utils import parse_bool +from ..utils import parse_list from ..utils import is_hostname from ..common import NOTIFY_TYPES from ..common import NotifyFormat @@ -120,6 +128,9 @@ class NotifyBase(object): # Default Notify Format notify_format = NotifyFormat.TEXT + # Maintain a set of tags to associate with this specific notification + tags = set() + # Logging logger = logging.getLogger(__name__) @@ -151,10 +162,11 @@ class NotifyBase(object): self.user = kwargs.get('user') self.password = kwargs.get('password') + self.headers = kwargs.get('headers') - if 'notify_format' in kwargs: - # Store the specified notify_format if specified - notify_format = kwargs.get('notify_format') + if 'format' in kwargs: + # Store the specified format if specified + notify_format = kwargs.get('format', '') if notify_format.lower() not in NOTIFY_FORMATS: self.logger.error( 'Invalid notification format %s' % notify_format, @@ -165,6 +177,12 @@ class NotifyBase(object): # Provide override self.notify_format = notify_format + if 'tag' in kwargs: + # We want to associate some tags with our notification service. + # the code below gets the 'tag' argument if defined, otherwise + # it just falls back to whatever was already defined globally + self.tags = set(parse_list(kwargs.get('tag', self.tags))) + def throttle(self, throttle_time=None): """ A common throttle control @@ -242,6 +260,19 @@ class NotifyBase(object): color_type=color_type, ) + def __contains__(self, tags): + """ + Returns true if the tag specified is associated with this notification. + + tag can also be a tuple, set, and/or list + + """ + if isinstance(tags, (tuple, set, list)): + return bool(set(tags) & self.tags) + + # return any match + return tags in self.tags + @property def app_id(self): return self.asset.app_id @@ -260,6 +291,10 @@ class NotifyBase(object): Takes html text as input and escapes it so that it won't conflict with any xml/html wrapping characters. """ + if not html: + # nothing more to do; return object as is + return html + escaped = _escape(html) if whitespace: @@ -390,4 +425,6 @@ class NotifyBase(object): if 'user' in results['qsd']: results['user'] = results['qsd']['user'] + results['headers'] = {k[1:]: v for k, v in results['qsd'].items() + if re.match(r'^-.', k)} return results diff --git a/libs/apprise/plugins/NotifyBoxcar.py b/libs/apprise/plugins/NotifyBoxcar.py index 5d3366479..58891b76a 100644 --- a/libs/apprise/plugins/NotifyBoxcar.py +++ b/libs/apprise/plugins/NotifyBoxcar.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Boxcar Notify Wrapper +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017-2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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. from json import dumps import requests diff --git a/libs/apprise/plugins/NotifyDiscord.py b/libs/apprise/plugins/NotifyDiscord.py index 7b41bd0d8..7cdf283c2 100644 --- a/libs/apprise/plugins/NotifyDiscord.py +++ b/libs/apprise/plugins/NotifyDiscord.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Discord Notify Wrapper +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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. # For this to work correctly you need to create a webhook. To do this just # click on the little gear icon next to the channel you're part of. From @@ -59,7 +66,7 @@ class NotifyDiscord(NotifyBase): secure_protocol = 'discord' # A URL that takes you to the setup/help of the specific protocol - setup_url = 'https://github.com/caronc/apprise/wiki/Notify_discored' + setup_url = 'https://github.com/caronc/apprise/wiki/Notify_discord' # Discord Webhook notify_url = 'https://discordapp.com/api/webhooks' @@ -70,9 +77,6 @@ class NotifyDiscord(NotifyBase): # The maximum allowable characters allowed in the body per message body_maxlen = 2000 - # Default Notify Format - notify_format = NotifyFormat.MARKDOWN - def __init__(self, webhook_id, webhook_token, tts=False, avatar=True, footer=False, thumbnail=True, **kwargs): """ @@ -129,9 +133,15 @@ class NotifyDiscord(NotifyBase): 'wait': self.tts is False, # Our color associated with our notification - 'color': self.color(notify_type, int), + 'color': self.color(notify_type, int) + } - 'embeds': [{ + # Acquire image_url + image_url = self.image_url(notify_type) + + if self.notify_format == NotifyFormat.MARKDOWN: + # Use embeds for payload + payload['embeds'] = [{ 'provider': { 'name': self.app_id, 'url': self.app_url, @@ -140,9 +150,8 @@ class NotifyDiscord(NotifyBase): 'type': 'rich', 'description': body, }] - } - if self.notify_format == NotifyFormat.MARKDOWN: + # Break titles out so that we can sort them in embeds fields = self.extract_markdown_sections(body) if len(fields) > 0: @@ -153,25 +162,29 @@ class NotifyDiscord(NotifyBase): fields[0].get('name') + fields[0].get('value') payload['embeds'][0]['fields'] = fields[1:] - if self.footer: - logo_url = self.image_url(notify_type, logo=True) - payload['embeds'][0]['footer'] = { - 'text': self.app_desc, - } - if logo_url: - payload['embeds'][0]['footer']['icon_url'] = logo_url + if self.footer: + logo_url = self.image_url(notify_type, logo=True) + payload['embeds'][0]['footer'] = { + 'text': self.app_desc, + } - image_url = self.image_url(notify_type) - if image_url: - if self.thumbnail: + if logo_url: + payload['embeds'][0]['footer']['icon_url'] = logo_url + + if self.thumbnail and image_url: payload['embeds'][0]['thumbnail'] = { 'url': image_url, 'height': 256, 'width': 256, } - if self.avatar: - payload['avatar_url'] = image_url + else: + # not markdown + payload['content'] = body if not title \ + else "{}\r\n{}".format(title, body) + + if self.avatar and image_url: + payload['avatar_url'] = image_url if self.user: # Optionally override the default username of the webhook @@ -271,7 +284,7 @@ class NotifyDiscord(NotifyBase): # Use Thumbnail results['thumbnail'] = \ - parse_bool(results['qsd'].get('thumbnail', True)) + parse_bool(results['qsd'].get('thumbnail', False)) return results @@ -284,8 +297,8 @@ class NotifyDiscord(NotifyBase): """ regex = re.compile( - r'\s*#+\s*(?P[^#\n]+)([ \r\t\v#]*)' - r'(?P(.+?)(\n(?!\s#))|\s*$)', flags=re.S) + r'^\s*#+\s*(?P[^#\n]+)([ \r\t\v#])?' + r'(?P([^ \r\t\v#].+?)(\n(?!\s#))|\s*$)', flags=re.S | re.M) common = regex.finditer(markdown) fields = list() diff --git a/libs/apprise/plugins/NotifyEmail.py b/libs/apprise/plugins/NotifyEmail.py index 1dcd5f388..69d836c85 100644 --- a/libs/apprise/plugins/NotifyEmail.py +++ b/libs/apprise/plugins/NotifyEmail.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- # -# Email Notify Wrapper +# Copyright (C) 2019 Chris Caron +# All rights reserved. # -# Copyright (C) 2017-2018 Chris Caron +# This code is licensed under the MIT License. # -# This file is part of apprise. +# 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 : # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. +# 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 @@ -40,6 +47,18 @@ class WebBaseLogin(object): USERID = 'UserID' +# Secure Email Modes +class SecureMailMode(object): + SSL = "ssl" + STARTTLS = "starttls" + + +# Define all of the secure modes (used during validation) +SECURE_MODES = ( + SecureMailMode.SSL, + SecureMailMode.STARTTLS, +) + # To attempt to make this script stupid proof, if we detect an email address # that is part of the this table, we can pre-use a lot more defaults if they # aren't otherwise specified on the users input. @@ -47,11 +66,14 @@ WEBBASE_LOOKUP_TABLE = ( # Google GMail ( 'Google Mail', - re.compile(r'^((?P