Update Apprise to 0.7.3

pull/489/head
Halali 6 years ago
parent 8dc026d19a
commit 1cdebd0617

@ -1,23 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Apprise Core # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# You should have received a copy of the GNU Lesser General Public License # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# along with apprise. If not, see <http://www.gnu.org/licenses/>. # THE SOFTWARE.
import re import re
import logging import logging
@ -27,6 +31,7 @@ from .common import NotifyType
from .common import NotifyFormat 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
from .utils import GET_SCHEMA_RE
from .AppriseAsset import AppriseAsset from .AppriseAsset import AppriseAsset
@ -39,9 +44,6 @@ logger = logging.getLogger(__name__)
# Build a list of supported plugins # Build a list of supported plugins
SCHEMA_MAP = {} SCHEMA_MAP = {}
# Used for attempting to acquire the schema if the URL can't be parsed.
GET_SCHEMA_RE = re.compile(r'\s*(?P<schema>[a-z0-9]{3,9})://.*$', re.I)
# Load our Lookup Matrix # Load our Lookup Matrix
def __load_matrix(): def __load_matrix():
@ -55,7 +57,7 @@ def __load_matrix():
# Get our plugin # Get our plugin
plugin = getattr(plugins, entry) 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 # Filter out non-notification modules
continue continue
@ -119,7 +121,7 @@ class Apprise(object):
self.add(servers) self.add(servers)
@staticmethod @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 Returns the instance of a instantiated plugin based on the provided
Server URL. If the url fails to be parsed, then None is returned. 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) logger.error('Could not parse URL: %s' % url)
return None return None
# Build a list of tags to associate with the newly added notifications
results['tag'] = set(parse_list(tag))
if suppress_exceptions: if suppress_exceptions:
try: try:
# Attempt to create an instance of our plugin using the parsed # Attempt to create an instance of our plugin using the parsed
@ -182,10 +187,16 @@ class Apprise(object):
return plugin 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. 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 # Initialize our return status
@ -200,12 +211,13 @@ class Apprise(object):
self.servers.append(servers) self.servers.append(servers)
return True return True
# build our server listings
servers = parse_list(servers) servers = parse_list(servers)
for _server in servers: for _server in servers:
# Instantiate ourselves an object, this function throws or # Instantiate ourselves an object, this function throws or
# returns None if it fails # returns None if it fails
instance = Apprise.instantiate(_server, asset=asset) instance = Apprise.instantiate(_server, asset=asset, tag=tag)
if not instance: if not instance:
return_status = False return_status = False
logging.error( logging.error(
@ -227,13 +239,18 @@ 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): body_format=None, tag=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 If the body_format specified is NotifyFormat.MARKDOWN, it will
be converted to HTML if the Notification type expects this. 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 # Initialize our return result
@ -245,8 +262,63 @@ class Apprise(object):
# Tracks conversions # Tracks conversions
conversion_map = dict() 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 # Iterate over our loaded plugins
for server in self.servers: 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 server.notify_format not in conversion_map:
if body_format == NotifyFormat.MARKDOWN and \ if body_format == NotifyFormat.MARKDOWN and \
server.notify_format == NotifyFormat.HTML: server.notify_format == NotifyFormat.HTML:
@ -254,6 +326,39 @@ class Apprise(object):
# Apply Markdown # Apply Markdown
conversion_map[server.notify_format] = markdown(body) 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'&': '&amp;',
# Spaces to &nbsp; for formatting purposes since
# multiple spaces are treated as one an this may not
# be the callers intention
r' ': '&nbsp;',
# Tab support
r'\t': '&nbsp;&nbsp;&nbsp;',
# Greater than and Less than Characters
r'>': '&gt;',
r'<': '&lt;',
}
# 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 <br/>
conversion_map[server.notify_format] = \
re.sub(r'\r*\n', '<br/>\r\n',
re_table.sub(lambda x: re_map[x.group()], body))
else: else:
# Store entry directly # Store entry directly
conversion_map[server.notify_format] = body conversion_map[server.notify_format] = body
@ -302,7 +407,7 @@ class Apprise(object):
# Get our plugin # Get our plugin
plugin = getattr(plugins, entry) 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 # Filter out non-notification modules
continue continue

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Apprise Asset # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
@ -227,7 +234,7 @@ class AppriseAsset(object):
'app_desc': self.app_desc, 'app_desc': self.app_desc,
'default_extension': self.default_extension, 'default_extension': self.default_extension,
'theme': self.theme, '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_mask': self.image_url_mask,
'image_url_logo': self.image_url_logo, 'image_url_logo': self.image_url_logo,
} }

@ -1,26 +1,35 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# base class for easier library inclusion # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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' __title__ = 'apprise'
__version__ = '0.5.0' __version__ = '0.7.3'
__author__ = 'Chris Caron <lead2gold@gmail.com>' __author__ = 'Chris Caron'
__license__ = 'GPLv3' __license__ = 'MIT'
__copywrite__ = 'Copyright 2017-2018 Chris Caron <lead2gold@gmail.com>' __copywrite__ = 'Copyright 2019 Chris Caron <lead2gold@gmail.com>'
__email__ = 'lead2gold@gmail.com'
__status__ = 'Production'
from .common import NotifyType from .common import NotifyType
from .common import NOTIFY_TYPES from .common import NOTIFY_TYPES

@ -1,24 +1,28 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Apprise CLI Tool # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# You should have received a copy of the GNU Lesser General Public License # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# along with apprise. If not, see <http://www.gnu.org/licenses/>. # THE SOFTWARE.
import click import click
import logging import logging

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Base Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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): class NotifyType(object):

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Base Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import logging import logging
@ -33,6 +40,7 @@ except ImportError:
from ..utils import parse_url from ..utils import parse_url
from ..utils import parse_bool from ..utils import parse_bool
from ..utils import parse_list
from ..utils import is_hostname from ..utils import is_hostname
from ..common import NOTIFY_TYPES from ..common import NOTIFY_TYPES
from ..common import NotifyFormat from ..common import NotifyFormat
@ -120,6 +128,9 @@ class NotifyBase(object):
# Default Notify Format # Default Notify Format
notify_format = NotifyFormat.TEXT notify_format = NotifyFormat.TEXT
# Maintain a set of tags to associate with this specific notification
tags = set()
# Logging # Logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -151,10 +162,11 @@ class NotifyBase(object):
self.user = kwargs.get('user') self.user = kwargs.get('user')
self.password = kwargs.get('password') self.password = kwargs.get('password')
self.headers = kwargs.get('headers')
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,
@ -165,6 +177,12 @@ class NotifyBase(object):
# Provide override # Provide override
self.notify_format = notify_format 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): def throttle(self, throttle_time=None):
""" """
A common throttle control A common throttle control
@ -242,6 +260,19 @@ class NotifyBase(object):
color_type=color_type, 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 @property
def app_id(self): def app_id(self):
return self.asset.app_id 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 Takes html text as input and escapes it so that it won't
conflict with any xml/html wrapping characters. conflict with any xml/html wrapping characters.
""" """
if not html:
# nothing more to do; return object as is
return html
escaped = _escape(html) escaped = _escape(html)
if whitespace: if whitespace:
@ -390,4 +425,6 @@ class NotifyBase(object):
if 'user' in results['qsd']: if 'user' in results['qsd']:
results['user'] = results['qsd']['user'] results['user'] = results['qsd']['user']
results['headers'] = {k[1:]: v for k, v in results['qsd'].items()
if re.match(r'^-.', k)}
return results return results

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Boxcar Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 from json import dumps
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Discord Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 # 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 # 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' secure_protocol = 'discord'
# 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_discored' setup_url = 'https://github.com/caronc/apprise/wiki/Notify_discord'
# Discord Webhook # Discord Webhook
notify_url = 'https://discordapp.com/api/webhooks' notify_url = 'https://discordapp.com/api/webhooks'
@ -70,9 +77,6 @@ class NotifyDiscord(NotifyBase):
# The maximum allowable characters allowed in the body per message # The maximum allowable characters allowed in the body per message
body_maxlen = 2000 body_maxlen = 2000
# Default Notify Format
notify_format = NotifyFormat.MARKDOWN
def __init__(self, webhook_id, webhook_token, tts=False, avatar=True, def __init__(self, webhook_id, webhook_token, tts=False, avatar=True,
footer=False, thumbnail=True, **kwargs): footer=False, thumbnail=True, **kwargs):
""" """
@ -129,9 +133,15 @@ class NotifyDiscord(NotifyBase):
'wait': self.tts is False, 'wait': self.tts is False,
# Our color associated with our notification # Our color associated with our notification
'color': self.color(notify_type, int), 'color': self.color(notify_type, int)
}
# Acquire image_url
image_url = self.image_url(notify_type)
'embeds': [{ if self.notify_format == NotifyFormat.MARKDOWN:
# Use embeds for payload
payload['embeds'] = [{
'provider': { 'provider': {
'name': self.app_id, 'name': self.app_id,
'url': self.app_url, 'url': self.app_url,
@ -140,9 +150,8 @@ class NotifyDiscord(NotifyBase):
'type': 'rich', 'type': 'rich',
'description': body, '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) fields = self.extract_markdown_sections(body)
if len(fields) > 0: if len(fields) > 0:
@ -153,25 +162,29 @@ class NotifyDiscord(NotifyBase):
fields[0].get('name') + fields[0].get('value') fields[0].get('name') + fields[0].get('value')
payload['embeds'][0]['fields'] = fields[1:] payload['embeds'][0]['fields'] = fields[1:]
if self.footer: if self.footer:
logo_url = self.image_url(notify_type, logo=True) logo_url = self.image_url(notify_type, logo=True)
payload['embeds'][0]['footer'] = { payload['embeds'][0]['footer'] = {
'text': self.app_desc, 'text': self.app_desc,
} }
if logo_url:
payload['embeds'][0]['footer']['icon_url'] = logo_url
image_url = self.image_url(notify_type) if logo_url:
if image_url: payload['embeds'][0]['footer']['icon_url'] = logo_url
if self.thumbnail:
if self.thumbnail and image_url:
payload['embeds'][0]['thumbnail'] = { payload['embeds'][0]['thumbnail'] = {
'url': image_url, 'url': image_url,
'height': 256, 'height': 256,
'width': 256, 'width': 256,
} }
if self.avatar: else:
payload['avatar_url'] = image_url # 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: if self.user:
# Optionally override the default username of the webhook # Optionally override the default username of the webhook
@ -271,7 +284,7 @@ class NotifyDiscord(NotifyBase):
# Use Thumbnail # Use Thumbnail
results['thumbnail'] = \ results['thumbnail'] = \
parse_bool(results['qsd'].get('thumbnail', True)) parse_bool(results['qsd'].get('thumbnail', False))
return results return results
@ -284,8 +297,8 @@ class NotifyDiscord(NotifyBase):
""" """
regex = re.compile( regex = re.compile(
r'\s*#+\s*(?P<name>[^#\n]+)([ \r\t\v#]*)' r'^\s*#+\s*(?P<name>[^#\n]+)([ \r\t\v#])?'
r'(?P<value>(.+?)(\n(?!\s#))|\s*$)', flags=re.S) r'(?P<value>([^ \r\t\v#].+?)(\n(?!\s#))|\s*$)', flags=re.S | re.M)
common = regex.finditer(markdown) common = regex.finditer(markdown)
fields = list() fields = list()

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Email Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
@ -40,6 +47,18 @@ class WebBaseLogin(object):
USERID = 'UserID' 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 # 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 # 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. # aren't otherwise specified on the users input.
@ -47,11 +66,14 @@ WEBBASE_LOOKUP_TABLE = (
# Google GMail # Google GMail
( (
'Google Mail', 'Google Mail',
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>gmail\.com)$', re.I), re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>gmail\.com)$', re.I),
{ {
'port': 587, 'port': 587,
'smtp_host': 'smtp.gmail.com', 'smtp_host': 'smtp.gmail.com',
'secure': True, 'secure': True,
'secure_mode': SecureMailMode.STARTTLS,
'login_type': (WebBaseLogin.EMAIL, ) 'login_type': (WebBaseLogin.EMAIL, )
}, },
), ),
@ -59,11 +81,14 @@ WEBBASE_LOOKUP_TABLE = (
# Pronto Mail # Pronto Mail
( (
'Pronto Mail', 'Pronto Mail',
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>prontomail\.com)$', re.I), re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>prontomail\.com)$', re.I),
{ {
'port': 465, 'port': 465,
'smtp_host': 'secure.emailsrvr.com', 'smtp_host': 'secure.emailsrvr.com',
'secure': True, 'secure': True,
'secure_mode': SecureMailMode.STARTTLS,
'login_type': (WebBaseLogin.EMAIL, ) 'login_type': (WebBaseLogin.EMAIL, )
}, },
), ),
@ -71,11 +96,14 @@ WEBBASE_LOOKUP_TABLE = (
# Microsoft Hotmail # Microsoft Hotmail
( (
'Microsoft Hotmail', 'Microsoft Hotmail',
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>(hotmail|live)\.com)$', re.I), re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>(hotmail|live)\.com)$', re.I),
{ {
'port': 587, 'port': 587,
'smtp_host': 'smtp.live.com', 'smtp_host': 'smtp.live.com',
'secure': True, 'secure': True,
'secure_mode': SecureMailMode.STARTTLS,
'login_type': (WebBaseLogin.EMAIL, ) 'login_type': (WebBaseLogin.EMAIL, )
}, },
), ),
@ -83,11 +111,83 @@ WEBBASE_LOOKUP_TABLE = (
# Yahoo Mail # Yahoo Mail
( (
'Yahoo Mail', 'Yahoo Mail',
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>yahoo\.(ca|com))$', re.I), re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>yahoo\.(ca|com))$', re.I),
{ {
'port': 465, 'port': 465,
'smtp_host': 'smtp.mail.yahoo.com', 'smtp_host': 'smtp.mail.yahoo.com',
'secure': True, 'secure': True,
'secure_mode': SecureMailMode.STARTTLS,
'login_type': (WebBaseLogin.EMAIL, )
},
),
# Fast Mail (Series 1)
(
'Fast Mail',
re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>fastmail\.(com|cn|co\.uk|com\.au|de|es|fm|fr|im|'
r'in|jp|mx|net|nl|org|se|to|tw|uk|us))$', re.I),
{
'port': 465,
'smtp_host': 'smtp.fastmail.com',
'secure': True,
'secure_mode': SecureMailMode.SSL,
'login_type': (WebBaseLogin.EMAIL, )
},
),
# Fast Mail (Series 2)
(
'Fast Mail Extended Addresses',
re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>123mail\.org|airpost\.net|eml\.cc|fmail\.co\.uk|'
r'fmgirl\.com|fmguy\.com|mailbolt\.com|mailcan\.com|'
r'mailhaven\.com|mailmight\.com|ml1\.net|mm\.st|myfastmail\.com|'
r'proinbox\.com|promessage\.com|rushpost\.com|sent\.(as|at|com)|'
r'speedymail\.org|warpmail\.net|xsmail\.com|150mail\.com|'
r'150ml\.com|16mail\.com|2-mail\.com|4email\.net|50mail\.com|'
r'allmail\.net|bestmail\.us|cluemail\.com|elitemail\.org|'
r'emailcorner\.net|emailengine\.(net|org)|emailgroups\.net|'
r'emailplus\.org|emailuser\.net|f-m\.fm|fast-email\.com|'
r'fast-mail\.org|fastem\.com|fastemail\.us|fastemailer\.com|'
r'fastest\.cc|fastimap\.com|fastmailbox\.net|fastmessaging\.com|'
r'fea\.st|fmailbox\.com|ftml\.net|h-mail\.us|hailmail\.net|'
r'imap-mail\.com|imap\.cc|imapmail\.org|inoutbox\.com|'
r'internet-e-mail\.com|internet-mail\.org|internetemails\.net|'
r'internetmailing\.net|jetemail\.net|justemail\.net|'
r'letterboxes\.org|mail-central\.com|mail-page\.com|'
r'mailandftp\.com|mailas\.com|mailc\.net|mailforce\.net|'
r'mailftp\.com|mailingaddress\.org|mailite\.com|mailnew\.com|'
r'mailsent\.net|mailservice\.ms|mailup\.net|mailworks\.org|'
r'mymacmail\.com|nospammail\.net|ownmail\.net|petml\.com|'
r'postinbox\.com|postpro\.net|realemail\.net|reallyfast\.biz|'
r'reallyfast\.info|speedpost\.net|ssl-mail\.com|swift-mail\.com|'
r'the-fastest\.net|the-quickest\.com|theinternetemail\.com|'
r'veryfast\.biz|veryspeedy\.net|yepmail\.net)$', re.I),
{
'port': 465,
'smtp_host': 'smtp.fastmail.com',
'secure': True,
'secure_mode': SecureMailMode.SSL,
'login_type': (WebBaseLogin.EMAIL, )
},
),
# Zoho Mail
(
'Zoho Mail',
re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>zoho\.com)$', re.I),
{
'port': 465,
'smtp_host': 'smtp.zoho.com',
'secure': True,
'secure_mode': SecureMailMode.SSL,
'login_type': (WebBaseLogin.EMAIL, ) 'login_type': (WebBaseLogin.EMAIL, )
}, },
), ),
@ -95,7 +195,9 @@ WEBBASE_LOOKUP_TABLE = (
# Catch All # Catch All
( (
'Custom', 'Custom',
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>.+)$', re.I), re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>.+)$', re.I),
{ {
# Setting smtp_host to None is a way of # Setting smtp_host to None is a way of
# auto-detecting it based on other parameters # auto-detecting it based on other parameters
@ -125,12 +227,18 @@ 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
# Default Secure Port # Default Secure Port
default_secure_port = 587 default_secure_port = 587
# Default Secure Mode
default_secure_mode = SecureMailMode.STARTTLS
# Default SMTP Timeout (in seconds) # Default SMTP Timeout (in seconds)
connect_timeout = 15 connect_timeout = 15
@ -171,6 +279,13 @@ class NotifyEmail(NotifyBase):
# Now detect the SMTP Server # Now detect the SMTP Server
self.smtp_host = kwargs.get('smtp_host', '') self.smtp_host = kwargs.get('smtp_host', '')
# Now detect secure mode
self.secure_mode = kwargs.get('secure_mode', self.default_secure_mode)
if self.secure_mode not in SECURE_MODES:
raise TypeError(
'Invalid secure mode specified: %s.' % self.secure_mode)
# Apply any defaults based on certain known configurations # Apply any defaults based on certain known configurations
self.NotifyEmailDefaults() self.NotifyEmailDefaults()
@ -202,7 +317,8 @@ class NotifyEmail(NotifyBase):
.get('port', self.port) .get('port', self.port)
self.secure = WEBBASE_LOOKUP_TABLE[i][2]\ self.secure = WEBBASE_LOOKUP_TABLE[i][2]\
.get('secure', self.secure) .get('secure', self.secure)
self.secure_mode = WEBBASE_LOOKUP_TABLE[i][2]\
.get('secure_mode', self.secure_mode)
self.smtp_host = WEBBASE_LOOKUP_TABLE[i][2]\ self.smtp_host = WEBBASE_LOOKUP_TABLE[i][2]\
.get('smtp_host', self.smtp_host) .get('smtp_host', self.smtp_host)
@ -246,11 +362,9 @@ class NotifyEmail(NotifyBase):
# Prepare Email Message # Prepare Email Message
if self.notify_format == NotifyFormat.HTML: if self.notify_format == NotifyFormat.HTML:
email = MIMEText(body, 'html') email = MIMEText(body, 'html')
email['Content-Type'] = 'text/html'
else: else:
email = MIMEText(body, 'text') email = MIMEText(body, 'plain')
email['Content-Type'] = 'text/plain'
email['Subject'] = title email['Subject'] = title
email['From'] = '%s <%s>' % (from_name, self.from_addr) email['From'] = '%s <%s>' % (from_name, self.from_addr)
@ -263,16 +377,21 @@ class NotifyEmail(NotifyBase):
socket = None socket = None
try: try:
self.logger.debug('Connecting to remote SMTP server...') self.logger.debug('Connecting to remote SMTP server...')
socket = smtplib.SMTP( socket_func = smtplib.SMTP
if self.secure and self.secure_mode == SecureMailMode.SSL:
self.logger.debug('Securing connection with SSL...')
socket_func = smtplib.SMTP_SSL
socket = socket_func(
self.smtp_host, self.smtp_host,
self.port, self.port,
None, None,
timeout=self.timeout, timeout=self.timeout,
) )
if self.secure: if self.secure and self.secure_mode == SecureMailMode.STARTTLS:
# Handle Secure Connections # Handle Secure Connections
self.logger.debug('Securing connection with TLS...') self.logger.debug('Securing connection with STARTTLS...')
socket.starttls() socket.starttls()
if self.user and self.password: if self.user and self.password:
@ -317,19 +436,10 @@ class NotifyEmail(NotifyBase):
# Apply our settings now # Apply our settings now
# Default Format is HTML
results['notify_format'] = NotifyFormat.HTML
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'])
@ -369,6 +479,10 @@ class NotifyEmail(NotifyBase):
# Extract the smtp server # Extract the smtp server
smtp_host = NotifyBase.unquote(results['qsd']['smtp']) smtp_host = NotifyBase.unquote(results['qsd']['smtp'])
if 'mode' in results['qsd'] and len(results['qsd']['mode']):
# Extract the secure mode to over-ride the default
results['secure_mode'] = results['qsd']['mode'].lower()
results['to'] = to_addr results['to'] = to_addr
results['from'] = from_addr results['from'] = from_addr
results['smtp_host'] = smtp_host results['smtp_host'] = smtp_host

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Emby Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 plugin to work correct, the Emby server must be set up to allow # For this plugin to work correct, the Emby server must be set up to allow
# for remote connections. # for remote connections.

@ -1,20 +1,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Faast Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 CON
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Growl Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re

@ -1,18 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# This file is part of apprise. # This code is licensed under the MIT License.
# #
# This program is free software; you can redistribute it and/or modify it # Permission is hereby granted, free of charge, to any person obtaining a copy
# under the terms of the GNU Lesser General Public License as published by # of this software and associated documentation files(the "Software"), to deal
# the Free Software Foundation; either version 3 of the License, or # in the Software without restriction, including without limitation the rights
# (at your option) any later version. # 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 distributed in the hope that it will be useful, # The above copyright notice and this permission notice shall be included in
# but WITHOUT ANY WARRANTY; without even the implied warranty of # all copies or substantial portions of the Software.
# 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 . import NotifyGrowl from . import NotifyGrowl

@ -21,7 +21,7 @@ __all__ = [
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class GrowlNotifier(gntp.notifier.GrowlNotifier): class GrowlNotifier(notifier.GrowlNotifier):
""" """
ConfigParser enhanced GrowlNotifier object ConfigParser enhanced GrowlNotifier object
@ -36,7 +36,7 @@ class GrowlNotifier(gntp.notifier.GrowlNotifier):
port = ? port = ?
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
config = gntp.shim.RawConfigParser({ config = shim.RawConfigParser({
'hostname': kwargs.get('hostname', 'localhost'), 'hostname': kwargs.get('hostname', 'localhost'),
'password': kwargs.get('password'), 'password': kwargs.get('password'),
'port': kwargs.get('port', 23053), 'port': kwargs.get('port', 23053),
@ -67,7 +67,7 @@ def mini(description, **kwargs):
:param string description: Notification message :param string description: Notification message
""" """
kwargs['notifierFactory'] = GrowlNotifier kwargs['notifierFactory'] = GrowlNotifier
gntp.notifier.mini(description, **kwargs) notifier.mini(description, **kwargs)
if __name__ == '__main__': if __name__ == '__main__':

@ -27,16 +27,16 @@ if PY3:
from configparser import RawConfigParser from configparser import RawConfigParser
else: else:
def b(s): def b(s):
if isinstance(s, unicode): if isinstance(s, unicode): # noqa
return s.encode('utf8', 'replace') return s.encode('utf8', 'replace')
return s return s
def u(s): def u(s):
if isinstance(s, unicode): if isinstance(s, unicode): # noqa
return s return s
if isinstance(s, int): if isinstance(s, int):
s = str(s) s = str(s)
return unicode(s, "utf8", "replace") return unicode(s, "utf8", "replace") # noqa
from StringIO import StringIO from StringIO import StringIO
from ConfigParser import RawConfigParser from ConfigParser import RawConfigParser

@ -2,19 +2,28 @@
# #
# IFTTT (If-This-Then-That) # IFTTT (If-This-Then-That)
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# This file is part of apprise. # This code is licensed under the MIT License.
# #
# This program is free software; you can redistribute it and/or modify it # Permission is hereby granted, free of charge, to any person obtaining a copy
# under the terms of the GNU Lesser General Public License as published by # of this software and associated documentation files(the "Software"), to deal
# the Free Software Foundation; either version 3 of the License, or # in the Software without restriction, including without limitation the rights
# (at your option) any later version. # 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 distributed in the hope that it will be useful, # The above copyright notice and this permission notice shall be included in
# but WITHOUT ANY WARRANTY; without even the implied warranty of # all copies or substantial portions of the Software.
# 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 plugin to work, you need to add the Maker applet to your profile # For this plugin to work, you need to add the Maker applet to your profile
# Simply visit https://ifttt.com/search and search for 'Webhooks' # Simply visit https://ifttt.com/search and search for 'Webhooks'

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# JSON Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 requests import requests
from json import dumps from json import dumps
@ -84,6 +91,9 @@ class NotifyJSON(NotifyBase):
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
if self.headers:
headers.update(self.headers)
auth = None auth = None
if self.user: if self.user:
auth = (self.user, self.password) auth = (self.user, self.password)

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Join Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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.
# Join URL: http://joaoapps.com/join/ # Join URL: http://joaoapps.com/join/
# To use this plugin, you need to first access (make sure your browser allows # To use this plugin, you need to first access (make sure your browser allows

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# MatterMost Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Prowl Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# PushBullet Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests

@ -1,161 +0,0 @@
# -*- coding: utf-8 -*-
#
# Pushalot Notify Wrapper
#
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com>
#
# This file is part of apprise.
#
# 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.
#
# 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.
import re
import requests
from json import dumps
from .NotifyBase import NotifyBase
from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyImageSize
# Extend HTTP Error Messages
PUSHALOT_HTTP_ERROR_MAP = HTTP_ERROR_MAP.copy()
PUSHALOT_HTTP_ERROR_MAP.update({
406: 'Message throttle limit hit.',
410: 'AuthorizedToken is no longer valid.',
})
# Used to validate Authorization Token
VALIDATE_AUTHTOKEN = re.compile(r'[A-Za-z0-9]{32}')
class NotifyPushalot(NotifyBase):
"""
A wrapper for Pushalot Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Pushalot'
# The services URL
service_url = 'https://pushalot.com/'
# The default protocol is always secured
secure_protocol = 'palot'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pushalot'
# Pushalot uses the http protocol with JSON requests
notify_url = 'https://pushalot.com/api/sendmessage'
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_72
def __init__(self, authtoken, is_important=False, **kwargs):
"""
Initialize Pushalot Object
"""
super(NotifyPushalot, self).__init__(**kwargs)
# Is Important Flag
self.is_important = is_important
self.authtoken = authtoken
# Validate authtoken
if not VALIDATE_AUTHTOKEN.match(authtoken):
self.logger.warning(
'Invalid Pushalot Authorization Token Specified.'
)
raise TypeError(
'Invalid Pushalot Authorization Token Specified.'
)
def notify(self, title, body, notify_type, **kwargs):
"""
Perform Pushalot Notification
"""
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json'
}
# prepare JSON Object
payload = {
'AuthorizationToken': self.authtoken,
'IsImportant': self.is_important,
'Title': title,
'Body': body,
'Source': self.app_id,
}
image_url = self.image_url(notify_type)
if image_url:
payload['Image'] = image_url
self.logger.debug('Pushalot POST URL: %s (cert_verify=%r)' % (
self.notify_url, self.verify_certificate,
))
self.logger.debug('Pushalot Payload: %s' % str(payload))
try:
r = requests.post(
self.notify_url,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
)
if r.status_code != requests.codes.ok:
# We had a problem
try:
self.logger.warning(
'Failed to send Pushalot notification: '
'%s (error=%s).' % (
PUSHALOT_HTTP_ERROR_MAP[r.status_code],
r.status_code))
except KeyError:
self.logger.warning(
'Failed to send Pushalot notification '
'(error=%s).' % r.status_code)
# Return; we're done
return False
else:
self.logger.info('Sent Pushalot notification.')
except requests.RequestException as e:
self.logger.warning(
'A Connection error occured sending Pushalot notification.')
self.logger.debug('Socket Exception: %s' % str(e))
# Return; we're done
return False
return True
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to substantiate this object.
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
# Apply our settings now
results['authtoken'] = results['host']
return results

@ -1,20 +1,28 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Pushjet Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
from .pushjet import errors from .pushjet import errors
from .pushjet import pushjet from .pushjet import pushjet
@ -35,9 +43,6 @@ class NotifyPushjet(NotifyBase):
# The default descriptive name associated with the Notification # The default descriptive name associated with the Notification
service_name = 'Pushjet' service_name = 'Pushjet'
# The services URL
service_url = 'https://pushjet.io/'
# The default protocol # The default protocol
protocol = 'pjet' protocol = 'pjet'
@ -58,21 +63,16 @@ class NotifyPushjet(NotifyBase):
Perform Pushjet Notification Perform Pushjet Notification
""" """
try: try:
if self.user and self.host: server = "http://"
server = "http://" if self.secure:
if self.secure: server = "https://"
server = "https://"
server += self.host
if self.port:
server += ":" + str(self.port)
api = pushjet.Api(server) server += self.host
service = api.Service(secret_key=self.user) if self.port:
server += ":" + str(self.port)
else: api = pushjet.Api(server)
api = pushjet.Api(pushjet.DEFAULT_API_URL) service = api.Service(secret_key=self.user)
service = api.Service(secret_key=self.host)
service.send(body, title) service.send(body, title)
self.logger.info('Sent Pushjet notification.') self.logger.info('Sent Pushjet notification.')
@ -83,3 +83,28 @@ class NotifyPushjet(NotifyBase):
return False return False
return True return True
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to substantiate this object.
Syntax:
pjet://secret@hostname
pjet://secret@hostname:port
pjets://secret@hostname
pjets://secret@hostname:port
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
if not results.get('user'):
# a username is required
return None
return results

@ -1,18 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# This file is part of apprise. # This code is licensed under the MIT License.
# #
# This program is free software; you can redistribute it and/or modify it # Permission is hereby granted, free of charge, to any person obtaining a copy
# under the terms of the GNU Lesser General Public License as published by # of this software and associated documentation files(the "Software"), to deal
# the Free Software Foundation; either version 3 of the License, or # in the Software without restriction, including without limitation the rights
# (at your option) any later version. # 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 distributed in the hope that it will be useful, # The above copyright notice and this permission notice shall be included in
# but WITHOUT ANY WARRANTY; without even the implied warranty of # all copies or substantial portions of the Software.
# 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 . import NotifyPushjet from . import NotifyPushjet

@ -1,8 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
import requests import requests
from functools import partial from functools import partial
from six import text_type
from six.moves.urllib.parse import urljoin
from .utilities import ( from .utilities import (
NoNoneDict, NoNoneDict,
requires_secret_key, with_api_bound, requires_secret_key, with_api_bound,
@ -10,14 +14,6 @@ from .utilities import (
) )
from .errors import NonexistentError, SubscriptionError, RequestError, ServerError from .errors import NonexistentError, SubscriptionError, RequestError, ServerError
import sys
if sys.version_info[0] >= 3:
from urllib.parse import urljoin
unicode_type = str
else:
from urlparse import urljoin
unicode_type = unicode
DEFAULT_API_URL = 'https://api.pushjet.io/' DEFAULT_API_URL = 'https://api.pushjet.io/'
class PushjetModel(object): class PushjetModel(object):
@ -52,8 +48,8 @@ class Service(PushjetModel):
raise ValueError("Invalid secret key provided.") raise ValueError("Invalid secret key provided.")
elif public_key and not is_valid_public_key(public_key): elif public_key and not is_valid_public_key(public_key):
raise ValueError("Invalid public key provided.") raise ValueError("Invalid public key provided.")
self.secret_key = unicode_type(secret_key) if secret_key else None self.secret_key = text_type(secret_key) if secret_key else None
self.public_key = unicode_type(public_key) if public_key else None self.public_key = text_type(public_key) if public_key else None
self.refresh() self.refresh()
def _request(self, endpoint, method, is_secret, params=None, data=None): def _request(self, endpoint, method, is_secret, params=None, data=None):
@ -97,8 +93,8 @@ class Service(PushjetModel):
if not data: if not data:
return return
self._request('service', 'PATCH', is_secret=True, data=data) self._request('service', 'PATCH', is_secret=True, data=data)
self.name = unicode_type(name) self.name = text_type(name)
self.icon_url = unicode_type(icon_url) self.icon_url = text_type(icon_url)
@requires_secret_key @requires_secret_key
def delete(self): def delete(self):
@ -171,10 +167,10 @@ class Device(PushjetModel):
return "<Pushjet Device: {}>".format(self.uuid) return "<Pushjet Device: {}>".format(self.uuid)
def __init__(self, uuid): def __init__(self, uuid):
uuid = unicode_type(uuid) uuid = text_type(uuid)
if not is_valid_uuid(uuid): if not is_valid_uuid(uuid):
raise ValueError("Invalid UUID provided. Try uuid.uuid4().") raise ValueError("Invalid UUID provided. Try uuid.uuid4().")
self.uuid = unicode_type(uuid) self.uuid = text_type(uuid)
def _request(self, endpoint, method, params=None, data=None): def _request(self, endpoint, method, params=None, data=None):
params = (params or {}) params = (params or {})
@ -292,7 +288,7 @@ class Api(object):
return "<Pushjet Api: {}>".format(self.url).encode(sys.stdout.encoding, errors='replace') return "<Pushjet Api: {}>".format(self.url).encode(sys.stdout.encoding, errors='replace')
def __init__(self, url): def __init__(self, url):
self.url = unicode_type(url) self.url = text_type(url)
self.Service = with_api_bound(Service, self) self.Service = with_api_bound(Service, self)
self.Device = with_api_bound(Device, self) self.Device = with_api_bound(Device, self)

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Pushover Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Notify Rocket.Chat Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests
@ -114,7 +121,7 @@ class NotifyRocketChat(NotifyBase):
continue continue
self.logger.warning( self.logger.warning(
'Dropped invalid channel/room ' + 'Dropped invalid channel/room '
'(%s) specified.' % recipient, '(%s) specified.' % recipient,
) )
@ -206,14 +213,14 @@ class NotifyRocketChat(NotifyBase):
# We had a problem # We had a problem
try: try:
self.logger.warning( self.logger.warning(
'Failed to send Rocket.Chat notification: ' + 'Failed to send Rocket.Chat notification: '
'%s (error=%s).' % ( '%s (error=%s).' % (
RC_HTTP_ERROR_MAP[r.status_code], RC_HTTP_ERROR_MAP[r.status_code],
r.status_code)) r.status_code))
except KeyError: except KeyError:
self.logger.warning( self.logger.warning(
'Failed to send Rocket.Chat notification ' + 'Failed to send Rocket.Chat notification '
'(error=%s).' % ( '(error=%s).' % (
r.status_code)) r.status_code))
@ -226,7 +233,7 @@ class NotifyRocketChat(NotifyBase):
except requests.RequestException as e: except requests.RequestException as e:
self.logger.warning( self.logger.warning(
'A Connection error occured sending Rocket.Chat ' + 'A Connection error occured sending Rocket.Chat '
'notification.') 'notification.')
self.logger.debug('Socket Exception: %s' % str(e)) self.logger.debug('Socket Exception: %s' % str(e))
@ -255,14 +262,14 @@ class NotifyRocketChat(NotifyBase):
# We had a problem # We had a problem
try: try:
self.logger.warning( self.logger.warning(
'Failed to authenticate with Rocket.Chat server: ' + 'Failed to authenticate with Rocket.Chat server: '
'%s (error=%s).' % ( '%s (error=%s).' % (
RC_HTTP_ERROR_MAP[r.status_code], RC_HTTP_ERROR_MAP[r.status_code],
r.status_code)) r.status_code))
except KeyError: except KeyError:
self.logger.warning( self.logger.warning(
'Failed to authenticate with Rocket.Chat server ' + 'Failed to authenticate with Rocket.Chat server '
'(error=%s).' % ( '(error=%s).' % (
r.status_code)) r.status_code))
@ -285,7 +292,7 @@ class NotifyRocketChat(NotifyBase):
except requests.RequestException as e: except requests.RequestException as e:
self.logger.warning( self.logger.warning(
'A Connection error occured authenticating to the ' + 'A Connection error occured authenticating to the '
'Rocket.Chat server.') 'Rocket.Chat server.')
self.logger.debug('Socket Exception: %s' % str(e)) self.logger.debug('Socket Exception: %s' % str(e))
return False return False
@ -306,14 +313,14 @@ class NotifyRocketChat(NotifyBase):
# We had a problem # We had a problem
try: try:
self.logger.warning( self.logger.warning(
'Failed to log off Rocket.Chat server: ' + 'Failed to log off Rocket.Chat server: '
'%s (error=%s).' % ( '%s (error=%s).' % (
RC_HTTP_ERROR_MAP[r.status_code], RC_HTTP_ERROR_MAP[r.status_code],
r.status_code)) r.status_code))
except KeyError: except KeyError:
self.logger.warning( self.logger.warning(
'Failed to log off Rocket.Chat server ' + 'Failed to log off Rocket.Chat server '
'(error=%s).' % ( '(error=%s).' % (
r.status_code)) r.status_code))
@ -327,7 +334,7 @@ class NotifyRocketChat(NotifyBase):
except requests.RequestException as e: except requests.RequestException as e:
self.logger.warning( self.logger.warning(
'A Connection error occured logging off the ' + 'A Connection error occured logging off the '
'Rocket.Chat server') 'Rocket.Chat server')
self.logger.debug('Socket Exception: %s' % str(e)) self.logger.debug('Socket Exception: %s' % str(e))
return False return False

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Slack Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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.
# To use this plugin, you need to first access https://api.slack.com # To use this plugin, you need to first access https://api.slack.com
# Specifically https://my.slack.com/services/new/incoming-webhook/ # Specifically https://my.slack.com/services/new/incoming-webhook/

@ -1,246 +0,0 @@
# -*- coding: utf-8 -*-
#
# Stride Notify Wrapper
#
# Copyright (C) 2018 Chris Caron <lead2gold@gmail.com>
#
# This file is part of apprise.
#
# 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.
#
# 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.
# When you sign-up with stride.com they'll ask if you want to join a channel
# or create your own.
#
# Once you get set up, you'll have the option of creating a channel.
#
# Now you'll want to connect apprise up. To do this, you need to go to
# the App Manager an choose to 'Connect your own app'. It will get you
# to provide a 'token name' which can be whatever you want. Call it
# 'Apprise' if you want (it really doesn't matter) and then click the
# 'Create' button.
#
# When it completes it will generate a token that looks something like:
# HQFtq4pF8rKFOlKTm9Th
#
# This will become your AUTH_TOKEN
#
# It will also provide you a conversation URL that might look like:
# https://api.atlassian.com/site/ce171c45-79ae-4fec-a73d-5a4b7a322872/\
# conversation/a54a80b3-eaad-4564-9a3a-f6653bcfb100/message
#
# Simplified, it looks like this:
# https://api.atlassian.com/site/CLOUD_ID/conversation/CONVO_ID/message
#
# This plugin will simply work using the url of:
# stride://AUTH_TOKEN/CLOUD_ID/CONVO_ID
#
import requests
import re
from json import dumps
from .NotifyBase import NotifyBase
from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyImageSize
# A Simple UUID4 checker
IS_VALID_TOKEN = re.compile(
r'([0-9a-f]{8})-*([0-9a-f]{4})-*(4[0-9a-f]{3})-*'
r'([89ab][0-9a-f]{3})-*([0-9a-f]{12})', re.I)
class NotifyStride(NotifyBase):
"""
A wrapper to Stride Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Stride'
# The services URL
service_url = 'https://www.stride.com/'
# The default secure protocol
secure_protocol = 'stride'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_stride'
# Stride Webhook
notify_url = 'https://api.atlassian.com/site/{cloud_id}/' \
'conversation/{convo_id}/message'
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_256
# The maximum allowable characters allowed in the body per message
body_maxlen = 2000
def __init__(self, auth_token, cloud_id, convo_id, **kwargs):
"""
Initialize Stride Object
"""
super(NotifyStride, self).__init__(**kwargs)
if not auth_token:
raise TypeError(
'An invalid Authorization token was specified.'
)
if not cloud_id:
raise TypeError('No Cloud ID was specified.')
cloud_id_re = IS_VALID_TOKEN.match(cloud_id)
if cloud_id_re is None:
raise TypeError('The specified Cloud ID is not a valid UUID.')
if not convo_id:
raise TypeError('No Conversation ID was specified.')
convo_id_re = IS_VALID_TOKEN.match(convo_id)
if convo_id_re is None:
raise TypeError(
'The specified Conversation ID is not a valid UUID.')
# Store our validated token
self.cloud_id = '{0}-{1}-{2}-{3}-{4}'.format(
cloud_id_re.group(0),
cloud_id_re.group(1),
cloud_id_re.group(2),
cloud_id_re.group(3),
cloud_id_re.group(4),
)
# Store our validated token
self.convo_id = '{0}-{1}-{2}-{3}-{4}'.format(
convo_id_re.group(0),
convo_id_re.group(1),
convo_id_re.group(2),
convo_id_re.group(3),
convo_id_re.group(4),
)
self.auth_token = auth_token
return
def notify(self, title, body, notify_type, **kwargs):
"""
Perform Stride Notification
"""
headers = {
'User-Agent': self.app_id,
'Authorization': 'Bearer {auth_token}'.format(
auth_token=self.auth_token),
'Content-Type': 'application/json',
}
# Prepare JSON Object
payload = {
"body": {
"version": 1,
"type": "doc",
"content": [{
"type": "paragraph",
"content": [{
"type": "text",
"text": body,
}],
}],
}
}
# Construct Notify URL
notify_url = self.notify_url.format(
cloud_id=self.cloud_id,
convo_id=self.convo_id,
)
self.logger.debug('Stride POST URL: %s (cert_verify=%r)' % (
notify_url, self.verify_certificate,
))
self.logger.debug('Stride Payload: %s' % str(payload))
try:
r = requests.post(
notify_url,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
)
if r.status_code not in (
requests.codes.ok, requests.codes.no_content):
# We had a problem
try:
self.logger.warning(
'Failed to send Stride notification: '
'%s (error=%s).' % (
HTTP_ERROR_MAP[r.status_code],
r.status_code))
except KeyError:
self.logger.warning(
'Failed to send Stride notification '
'(error=%s).' % r.status_code)
self.logger.debug('Response Details: %s' % r.raw.read())
# Return; we're done
return False
else:
self.logger.info('Sent Stride notification.')
except requests.RequestException as e:
self.logger.warning(
'A Connection error occured sending Stride '
'notification.'
)
self.logger.debug('Socket Exception: %s' % str(e))
return False
return True
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to substantiate this object.
Syntax:
stride://auth_token/cloud_id/convo_id
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
# Store our Authentication Token
auth_token = results['host']
# Now fetch our tokens
try:
(ta, tb) = [x for x in filter(bool, NotifyBase.split_path(
results['fullpath']))][0:2]
except (ValueError, AttributeError, IndexError):
# Force some bad values that will get caught
# in parsing later
ta = None
tb = None
results['cloud_id'] = ta
results['convo_id'] = tb
results['auth_token'] = auth_token
return results

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Telegram Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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.
# To use this plugin, you need to first access https://api.telegram.org # To use this plugin, you need to first access https://api.telegram.org
# You need to create a bot and acquire it's Token Identifier (bot_token) # You need to create a bot and acquire it's Token Identifier (bot_token)
@ -55,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
@ -255,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:
@ -349,24 +357,50 @@ class NotifyTelegram(NotifyBase):
payload = {} payload = {}
# HTML Spaces (&nbsp;) and tabs (&emsp;) aren't supported # Prepare Email Message
# See https://core.telegram.org/bots/api#html-style if self.notify_format == NotifyFormat.MARKDOWN:
title = re.sub('&nbsp;?', ' ', title, re.I) payload['parse_mode'] = 'MARKDOWN'
body = re.sub('&nbsp;?', ' ', body, re.I)
# Tabs become 3 spaces
title = re.sub('&emsp;?', ' ', title, re.I)
body = re.sub('&emsp;?', ' ', body, re.I)
# HTML else:
title = NotifyBase.escape_html(title, whitespace=False) # Either TEXT or HTML; if TEXT we'll make it HTML
body = NotifyBase.escape_html(body, whitespace=False) payload['parse_mode'] = 'HTML'
payload['parse_mode'] = 'HTML' # HTML Spaces (&nbsp;) and tabs (&emsp;) aren't supported
# See https://core.telegram.org/bots/api#html-style
body = re.sub('&nbsp;?', ' ', body, re.I)
payload['text'] = '<b>%s</b>\r\n%s' % ( # Tabs become 3 spaces
title, body = re.sub('&emsp;?', ' ', body, re.I)
body,
) if title:
# HTML Spaces (&nbsp;) and tabs (&emsp;) aren't supported
# See https://core.telegram.org/bots/api#html-style
title = re.sub('&nbsp;?', ' ', title, re.I)
# Tabs become 3 spaces
title = re.sub('&emsp;?', ' ', title, re.I)
# HTML
title = NotifyBase.escape_html(title, whitespace=False)
body = NotifyBase.escape_html(body, whitespace=False)
# 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' % (
title,
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)
@ -419,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:

@ -1,180 +0,0 @@
# -*- coding: utf-8 -*-
#
# (Super) Toasty Notify Wrapper
#
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com>
#
# This file is part of apprise.
#
# 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.
#
# 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.
import re
import requests
from .NotifyBase import NotifyBase
from .NotifyBase import HTTP_ERROR_MAP
from ..common import NotifyImageSize
from ..utils import compat_is_basestring
# Used to break apart list of potential devices by their delimiter
# into a usable list.
DEVICES_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+')
class NotifyToasty(NotifyBase):
"""
A wrapper for Toasty Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Toasty'
# The services URL
service_url = 'http://supertoasty.com/'
# The default protocol
protocol = 'toasty'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_toasty'
# Toasty uses the http protocol with JSON requests
notify_url = 'http://api.supertoasty.com/notify/'
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_128
def __init__(self, devices, **kwargs):
"""
Initialize Toasty Object
"""
super(NotifyToasty, self).__init__(**kwargs)
if compat_is_basestring(devices):
self.devices = [x for x in filter(bool, DEVICES_LIST_DELIM.split(
devices,
))]
elif isinstance(devices, (set, tuple, list)):
self.devices = devices
else:
self.devices = list()
if len(devices) == 0:
raise TypeError('You must specify at least 1 device.')
if not self.user:
raise TypeError('You must specify a username.')
def notify(self, title, body, notify_type, **kwargs):
"""
Perform Toasty Notification
"""
headers = {
'User-Agent': self.app_id,
'Content-Type': 'multipart/form-data',
}
# error tracking (used for function return)
has_error = False
# Create a copy of the devices list
devices = list(self.devices)
while len(devices):
device = devices.pop(0)
# prepare JSON Object
payload = {
'sender': NotifyBase.quote(self.user),
'title': NotifyBase.quote(title),
'text': NotifyBase.quote(body),
}
image_url = self.image_url(notify_type)
if image_url:
payload['image'] = image_url
# URL to transmit content via
url = '%s%s' % (self.notify_url, device)
self.logger.debug('Toasty POST URL: %s (cert_verify=%r)' % (
url, self.verify_certificate,
))
self.logger.debug('Toasty Payload: %s' % str(payload))
try:
r = requests.get(
url,
data=payload,
headers=headers,
verify=self.verify_certificate,
)
if r.status_code != requests.codes.ok:
# We had a problem
try:
self.logger.warning(
'Failed to send Toasty:%s '
'notification: %s (error=%s).' % (
device,
HTTP_ERROR_MAP[r.status_code],
r.status_code))
except KeyError:
self.logger.warning(
'Failed to send Toasty:%s '
'notification (error=%s).' % (
device,
r.status_code))
# self.logger.debug('Response Details: %s' % r.raw.read())
# Return; we're done
has_error = True
else:
self.logger.info(
'Sent Toasty notification to %s.' % device)
except requests.RequestException as e:
self.logger.warning(
'A Connection error occured sending Toasty:%s ' % (
device) + 'notification.'
)
self.logger.debug('Socket Exception: %s' % str(e))
has_error = True
if len(devices):
# Prevent thrashing requests
self.throttle()
return not has_error
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to substantiate this object.
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
# Apply our settings now
devices = NotifyBase.unquote(results['fullpath'])
# Store our devices
results['devices'] = '%s/%s' % (results['host'], devices)
return results

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Twitter Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 . import tweepy from . import tweepy
from ..NotifyBase import NotifyBase from ..NotifyBase import NotifyBase

@ -1,18 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# This file is part of apprise. # This code is licensed under the MIT License.
# #
# This program is free software; you can redistribute it and/or modify it # Permission is hereby granted, free of charge, to any person obtaining a copy
# under the terms of the GNU Lesser General Public License as published by # of this software and associated documentation files(the "Software"), to deal
# the Free Software Foundation; either version 3 of the License, or # in the Software without restriction, including without limitation the rights
# (at your option) any later version. # 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 distributed in the hope that it will be useful, # The above copyright notice and this permission notice shall be included in
# but WITHOUT ANY WARRANTY; without even the implied warranty of # all copies or substantial portions of the Software.
# 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 . import NotifyTwitter from . import NotifyTwitter

@ -1,20 +1,28 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Windows Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 __future__ import absolute_import from __future__ import absolute_import
from __future__ import print_function from __future__ import print_function

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# XBMC/KODI Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# XML Notify Wrapper # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
import requests import requests
@ -89,6 +96,9 @@ class NotifyXML(NotifyBase):
'Content-Type': 'application/xml' 'Content-Type': 'application/xml'
} }
if self.headers:
headers.update(self.headers)
re_map = { re_map = {
'{MESSAGE_TYPE}': NotifyBase.quote(notify_type), '{MESSAGE_TYPE}': NotifyBase.quote(notify_type),
'{SUBJECT}': NotifyBase.quote(title), '{SUBJECT}': NotifyBase.quote(title),

@ -1,45 +1,55 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Our service wrappers # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017-2018 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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.
# Used for Testing; specifically test_email_plugin.py needs access # Used for Testing; specifically test_email_plugin.py needs access
# to the modules WEBBASE_LOOKUP_TABLE and WebBaseLogin objects # to the modules WEBBASE_LOOKUP_TABLE and WebBaseLogin objects
from . import NotifyEmail as NotifyEmailBase from . import NotifyEmail as NotifyEmailBase
from .NotifyBoxcar import NotifyBoxcar from .NotifyBoxcar import NotifyBoxcar
from .NotifyDBus import NotifyDBus
from .NotifyDiscord import NotifyDiscord from .NotifyDiscord import NotifyDiscord
from .NotifyEmail import NotifyEmail from .NotifyEmail import NotifyEmail
from .NotifyEmby import NotifyEmby from .NotifyEmby import NotifyEmby
from .NotifyFaast import NotifyFaast from .NotifyFaast import NotifyFaast
from .NotifyGrowl.NotifyGrowl import NotifyGrowl from .NotifyGrowl.NotifyGrowl import NotifyGrowl
from .NotifyGnome import NotifyGnome
from .NotifyIFTTT import NotifyIFTTT from .NotifyIFTTT import NotifyIFTTT
from .NotifyJoin import NotifyJoin from .NotifyJoin import NotifyJoin
from .NotifyJSON import NotifyJSON from .NotifyJSON import NotifyJSON
from .NotifyMatrix import NotifyMatrix
from .NotifyMatterMost import NotifyMatterMost from .NotifyMatterMost import NotifyMatterMost
from .NotifyProwl import NotifyProwl from .NotifyProwl import NotifyProwl
from .NotifyPushalot import NotifyPushalot from .NotifyPushed import NotifyPushed
from .NotifyPushBullet import NotifyPushBullet from .NotifyPushBullet import NotifyPushBullet
from .NotifyPushjet.NotifyPushjet import NotifyPushjet from .NotifyPushjet.NotifyPushjet import NotifyPushjet
from .NotifyPushover import NotifyPushover from .NotifyPushover import NotifyPushover
from .NotifyRocketChat import NotifyRocketChat from .NotifyRocketChat import NotifyRocketChat
from .NotifyRyver import NotifyRyver
from .NotifySlack import NotifySlack from .NotifySlack import NotifySlack
from .NotifyStride import NotifyStride from .NotifySNS import NotifySNS
from .NotifyTelegram import NotifyTelegram from .NotifyTelegram import NotifyTelegram
from .NotifyToasty import NotifyToasty
from .NotifyTwitter.NotifyTwitter import NotifyTwitter from .NotifyTwitter.NotifyTwitter import NotifyTwitter
from .NotifyXBMC import NotifyXBMC from .NotifyXBMC import NotifyXBMC
from .NotifyXML import NotifyXML from .NotifyXML import NotifyXML
@ -56,12 +66,13 @@ from ..common import NOTIFY_TYPES
__all__ = [ __all__ = [
# Notification Services # Notification Services
'NotifyBoxcar', 'NotifyEmail', 'NotifyEmby', 'NotifyDiscord', 'NotifyBoxcar', 'NotifyDBus', 'NotifyEmail', 'NotifyEmby', 'NotifyDiscord',
'NotifyFaast', 'NotifyGrowl', 'NotifyIFTTT', 'NotifyJoin', 'NotifyJSON', 'NotifyFaast', 'NotifyGnome', 'NotifyGrowl', 'NotifyIFTTT', 'NotifyJoin',
'NotifyMatterMost', 'NotifyProwl', 'NotifyPushalot', 'NotifyJSON', 'NotifyMatrix', 'NotifyMatterMost', 'NotifyProwl',
'NotifyPushBullet', 'NotifyPushjet', 'NotifyPushover', 'NotifyRocketChat', 'NotifyPushed', 'NotifyPushBullet', 'NotifyPushjet',
'NotifySlack', 'NotifyStride', 'NotifyToasty', 'NotifyTwitter', 'NotifyPushover', 'NotifyRocketChat', 'NotifyRyver', 'NotifySlack',
'NotifyTelegram', 'NotifyXBMC', 'NotifyXML', 'NotifyWindows', 'NotifySNS', 'NotifyTwitter', 'NotifyTelegram', 'NotifyXBMC',
'NotifyXML', 'NotifyWindows',
# Reference # Reference
'NotifyImageSize', 'NOTIFY_IMAGE_SIZES', 'NotifyType', 'NOTIFY_TYPES', 'NotifyImageSize', 'NOTIFY_IMAGE_SIZES', 'NotifyType', 'NOTIFY_TYPES',

@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# A simple collection of general functions # Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# #
# Copyright (C) 2017 Chris Caron <lead2gold@gmail.com> # 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 # The above copyright notice and this permission notice shall be included in
# under the terms of the GNU Lesser General Public License as published by # all copies or substantial portions of the Software.
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# but WITHOUT ANY WARRANTY; without even the implied warranty of # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# GNU Lesser General Public License for more details. # 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 re
@ -84,6 +91,9 @@ TIDY_NUX_TRIM_RE = re.compile(
), ),
) )
# Used for attempting to acquire the schema if the URL can't be parsed.
GET_SCHEMA_RE = re.compile(r'\s*(?P<schema>[a-z0-9]{2,9})://.*$', re.I)
def is_hostname(hostname): def is_hostname(hostname):
""" """

Loading…
Cancel
Save