Updated apprise module to improve notification system. #2163

pull/2131/head
morpheus65535 12 months ago
parent 0956d401bc
commit 07f601f407

@ -1,28 +1,37 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import asyncio
import concurrent.futures as cf
import os
from itertools import chain
from . import common
@ -43,11 +52,6 @@ from .plugins.NotifyBase import NotifyBase
from . import plugins
from . import __version__
# Python v3+ support code made importable, so it can remain backwards
# compatible with Python v2
# TODO: Review after dropping support for Python 2.
from . import py3compat
class Apprise:
"""
@ -369,91 +373,83 @@ class Apprise:
such as turning a \n into an actual new line, etc.
"""
return py3compat.asyncio.tosync(
self.async_notify(
try:
# Process arguments and build synchronous and asynchronous calls
# (this step can throw internal errors).
sequential_calls, parallel_calls = self._create_notify_calls(
body, title,
notify_type=notify_type, body_format=body_format,
tag=tag, match_always=match_always, attach=attach,
interpret_escapes=interpret_escapes,
),
debug=self.debug
)
interpret_escapes=interpret_escapes
)
except TypeError:
# No notifications sent, and there was an internal error.
return False
if not sequential_calls and not parallel_calls:
# Nothing to send
return None
sequential_result = Apprise._notify_sequential(*sequential_calls)
parallel_result = Apprise._notify_parallel_threadpool(*parallel_calls)
return sequential_result and parallel_result
def async_notify(self, *args, **kwargs):
async def async_notify(self, *args, **kwargs):
"""
Send a notification to all the plugins previously loaded, for
asynchronous callers. This method is an async method that should be
awaited on, even if it is missing the async keyword in its signature.
(This is omitted to preserve syntax compatibility with Python 2.)
asynchronous callers.
The arguments are identical to those of Apprise.notify().
"""
try:
coroutines = list(
self._notifyall(
Apprise._notifyhandlerasync, *args, **kwargs))
# Process arguments and build synchronous and asynchronous calls
# (this step can throw internal errors).
sequential_calls, parallel_calls = self._create_notify_calls(
*args, **kwargs)
except TypeError:
# No notifications sent, and there was an internal error.
return py3compat.asyncio.toasyncwrapvalue(False)
return False
else:
if len(coroutines) > 0:
# All notifications sent, return False if any failed.
return py3compat.asyncio.notify(coroutines)
if not sequential_calls and not parallel_calls:
# Nothing to send
return None
else:
# No notifications sent.
return py3compat.asyncio.toasyncwrapvalue(None)
sequential_result = Apprise._notify_sequential(*sequential_calls)
parallel_result = \
await Apprise._notify_parallel_asyncio(*parallel_calls)
return sequential_result and parallel_result
@staticmethod
def _notifyhandler(server, **kwargs):
"""
The synchronous notification sender. Returns True if the notification
sent successfully.
def _create_notify_calls(self, *args, **kwargs):
"""
Creates notifications for all the plugins loaded.
try:
# Send notification
return server.notify(**kwargs)
except TypeError:
# These our our internally thrown notifications
return False
except Exception:
# A catch all so we don't have to abort early
# just because one of our plugins has a bug in it.
logger.exception("Unhandled Notification Exception")
return False
@staticmethod
def _notifyhandlerasync(server, **kwargs):
"""
The asynchronous notification sender. Returns a coroutine that yields
True if the notification sent successfully.
Returns a list of (server, notify() kwargs) tuples for plugins with
parallelism disabled and another list for plugins with parallelism
enabled.
"""
if server.asset.async_mode:
return server.async_notify(**kwargs)
all_calls = list(self._create_notify_gen(*args, **kwargs))
else:
# Send the notification immediately, and wrap the result in a
# coroutine.
status = Apprise._notifyhandler(server, **kwargs)
return py3compat.asyncio.toasyncwrapvalue(status)
# Split into sequential and parallel notify() calls.
sequential, parallel = [], []
for (server, notify_kwargs) in all_calls:
if server.asset.async_mode:
parallel.append((server, notify_kwargs))
else:
sequential.append((server, notify_kwargs))
def _notifyall(self, handler, body, title='',
notify_type=common.NotifyType.INFO, body_format=None,
tag=common.MATCH_ALL_TAG, match_always=True, attach=None,
interpret_escapes=None):
"""
Creates notifications for all the plugins loaded.
return sequential, parallel
Returns a generator that calls handler for each notification. The first
and only argument supplied to handler is the server, and the keyword
arguments are exactly as they would be passed to server.notify().
def _create_notify_gen(self, body, title='',
notify_type=common.NotifyType.INFO,
body_format=None, tag=common.MATCH_ALL_TAG,
match_always=True, attach=None,
interpret_escapes=None):
"""
Internal generator function for _create_notify_calls().
"""
if len(self) == 0:
@ -546,14 +542,121 @@ class Apprise:
logger.error(msg)
raise TypeError(msg)
yield handler(
server,
kwargs = dict(
body=conversion_body_map[server.notify_format],
title=conversion_title_map[server.notify_format],
notify_type=notify_type,
attach=attach,
body_format=body_format,
body_format=body_format
)
yield (server, kwargs)
@staticmethod
def _notify_sequential(*servers_kwargs):
"""
Process a list of notify() calls sequentially and synchronously.
"""
success = True
for (server, kwargs) in servers_kwargs:
try:
# Send notification
result = server.notify(**kwargs)
success = success and result
except TypeError:
# These are our internally thrown notifications.
success = False
except Exception:
# A catch all so we don't have to abort early
# just because one of our plugins has a bug in it.
logger.exception("Unhandled Notification Exception")
success = False
return success
@staticmethod
def _notify_parallel_threadpool(*servers_kwargs):
"""
Process a list of notify() calls in parallel and synchronously.
"""
n_calls = len(servers_kwargs)
# 0-length case
if n_calls == 0:
return True
# There's no need to use a thread pool for just a single notification
if n_calls == 1:
return Apprise._notify_sequential(servers_kwargs[0])
# Create log entry
logger.info(
'Notifying %d service(s) with threads.', len(servers_kwargs))
with cf.ThreadPoolExecutor() as executor:
success = True
futures = [executor.submit(server.notify, **kwargs)
for (server, kwargs) in servers_kwargs]
for future in cf.as_completed(futures):
try:
result = future.result()
success = success and result
except TypeError:
# These are our internally thrown notifications.
success = False
except Exception:
# A catch all so we don't have to abort early
# just because one of our plugins has a bug in it.
logger.exception("Unhandled Notification Exception")
success = False
return success
@staticmethod
async def _notify_parallel_asyncio(*servers_kwargs):
"""
Process a list of async_notify() calls in parallel and asynchronously.
"""
n_calls = len(servers_kwargs)
# 0-length case
if n_calls == 0:
return True
# (Unlike with the thread pool, we don't optimize for the single-
# notification case because asyncio can do useful work while waiting
# for that thread to complete)
# Create log entry
logger.info(
'Notifying %d service(s) asynchronously.', len(servers_kwargs))
async def do_call(server, kwargs):
return await server.async_notify(**kwargs)
cors = (do_call(server, kwargs) for (server, kwargs) in servers_kwargs)
results = await asyncio.gather(*cors, return_exceptions=True)
if any(isinstance(status, Exception)
and not isinstance(status, TypeError) for status in results):
# A catch all so we don't have to abort early just because
# one of our plugins has a bug in it.
logger.exception("Unhandled Notification Exception")
return False
if any(isinstance(status, TypeError) for status in results):
# These are our internally thrown notifications.
return False
return all(results)
def details(self, lang=None, show_requirements=False, show_disabled=False):
"""
@ -581,6 +684,7 @@ class Apprise:
'setup_url': getattr(plugin, 'setup_url', None),
# Placeholder - populated below
'details': None,
# Differentiat between what is a custom loaded plugin and
# which is native.
'category': getattr(plugin, 'category', None)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
from uuid import uuid4

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from . import attachment
from . import URLBase
@ -170,6 +177,11 @@ class AppriseAttachment:
return_status = False
continue
elif isinstance(_attachment, AppriseAttachment):
# We were provided a list of Apprise Attachments
# append our content together
instance = _attachment.attachments
elif not isinstance(_attachment, attachment.AttachBase):
logger.warning(
"An invalid attachment (type={}) was specified.".format(
@ -196,7 +208,11 @@ class AppriseAttachment:
continue
# Add our initialized plugin to our server listings
self.attachments.append(instance)
if isinstance(instance, list):
self.attachments.extend(instance)
else:
self.attachments.append(instance)
# Return our status
return return_status

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from . import config
from . import ConfigBase

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import ctypes
import locale
@ -67,7 +74,7 @@ class LazyTranslation:
"""
self.text = text
super(LazyTranslation, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def __str__(self):
return gettext.gettext(self.text)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
from .logger import logger
@ -194,7 +201,7 @@ class URLBase:
asset if isinstance(asset, AppriseAsset) else AppriseAsset()
# Certificate Verification (for SSL calls); default to being enabled
self.verify_certificate = kwargs.get('verify', True)
self.verify_certificate = parse_bool(kwargs.get('verify', True))
# Secure Mode
self.secure = kwargs.get('secure', False)
@ -222,24 +229,22 @@ class URLBase:
self.password = URLBase.unquote(self.password)
# Store our Timeout Variables
if 'socket_read_timeout' in kwargs:
if 'rto' in kwargs:
try:
self.socket_read_timeout = \
float(kwargs.get('socket_read_timeout'))
self.socket_read_timeout = float(kwargs.get('rto'))
except (TypeError, ValueError):
self.logger.warning(
'Invalid socket read timeout (rto) was specified {}'
.format(kwargs.get('socket_read_timeout')))
.format(kwargs.get('rto')))
if 'socket_connect_timeout' in kwargs:
if 'cto' in kwargs:
try:
self.socket_connect_timeout = \
float(kwargs.get('socket_connect_timeout'))
self.socket_connect_timeout = float(kwargs.get('cto'))
except (TypeError, ValueError):
self.logger.warning(
'Invalid socket connect timeout (cto) was specified {}'
.format(kwargs.get('socket_connect_timeout')))
.format(kwargs.get('cto')))
if 'tag' in kwargs:
# We want to associate some tags with our notification service.
@ -598,7 +603,7 @@ class URLBase:
}
@staticmethod
def parse_url(url, verify_host=True):
def parse_url(url, verify_host=True, plus_to_space=False):
"""Parses the URL and returns it broken apart into a dictionary.
This is very specific and customized for Apprise.
@ -618,7 +623,8 @@ class URLBase:
"""
results = parse_url(
url, default_schema='unknown', verify_host=verify_host)
url, default_schema='unknown', verify_host=verify_host,
plus_to_space=plus_to_space)
if not results:
# We're done; we failed to parse our url
@ -646,11 +652,11 @@ class URLBase:
# Store our socket read timeout if specified
if 'rto' in results['qsd']:
results['socket_read_timeout'] = results['qsd']['rto']
results['rto'] = results['qsd']['rto']
# Store our socket connect timeout if specified
if 'cto' in results['qsd']:
results['socket_connect_timeout'] = results['qsd']['cto']
results['cto'] = results['qsd']['cto']
if 'port' in results['qsd']:
results['port'] = results['qsd']['port']
@ -679,6 +685,15 @@ class URLBase:
return response
def __len__(self):
"""
Should be over-ridden and allows the tracking of how many targets
are associated with each URLBase object.
Default is always 1
"""
return 1
def schemas(self):
"""A simple function that returns a set of all schemas associated
with this object based on the object.protocol and

@ -1,33 +1,40 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
__title__ = 'Apprise'
__version__ = '1.1.0'
__version__ = '1.4.0'
__author__ = 'Chris Caron'
__license__ = 'MIT'
__copywrite__ = 'Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>'
__license__ = 'BSD'
__copywrite__ = 'Copyright (C) 2023 Chris Caron <lead2gold@gmail.com>'
__email__ = 'lead2gold@gmail.com'
__status__ = 'Production'

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import time
@ -120,7 +127,7 @@ class AttachBase(URLBase):
should be considered expired.
"""
super(AttachBase, self).__init__(**kwargs)
super().__init__(**kwargs)
if not mimetypes.inited:
# Ensure mimetypes has been initialized

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import os
@ -50,7 +57,7 @@ class AttachFile(AttachBase):
Initialize Local File Attachment Object
"""
super(AttachFile, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store path but mark it dirty since we have not performed any
# verification at this point.

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import os
@ -61,7 +68,7 @@ class AttachHTTP(AttachBase):
additionally include as part of the server headers to post with
"""
super(AttachHTTP, self).__init__(**kwargs)
super().__init__(**kwargs)
self.schema = 'https' if self.secure else 'http'
@ -254,7 +261,7 @@ class AttachHTTP(AttachBase):
self._temp_file.close()
self._temp_file = None
super(AttachHTTP, self).invalidate()
super().invalidate()
def url(self, privacy=False, *args, **kwargs):
"""

@ -1,30 +1,36 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
from os import listdir
from os.path import dirname
from os.path import abspath

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# BSD 3-Clause License
#
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# This code is licensed under the MIT License.
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 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 :
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# 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.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import click
import logging
@ -73,28 +80,64 @@ DEFAULT_CONFIG_PATHS = (
'~/.apprise/apprise.yml',
'~/.config/apprise/apprise',
'~/.config/apprise/apprise.yml',
# Global Configuration Support
'/etc/apprise',
'/etc/apprise.yml',
'/etc/apprise/apprise',
'/etc/apprise/apprise.yml',
)
# Define our paths to search for plugins
DEFAULT_PLUGIN_PATHS = (
'~/.apprise/plugins',
'~/.config/apprise/plugins',
# Global Plugin Support
'/var/lib/apprise/plugins',
)
# Detect Windows
if platform.system() == 'Windows':
# Default Config Search Path for Windows Users
DEFAULT_CONFIG_PATHS = (
expandvars('%APPDATA%/Apprise/apprise'),
expandvars('%APPDATA%/Apprise/apprise.yml'),
expandvars('%LOCALAPPDATA%/Apprise/apprise'),
expandvars('%LOCALAPPDATA%/Apprise/apprise.yml'),
expandvars('%APPDATA%\\Apprise\\apprise'),
expandvars('%APPDATA%\\Apprise\\apprise.yml'),
expandvars('%LOCALAPPDATA%\\Apprise\\apprise'),
expandvars('%LOCALAPPDATA%\\Apprise\\apprise.yml'),
#
# Global Support
#
# C:\ProgramData\Apprise\
expandvars('%ALLUSERSPROFILE%\\Apprise\\apprise'),
expandvars('%ALLUSERSPROFILE%\\Apprise\\apprise.yml'),
# C:\Program Files\Apprise
expandvars('%PROGRAMFILES%\\Apprise\\apprise'),
expandvars('%PROGRAMFILES%\\Apprise\\apprise.yml'),
# C:\Program Files\Common Files
expandvars('%COMMONPROGRAMFILES%\\Apprise\\apprise'),
expandvars('%COMMONPROGRAMFILES%\\Apprise\\apprise.yml'),
)
# Default Plugin Search Path for Windows Users
DEFAULT_PLUGIN_PATHS = (
expandvars('%APPDATA%/Apprise/plugins'),
expandvars('%LOCALAPPDATA%/Apprise/plugins'),
expandvars('%APPDATA%\\Apprise\\plugins'),
expandvars('%LOCALAPPDATA%\\Apprise\\plugins'),
#
# Global Support
#
# C:\ProgramData\Apprise\plugins
expandvars('%ALLUSERSPROFILE%\\Apprise\\plugins'),
# C:\Program Files\Apprise\plugins
expandvars('%PROGRAMFILES%\\Apprise\\plugins'),
# C:\Program Files\Common Files
expandvars('%COMMONPROGRAMFILES%\\Apprise\\plugins'),
)

@ -1,28 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# we mirror our base purely for the ability to reset everything; this
# is generally only used in testing and should not be used by developers

@ -1,3 +1,7 @@
import types
import typing as t
class NotifyType:
INFO: NotifyType
SUCCESS: NotifyType
@ -12,4 +16,7 @@ class NotifyFormat:
class ContentLocation:
LOCAL: ContentLocation
HOSTED: ContentLocation
INACCESSIBLE: ContentLocation
INACCESSIBLE: ContentLocation
NOTIFY_MODULE_MAP: t.Dict[str, t.Dict[str, t.Union[t.Type["NotifyBase"], types.ModuleType]]]

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import re
@ -113,7 +120,7 @@ class ConfigBase(URLBase):
these 'include' entries to be honored, this value must be set to True.
"""
super(ConfigBase, self).__init__(**kwargs)
super().__init__(**kwargs)
# Tracks the time the content was last retrieved on. This place a role
# for cases where we are not caching our response and are required to
@ -548,7 +555,7 @@ class ConfigBase(URLBase):
# Define what a valid line should look like
valid_line_re = re.compile(
r'^\s*(?P<line>([;#]+(?P<comment>.*))|'
r'(\s*(?P<tags>[^=]+)=|=)?\s*'
r'(\s*(?P<tags>[a-z0-9, \t_-]+)\s*=|=)?\s*'
r'(?P<url>[a-z0-9]{2,9}://.*)|'
r'include\s+(?P<config>.+))?\s*$', re.I)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import os
@ -53,7 +60,7 @@ class ConfigFile(ConfigBase):
additionally include as part of the server headers to post with
"""
super(ConfigFile, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store our file path as it was set
self.path = os.path.abspath(os.path.expanduser(path))

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -75,7 +82,7 @@ class ConfigHTTP(ConfigBase):
additionally include as part of the server headers to post with
"""
super(ConfigHTTP, self).__init__(**kwargs)
super().__init__(**kwargs)
self.schema = 'https' if self.secure else 'http'

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from .ConfigBase import ConfigBase
from ..AppriseLocale import gettext_lazy as _
@ -46,7 +53,7 @@ class ConfigMemory(ConfigBase):
Memory objects just store the raw configuration in memory. There is
no external reference point. It's always considered cached.
"""
super(ConfigMemory, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store our raw config into memory
self.content = content

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
from os import listdir

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
from markdown import markdown
@ -99,7 +106,7 @@ class HTMLConverter(HTMLParser, object):
BLOCK_END = {}
def __init__(self, **kwargs):
super(HTMLConverter, self).__init__(**kwargs)
super().__init__(**kwargs)
# Shoudl we store the text content or not?
self._do_store = True

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from ..plugins.NotifyBase import NotifyBase
from ..utils import URL_DETAILS_RE
from ..utils import parse_url
@ -134,7 +142,7 @@ class CustomNotifyPlugin(NotifyBase):
"""
# init parent
super(CustomNotifyPluginWrapper, self).__init__(**kwargs)
super().__init__(**kwargs)
self._default_args = {}

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from .notify import notify

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from .CustomNotifyPlugin import CustomNotifyPlugin

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import logging
@ -181,6 +188,7 @@ class LogCapture:
if self.__path:
# Close our file pointer
self.__buffer_ptr.close()
self.__handler.close()
if self.__delete:
try:
# Always remove file afterwards

@ -1,31 +1,39 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
from json import dumps
import base64
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
@ -35,6 +43,20 @@ from ..utils import validate_regex
from ..AppriseLocale import gettext_lazy as _
class AppriseAPIMethod:
"""
Defines the method to post data tot he remote server
"""
JSON = 'json'
FORM = 'form'
APPRISE_API_METHODS = (
AppriseAPIMethod.FORM,
AppriseAPIMethod.JSON,
)
class NotifyAppriseAPI(NotifyBase):
"""
A wrapper for Apprise (Persistent) API Notifications
@ -57,7 +79,7 @@ class NotifyAppriseAPI(NotifyBase):
# Depending on the number of transactions/notifications taking place, this
# could take a while. 30 seconds should be enough to perform the task
socket_connect_timeout = 30.0
socket_read_timeout = 30.0
# Disable throttle rate for Apprise API requests since they are normally
# local anyway
@ -112,6 +134,12 @@ class NotifyAppriseAPI(NotifyBase):
'name': _('Tags'),
'type': 'string',
},
'method': {
'name': _('Query Method'),
'type': 'choice:string',
'values': APPRISE_API_METHODS,
'default': APPRISE_API_METHODS[0],
},
'to': {
'alias_of': 'token',
},
@ -125,7 +153,8 @@ class NotifyAppriseAPI(NotifyBase):
},
}
def __init__(self, token=None, tags=None, headers=None, **kwargs):
def __init__(self, token=None, tags=None, method=None, headers=None,
**kwargs):
"""
Initialize Apprise API Object
@ -133,7 +162,7 @@ class NotifyAppriseAPI(NotifyBase):
additionally include as part of the server headers to post with
"""
super(NotifyAppriseAPI, self).__init__(**kwargs)
super().__init__(**kwargs)
self.fullpath = kwargs.get('fullpath')
if not isinstance(self.fullpath, str):
@ -147,6 +176,14 @@ class NotifyAppriseAPI(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
self.method = self.template_args['method']['default'] \
if not isinstance(method, str) else method.lower()
if self.method not in APPRISE_API_METHODS:
msg = 'The method specified ({}) is invalid.'.format(method)
self.logger.warning(msg)
raise TypeError(msg)
# Build list of tags
self.__tags = parse_list(tags)
@ -162,8 +199,13 @@ class NotifyAppriseAPI(NotifyBase):
Returns the URL built dynamically based on specified arguments.
"""
# Our URL parameters
params = self.url_parameters(privacy=privacy, *args, **kwargs)
# Define any URL parameters
params = {
'method': self.method,
}
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
# Append our headers into our parameters
params.update({'+{}'.format(k): v for k, v in self.headers.items()})
@ -202,15 +244,61 @@ class NotifyAppriseAPI(NotifyBase):
token=self.pprint(self.token, privacy, safe=''),
params=NotifyAppriseAPI.urlencode(params))
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
def send(self, body, title='', notify_type=NotifyType.INFO, attach=None,
**kwargs):
"""
Perform Apprise API Notification
"""
headers = {}
# Prepare HTTP Headers
headers = {
'User-Agent': self.app_id,
}
# Apply any/all header over-rides defined
headers.update(self.headers)
attachments = []
files = []
if attach:
for no, attachment in enumerate(attach, start=1):
# Perform some simple error checking
if not attachment:
# We could not access the attachment
self.logger.error(
'Could not access attachment {}.'.format(
attachment.url(privacy=True)))
return False
try:
if self.method == AppriseAPIMethod.JSON:
with open(attachment.path, 'rb') as f:
# Output must be in a DataURL format (that's what
# PushSafer calls it):
attachments.append({
'filename': attachment.name,
'base64': base64.b64encode(f.read())
.decode('utf-8'),
'mimetype': attachment.mimetype,
})
else: # AppriseAPIMethod.FORM
files.append((
'file{:02d}'.format(no),
(
attachment.name,
open(attachment.path, 'rb'),
attachment.mimetype,
)
))
except (OSError, IOError) as e:
self.logger.warning(
'An I/O error occurred while reading {}.'.format(
attachment.name if attachment else 'attachment'))
self.logger.debug('I/O Exception: %s' % str(e))
return False
# prepare Apprise API Object
payload = {
# Apprise API Payload
@ -220,6 +308,11 @@ class NotifyAppriseAPI(NotifyBase):
'format': self.notify_format,
}
if self.method == AppriseAPIMethod.JSON:
headers['Content-Type'] = 'application/json'
payload['attachments'] = attachments
payload = dumps(payload)
if self.__tags:
payload['tag'] = self.__tags
@ -240,8 +333,8 @@ class NotifyAppriseAPI(NotifyBase):
# Some entries can not be over-ridden
headers.update({
'User-Agent': self.app_id,
'Content-Type': 'application/json',
# Our response to be in JSON format always
'Accept': 'application/json',
# Pass our Source UUID4 Identifier
'X-Apprise-ID': self.asset._uid,
# Pass our current recursion count to our upstream server
@ -259,9 +352,10 @@ class NotifyAppriseAPI(NotifyBase):
try:
r = requests.post(
url,
data=dumps(payload),
data=payload,
headers=headers,
auth=auth,
files=files if files else None,
verify=self.verify_certificate,
timeout=self.request_timeout,
)
@ -283,7 +377,8 @@ class NotifyAppriseAPI(NotifyBase):
return False
else:
self.logger.info('Sent Apprise API notification.')
self.logger.info(
'Sent Apprise API notification; method=%s.', self.method)
except requests.RequestException as e:
self.logger.warning(
@ -294,6 +389,18 @@ class NotifyAppriseAPI(NotifyBase):
# Return; we're done
return False
except (OSError, IOError) as e:
self.logger.warning(
'An I/O error occurred while reading one of the '
'attached files.')
self.logger.debug('I/O Exception: %s' % str(e))
return False
finally:
for file in files:
# Ensure all files are closed
file[1][1].close()
return True
@staticmethod
@ -370,4 +477,9 @@ class NotifyAppriseAPI(NotifyBase):
# re-assemble our full path
results['fullpath'] = '/'.join(entries)
# Set method if specified
if 'method' in results['qsd'] and len(results['qsd']['method']):
results['method'] = \
NotifyAppriseAPI.unquote(results['qsd']['method'])
return results

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# API: https://github.com/Finb/bark-server/blob/master/docs/API_V2.md#python
#
@ -204,7 +212,7 @@ class NotifyBark(NotifyBase):
"""
Initialize Notify Bark Object
"""
super(NotifyBark, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare our URL
self.notify_url = '%s://%s%s/push' % (
@ -272,7 +280,7 @@ class NotifyBark(NotifyBase):
# error tracking (used for function return)
has_error = False
if not len(self.targets):
if not self.targets:
# We have nothing to notify; we're done
self.logger.warning('There are no Bark devices to notify')
return False
@ -448,6 +456,12 @@ class NotifyBark(NotifyBase):
params=NotifyBark.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,29 +1,38 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import asyncio
import re
from functools import partial
from ..URLBase import URLBase
from ..common import NotifyType
@ -36,12 +45,7 @@ from ..AppriseLocale import gettext_lazy as _
from ..AppriseAttachment import AppriseAttachment
# Wrap our base with the asyncio wrapper
from ..py3compat.asyncio import AsyncNotifyBase
BASE_OBJECT = AsyncNotifyBase
class NotifyBase(BASE_OBJECT):
class NotifyBase(URLBase):
"""
This is the base class for all notification services
"""
@ -180,7 +184,7 @@ class NotifyBase(BASE_OBJECT):
"""
super(NotifyBase, self).__init__(**kwargs)
super().__init__(**kwargs)
if 'format' in kwargs:
# Store the specified format if specified
@ -267,19 +271,64 @@ class NotifyBase(BASE_OBJECT):
color_type=color_type,
)
def notify(self, body, title=None, notify_type=NotifyType.INFO,
overflow=None, attach=None, body_format=None, **kwargs):
def notify(self, *args, **kwargs):
"""
Performs notification
"""
try:
# Build a list of dictionaries that can be used to call send().
send_calls = list(self._build_send_calls(*args, **kwargs))
except TypeError:
# Internal error
return False
else:
# Loop through each call, one at a time. (Use a list rather than a
# generator to call all the partials, even in case of a failure.)
the_calls = [self.send(**kwargs2) for kwargs2 in send_calls]
return all(the_calls)
async def async_notify(self, *args, **kwargs):
"""
Performs notification for asynchronous callers
"""
try:
# Build a list of dictionaries that can be used to call send().
send_calls = list(self._build_send_calls(*args, **kwargs))
except TypeError:
# Internal error
return False
else:
loop = asyncio.get_event_loop()
# Wrap each call in a coroutine that uses the default executor.
# TODO: In the future, allow plugins to supply a native
# async_send() method.
async def do_send(**kwargs2):
send = partial(self.send, **kwargs2)
result = await loop.run_in_executor(None, send)
return result
# gather() all calls in parallel.
the_cors = (do_send(**kwargs2) for kwargs2 in send_calls)
return all(await asyncio.gather(*the_cors))
def _build_send_calls(self, body, title=None,
notify_type=NotifyType.INFO, overflow=None,
attach=None, body_format=None, **kwargs):
"""
Get a list of dictionaries that can be used to call send() or
(in the future) async_send().
"""
if not self.enabled:
# Deny notifications issued to services that are disabled
self.logger.warning(
"{} is currently disabled on this system.".format(
self.service_name))
return False
msg = f"{self.service_name} is currently disabled on this system."
self.logger.warning(msg)
raise TypeError(msg)
# Prepare attachments if required
if attach is not None and not isinstance(attach, AppriseAttachment):
@ -288,7 +337,7 @@ class NotifyBase(BASE_OBJECT):
except TypeError:
# bad attachments
return False
raise
# Handle situations where the title is None
title = '' if not title else title
@ -299,14 +348,11 @@ class NotifyBase(BASE_OBJECT):
body_format=body_format):
# Send notification
if not self.send(body=chunk['body'], title=chunk['title'],
notify_type=notify_type, attach=attach,
body_format=body_format):
# Toggle our return status flag
return False
return True
yield dict(
body=chunk['body'], title=chunk['title'],
notify_type=notify_type, attach=attach,
body_format=body_format
)
def _apply_overflow(self, body, title=None, overflow=None,
body_format=None):
@ -423,13 +469,13 @@ class NotifyBase(BASE_OBJECT):
'overflow': self.overflow_mode,
}
params.update(super(NotifyBase, self).url_parameters(*args, **kwargs))
params.update(super().url_parameters(*args, **kwargs))
# return default parameters
return params
@staticmethod
def parse_url(url, verify_host=True):
def parse_url(url, verify_host=True, plus_to_space=False):
"""Parses the URL and returns it broken apart into a dictionary.
This is very specific and customized for Apprise.
@ -447,7 +493,8 @@ class NotifyBase(BASE_OBJECT):
A dictionary is returned containing the URL fully parsed if
successful, otherwise None is returned.
"""
results = URLBase.parse_url(url, verify_host=verify_host)
results = URLBase.parse_url(
url, verify_host=verify_host, plus_to_space=plus_to_space)
if not results:
# We're done; we failed to parse our url

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -39,6 +46,7 @@ except ImportError:
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..utils import parse_bool
from ..utils import parse_list
from ..utils import validate_regex
from ..common import NotifyType
from ..common import NotifyImageSize
@ -51,7 +59,7 @@ DEFAULT_TAG = '@all'
# list of tagged devices that the notification need to be send to, and a
# boolean operator (and / or) that defines the criteria to match devices
# against those tags.
IS_TAG = re.compile(r'^[@](?P<name>[A-Z0-9]{1,63})$', re.I)
IS_TAG = re.compile(r'^[@]?(?P<name>[A-Z0-9]{1,63})$', re.I)
# Device tokens are only referenced when developing.
# It's not likely you'll send a message directly to a device, but if you do;
@ -150,10 +158,10 @@ class NotifyBoxcar(NotifyBase):
"""
Initialize Boxcar Object
"""
super(NotifyBoxcar, self).__init__(**kwargs)
super().__init__(**kwargs)
# Initialize tag list
self.tags = list()
self._tags = list()
# Initialize device_token list
self.device_tokens = list()
@ -177,29 +185,27 @@ class NotifyBoxcar(NotifyBase):
raise TypeError(msg)
if not targets:
self.tags.append(DEFAULT_TAG)
self._tags.append(DEFAULT_TAG)
targets = []
elif isinstance(targets, str):
targets = [x for x in filter(bool, TAGS_LIST_DELIM.split(
targets,
))]
# Validate targets and drop bad ones:
for target in targets:
if IS_TAG.match(target):
for target in parse_list(targets):
result = IS_TAG.match(target)
if result:
# store valid tag/alias
self.tags.append(IS_TAG.match(target).group('name'))
self._tags.append(result.group('name'))
continue
elif IS_DEVICETOKEN.match(target):
result = IS_DEVICETOKEN.match(target)
if result:
# store valid device
self.device_tokens.append(target)
continue
else:
self.logger.warning(
'Dropped invalid tag/alias/device_token '
'({}) specified.'.format(target),
)
self.logger.warning(
'Dropped invalid tag/alias/device_token '
'({}) specified.'.format(target),
)
# Track whether or not we want to send an image with our notification
# or not.
@ -231,8 +237,8 @@ class NotifyBoxcar(NotifyBase):
if body:
payload['aps']['alert'] = body
if self.tags:
payload['tags'] = {'or': self.tags}
if self._tags:
payload['tags'] = {'or': self._tags}
if self.device_tokens:
payload['device_tokens'] = self.device_tokens
@ -334,10 +340,18 @@ class NotifyBoxcar(NotifyBase):
self.secret, privacy, mode=PrivacyMode.Secret, safe=''),
targets='/'.join([
NotifyBoxcar.quote(x, safe='') for x in chain(
self.tags, self.device_tokens) if x != DEFAULT_TAG]),
self._tags, self.device_tokens) if x != DEFAULT_TAG]),
params=NotifyBoxcar.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self._tags) + len(self.device_tokens)
# DEFAULT_TAG is set if no tokens/tags are otherwise set
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this service you will need a BulkSMS account
# You will need credits (new accounts start with a few)
@ -30,7 +37,6 @@
# API is documented here:
# - https://www.bulksms.com/developer/json/v1/#tag/Message
import re
import six
import requests
import json
from itertools import chain
@ -192,7 +198,7 @@ class NotifyBulkSMS(NotifyBase):
# Setup our route
self.route = self.template_args['route']['default'] \
if not isinstance(route, six.string_types) else route.upper()
if not isinstance(route, str) else route.upper()
if self.route not in BULKSMS_ROUTING_GROUPS:
msg = 'The route specified ({}) is invalid.'.format(route)
self.logger.warning(msg)
@ -408,6 +414,24 @@ class NotifyBulkSMS(NotifyBase):
for x in self.groups])),
params=NotifyBulkSMS.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
# Note: Groups always require a separate request (and can not be
# included in batch calculations)
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets + len(self.groups)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, simply signup with clicksend:
# https://www.clicksend.com/
@ -132,7 +139,7 @@ class NotifyClickSend(NotifyBase):
"""
Initialize ClickSend Object
"""
super(NotifyClickSend, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare Batch Mode Flag
self.batch = batch
@ -281,6 +288,21 @@ class NotifyClickSend(NotifyBase):
params=NotifyClickSend.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this service you will need a D7 Networks account from their website
# at https://d7networks.com/
@ -29,17 +36,18 @@
# After you've established your account you can get your api login credentials
# (both user and password) from the API Details section from within your
# account profile area: https://d7networks.com/accounts/profile/
#
# API Reference: https://d7networks.com/docs/Messages/Send_Message/
import requests
import base64
from json import dumps
from json import loads
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..common import NotifyType
from ..utils import is_phone_no
from ..utils import parse_phone_no
from ..utils import validate_regex
from ..utils import parse_bool
from ..AppriseLocale import gettext_lazy as _
@ -52,25 +60,6 @@ D7NETWORKS_HTTP_ERROR_MAP = {
}
# Priorities
class D7SMSPriority:
"""
D7 Networks SMS Message Priority
"""
LOW = 0
MODERATE = 1
NORMAL = 2
HIGH = 3
D7NETWORK_SMS_PRIORITIES = (
D7SMSPriority.LOW,
D7SMSPriority.MODERATE,
D7SMSPriority.NORMAL,
D7SMSPriority.HIGH,
)
class NotifyD7Networks(NotifyBase):
"""
A wrapper for D7 Networks Notifications
@ -92,11 +81,8 @@ class NotifyD7Networks(NotifyBase):
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_d7networks'
# D7 Networks batch notification URL
notify_batch_url = 'http://rest-api.d7networks.com/secure/sendbatch'
# D7 Networks single notification URL
notify_url = 'http://rest-api.d7networks.com/secure/send'
notify_url = 'https://api.d7networks.com/messages/v1/send'
# The maximum length of the body
body_maxlen = 160
@ -107,21 +93,16 @@ class NotifyD7Networks(NotifyBase):
# Define object templates
templates = (
'{schema}://{user}:{password}@{targets}',
'{schema}://{token}@{targets}',
)
# Define our template tokens
template_tokens = dict(NotifyBase.template_tokens, **{
'user': {
'name': _('Username'),
'token': {
'name': _('API Access Token'),
'type': 'string',
'required': True,
},
'password': {
'name': _('Password'),
'type': 'string',
'private': True,
'required': True,
},
'target_phone': {
'name': _('Target Phone No'),
@ -138,16 +119,11 @@ class NotifyD7Networks(NotifyBase):
# Define our template arguments
template_args = dict(NotifyBase.template_args, **{
'priority': {
'name': _('Priority'),
'type': 'choice:int',
'min': D7SMSPriority.LOW,
'max': D7SMSPriority.HIGH,
'values': D7NETWORK_SMS_PRIORITIES,
# The website identifies that the default priority is low; so
# this plugin will honor that same default
'default': D7SMSPriority.LOW,
'unicode': {
# Unicode characters (default is 'auto')
'name': _('Unicode Characters'),
'type': 'bool',
'default': False,
},
'batch': {
'name': _('Batch Mode'),
@ -172,19 +148,12 @@ class NotifyD7Networks(NotifyBase):
},
})
def __init__(self, targets=None, priority=None, source=None, batch=False,
**kwargs):
def __init__(self, token=None, targets=None, source=None,
batch=False, unicode=None, **kwargs):
"""
Initialize D7 Networks Object
"""
super(NotifyD7Networks, self).__init__(**kwargs)
# The Priority of the message
if priority not in D7NETWORK_SMS_PRIORITIES:
self.priority = self.template_args['priority']['default']
else:
self.priority = priority
super().__init__(**kwargs)
# Prepare Batch Mode Flag
self.batch = batch
@ -193,8 +162,15 @@ class NotifyD7Networks(NotifyBase):
self.source = None \
if not isinstance(source, str) else source.strip()
if not (self.user and self.password):
msg = 'A D7 Networks user/pass was not provided.'
# Define whether or not we should set the unicode flag
self.unicode = self.template_args['unicode']['default'] \
if unicode is None else bool(unicode)
# The token associated with the account
self.token = validate_regex(token)
if not self.token:
msg = 'The D7 Networks token specified ({}) is invalid.'\
.format(token)
self.logger.warning(msg)
raise TypeError(msg)
@ -229,40 +205,41 @@ class NotifyD7Networks(NotifyBase):
# error tracking (used for function return)
has_error = False
auth = '{user}:{password}'.format(
user=self.user, password=self.password)
# Python 3's versio of b64encode() expects a byte array and not
# a string. To accommodate this, we encode the content here
auth = auth.encode('utf-8')
# Prepare our headers
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic {}'.format(base64.b64encode(auth))
'Authorization': f'Bearer {self.token}',
}
# Our URL varies depending if we're doing a batch mode or not
url = self.notify_batch_url if self.batch else self.notify_url
payload = {
'message_globals': {
'channel': 'sms',
},
'messages': [{
# Populated later on
'recipients': None,
'content': body,
'data_coding':
# auto is a better substitute over 'text' as text is easier to
# detect from a post than `unicode` is.
'auto' if not self.unicode else 'unicode',
}],
}
# use the list directly
targets = list(self.targets)
if self.source:
payload['message_globals']['originator'] = self.source
target = None
while len(targets):
if self.batch:
# Prepare our payload
payload = {
'globals': {
'priority': self.priority,
'from': self.source if self.source else self.app_id,
},
'messages': [{
'to': self.targets,
'content': body,
}],
}
payload['messages'][0]['recipients'] = self.targets
# Reset our targets so we don't keep going. This is required
# because we're in batch mode; we only need to loop once.
@ -274,24 +251,19 @@ class NotifyD7Networks(NotifyBase):
target = targets.pop(0)
# Prepare our payload
payload = {
'priority': self.priority,
'content': body,
'to': target,
'from': self.source if self.source else self.app_id,
}
payload['messages'][0]['recipients'] = [target]
# Some Debug Logging
self.logger.debug(
'D7 Networks POST URL: {} (cert_verify={})'.format(
url, self.verify_certificate))
self.notify_url, self.verify_certificate))
self.logger.debug('D7 Networks Payload: {}' .format(payload))
# Always call throttle before any remote server i/o is made
self.throttle()
try:
r = requests.post(
url,
self.notify_url,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
@ -337,29 +309,9 @@ class NotifyD7Networks(NotifyBase):
else:
if self.batch:
count = len(self.targets)
try:
# Get our message delivery count if we can
json_response = loads(r.content)
count = int(json_response.get(
'data', {}).get('messageCount', -1))
except (AttributeError, TypeError, ValueError):
# ValueError = r.content is Unparsable
# TypeError = r.content is None
# AttributeError = r is None
# We could not parse JSON response. Assume that
# our delivery is okay for now.
pass
if count != len(self.targets):
has_error = True
self.logger.info(
'Sent D7 Networks batch SMS notification to '
'{} of {} target(s).'.format(
count, len(self.targets)))
'{} target(s).'.format(len(self.targets)))
else:
self.logger.info(
@ -389,26 +341,31 @@ class NotifyD7Networks(NotifyBase):
# Define any URL parameters
params = {
'batch': 'yes' if self.batch else 'no',
'unicode': 'yes' if self.unicode else 'no',
}
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
if self.priority != self.template_args['priority']['default']:
params['priority'] = str(self.priority)
if self.source:
params['from'] = self.source
return '{schema}://{user}:{password}@{targets}/?{params}'.format(
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
return '{schema}://{token}@{targets}/?{params}'.format(
schema=self.secure_protocol,
user=NotifyD7Networks.quote(self.user, safe=''),
password=self.pprint(
self.password, privacy, mode=PrivacyMode.Secret, safe=''),
token=self.pprint(self.token, privacy, safe=''),
targets='/'.join(
[NotifyD7Networks.quote(x, safe='') for x in self.targets]),
params=NotifyD7Networks.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
return len(self.targets) if not self.batch else 1
@staticmethod
def parse_url(url):
"""
@ -421,6 +378,23 @@ class NotifyD7Networks(NotifyBase):
# We're done early as we couldn't load the results
return results
if 'token' in results['qsd'] and len(results['qsd']['token']):
results['token'] = \
NotifyD7Networks.unquote(results['qsd']['token'])
elif results['user']:
results['token'] = NotifyD7Networks.unquote(results['user'])
if results['password']:
# Support token containing a colon (:)
results['token'] += \
':' + NotifyD7Networks.unquote(results['password'])
elif results['password']:
# Support token starting with a colon (:)
results['token'] = \
':' + NotifyD7Networks.unquote(results['password'])
# Initialize our targets
results['targets'] = list()
@ -432,44 +406,27 @@ class NotifyD7Networks(NotifyBase):
results['targets'].extend(
NotifyD7Networks.split_path(results['fullpath']))
# Set our priority
if 'priority' in results['qsd'] and len(results['qsd']['priority']):
_map = {
'l': D7SMSPriority.LOW,
'0': D7SMSPriority.LOW,
'm': D7SMSPriority.MODERATE,
'1': D7SMSPriority.MODERATE,
'n': D7SMSPriority.NORMAL,
'2': D7SMSPriority.NORMAL,
'h': D7SMSPriority.HIGH,
'3': D7SMSPriority.HIGH,
}
try:
results['priority'] = \
_map[results['qsd']['priority'][0].lower()]
except KeyError:
# No priority was set
pass
# Support the 'from' and 'source' variable so that we can support
# targets this way too.
# The 'from' makes it easier to use yaml configuration
if 'from' in results['qsd'] and len(results['qsd']['from']):
results['source'] = \
NotifyD7Networks.unquote(results['qsd']['from'])
if 'source' in results['qsd'] and len(results['qsd']['source']):
results['source'] = \
NotifyD7Networks.unquote(results['qsd']['source'])
# Get Batch Mode Flag
results['batch'] = \
parse_bool(results['qsd'].get('batch', False))
# Get Unicode Flag
results['unicode'] = \
parse_bool(results['qsd'].get('unicode', False))
# Support the 'to' variable so that we can support targets this way too
# The 'to' makes it easier to use yaml configuration
if 'to' in results['qsd'] and len(results['qsd']['to']):
results['targets'] += \
NotifyD7Networks.parse_phone_no(results['qsd']['to'])
# Support the 'from' and source variable
if 'from' in results['qsd'] and len(results['qsd']['from']):
results['source'] = \
NotifyD7Networks.unquote(results['qsd']['from'])
elif 'source' in results['qsd'] and len(results['qsd']['source']):
results['source'] = \
NotifyD7Networks.unquote(results['qsd']['source'])
return results

@ -1,31 +1,39 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import
from __future__ import print_function
import sys
from .NotifyBase import NotifyBase
from ..common import NotifyImageSize
from ..common import NotifyType
@ -77,6 +85,13 @@ try:
NOTIFY_DBUS_SUPPORT_ENABLED = (
LOOP_GLIB is not None or LOOP_QT is not None)
# ImportError: When using gi.repository you must not import static modules
# like "gobject". Please change all occurrences of "import gobject" to
# "from gi.repository import GObject".
# See: https://bugzilla.gnome.org/show_bug.cgi?id=709183
if "gobject" in sys.modules: # pragma: no cover
del sys.modules["gobject"]
try:
# The following is required for Image/Icon loading only
import gi
@ -233,7 +248,7 @@ class NotifyDBus(NotifyBase):
Initialize DBus Object
"""
super(NotifyDBus, self).__init__(**kwargs)
super().__init__(**kwargs)
# Track our notifications
self.registry = {}
@ -272,12 +287,9 @@ class NotifyDBus(NotifyBase):
self.x_axis = None
self.y_axis = None
# Track whether or not we want to send an image with our notification
# or not.
# Track whether we want to add an image to the notification.
self.include_image = include_image
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
Perform DBus Notification
@ -286,10 +298,10 @@ class NotifyDBus(NotifyBase):
try:
session = SessionBus(mainloop=MAINLOOP_MAP[self.schema])
except DBusException:
except DBusException as e:
# Handle exception
self.logger.warning('Failed to send DBus notification.')
self.logger.exception('DBus Exception')
self.logger.debug(f'DBus Exception: {e}')
return False
# If there is no title, but there is a body, swap the two to get rid
@ -342,8 +354,8 @@ class NotifyDBus(NotifyBase):
except Exception as e:
self.logger.warning(
"Could not load Gnome notification icon ({}): {}"
.format(icon_path, e))
"Could not load notification icon (%s).", icon_path)
self.logger.debug(f'DBus Exception: {e}')
try:
# Always call throttle() before any remote execution is made
@ -370,9 +382,9 @@ class NotifyDBus(NotifyBase):
self.logger.info('Sent DBus notification.')
except Exception:
except Exception as e:
self.logger.warning('Failed to send DBus notification.')
self.logger.exception('DBus Exception')
self.logger.debug(f'DBus Exception: {e}')
return False
return True

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, sign up with Hampager (you need to be a licensed
# ham radio operator
@ -179,7 +186,7 @@ class NotifyDapnet(NotifyBase):
"""
Initialize Dapnet Object
"""
super(NotifyDapnet, self).__init__(**kwargs)
super().__init__(**kwargs)
# Parse our targets
self.targets = list()
@ -343,6 +350,21 @@ class NotifyDapnet(NotifyBase):
params=NotifyDapnet.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import time
@ -124,7 +131,7 @@ class NotifyDingTalk(NotifyBase):
"""
Initialize DingTalk Object
"""
super(NotifyDingTalk, self).__init__(**kwargs)
super().__init__(**kwargs)
# Secret Key (associated with project)
self.token = validate_regex(
@ -302,6 +309,13 @@ class NotifyDingTalk(NotifyBase):
[NotifyDingTalk.quote(x, safe='') for x in self.targets]),
args=NotifyDingTalk.urlencode(args))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 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
@ -164,7 +171,7 @@ class NotifyDiscord(NotifyBase):
Initialize Discord Object
"""
super(NotifyDiscord, self).__init__(**kwargs)
super().__init__(**kwargs)
# Webhook ID (associated with project)
self.webhook_id = validate_regex(webhook_id)
@ -283,9 +290,6 @@ class NotifyDiscord(NotifyBase):
payload['content'] = \
body if not title else "{}\r\n{}".format(title, body)
if self.thread_id:
payload['thread_id'] = self.thread_id
if self.avatar and (image_url or self.avatar_url):
payload['avatar_url'] = \
self.avatar_url if self.avatar_url else image_url
@ -294,7 +298,8 @@ class NotifyDiscord(NotifyBase):
# Optionally override the default username of the webhook
payload['username'] = self.user
if not self._send(payload):
params = {'thread_id': self.thread_id} if self.thread_id else None
if not self._send(payload, params=params):
# We failed to post our message
return False
@ -338,7 +343,7 @@ class NotifyDiscord(NotifyBase):
# Otherwise return
return True
def _send(self, payload, attach=None, **kwargs):
def _send(self, payload, attach=None, params=None, **kwargs):
"""
Wrapper to the requests (post) object
"""
@ -389,6 +394,7 @@ class NotifyDiscord(NotifyBase):
r = requests.post(
notify_url,
params=params,
data=payload if files else dumps(payload),
headers=headers,
files=files,
@ -580,7 +586,7 @@ class NotifyDiscord(NotifyBase):
if description:
# Strip description from our string since it has been handled
# now.
markdown = re.sub(description, '', markdown, count=1)
markdown = re.sub(re.escape(description), '', markdown, count=1)
regex = re.compile(
r'\s*#[# \t\v]*(?P<name>[^\n]+)(\n|\s*$)'

@ -1,30 +1,39 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import dataclasses
import re
import smtplib
import typing as t
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
@ -41,6 +50,7 @@ from ..common import NotifyFormat, NotifyType
from ..conversion import convert_between
from ..utils import is_email, parse_emails
from ..AppriseLocale import gettext_lazy as _
from ..logger import logger
# Globally Default encoding mode set to Quoted Printable.
charset.add_charset('utf-8', charset.QP, charset.QP, 'utf-8')
@ -60,15 +70,23 @@ class WebBaseLogin:
# Secure Email Modes
class SecureMailMode:
INSECURE = "insecure"
SSL = "ssl"
STARTTLS = "starttls"
# Define all of the secure modes (used during validation)
SECURE_MODES = (
SecureMailMode.SSL,
SecureMailMode.STARTTLS,
)
SECURE_MODES = {
SecureMailMode.STARTTLS: {
'default_port': 587,
},
SecureMailMode.SSL: {
'default_port': 465,
},
SecureMailMode.INSECURE: {
'default_port': 25,
},
}
# 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
@ -109,7 +127,7 @@ EMAIL_TEMPLATES = (
'Microsoft Hotmail',
re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>(outlook|hotmail|live)\.com(\.au)?)$', re.I),
r'(?P<domain>(hotmail|live)\.com(\.au)?)$', re.I),
{
'port': 587,
'smtp_host': 'smtp-mail.outlook.com',
@ -119,6 +137,21 @@ EMAIL_TEMPLATES = (
},
),
# Microsoft Outlook
(
'Microsoft Outlook',
re.compile(
r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@'
r'(?P<domain>(smtp\.)?outlook\.com(\.au)?)$', re.I),
{
'port': 587,
'smtp_host': 'smtp.outlook.com',
'secure': True,
'secure_mode': SecureMailMode.STARTTLS,
'login_type': (WebBaseLogin.EMAIL, )
},
),
# Microsoft Office 365 (Email Server)
# You must specify an authenticated sender address in the from= settings
# and a valid email in the to= to deliver your emails to
@ -282,6 +315,13 @@ EMAIL_TEMPLATES = (
)
@dataclasses.dataclass
class EmailMessage:
recipient: str
to_addrs: t.List[str]
body: str
class NotifyEmail(NotifyBase):
"""
A wrapper to Email Notifications
@ -303,15 +343,6 @@ class NotifyEmail(NotifyBase):
# Default Notify Format
notify_format = NotifyFormat.HTML
# Default Non-Encryption Port
default_port = 25
# Default Secure Port
default_secure_port = 587
# Default Secure Mode
default_secure_mode = SecureMailMode.STARTTLS
# Default SMTP Timeout (in seconds)
socket_connect_timeout = 15
@ -373,7 +404,7 @@ class NotifyEmail(NotifyBase):
'name': {
'name': _('From Name'),
'type': 'string',
'map_to': 'from_name',
'map_to': 'from_addr',
},
'cc': {
'name': _('Carbon Copy'),
@ -410,24 +441,16 @@ class NotifyEmail(NotifyBase):
},
}
def __init__(self, smtp_host=None, from_name=None,
from_addr=None, secure_mode=None, targets=None, cc=None,
bcc=None, reply_to=None, headers=None, **kwargs):
def __init__(self, smtp_host=None, from_addr=None, secure_mode=None,
targets=None, cc=None, bcc=None, reply_to=None, headers=None,
**kwargs):
"""
Initialize Email Object
The smtp_host and secure_mode can be automatically detected depending
on how the URL was built
"""
super(NotifyEmail, self).__init__(**kwargs)
# Handle SMTP vs SMTPS (Secure vs UnSecure)
if not self.port:
if self.secure:
self.port = self.default_secure_port
else:
self.port = self.default_port
super().__init__(**kwargs)
# Acquire Email 'To'
self.targets = list()
@ -451,40 +474,49 @@ class NotifyEmail(NotifyBase):
# Now we want to construct the To and From email
# addresses from the URL provided
self.from_addr = from_addr
self.from_addr = [False, '']
if self.user and not self.from_addr:
# detect our email address
self.from_addr = '{}@{}'.format(
if self.user and self.host:
# Prepare the bases of our email
self.from_addr = [self.app_id, '{}@{}'.format(
re.split(r'[\s@]+', self.user)[0],
self.host,
)
)]
if from_addr:
result = is_email(from_addr)
if result:
self.from_addr = (
result['name'] if result['name'] else False,
result['full_email'])
else:
self.from_addr[0] = from_addr
result = is_email(self.from_addr)
result = is_email(self.from_addr[1])
if not result:
# Parse Source domain based on from_addr
msg = 'Invalid ~From~ email specified: {}'.format(self.from_addr)
msg = 'Invalid ~From~ email specified: {}'.format(
'{} <{}>'.format(self.from_addr[0], self.from_addr[1])
if self.from_addr[0] else '{}'.format(self.from_addr[1]))
self.logger.warning(msg)
raise TypeError(msg)
# Store our email address
self.from_addr = result['full_email']
# Set our from name
self.from_name = from_name if from_name else result['name']
# Store our lookup
self.names[self.from_addr] = \
self.from_name if self.from_name else False
self.names[self.from_addr[1]] = self.from_addr[0]
# Now detect the SMTP Server
self.smtp_host = \
smtp_host if isinstance(smtp_host, str) else ''
# Now detect secure mode
self.secure_mode = self.default_secure_mode \
if not isinstance(secure_mode, str) \
else secure_mode.lower()
if secure_mode:
self.secure_mode = None \
if not isinstance(secure_mode, str) \
else secure_mode.lower()
else:
self.secure_mode = SecureMailMode.INSECURE \
if not self.secure else self.template_args['mode']['default']
if self.secure_mode not in SECURE_MODES:
msg = 'The secure mode specified ({}) is invalid.'\
.format(secure_mode)
@ -508,8 +540,7 @@ class NotifyEmail(NotifyBase):
else:
# If our target email list is empty we want to add ourselves to it
self.targets.append(
(self.from_name if self.from_name else False, self.from_addr))
self.targets.append((False, self.from_addr[1]))
# Validate recipients (cc:) and drop bad ones:
for recipient in parse_emails(cc):
@ -562,6 +593,15 @@ class NotifyEmail(NotifyBase):
# Apply any defaults based on certain known configurations
self.NotifyEmailDefaults(secure_mode=secure_mode, **kwargs)
if not self.secure and self.secure_mode != SecureMailMode.INSECURE:
# Enable Secure mode if not otherwise set
self.secure = True
if not self.port:
# Assign our port based on our secure_mode if not otherwise
# detected
self.port = SECURE_MODES[self.secure_mode]['default_port']
# if there is still no smtp_host then we fall back to the hostname
if not self.smtp_host:
self.smtp_host = self.host
@ -625,11 +665,11 @@ class NotifyEmail(NotifyBase):
if login_type:
# only apply additional logic to our user if a login_type
# was specified.
if is_email(self.user) and \
WebBaseLogin.EMAIL not in login_type:
# Email specified but login type
# not supported; switch it to user id
self.user = match.group('id')
if is_email(self.user):
if WebBaseLogin.EMAIL not in login_type:
# Email specified but login type
# not supported; switch it to user id
self.user = match.group('id')
elif WebBaseLogin.USERID not in login_type:
# user specified but login type
@ -656,18 +696,14 @@ class NotifyEmail(NotifyBase):
Perform Email Notification
"""
# Initialize our default from name
from_name = self.from_name if self.from_name else self.app_desc
# error tracking (used for function return)
has_error = False
if not self.targets:
# There is no one to email; we're done
self.logger.warning(
'There are no Email recipients to notify')
return False
messages: t.List[EmailMessage] = []
# Create a copy of the targets list
emails = list(self.targets)
while len(emails):
@ -700,7 +736,9 @@ class NotifyEmail(NotifyBase):
for addr in reply_to]
self.logger.debug(
'Email From: {} <{}>'.format(from_name, self.from_addr))
'Email From: {}'.format(
formataddr(self.from_addr, charset='utf-8')))
self.logger.debug('Email To: {}'.format(to_addr))
if cc:
self.logger.debug('Email Cc: {}'.format(', '.join(cc)))
@ -763,9 +801,7 @@ class NotifyEmail(NotifyBase):
base[k] = Header(v, self._get_charset(v))
base['Subject'] = Header(title, self._get_charset(title))
base['From'] = formataddr(
(from_name if from_name else False, self.from_addr),
charset='utf-8')
base['From'] = formataddr(self.from_addr, charset='utf-8')
base['To'] = formataddr((to_name, to_addr), charset='utf-8')
base['Message-ID'] = make_msgid(domain=self.smtp_host)
base['Date'] = \
@ -778,58 +814,79 @@ class NotifyEmail(NotifyBase):
if reply_to:
base['Reply-To'] = ','.join(reply_to)
# bind the socket variable to the current namespace
socket = None
message = EmailMessage(
recipient=to_addr,
to_addrs=[to_addr] + list(cc) + list(bcc),
body=base.as_string())
messages.append(message)
# Always call throttle before any remote server i/o is made
self.throttle()
return self.submit(messages)
try:
self.logger.debug('Connecting to remote SMTP server...')
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
def submit(self, messages: t.List[EmailMessage]):
socket = socket_func(
self.smtp_host,
self.port,
None,
timeout=self.socket_connect_timeout,
)
# error tracking (used for function return)
has_error = False
if self.secure and self.secure_mode == SecureMailMode.STARTTLS:
# Handle Secure Connections
self.logger.debug('Securing connection with STARTTLS...')
socket.starttls()
# bind the socket variable to the current namespace
socket = None
if self.user and self.password:
# Apply Login credetials
self.logger.debug('Applying user credentials...')
socket.login(self.user, self.password)
# Always call throttle before any remote server i/o is made
self.throttle()
# Send the email
socket.sendmail(
self.from_addr,
[to_addr] + list(cc) + list(bcc),
base.as_string())
try:
self.logger.debug('Connecting to remote SMTP server...')
socket_func = smtplib.SMTP
if self.secure_mode == SecureMailMode.SSL:
self.logger.debug('Securing connection with SSL...')
socket_func = smtplib.SMTP_SSL
self.logger.info(
'Sent Email notification to "{}".'.format(to_addr))
socket = socket_func(
self.smtp_host,
self.port,
None,
timeout=self.socket_connect_timeout,
)
except (SocketError, smtplib.SMTPException, RuntimeError) as e:
self.logger.warning(
'A Connection error occurred sending Email '
'notification to {}.'.format(self.smtp_host))
self.logger.debug('Socket Exception: %s' % str(e))
if self.secure_mode == SecureMailMode.STARTTLS:
# Handle Secure Connections
self.logger.debug('Securing connection with STARTTLS...')
socket.starttls()
if self.user and self.password:
# Apply Login credetials
self.logger.debug('Applying user credentials...')
socket.login(self.user, self.password)
# Send the emails
for message in messages:
try:
socket.sendmail(
self.from_addr[1],
message.to_addrs,
message.body)
self.logger.info(
f'Sent Email notification to "{message.recipient}".')
except (SocketError, smtplib.SMTPException, RuntimeError) as e:
self.logger.warning(
f'Sending email to "{message.recipient}" failed. '
f'Reason: {e}')
# Mark as failure
has_error = True
except (SocketError, smtplib.SMTPException, RuntimeError) as e:
self.logger.warning(
f'Connection error while submitting email to {self.smtp_host}.'
f' Reason: {e}')
# Mark our failure
has_error = True
# Mark as failure
has_error = True
finally:
# Gracefully terminate the connection with the server
if socket is not None: # pragma: no branch
socket.quit()
finally:
# Gracefully terminate the connection with the server
if socket is not None: # pragma: no branch
socket.quit()
return not has_error
@ -839,12 +896,7 @@ class NotifyEmail(NotifyBase):
"""
# Define an URL parameters
params = {
'from': self.from_addr,
'mode': self.secure_mode,
'smtp': self.smtp_host,
'user': self.user,
}
params = {}
# Append our headers into our parameters
params.update({'+{}'.format(k): v for k, v in self.headers.items()})
@ -852,30 +904,60 @@ class NotifyEmail(NotifyBase):
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
if self.from_name:
params['name'] = self.from_name
from_addr = None
if len(self.targets) == 1 and self.targets[0][1] != self.from_addr[1]:
# A custom email was provided
from_addr = self.from_addr[1]
if self.smtp_host != self.host:
# Apply our SMTP Host only if it differs from the provided hostname
params['smtp'] = self.smtp_host
if self.secure:
# Mode is only requried if we're dealing with a secure connection
params['mode'] = self.secure_mode
if self.from_addr[0] and self.from_addr[0] != self.app_id:
# A custom name was provided
params['from'] = self.from_addr[0] if not from_addr else \
formataddr((self.from_addr[0], from_addr), charset='utf-8')
elif from_addr:
params['from'] = formataddr((False, from_addr), charset='utf-8')
elif not self.user:
params['from'] = \
formataddr((False, self.from_addr[1]), charset='utf-8')
if len(self.cc) > 0:
# Handle our Carbon Copy Addresses
params['cc'] = ','.join(
['{}{}'.format(
'' if not e not in self.names
else '{}:'.format(self.names[e]), e) for e in self.cc])
params['cc'] = ','.join([
formataddr(
(self.names[e] if e in self.names else False, e),
# Swap comma for it's escaped url code (if detected) since
# we're using that as a delimiter
charset='utf-8').replace(',', '%2C')
for e in self.cc])
if len(self.bcc) > 0:
# Handle our Blind Carbon Copy Addresses
params['bcc'] = ','.join(
['{}{}'.format(
'' if not e not in self.names
else '{}:'.format(self.names[e]), e) for e in self.bcc])
params['bcc'] = ','.join([
formataddr(
(self.names[e] if e in self.names else False, e),
# Swap comma for it's escaped url code (if detected) since
# we're using that as a delimiter
charset='utf-8').replace(',', '%2C')
for e in self.bcc])
if self.reply_to:
# Handle our Reply-To Addresses
params['reply'] = ','.join(
['{}{}'.format(
'' if not e not in self.names
else '{}:'.format(self.names[e]), e)
for e in self.reply_to])
params['reply'] = ','.join([
formataddr(
(self.names[e] if e in self.names else False, e),
# Swap comma for it's escaped url code (if detected) since
# we're using that as a delimiter
charset='utf-8').replace(',', '%2C')
for e in self.reply_to])
# pull email suffix from username (if present)
user = None if not self.user else self.user.split('@')[0]
@ -895,14 +977,13 @@ class NotifyEmail(NotifyBase):
)
# Default Port setup
default_port = \
self.default_secure_port if self.secure else self.default_port
default_port = SECURE_MODES[self.secure_mode]['default_port']
# a simple boolean check as to whether we display our target emails
# or not
has_targets = \
not (len(self.targets) == 1
and self.targets[0][1] == self.from_addr)
and self.targets[0][1] == self.from_addr[1])
return '{schema}://{auth}{hostname}{port}/{targets}?{params}'.format(
schema=self.secure_protocol if self.secure else self.protocol,
@ -918,6 +999,13 @@ class NotifyEmail(NotifyBase):
params=NotifyEmail.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""
@ -946,14 +1034,24 @@ class NotifyEmail(NotifyBase):
if 'from' in results['qsd'] and len(results['qsd']['from']):
from_addr = NotifyEmail.unquote(results['qsd']['from'])
if 'name' in results['qsd'] and len(results['qsd']['name']):
# Depricate use of both `from=` and `name=` in the same url as
# they will be synomomus of one another in the future.
from_addr = formataddr(
(NotifyEmail.unquote(results['qsd']['name']), from_addr),
charset='utf-8')
logger.warning(
'Email name= and from= are synonymous; '
'use one or the other.')
elif 'name' in results['qsd'] and len(results['qsd']['name']):
# Extract from name to associate with from address
from_addr = NotifyEmail.unquote(results['qsd']['name'])
# Attempt to detect 'to' email address
if 'to' in results['qsd'] and len(results['qsd']['to']):
results['targets'].append(results['qsd']['to'])
if 'name' in results['qsd'] and len(results['qsd']['name']):
# Extract from name to associate with from address
results['from_name'] = NotifyEmail.unquote(results['qsd']['name'])
# Store SMTP Host if specified
if 'smtp' in results['qsd'] and len(results['qsd']['smtp']):
# Extract the smtp server

@ -1,30 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 correct, the Emby server must be set up to allow
# for remote connections.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Emby Docker configuration: https://hub.docker.com/r/emby/embyserver/
# Authentication: https://github.com/MediaBrowser/Emby/wiki/Authentication
@ -117,7 +121,7 @@ class NotifyEmby(NotifyBase):
Initialize Emby Object
"""
super(NotifyEmby, self).__init__(**kwargs)
super().__init__(**kwargs)
if self.secure:
self.schema = 'https'

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Sources
# - https://dreambox.de/en/
@ -155,7 +162,7 @@ class NotifyEnigma2(NotifyBase):
headers can be a dictionary of key/value pairs that you want to
additionally include as part of the server headers to post with
"""
super(NotifyEnigma2, self).__init__(**kwargs)
super().__init__(**kwargs)
try:
self.timeout = int(timeout)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# For this plugin to work correct, the FCM server must be set up to allow
# for remote connections.
@ -218,7 +225,7 @@ class NotifyFCM(NotifyBase):
Initialize Firebase Cloud Messaging
"""
super(NotifyFCM, self).__init__(**kwargs)
super().__init__(**kwargs)
if mode is None:
# Detect our mode
@ -548,6 +555,12 @@ class NotifyFCM(NotifyBase):
params=NotifyFCM.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# New priorities are defined here:
# - https://firebase.google.com/docs/reference/fcm/rest/v1/\

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
class FCMMode:
"""
Define the Firebase Cloud Messaging Modes

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# To generate a private key file for your service account:
#

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# New priorities are defined here:
# - https://firebase.google.com/docs/reference/fcm/rest/v1/\

@ -1,26 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 CON
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
@ -84,7 +92,7 @@ class NotifyFaast(NotifyBase):
"""
Initialize Faast Object
"""
super(NotifyFaast, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store the Authentication Token
self.authtoken = validate_regex(authtoken)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, you need to first access https://dev.flock.com/webhooks
# Specifically https://dev.flock.com/webhooks/incoming
@ -145,7 +152,7 @@ class NotifyFlock(NotifyBase):
"""
Initialize Flock Object
"""
super(NotifyFlock, self).__init__(**kwargs)
super().__init__(**kwargs)
# Build ourselves a target list
self.targets = list()
@ -327,6 +334,13 @@ class NotifyFlock(NotifyBase):
params=NotifyFlock.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,28 +1,36 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
from .NotifyBase import NotifyBase
@ -32,13 +40,24 @@ from ..common import NotifyType
from ..AppriseLocale import gettext_lazy as _
class FORMPayloadField:
"""
Identifies the fields available in the FORM Payload
"""
VERSION = 'version'
TITLE = 'title'
MESSAGE = 'message'
MESSAGETYPE = 'type'
# Defines the method to send the notification
METHODS = (
'POST',
'GET',
'DELETE',
'PUT',
'HEAD'
'HEAD',
'PATCH'
)
@ -47,6 +66,27 @@ class NotifyForm(NotifyBase):
A wrapper for Form Notifications
"""
# Support
# - file*
# - file?
# - file*name
# - file?name
# - ?file
# - *file
# - file
# The code will convert the ? or * to the digit increments
__attach_as_re = re.compile(
r'((?P<match1>(?P<id1a>[a-z0-9_-]+)?'
r'(?P<wc1>[*?+$:.%]+)(?P<id1b>[a-z0-9_-]+))'
r'|(?P<match2>(?P<id2>[a-z0-9_-]+)(?P<wc2>[*?+$:.%]?)))',
re.IGNORECASE)
# Our count
attach_as_count = '{:02d}'
# the default attach_as value
attach_as_default = f'file{attach_as_count}'
# The default descriptive name associated with the Notification
service_name = 'Form'
@ -66,6 +106,12 @@ class NotifyForm(NotifyBase):
# local anyway
request_rate_per_sec = 0
# Define the FORM version to place in all payloads
# Version: Major.Minor, Major is only updated if the entire schema is
# changed. If just adding new items (or removing old ones, only increment
# the Minor!
form_version = '1.0'
# Define object templates
templates = (
'{schema}://{host}',
@ -111,6 +157,12 @@ class NotifyForm(NotifyBase):
'values': METHODS,
'default': METHODS[0],
},
'attach-as': {
'name': _('Attach File As'),
'type': 'string',
'default': 'file*',
'map_to': 'attach_as',
},
})
# Define any kwargs we're using
@ -123,9 +175,14 @@ class NotifyForm(NotifyBase):
'name': _('Payload Extras'),
'prefix': ':',
},
'params': {
'name': _('GET Params'),
'prefix': '-',
},
}
def __init__(self, headers=None, method=None, payload=None, **kwargs):
def __init__(self, headers=None, method=None, payload=None, params=None,
attach_as=None, **kwargs):
"""
Initialize Form Object
@ -133,7 +190,7 @@ class NotifyForm(NotifyBase):
additionally include as part of the server headers to post with
"""
super(NotifyForm, self).__init__(**kwargs)
super().__init__(**kwargs)
self.fullpath = kwargs.get('fullpath')
if not isinstance(self.fullpath, str):
@ -147,15 +204,72 @@ class NotifyForm(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
# Custom File Attachment Over-Ride Support
if not isinstance(attach_as, str):
# Default value
self.attach_as = self.attach_as_default
self.attach_multi_support = True
else:
result = self.__attach_as_re.match(attach_as.strip())
if not result:
msg = 'The attach-as specified ({}) is invalid.'.format(
attach_as)
self.logger.warning(msg)
raise TypeError(msg)
self.attach_as = ''
self.attach_multi_support = False
if result.group('match1'):
if result.group('id1a'):
self.attach_as += result.group('id1a')
self.attach_as += self.attach_as_count
self.attach_multi_support = True
self.attach_as += result.group('id1b')
else: # result.group('match2'):
self.attach_as += result.group('id2')
if result.group('wc2'):
self.attach_as += self.attach_as_count
self.attach_multi_support = True
# A payload map allows users to over-ride the default mapping if
# they're detected with the :overide=value. Normally this would
# create a new key and assign it the value specified. However
# if the key you specify is actually an internally mapped one,
# then a re-mapping takes place using the value
self.payload_map = {
FORMPayloadField.VERSION: FORMPayloadField.VERSION,
FORMPayloadField.TITLE: FORMPayloadField.TITLE,
FORMPayloadField.MESSAGE: FORMPayloadField.MESSAGE,
FORMPayloadField.MESSAGETYPE: FORMPayloadField.MESSAGETYPE,
}
self.params = {}
if params:
# Store our extra headers
self.params.update(params)
self.headers = {}
if headers:
# Store our extra headers
self.headers.update(headers)
self.payload_overrides = {}
self.payload_extras = {}
if payload:
# Store our extra payload entries
self.payload_extras.update(payload)
for key in list(self.payload_extras.keys()):
# Any values set in the payload to alter a system related one
# alters the system key. Hence :message=msg maps the 'message'
# variable that otherwise already contains the payload to be
# 'msg' instead (containing the payload)
if key in self.payload_map:
self.payload_map[key] = self.payload_extras[key]
self.payload_overrides[key] = self.payload_extras[key]
del self.payload_extras[key]
return
@ -175,9 +289,18 @@ class NotifyForm(NotifyBase):
# Append our headers into our parameters
params.update({'+{}'.format(k): v for k, v in self.headers.items()})
# Append our GET params into our parameters
params.update({'-{}'.format(k): v for k, v in self.params.items()})
# Append our payload extra's into our parameters
params.update(
{':{}'.format(k): v for k, v in self.payload_extras.items()})
params.update(
{':{}'.format(k): v for k, v in self.payload_overrides.items()})
if self.attach_as != self.attach_as_default:
# Provide Attach-As extension details
params['attach-as'] = self.attach_as
# Determine Authentication
auth = ''
@ -212,6 +335,7 @@ class NotifyForm(NotifyBase):
Perform Form Notification
"""
# Prepare HTTP Headers
headers = {
'User-Agent': self.app_id,
}
@ -233,7 +357,8 @@ class NotifyForm(NotifyBase):
try:
files.append((
'file{:02d}'.format(no), (
self.attach_as.format(no)
if self.attach_multi_support else self.attach_as, (
attachment.name,
open(attachment.path, 'rb'),
attachment.mimetype)
@ -246,22 +371,24 @@ class NotifyForm(NotifyBase):
self.logger.debug('I/O Exception: %s' % str(e))
return False
finally:
for file in files:
# Ensure all files are closed
if file[1][1]:
file[1][1].close()
if not self.attach_multi_support and no > 1:
self.logger.warning(
'Multiple attachments provided while '
'form:// Multi-Attachment Support not enabled')
# prepare Form Object
payload = {
# Version: Major.Minor, Major is only updated if the entire
# schema is changed. If just adding new items (or removing
# old ones, only increment the Minor!
'version': '1.0',
'title': title,
'message': body,
'type': notify_type,
}
payload = {}
for key, value in (
(FORMPayloadField.VERSION, self.form_version),
(FORMPayloadField.TITLE, title),
(FORMPayloadField.MESSAGE, body),
(FORMPayloadField.MESSAGETYPE, notify_type)):
if not self.payload_map[key]:
# Do not store element in payload response
continue
payload[self.payload_map[key]] = value
# Apply any/all payload over-rides defined
payload.update(self.payload_extras)
@ -289,10 +416,14 @@ class NotifyForm(NotifyBase):
if self.method == 'GET':
method = requests.get
payload.update(self.params)
elif self.method == 'PUT':
method = requests.put
elif self.method == 'PATCH':
method = requests.patch
elif self.method == 'DELETE':
method = requests.delete
@ -307,7 +438,7 @@ class NotifyForm(NotifyBase):
url,
files=None if not files else files,
data=payload if self.method != 'GET' else None,
params=payload if self.method == 'GET' else None,
params=payload if self.method == 'GET' else self.params,
headers=headers,
auth=auth,
verify=self.verify_certificate,
@ -377,6 +508,16 @@ class NotifyForm(NotifyBase):
results['headers'] = {NotifyForm.unquote(x): NotifyForm.unquote(y)
for x, y in results['qsd+'].items()}
# Add our GET paramters in the event the user wants to pass these along
results['params'] = {NotifyForm.unquote(x): NotifyForm.unquote(y)
for x, y in results['qsd-'].items()}
# Allow Attach-As Support which over-rides the name of the filename
# posted with the form://
# the default is file01, file02, file03, etc
if 'attach-as' in results['qsd'] and len(results['qsd']['attach-as']):
results['attach_as'] = results['qsd']['attach-as']
# Set method if not otherwise set
if 'method' in results['qsd'] and len(results['qsd']['method']):
results['method'] = NotifyForm.unquote(results['qsd']['method'])

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Once you visit: https://developer.gitter.im/apps you'll get a personal
# access token that will look something like this:
@ -137,7 +144,7 @@ class NotifyGitter(NotifyBase):
"""
Initialize Gitter Object
"""
super(NotifyGitter, self).__init__(**kwargs)
super().__init__(**kwargs)
# Secret Key (associated with project)
self.token = validate_regex(
@ -382,6 +389,12 @@ class NotifyGitter(NotifyBase):
[NotifyGitter.quote(x, safe='') for x in self.targets]),
params=NotifyGitter.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import
from __future__ import print_function
@ -54,8 +61,8 @@ except (ImportError, ValueError, AttributeError):
# be in microsoft windows, or we just don't have the python-gobject
# library available to us (or maybe one we don't support)?
# Alternativey A ValueError will get thrown upon calling
# gi.require_version() if the requested Notify namespace isn't available
# Alternatively, a `ValueError` will get raised upon calling
# gi.require_version() if the requested Notify namespace isn't available.
pass
@ -164,7 +171,7 @@ class NotifyGnome(NotifyBase):
Initialize Gnome Object
"""
super(NotifyGnome, self).__init__(**kwargs)
super().__init__(**kwargs)
# The urgency of the message
self.urgency = int(
@ -175,12 +182,9 @@ class NotifyGnome(NotifyBase):
if str(urgency).lower().startswith(k)),
NotifyGnome.template_args['urgency']['default']))
# Track whether or not we want to send an image with our notification
# or not.
# Track whether we want to add an image to the notification.
self.include_image = include_image
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
Perform Gnome Notification
@ -214,15 +218,15 @@ class NotifyGnome(NotifyBase):
except Exception as e:
self.logger.warning(
"Could not load Gnome notification icon ({}): {}"
.format(icon_path, e))
"Could not load notification icon (%s).", icon_path)
self.logger.debug(f'Gnome Exception: {e}')
notification.show()
self.logger.info('Sent Gnome notification.')
except Exception:
except Exception as e:
self.logger.warning('Failed to send Gnome notification.')
self.logger.exception('Gnome Exception')
self.logger.debug(f'Gnome Exception: {e}')
return False
return True

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# For this to work correctly you need to create a webhook. You'll also
# need a GSuite account (there are free trials if you don't have one)
@ -80,8 +87,7 @@ class NotifyGoogleChat(NotifyBase):
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_googlechat'
# Google Chat Webhook
notify_url = 'https://chat.googleapis.com/v1/spaces/{workspace}/messages' \
'?key={key}&token={token}'
notify_url = 'https://chat.googleapis.com/v1/spaces/{workspace}/messages'
# Default Notify Format
notify_format = NotifyFormat.MARKDOWN
@ -96,6 +102,7 @@ class NotifyGoogleChat(NotifyBase):
# Define object templates
templates = (
'{schema}://{workspace}/{webhook_key}/{webhook_token}',
'{schema}://{workspace}/{webhook_key}/{webhook_token}/{thread_key}',
)
# Define our template tokens
@ -118,6 +125,11 @@ class NotifyGoogleChat(NotifyBase):
'private': True,
'required': True,
},
'thread_key': {
'name': _('Thread Key'),
'type': 'string',
'private': True,
},
})
# Define our template arguments
@ -131,14 +143,18 @@ class NotifyGoogleChat(NotifyBase):
'token': {
'alias_of': 'webhook_token',
},
'thread': {
'alias_of': 'thread_key',
},
})
def __init__(self, workspace, webhook_key, webhook_token, **kwargs):
def __init__(self, workspace, webhook_key, webhook_token,
thread_key=None, **kwargs):
"""
Initialize Google Chat Object
"""
super(NotifyGoogleChat, self).__init__(**kwargs)
super().__init__(**kwargs)
# Workspace (associated with project)
self.workspace = validate_regex(workspace)
@ -164,6 +180,16 @@ class NotifyGoogleChat(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
if thread_key:
self.thread_key = validate_regex(thread_key)
if not self.thread_key:
msg = 'An invalid Google Chat Thread Key ' \
'({}) was specified.'.format(thread_key)
self.logger.warning(msg)
raise TypeError(msg)
else:
self.thread_key = None
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
@ -185,13 +211,21 @@ class NotifyGoogleChat(NotifyBase):
# Construct Notify URL
notify_url = self.notify_url.format(
workspace=self.workspace,
key=self.webhook_key,
token=self.webhook_token,
)
params = {
# Prepare our URL Parameters
'token': self.webhook_token,
'key': self.webhook_key,
}
if self.thread_key:
params['threadKey'] = self.thread_key
self.logger.debug('Google Chat POST URL: %s (cert_verify=%r)' % (
notify_url, self.verify_certificate,
))
self.logger.debug('Google Chat Parameters: %s' % str(params))
self.logger.debug('Google Chat Payload: %s' % str(payload))
# Always call throttle before any remote server i/o is made
@ -199,6 +233,7 @@ class NotifyGoogleChat(NotifyBase):
try:
r = requests.post(
notify_url,
params=params,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
@ -242,11 +277,13 @@ class NotifyGoogleChat(NotifyBase):
# Set our parameters
params = self.url_parameters(privacy=privacy, *args, **kwargs)
return '{schema}://{workspace}/{key}/{token}/?{params}'.format(
return '{schema}://{workspace}/{key}/{token}/{thread}?{params}'.format(
schema=self.secure_protocol,
workspace=self.pprint(self.workspace, privacy, safe=''),
key=self.pprint(self.webhook_key, privacy, safe=''),
token=self.pprint(self.webhook_token, privacy, safe=''),
thread='' if not self.thread_key
else self.pprint(self.thread_key, privacy, safe=''),
params=NotifyGoogleChat.urlencode(params),
)
@ -258,6 +295,7 @@ class NotifyGoogleChat(NotifyBase):
Syntax:
gchat://workspace/webhook_key/webhook_token
gchat://workspace/webhook_key/webhook_token/thread_key
"""
results = NotifyBase.parse_url(url, verify_host=False)
@ -277,6 +315,9 @@ class NotifyGoogleChat(NotifyBase):
# Store our Webhook Token
results['webhook_token'] = tokens.pop(0) if tokens else None
# Store our Thread Key
results['thread_key'] = tokens.pop(0) if tokens else None
# Support arguments as overrides (if specified)
if 'workspace' in results['qsd']:
results['workspace'] = \
@ -290,6 +331,17 @@ class NotifyGoogleChat(NotifyBase):
results['webhook_token'] = \
NotifyGoogleChat.unquote(results['qsd']['token'])
if 'thread' in results['qsd']:
results['thread_key'] = \
NotifyGoogleChat.unquote(results['qsd']['thread'])
elif 'threadkey' in results['qsd']:
# Support Google Chat's Thread Key (if set)
# keys are always made lowercase; so check above is attually
# testing threadKey successfully as well
results['thread_key'] = \
NotifyGoogleChat.unquote(results['qsd']['threadkey'])
return results
@staticmethod
@ -298,6 +350,8 @@ class NotifyGoogleChat(NotifyBase):
Support
https://chat.googleapis.com/v1/spaces/{workspace}/messages
'?key={key}&token={token}
https://chat.googleapis.com/v1/spaces/{workspace}/messages
'?key={key}&token={token}&threadKey={thread}
"""
result = re.match(

@ -1,30 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 correct, the Gotify server must be set up to allow
# for remote connections.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Gotify Docker configuration: https://hub.docker.com/r/gotify/server
# Example: https://github.com/gotify/server/blob/\
@ -155,7 +159,7 @@ class NotifyGotify(NotifyBase):
Initialize Gotify Object
"""
super(NotifyGotify, self).__init__(**kwargs)
super().__init__(**kwargs)
# Token (associated with project)
self.token = validate_regex(token)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
@ -187,7 +194,7 @@ class NotifyGrowl(NotifyBase):
"""
Initialize Growl Object
"""
super(NotifyGrowl, self).__init__(**kwargs)
super().__init__(**kwargs)
if not self.port:
self.port = self.default_port

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 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

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# You must generate a "Long-Lived Access Token". This can be done from your
# Home Assistant Profile page.
@ -115,7 +122,7 @@ class NotifyHomeAssistant(NotifyBase):
"""
Initialize Home Assistant Object
"""
super(NotifyHomeAssistant, self).__init__(**kwargs)
super().__init__(**kwargs)
self.fullpath = kwargs.get('fullpath', '')

@ -1,29 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# IFTTT (If-This-Then-That)
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# This code is licensed under the MIT License.
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 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 :
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# 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.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# 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'
@ -147,7 +153,7 @@ class NotifyIFTTT(NotifyBase):
reference to Value1, Value2, and/or Value3
"""
super(NotifyIFTTT, self).__init__(**kwargs)
super().__init__(**kwargs)
# Webhook ID (associated with project)
self.webhook_id = validate_regex(webhook_id)
@ -306,6 +312,12 @@ class NotifyIFTTT(NotifyBase):
params=NotifyIFTTT.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.events)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
import base64
@ -34,13 +41,25 @@ from ..common import NotifyType
from ..AppriseLocale import gettext_lazy as _
class JSONPayloadField:
"""
Identifies the fields available in the JSON Payload
"""
VERSION = 'version'
TITLE = 'title'
MESSAGE = 'message'
ATTACHMENTS = 'attachments'
MESSAGETYPE = 'type'
# Defines the method to send the notification
METHODS = (
'POST',
'GET',
'DELETE',
'PUT',
'HEAD'
'HEAD',
'PATCH'
)
@ -68,6 +87,12 @@ class NotifyJSON(NotifyBase):
# local anyway
request_rate_per_sec = 0
# Define the JSON version to place in all payloads
# Version: Major.Minor, Major is only updated if the entire schema is
# changed. If just adding new items (or removing old ones, only increment
# the Minor!
json_version = '1.0'
# Define object templates
templates = (
'{schema}://{host}',
@ -125,9 +150,14 @@ class NotifyJSON(NotifyBase):
'name': _('Payload Extras'),
'prefix': ':',
},
'params': {
'name': _('GET Params'),
'prefix': '-',
},
}
def __init__(self, headers=None, method=None, payload=None, **kwargs):
def __init__(self, headers=None, method=None, payload=None, params=None,
**kwargs):
"""
Initialize JSON Object
@ -135,7 +165,7 @@ class NotifyJSON(NotifyBase):
additionally include as part of the server headers to post with
"""
super(NotifyJSON, self).__init__(**kwargs)
super().__init__(**kwargs)
self.fullpath = kwargs.get('fullpath')
if not isinstance(self.fullpath, str):
@ -149,15 +179,44 @@ class NotifyJSON(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
# A payload map allows users to over-ride the default mapping if
# they're detected with the :overide=value. Normally this would
# create a new key and assign it the value specified. However
# if the key you specify is actually an internally mapped one,
# then a re-mapping takes place using the value
self.payload_map = {
JSONPayloadField.VERSION: JSONPayloadField.VERSION,
JSONPayloadField.TITLE: JSONPayloadField.TITLE,
JSONPayloadField.MESSAGE: JSONPayloadField.MESSAGE,
JSONPayloadField.ATTACHMENTS: JSONPayloadField.ATTACHMENTS,
JSONPayloadField.MESSAGETYPE: JSONPayloadField.MESSAGETYPE,
}
self.params = {}
if params:
# Store our extra headers
self.params.update(params)
self.headers = {}
if headers:
# Store our extra headers
self.headers.update(headers)
self.payload_overrides = {}
self.payload_extras = {}
if payload:
# Store our extra payload entries
self.payload_extras.update(payload)
for key in list(self.payload_extras.keys()):
# Any values set in the payload to alter a system related one
# alters the system key. Hence :message=msg maps the 'message'
# variable that otherwise already contains the payload to be
# 'msg' instead (containing the payload)
if key in self.payload_map:
self.payload_map[key] = self.payload_extras[key].strip()
self.payload_overrides[key] = \
self.payload_extras[key].strip()
del self.payload_extras[key]
return
@ -177,9 +236,14 @@ class NotifyJSON(NotifyBase):
# Append our headers into our parameters
params.update({'+{}'.format(k): v for k, v in self.headers.items()})
# Append our GET params into our parameters
params.update({'-{}'.format(k): v for k, v in self.params.items()})
# Append our payload extra's into our parameters
params.update(
{':{}'.format(k): v for k, v in self.payload_extras.items()})
params.update(
{':{}'.format(k): v for k, v in self.payload_overrides.items()})
# Determine Authentication
auth = ''
@ -214,6 +278,7 @@ class NotifyJSON(NotifyBase):
Perform JSON Notification
"""
# Prepare HTTP Headers
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json'
@ -253,16 +318,18 @@ class NotifyJSON(NotifyBase):
return False
# prepare JSON Object
payload = {
# Version: Major.Minor, Major is only updated if the entire
# schema is changed. If just adding new items (or removing
# old ones, only increment the Minor!
'version': '1.0',
'title': title,
'message': body,
'attachments': attachments,
'type': notify_type,
}
payload = {}
for key, value in (
(JSONPayloadField.VERSION, self.json_version),
(JSONPayloadField.TITLE, title),
(JSONPayloadField.MESSAGE, body),
(JSONPayloadField.ATTACHMENTS, attachments),
(JSONPayloadField.MESSAGETYPE, notify_type)):
if not self.payload_map[key]:
# Do not store element in payload response
continue
payload[self.payload_map[key]] = value
# Apply any/all payload over-rides defined
payload.update(self.payload_extras)
@ -294,6 +361,9 @@ class NotifyJSON(NotifyBase):
elif self.method == 'PUT':
method = requests.put
elif self.method == 'PATCH':
method = requests.patch
elif self.method == 'DELETE':
method = requests.delete
@ -307,6 +377,7 @@ class NotifyJSON(NotifyBase):
r = method(
url,
data=dumps(payload),
params=self.params,
headers=headers,
auth=auth,
verify=self.verify_certificate,
@ -364,6 +435,10 @@ class NotifyJSON(NotifyBase):
results['headers'] = {NotifyJSON.unquote(x): NotifyJSON.unquote(y)
for x, y in results['qsd+'].items()}
# Add our GET paramters in the event the user wants to pass these along
results['params'] = {NotifyJSON.unquote(x): NotifyJSON.unquote(y)
for x, y in results['qsd-'].items()}
# Set method if not otherwise set
if 'method' in results['qsd'] and len(results['qsd']['method']):
results['method'] = NotifyJSON.unquote(results['qsd']['method'])

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Join URL: http://joaoapps.com/join/
# To use this plugin, you need to first access (make sure your browser allows
@ -194,7 +201,7 @@ class NotifyJoin(NotifyBase):
"""
Initialize Join Object
"""
super(NotifyJoin, self).__init__(**kwargs)
super().__init__(**kwargs)
# Track whether or not we want to send an image with our notification
# or not.
@ -366,6 +373,12 @@ class NotifyJoin(NotifyBase):
for x in self.targets]),
params=NotifyJoin.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this service you will need a Kavenegar account from their website
# at https://kavenegar.com/
@ -149,7 +156,7 @@ class NotifyKavenegar(NotifyBase):
"""
Initialize Kavenegar Object
"""
super(NotifyKavenegar, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(
@ -317,6 +324,12 @@ class NotifyKavenegar(NotifyBase):
[NotifyKavenegar.quote(x, safe='') for x in self.targets]),
params=NotifyKavenegar.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, you must have a Kumulos account set up. Add a client
# and link it with your phone using the phone app (using your Companion App
@ -104,7 +111,7 @@ class NotifyKumulos(NotifyBase):
"""
Initialize Kumulos Object
"""
super(NotifyKumulos, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# For LaMetric to work, you need to first setup a custom application on their
# website. it can be done as follows:
@ -467,7 +474,7 @@ class NotifyLametric(NotifyBase):
"""
Initialize LaMetric Object
"""
super(NotifyLametric, self).__init__(**kwargs)
super().__init__(**kwargs)
self.mode = mode.strip().lower() \
if isinstance(mode, str) \

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# API Docs: https://developers.line.biz/en/reference/messaging-api/
@ -114,7 +122,7 @@ class NotifyLine(NotifyBase):
"""
Initialize Line Object
"""
super(NotifyLine, self).__init__(**kwargs)
super().__init__(**kwargs)
# Long-Lived Access token (generated from User Profile)
self.token = validate_regex(token)
@ -259,6 +267,12 @@ class NotifyLine(NotifyBase):
params=NotifyLine.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# PAHO MQTT Documentation:
# https://www.eclipse.org/paho/index.php?page=clients/python/docs/index.php
@ -132,20 +139,6 @@ class NotifyMQTT(NotifyBase):
# through their network flow at once.
mqtt_inflight_messages = 200
# Taken from https://golang.org/src/crypto/x509/root_linux.go
CA_CERTIFICATE_FILE_LOCATIONS = [
# Debian/Ubuntu/Gentoo etc.
"/etc/ssl/certs/ca-certificates.crt",
# Fedora/RHEL 6
"/etc/pki/tls/certs/ca-bundle.crt",
# OpenSUSE
"/etc/ssl/ca-bundle.pem",
# OpenELEC
"/etc/pki/tls/cacert.pem",
# CentOS/RHEL 7
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
]
# Define object templates
templates = (
'{schema}://{user}@{host}/{topic}',
@ -223,7 +216,7 @@ class NotifyMQTT(NotifyBase):
Initialize MQTT Object
"""
super(NotifyMQTT, self).__init__(**kwargs)
super().__init__(**kwargs)
# Initialize topics
self.topics = parse_list(targets)
@ -264,6 +257,9 @@ class NotifyMQTT(NotifyBase):
self.ca_certs = None
if self.secure:
# verify SSL key or abort
# TODO: There is no error reporting or aborting here?
# It could be useful to inform the user _where_ Apprise
# tried to find the root CA certificates file.
self.ca_certs = next(
(cert for cert in self.CA_CERTIFICATE_FILE_LOCATIONS
if isfile(cert)), None)
@ -316,9 +312,9 @@ class NotifyMQTT(NotifyBase):
if self.secure:
if self.ca_certs is None:
self.logger.warning(
'MQTT Secure comunication can not be verified; '
'no local CA certificate file')
self.logger.error(
'MQTT secure communication can not be verified, '
'CA certificates file missing')
return False
self.client.tls_set(
@ -328,7 +324,7 @@ class NotifyMQTT(NotifyBase):
ciphers=None)
# Set our TLS Verify Flag
self.client.tls_insecure_set(self.verify_certificate)
self.client.tls_insecure_set(not self.verify_certificate)
# Establish our connection
if self.client.connect(
@ -480,6 +476,12 @@ class NotifyMQTT(NotifyBase):
params=NotifyMQTT.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.topics)
@staticmethod
def parse_url(url):
"""
@ -528,3 +530,38 @@ class NotifyMQTT(NotifyBase):
# return results
return results
@property
def CA_CERTIFICATE_FILE_LOCATIONS(self):
"""
Return possible locations to root certificate authority (CA) bundles.
Taken from https://golang.org/src/crypto/x509/root_linux.go
TODO: Maybe refactor to a general utility function?
"""
candidates = [
# Debian/Ubuntu/Gentoo etc.
"/etc/ssl/certs/ca-certificates.crt",
# Fedora/RHEL 6
"/etc/pki/tls/certs/ca-bundle.crt",
# OpenSUSE
"/etc/ssl/ca-bundle.pem",
# OpenELEC
"/etc/pki/tls/cacert.pem",
# CentOS/RHEL 7
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
# macOS Homebrew; brew install ca-certificates
"/usr/local/etc/ca-certificates/cert.pem",
]
# Certifi provides Mozillas carefully curated collection of Root
# Certificates for validating the trustworthiness of SSL certificates
# while verifying the identity of TLS hosts. It has been extracted from
# the Requests project.
try:
import certifi
candidates.append(certifi.where())
except ImportError: # pragma: no cover
pass
return candidates

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Create an account https://msg91.com/ if you don't already have one
#
@ -156,7 +163,7 @@ class NotifyMSG91(NotifyBase):
"""
Initialize MSG91 Object
"""
super(NotifyMSG91, self).__init__(**kwargs)
super().__init__(**kwargs)
# Authentication Key (associated with project)
self.authkey = validate_regex(
@ -322,6 +329,12 @@ class NotifyMSG91(NotifyBase):
[NotifyMSG91.quote(x, safe='') for x in self.targets]),
params=NotifyMSG91.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, you need to create a webhook; you can read more about
# this here:
@ -214,7 +221,7 @@ class NotifyMSTeams(NotifyBase):
template arguments that can not be over-ridden are:
`body`, `title`, and `type`.
"""
super(NotifyMSTeams, self).__init__(**kwargs)
super().__init__(**kwargs)
try:
self.version = int(version)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import
from __future__ import print_function
@ -39,13 +46,15 @@ from ..AppriseLocale import gettext_lazy as _
# Default our global support flag
NOTIFY_MACOSX_SUPPORT_ENABLED = False
# TODO: The module will be easier to test without module-level code.
if platform.system() == 'Darwin':
# Check this is Mac OS X 10.8, or higher
major, minor = platform.mac_ver()[0].split('.')[:2]
# Toggle our enabled flag if verion is correct and executable
# Toggle our enabled flag, if version is correct and executable
# found. This is done in such a way to provide verbosity to the
# end user so they know why it may or may not work for them.
# end user, so they know why it may or may not work for them.
NOTIFY_MACOSX_SUPPORT_ENABLED = \
(int(major) > 10 or (int(major) == 10 and int(minor) >= 8))
@ -95,6 +104,8 @@ class NotifyMacOSX(NotifyBase):
notify_paths = (
'/opt/homebrew/bin/terminal-notifier',
'/usr/local/bin/terminal-notifier',
'/usr/bin/terminal-notifier',
'/bin/terminal-notifier',
)
# Define object templates
@ -117,26 +128,32 @@ class NotifyMacOSX(NotifyBase):
'name': _('Sound'),
'type': 'string',
},
'click': {
'name': _('Open/Click URL'),
'type': 'string',
},
})
def __init__(self, sound=None, include_image=True, **kwargs):
def __init__(self, sound=None, include_image=True, click=None, **kwargs):
"""
Initialize MacOSX Object
"""
super(NotifyMacOSX, self).__init__(**kwargs)
super().__init__(**kwargs)
# Track whether or not we want to send an image with our notification
# or not.
# Track whether we want to add an image to the notification.
self.include_image = include_image
# Acquire the notify path
# Acquire the path to the `terminal-notifier` program.
self.notify_path = next( # pragma: no branch
(p for p in self.notify_paths if os.access(p, os.X_OK)), None)
# Click URL
# Allow user to provide the `--open` argument on the notify wrapper
self.click = click
# Set sound object (no q/a for now)
self.sound = sound
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
@ -160,6 +177,9 @@ class NotifyMacOSX(NotifyBase):
if title:
cmd.extend(['-title', title])
if self.click:
cmd.extend(['-open', self.click])
# The sound to play
if self.sound:
cmd.extend(['-sound', self.sound])
@ -201,6 +221,9 @@ class NotifyMacOSX(NotifyBase):
'image': 'yes' if self.include_image else 'no',
}
if self.click:
params['click'] = self.click
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
@ -228,6 +251,10 @@ class NotifyMacOSX(NotifyBase):
results['include_image'] = \
parse_bool(results['qsd'].get('image', True))
# Support 'click'
if 'click' in results['qsd'] and len(results['qsd']['click']):
results['click'] = NotifyMacOSX.unquote(results['qsd']['click'])
# Support 'sound'
if 'sound' in results['qsd'] and len(results['qsd']['sound']):
results['sound'] = NotifyMacOSX.unquote(results['qsd']['sound'])

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Signup @ https://www.mailgun.com/
#
@ -60,6 +67,7 @@ from ..utils import parse_emails
from ..utils import parse_bool
from ..utils import is_email
from ..utils import validate_regex
from ..logger import logger
from ..AppriseLocale import gettext_lazy as _
# Provide some known codes Mailgun uses and what they translate to:
@ -116,9 +124,6 @@ class NotifyMailgun(NotifyBase):
# Default Notify Format
notify_format = NotifyFormat.HTML
# The default region to use if one isn't otherwise specified
mailgun_default_region = MailgunRegion.US
# The maximum amount of emails that can reside within a single
# batch transfer
default_batch_size = 2000
@ -158,7 +163,10 @@ class NotifyMailgun(NotifyBase):
'name': {
'name': _('From Name'),
'type': 'string',
'map_to': 'from_name',
'map_to': 'from_addr',
},
'from': {
'alias_of': 'name',
},
'region': {
'name': _('Region Name'),
@ -197,13 +205,13 @@ class NotifyMailgun(NotifyBase):
},
}
def __init__(self, apikey, targets, cc=None, bcc=None, from_name=None,
def __init__(self, apikey, targets, cc=None, bcc=None, from_addr=None,
region_name=None, headers=None, tokens=None, batch=False,
**kwargs):
"""
Initialize Mailgun Object
"""
super(NotifyMailgun, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(apikey)
@ -246,7 +254,8 @@ class NotifyMailgun(NotifyBase):
# Store our region
try:
self.region_name = self.mailgun_default_region \
self.region_name = \
NotifyMailgun.template_args['region']['default'] \
if region_name is None else region_name.lower()
if self.region_name not in MAILGUN_REGIONS:
@ -260,12 +269,20 @@ class NotifyMailgun(NotifyBase):
raise TypeError(msg)
# Get our From username (if specified)
self.from_name = from_name
# Get our from email address
self.from_addr = '{user}@{host}'.format(user=self.user, host=self.host)
if not is_email(self.from_addr):
self.from_addr = [
self.app_id, '{user}@{host}'.format(
user=self.user, host=self.host)]
if from_addr:
result = is_email(from_addr)
if result:
self.from_addr = (
result['name'] if result['name'] else False,
result['full_email'])
else:
self.from_addr[0] = from_addr
if not is_email(self.from_addr[1]):
# Parse Source domain based on from_addr
msg = 'Invalid ~From~ email format: {}'.format(self.from_addr)
self.logger.warning(msg)
@ -288,8 +305,7 @@ class NotifyMailgun(NotifyBase):
else:
# If our target email list is empty we want to add ourselves to it
self.targets.append(
(self.from_name if self.from_name else False, self.from_addr))
self.targets.append((False, self.from_addr[1]))
# Validate recipients (cc:) and drop bad ones:
for recipient in parse_emails(cc):
@ -383,9 +399,7 @@ class NotifyMailgun(NotifyBase):
return False
reply_to = formataddr(
(self.from_name if self.from_name else False,
self.from_addr), charset='utf-8')
reply_to = formataddr(self.from_addr, charset='utf-8')
# Prepare our payload
payload = {
@ -581,9 +595,9 @@ class NotifyMailgun(NotifyBase):
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
if self.from_name is not None:
# from_name specified; pass it back on the url
params['name'] = self.from_name
if self.from_addr[0]:
# from_addr specified; pass it back on the url
params['name'] = self.from_addr[0]
if self.cc:
# Handle our Carbon Copy Addresses
@ -613,6 +627,20 @@ class NotifyMailgun(NotifyBase):
safe='') for e in self.targets]),
params=NotifyMailgun.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""
@ -637,13 +665,28 @@ class NotifyMailgun(NotifyBase):
# We're done - no API Key found
results['apikey'] = None
if 'name' in results['qsd'] and len(results['qsd']['name']):
# Attempt to detect 'from' email address
if 'from' in results['qsd'] and len(results['qsd']['from']):
results['from_addr'] = \
NotifyMailgun.unquote(results['qsd']['from'])
if 'name' in results['qsd'] and len(results['qsd']['name']):
# Depricate use of both `from=` and `name=` in the same url as
# they will be synomomus of one another in the future.
results['from_addr'] = formataddr(
(NotifyMailgun.unquote(results['qsd']['name']),
results['from_addr']), charset='utf-8')
logger.warning(
'Mailgun name= and from= are synonymous; '
'use one or the other.')
elif 'name' in results['qsd'] and len(results['qsd']['name']):
# Extract from name to associate with from address
results['from_name'] = \
results['from_addr'] = \
NotifyMailgun.unquote(results['qsd']['name'])
if 'region' in results['qsd'] and len(results['qsd']['region']):
# Extract from name to associate with from address
# Acquire region if defined
results['region_name'] = \
NotifyMailgun.unquote(results['qsd']['region'])

@ -0,0 +1,990 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
from copy import deepcopy
from json import dumps, loads
from datetime import datetime
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..common import NotifyImageSize
from ..common import NotifyFormat
from ..common import NotifyType
from ..utils import parse_list
from ..utils import parse_bool
from ..utils import validate_regex
from ..AppriseLocale import gettext_lazy as _
from ..attachment.AttachBase import AttachBase
# Accept:
# - @username
# - username
# - username@host.com
# - @username@host.com
IS_USER = re.compile(
r'^\s*@?(?P<user>[A-Z0-9_]+(?:@(?P<host>[A-Z0-9_.-]+))?)$', re.I)
USER_DETECTION_RE = re.compile(
r'(@[A-Z0-9_]+(?:@[A-Z0-9_.-]+)?)(?=$|[\s,.&()\[\]]+)', re.I)
class MastodonMessageVisibility:
"""
The visibility of any status message made
"""
# post visibility defaults to the accounts default-visibilty setting
DEFAULT = 'default'
# post will be visible only to mentioned users
# similar to a Twitter DM
DIRECT = 'direct'
# post will be visible only to followers
PRIVATE = 'private'
# post will be public but not appear on the public timeline
UNLISTED = 'unlisted'
# post will be public
PUBLIC = 'public'
# Define the types in a list for validation purposes
MASTODON_MESSAGE_VISIBILITIES = (
MastodonMessageVisibility.DEFAULT,
MastodonMessageVisibility.DIRECT,
MastodonMessageVisibility.PRIVATE,
MastodonMessageVisibility.UNLISTED,
MastodonMessageVisibility.PUBLIC,
)
class NotifyMastodon(NotifyBase):
"""
A wrapper for Notify Mastodon Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Mastodon'
# The services URL
service_url = 'https://joinmastodon.org'
# The default protocol
protocol = ('mastodon', 'toot')
# The default secure protocol
secure_protocol = ('mastodons', 'toots')
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_mastodon'
# Allows the user to specify the NotifyImageSize object; this is supported
# through the webhook
image_size = NotifyImageSize.XY_128
# it is documented on the site that the maximum images per toot
# is 4 (unless it's a GIF, then it's only 1)
__toot_non_gif_images_batch = 4
# Mastodon API Reference To Acquire Current Users Information
# See: https://docs.joinmastodon.org/methods/accounts/
# Requires Scope Element: read:accounts
mastodon_whoami = '/api/v1/accounts/verify_credentials'
# URL for posting media files
mastodon_media = '/api/v1/media'
# URL for posting status messages
mastodon_toot = '/api/v1/statuses'
# URL for posting direct messages
mastodon_dm = '/api/v1/dm'
# The title is not used
title_maxlen = 0
# The maximum size of the message
body_maxlen = 500
# Default to text
notify_format = NotifyFormat.TEXT
# Mastodon is kind enough to return how many more requests we're allowed to
# continue to make within it's header response as:
# X-Rate-Limit-Reset: The epoc time (in seconds) we can expect our
# rate-limit to be reset.
# X-Rate-Limit-Remaining: an integer identifying how many requests we're
# still allow to make.
request_rate_per_sec = 0
# For Tracking Purposes
ratelimit_reset = datetime.utcnow()
# Default to 1000; users can send up to 1000 DM's and 2400 toot a day
# This value only get's adjusted if the server sets it that way
ratelimit_remaining = 1
# Define object templates
templates = (
'{schema}://{token}@{host}',
'{schema}://{token}@{host}:{port}',
'{schema}://{token}@{host}/{targets}',
'{schema}://{token}@{host}:{port}/{targets}',
)
# Define our template arguments
template_tokens = dict(NotifyBase.template_tokens, **{
'host': {
'name': _('Hostname'),
'type': 'string',
'required': True,
},
'token': {
'name': _('Access Token'),
'type': 'string',
'required': True,
},
'port': {
'name': _('Port'),
'type': 'int',
'min': 1,
'max': 65535,
},
'target_user': {
'name': _('Target User'),
'type': 'string',
'prefix': '@',
'map_to': 'targets',
},
'targets': {
'name': _('Targets'),
'type': 'list:string',
},
})
# Define our template arguments
template_args = dict(NotifyBase.template_args, **{
'token': {
'alias_of': 'token',
},
'visibility': {
'name': _('Visibility'),
'type': 'choice:string',
'values': MASTODON_MESSAGE_VISIBILITIES,
'default': MastodonMessageVisibility.DEFAULT,
},
'cache': {
'name': _('Cache Results'),
'type': 'bool',
'default': True,
},
'batch': {
'name': _('Batch Mode'),
'type': 'bool',
'default': True,
},
'sensitive': {
'name': _('Sensitive Attachments'),
'type': 'bool',
'default': False,
},
'spoiler': {
'name': _('Spoiler Text'),
'type': 'string',
},
'key': {
'name': _('Idempotency-Key'),
'type': 'string',
},
'language': {
'name': _('Language Code'),
'type': 'string',
},
'to': {
'alias_of': 'targets',
},
})
def __init__(self, token=None, targets=None, batch=True,
sensitive=None, spoiler=None, visibility=None, cache=True,
key=None, language=None, **kwargs):
"""
Initialize Notify Mastodon Object
"""
super().__init__(**kwargs)
# Set our schema
self.schema = 'https' if self.secure else 'http'
# Initialize our cache value
self._whoami_cache = None
self.token = validate_regex(token)
if not self.token:
msg = 'An invalid Mastodon Access Token was specified.'
self.logger.warning(msg)
raise TypeError(msg)
if visibility:
# Input is a string; attempt to get the lookup from our
# sound mapping
vis = 'invalid' if not isinstance(visibility, str) \
else visibility.lower().strip()
# This little bit of black magic allows us to match against
# against multiple versions of the same string
# ... etc
self.visibility = \
next((v for v in MASTODON_MESSAGE_VISIBILITIES
if v.startswith(vis)), None)
if self.visibility not in MASTODON_MESSAGE_VISIBILITIES:
msg = 'The Mastodon visibility specified ({}) is invalid.' \
.format(visibility)
self.logger.warning(msg)
raise TypeError(msg)
else:
self.visibility = \
self.template_args['visibility']['default']
# Prepare our URL
self.api_url = '%s://%s' % (self.schema, self.host)
if isinstance(self.port, int):
self.api_url += ':%d' % self.port
# Set Cache Flag
self.cache = cache
# Prepare Image Batch Mode Flag
self.batch = self.template_args['batch']['default'] \
if batch is None else batch
# Images to be marked sensitive
self.sensitive = self.template_args['sensitive']['default'] \
if sensitive is None else sensitive
# Text marked as being a spoiler
self.spoiler = spoiler if isinstance(spoiler, str) else None
# Idempotency Key
self.idempotency_key = key if isinstance(key, str) else None
# Over-ride default language (ISO 639) (e.g: en, fr, es, etc)
self.language = language if isinstance(language, str) else None
# Our target users
self.targets = []
# Track any errors
has_error = False
# Identify our targets
for target in parse_list(targets):
match = IS_USER.match(target)
if match and match.group('user'):
self.targets.append('@' + match.group('user'))
continue
has_error = True
self.logger.warning(
'Dropped invalid Mastodon user ({}) specified.'.format(target),
)
if has_error and not self.targets:
# We have specified that we want to notify one or more individual
# and we failed to load any of them. Since it's also valid to
# notify no one at all (which means we notify ourselves), it's
# important we don't switch from the users original intentions
msg = 'No Mastodon targets to notify.'
self.logger.warning(msg)
raise TypeError(msg)
return
def url(self, privacy=False, *args, **kwargs):
"""
Returns the URL built dynamically based on specified arguments.
"""
# Define any URL parameters
params = {
'visibility': self.visibility,
'batch': 'yes' if self.batch else 'no',
'sensitive': 'yes' if self.sensitive else 'no',
}
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
if self.spoiler:
# Our Spoiler if one was specified
params['spoiler'] = self.spoiler
if self.idempotency_key:
# Our Idempotency Key
params['key'] = self.idempotency_key
if self.language:
# Override Language
params['language'] = self.language
default_port = 443 if self.secure else 80
return '{schema}://{token}@{host}{port}/{targets}?{params}'.format(
schema=self.secure_protocol[0]
if self.secure else self.protocol[0],
token=self.pprint(
self.token, privacy, mode=PrivacyMode.Secret, safe=''),
# never encode hostname since we're expecting it to be a valid one
host=self.host,
port='' if self.port is None or self.port == default_port
else ':{}'.format(self.port),
targets='/'.join(
[NotifyMastodon.quote(x, safe='@') for x in self.targets]),
params=NotifyMastodon.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
def send(self, body, title='', notify_type=NotifyType.INFO, attach=None,
**kwargs):
"""
wrapper to _send since we can alert more then one channel
"""
# Build a list of our attachments
attachments = []
# Smart Target Detection for Direct Messages; this prevents us from
# adding @user entries that were already placed in the message body
users = set(USER_DETECTION_RE.findall(body))
targets = users - set(self.targets.copy())
if not self.targets and self.visibility == \
MastodonMessageVisibility.DIRECT:
result = self._whoami()
if not result:
# Could not access our status
return False
myself = '@' + next(iter(result.keys()))
if myself in users:
targets.remove(myself)
else:
targets.add(myself)
if attach:
# We need to upload our payload first so that we can source it
# in remaining messages
for attachment in attach:
# Perform some simple error checking
if not attachment:
# We could not access the attachment
self.logger.error(
'Could not access attachment {}.'.format(
attachment.url(privacy=True)))
return False
#
# Images (PNG, JPG, GIF) up to 8MB.
# - Images will be downscaled to 1.6 megapixels (enough for a
# 1280x1280 image).
# - Up to 4 images can be attached.
# - Animated GIFs are converted to soundless MP4s like on
# Imgur/Gfycat (GIFV).
# - You can also upload soundless MP4 and WebM, which will
# be handled the same way.
# Videos (MP4, M4V, MOV, WebM) up to 40MB.
# - Video will be transcoded to H.264 MP4 with a maximum
# bitrate of 1300kbps and framerate of 60fps.
# Audio (MP3, OGG, WAV, FLAC, OPUS, AAC, M4A, 3GP) up to 40MB.
# - Audio will be transcoded to MP3 using V2 VBR (roughly
# 192kbps).
if not re.match(r'^(image|video|audio)/.*',
attachment.mimetype, re.I):
# Only support images at this time
self.logger.warning(
'Ignoring unsupported Mastodon attachment {}.'.format(
attachment.url(privacy=True)))
continue
self.logger.debug(
'Preparing Mastodon attachment {}'.format(
attachment.url(privacy=True)))
# Upload our image and get our id associated with it
postokay, response = self._request(
self.mastodon_media,
payload=attachment,
)
if not postokay:
# We can't post our attachment
if response and 'authorized scopes' \
in response.get('error', ''):
self.logger.warning(
'Failed to Send Attachment to Mastodon: '
'missing scope: write:media')
# All other failures should cause us to abort
return False
if not (isinstance(response, dict)
and response.get('id')):
self.logger.debug(
'Could not attach the file to Mastodon: %s (mime=%s)',
attachment.name, attachment.mimetype)
continue
# If we get here, our output will look something like this:
# {
# 'id': '12345',
# 'type': 'image',
# 'url': 'https://.../6dad4663a.jpeg',
# 'preview_url': 'https://.../adde6dad4663a.jpeg',
# 'remote_url': None,
# 'preview_remote_url': None,
# 'text_url': None,
# 'meta': {
# 'original': {
# 'width': 640,
# 'height': 640,
# 'size': '640x640',
# 'aspect': 1.0
# },
# 'small': {
# 'width': 400,
# 'height': 400,
# 'size': '400x400',
# 'aspect': 1.0
# }
# },
# 'description': None,
# 'blurhash': 'UmIsdJnT^mX4V@XQofnQ~Ebq%4o3ofnQjZbt'
# }
response.update({
# Update our response to additionally include the
# attachment details
'file_name': attachment.name,
'file_mime': attachment.mimetype,
'file_path': attachment.path,
})
# Save our pre-prepared payload for attachment posting
attachments.append(response)
payload = {
'status': '{} {}'.format(' '.join(targets), body)
if targets else body,
'sensitive': self.sensitive,
}
# Handle Visibility Flag
if self.visibility != MastodonMessageVisibility.DEFAULT:
payload['visibility'] = self.visibility
# Set Spoiler text (if set)
if self.spoiler:
payload['spoiler_text'] = self.spoiler
# Set Idempotency-Key (if set)
if self.idempotency_key:
payload['Idempotency-Key'] = self.idempotency_key
# Set Language
if self.language:
payload['language'] = self.language
payloads = []
if not attachments:
payloads.append(payload)
else:
# Group our images if batch is set to do so
batch_size = 1 if not self.batch \
else self.__toot_non_gif_images_batch
# Track our batch control in our message generation
batches = []
batch = []
for attachment in attachments:
batch.append(attachment['id'])
# Mastodon supports batching images together. This allows
# the batching of multiple images together. Mastodon also
# makes it clear that you can't batch `gif` files; they need
# to be separate. So the below preserves the ordering that
# a user passed their attachments in. if 4-non-gif images
# are passed, they are all part of a single message.
#
# however, if they pass in image, gif, image, gif. The
# gif's inbetween break apart the batches so this would
# produce 4 separate toots.
#
# If you passed in, image, image, gif, image. <- This would
# produce 3 images (as the first 2 images could be lumped
# together as a batch)
if not re.match(
r'^image/(png|jpe?g)', attachment['file_mime'], re.I) \
or len(batch) >= batch_size:
batches.append(batch)
batch = []
if batch:
batches.append(batch)
for no, media_ids in enumerate(batches):
_payload = deepcopy(payload)
_payload['media_ids'] = media_ids
if no:
# strip text and replace it with the image representation
_payload['status'] = \
'{:02d}/{:02d}'.format(no + 1, len(batches))
# No longer sensitive information
_payload['sensitive'] = False
if self.idempotency_key:
# Support multiposts while a Idempotency Key has been
# defined
_payload['Idempotency-Key'] = '{}-part{:02d}'.format(
self.idempotency_key, no)
payloads.append(_payload)
# Error Tracking
has_error = False
for no, payload in enumerate(payloads, start=1):
postokay, response = self._request(self.mastodon_toot, payload)
if not postokay:
# Track our error
has_error = True
# We can't post our attachment
if response and 'authorized scopes' \
in response.get('error', ''):
self.logger.warning(
'Failed to Send Status to Mastodon: '
'missing scope: write:statuses')
continue
# Example Attachment Output:
# {
# "id":"109315796435904505",
# "created_at":"2022-11-09T20:44:39.017Z",
# "in_reply_to_id":null,
# "in_reply_to_account_id":null,
# "sensitive":false,
# "spoiler_text":"",
# "visibility":"public",
# "language":"en",
# "uri":"https://host/users/caronc/statuses/109315796435904505",
# "url":"https://host/@caronc/109315796435904505",
# "replies_count":0,
# "reblogs_count":0,
# "favourites_count":0,
# "edited_at":null,
# "favourited":false,
# "reblogged":false,
# "muted":false,
# "bookmarked":false,
# "pinned":false,
# "content":"<p>test</p>",
# "reblog":null,
# "application":{
# "name":"Apprise Notifications",
# "website":"https://github.com/caronc/apprise"
# },
# "account":{
# "id":"109310334138718878",
# "username":"caronc",
# "acct":"caronc",
# "display_name":"Chris",
# "locked":false,
# "bot":false,
# "discoverable":false,
# "group":false,
# "created_at":"2022-11-08T00:00:00.000Z",
# "note":"content",
# "url":"https://host/@caronc",
# "avatar":"https://host/path/file.png",
# "avatar_static":"https://host/path/file.png",
# "header":"https://host/headers/original/missing.png",
# "header_static":"https://host/path/missing.png",
# "followers_count":0,
# "following_count":0,
# "statuses_count":15,
# "last_status_at":"2022-11-09",
# "emojis":[
#
# ],
# "fields":[
#
# ]
# },
# "media_attachments":[
# {
# "id":"109315796405707501",
# "type":"image",
# "url":"https://host/path/file.jpeg",
# "preview_url":"https://host/path/file.jpeg",
# "remote_url":null,
# "preview_remote_url":null,
# "text_url":null,
# "meta":{
# "original":{
# "width":640,
# "height":640,
# "size":"640x640",
# "aspect":1.0
# },
# "small":{
# "width":400,
# "height":400,
# "size":"400x400",
# "aspect":1.0
# }
# },
# "description":null,
# "blurhash":"UmIsdJnT^mX4V@XQofnQ~Ebq%4o3ofnQjZbt"
# }
# ],
# "mentions":[
#
# ],
# "tags":[
#
# ],
# "emojis":[
#
# ],
# "card":null,
# "poll":null
# }
try:
url = '{}/web/@{}'.format(
self.api_url,
response['account']['username'])
except (KeyError, TypeError):
url = 'unknown'
self.logger.debug(
'Mastodon [%.2d/%.2d] (%d attached) delivered to %s',
no, len(payloads), len(payload.get('media_ids', [])), url)
self.logger.info(
'Sent [%.2d/%.2d] Mastodon notification as public toot.',
no, len(payloads))
return not has_error
def _whoami(self, lazy=True):
"""
Looks details of current authenticated user
"""
if lazy and self._whoami_cache is not None:
# Use cached response
return self._whoami_cache
# Send Mastodon Whoami request
postokay, response = self._request(
self.mastodon_whoami,
method='GET',
)
if postokay:
# Sample Response:
# {
# 'id': '12345',
# 'username': 'caronc',
# 'acct': 'caronc',
# 'display_name': 'Chris',
# 'locked': False,
# 'bot': False,
# 'discoverable': False,
# 'group': False,
# 'created_at': '2022-11-08T00:00:00.000Z',
# 'note': 'details',
# 'url': 'https://noc.social/@caronc',
# 'avatar': 'https://host/path/image.png',
# 'avatar_static': 'https://host/path/image.png',
# 'header': 'https://host/path/missing.png',
# 'header_static': 'https://host/path/missing.png',
# 'followers_count': 0,
# 'following_count': 0,
# 'statuses_count': 2,
# 'last_status_at': '2022-11-09',
# 'source': {
# 'privacy': 'public',
# 'sensitive': False,
# 'language': None,
# 'note': 'details',
# 'fields': [],
# 'follow_requests_count': 0
# },
# 'emojis': [],
# 'fields': []
# }
try:
# Cache our response for future references
self._whoami_cache = {
response['username']: response['id']}
except (TypeError, KeyError):
pass
elif response and 'authorized scopes' in response.get('error', ''):
self.logger.warning(
'Failed to lookup Mastodon Auth details; '
'missing scope: read:accounts')
return self._whoami_cache if postokay else {}
def _request(self, path, payload=None, method='POST'):
"""
Wrapper to Mastodon API requests object
"""
headers = {
'User-Agent': self.app_id,
'Authorization': f'Bearer {self.token}',
}
data = None
files = None
# Prepare our message
url = '{}{}'.format(self.api_url, path)
# Some Debug Logging
self.logger.debug('Mastodon {} URL: {} (cert_verify={})'.format(
method, url, self.verify_certificate))
# Open our attachment path if required:
if isinstance(payload, AttachBase):
# prepare payload
files = {
'file': (payload.name, open(payload.path, 'rb'),
'application/octet-stream')}
# Provide a description
data = {
'description': payload.name,
}
else:
headers['Content-Type'] = 'application/json'
data = dumps(payload)
self.logger.debug('Mastodon Payload: %s' % str(payload))
# Default content response object
content = {}
# By default set wait to None
wait = None
if self.ratelimit_remaining == 0:
# Determine how long we should wait for or if we should wait at
# all. This isn't fool-proof because we can't be sure the client
# time (calling this script) is completely synced up with the
# Mastodon server. One would hope we're on NTP and our clocks are
# the same allowing this to role smoothly:
now = datetime.utcnow()
if now < self.ratelimit_reset:
# We need to throttle for the difference in seconds
# We add 0.5 seconds to the end just to allow a grace
# period.
wait = (self.ratelimit_reset - now).total_seconds() + 0.5
# Always call throttle before any remote server i/o is made;
self.throttle(wait=wait)
# acquire our request mode
fn = requests.post if method == 'POST' else requests.get
try:
r = fn(
url,
data=data,
files=files,
headers=headers,
verify=self.verify_certificate,
timeout=self.request_timeout,
)
try:
content = loads(r.content)
except (AttributeError, TypeError, ValueError):
# ValueError = r.content is Unparsable
# TypeError = r.content is None
# AttributeError = r is None
content = {}
if r.status_code not in (
requests.codes.ok, requests.codes.created,
requests.codes.accepted):
# We had a problem
status_str = \
NotifyMastodon.http_response_code_lookup(r.status_code)
self.logger.warning(
'Failed to send Mastodon {} to {}: '
'{}error={}.'.format(
method,
url,
', ' if status_str else '',
r.status_code))
self.logger.debug(
'Response Details:\r\n{}'.format(r.content))
# Mark our failure
return (False, content)
try:
# Capture rate limiting if possible
self.ratelimit_remaining = \
int(r.headers.get('X-RateLimit-Remaining'))
self.ratelimit_reset = datetime.utcfromtimestamp(
int(r.headers.get('X-RateLimit-Limit')))
except (TypeError, ValueError):
# This is returned if we could not retrieve this information
# gracefully accept this state and move on
pass
except requests.RequestException as e:
self.logger.warning(
'Exception received when sending Mastodon {} to {}: '.
format(method, url))
self.logger.debug('Socket Exception: %s' % str(e))
# Mark our failure
return (False, content)
except (OSError, IOError) as e:
self.logger.warning(
'An I/O error occurred while handling {}.'.format(
payload.name if isinstance(payload, AttachBase)
else payload))
self.logger.debug('I/O Exception: %s' % str(e))
return (False, content)
finally:
# Close our file (if it's open) stored in the second element
# of our files tuple (index 1)
if files:
files['file'][1].close()
return (True, content)
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to re-instantiate this object.
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
if 'token' in results['qsd'] and len(results['qsd']['token']):
results['token'] = NotifyMastodon.unquote(results['qsd']['token'])
elif not results['password'] and results['user']:
results['token'] = NotifyMastodon.unquote(results['user'])
# Apply our targets
results['targets'] = NotifyMastodon.split_path(results['fullpath'])
# The defined Mastodon visibility
if 'visibility' in results['qsd'] and \
len(results['qsd']['visibility']):
# Simplified version
results['visibility'] = \
NotifyMastodon.unquote(results['qsd']['visibility'])
elif results['schema'].startswith('toot'):
results['visibility'] = MastodonMessageVisibility.PUBLIC
# Get Idempotency Key (if specified)
if 'key' in results['qsd'] and len(results['qsd']['key']):
results['key'] = \
NotifyMastodon.unquote(results['qsd']['key'])
# Get Spoiler Text
if 'spoiler' in results['qsd'] and len(results['qsd']['spoiler']):
results['spoiler'] = \
NotifyMastodon.unquote(results['qsd']['spoiler'])
# Get Language (if specified)
if 'language' in results['qsd'] and len(results['qsd']['language']):
results['language'] = \
NotifyMastodon.unquote(results['qsd']['language'])
# Get Sensitive Flag (for Attachments)
results['sensitive'] = \
parse_bool(results['qsd'].get(
'sensitive',
NotifyMastodon.template_args['sensitive']['default']))
# Get Batch Mode Flag
results['batch'] = \
parse_bool(results['qsd'].get(
'batch', NotifyMastodon.template_args['batch']['default']))
# The 'to' makes it easier to use yaml configuration
if 'to' in results['qsd'] and len(results['qsd']['to']):
results['targets'] += \
NotifyMastodon.parse_list(results['qsd']['to'])
return results

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Great sources
# - https://github.com/matrix-org/matrix-python-sdk
@ -128,7 +135,14 @@ class NotifyMatrix(NotifyBase):
image_size = NotifyImageSize.XY_32
# The maximum allowable characters allowed in the body per message
body_maxlen = 1000
# https://spec.matrix.org/v1.6/client-server-api/#size-limits
# The complete event MUST NOT be larger than 65536 bytes, when formatted
# with the federation event format, including any signatures, and encoded
# as Canonical JSON.
#
# To gracefully allow for some overhead' we'll define a max body length
# of just slighty lower then the limit of the full message itself.
body_maxlen = 65000
# Throttle a wee-bit to avoid thrashing
request_rate_per_sec = 0.5
@ -239,7 +253,7 @@ class NotifyMatrix(NotifyBase):
"""
Initialize Matrix Object
"""
super(NotifyMatrix, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare a list of rooms to connect and notify
self.rooms = parse_list(targets)
@ -1182,6 +1196,13 @@ class NotifyMatrix(NotifyBase):
params=NotifyMatrix.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.rooms)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Create an incoming webhook; the website will provide you with something like:
# http://localhost:8065/hooks/yobjmukpaw3r3urc5h6i369yima
@ -145,7 +152,7 @@ class NotifyMattermost(NotifyBase):
"""
Initialize Mattermost Object
"""
super(NotifyMattermost, self).__init__(**kwargs)
super().__init__(**kwargs)
if self.secure:
self.schema = 'https'

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Create an account https://messagebird.com if you don't already have one
#
@ -115,7 +122,7 @@ class NotifyMessageBird(NotifyBase):
"""
Initialize MessageBird Object
"""
super(NotifyMessageBird, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(
@ -304,6 +311,13 @@ class NotifyMessageBird(NotifyBase):
[NotifyMessageBird.quote(x, safe='') for x in self.targets]),
params=NotifyMessageBird.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -0,0 +1,310 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 1. visit https://misskey-hub.net/ and see what it's all about if you want.
# Choose a service you want to create an account on from here:
# https://misskey-hub.net/en/instances.html
#
# - For this plugin, I tested using https://misskey.sda1.net and created an
# account.
#
# 2. Generate an API Key:
# - Settings > API > Generate Key
# - Name it whatever you want
# - Assign it 'AT LEAST':
# a. Compose or delete chat messages
# b. Compose or delete notes
#
#
# This plugin also supports taking the URL (as identified above) directly
# as well.
import requests
from json import dumps
from .NotifyBase import NotifyBase
from ..common import NotifyType
from ..utils import validate_regex
from ..AppriseLocale import gettext_lazy as _
class MisskeyVisibility:
"""
The visibility of any note created
"""
# post will be public
PUBLIC = 'public'
HOME = 'home'
FOLLOWERS = 'followers'
PRIVATE = 'private'
SPECIFIED = 'specified'
# Define the types in a list for validation purposes
MISSKEY_VISIBILITIES = (
MisskeyVisibility.PUBLIC,
MisskeyVisibility.HOME,
MisskeyVisibility.FOLLOWERS,
MisskeyVisibility.PRIVATE,
MisskeyVisibility.SPECIFIED,
)
class NotifyMisskey(NotifyBase):
"""
A wrapper for Misskey Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Misskey'
# The services URL
service_url = 'https://misskey-hub.net/'
# The default protocol
protocol = 'misskey'
# The default secure protocol
secure_protocol = 'misskeys'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_misskey'
# The title is not used
title_maxlen = 0
# The maximum allowable characters allowed in the body per message
body_maxlen = 512
# Define object templates
templates = (
'{schema}://{project_id}/{msghook}',
)
# Define object templates
templates = (
'{schema}://{token}@{host}',
'{schema}://{token}@{host}:{port}',
)
# Define our template arguments
# Define our template arguments
template_tokens = dict(NotifyBase.template_tokens, **{
'host': {
'name': _('Hostname'),
'type': 'string',
'required': True,
},
'token': {
'name': _('Access Token'),
'type': 'string',
'required': True,
},
'port': {
'name': _('Port'),
'type': 'int',
'min': 1,
'max': 65535,
},
})
# Define our template arguments
template_args = dict(NotifyBase.template_args, **{
'token': {
'alias_of': 'token',
},
'visibility': {
'name': _('Visibility'),
'type': 'choice:string',
'values': MISSKEY_VISIBILITIES,
'default': MisskeyVisibility.PUBLIC,
},
})
def __init__(self, token=None, visibility=None, **kwargs):
"""
Initialize Misskey Object
"""
super().__init__(**kwargs)
self.token = validate_regex(token)
if not self.token:
msg = 'An invalid Misskey Access Token was specified.'
self.logger.warning(msg)
raise TypeError(msg)
if visibility:
# Input is a string; attempt to get the lookup from our
# sound mapping
vis = 'invalid' if not isinstance(visibility, str) \
else visibility.lower().strip()
# This little bit of black magic allows us to match against
# against multiple versions of the same string ... etc
self.visibility = \
next((v for v in MISSKEY_VISIBILITIES
if v.startswith(vis)), None)
if self.visibility not in MISSKEY_VISIBILITIES:
msg = 'The Misskey visibility specified ({}) is invalid.' \
.format(visibility)
self.logger.warning(msg)
raise TypeError(msg)
else:
self.visibility = self.template_args['visibility']['default']
# Prepare our URL
self.schema = 'https' if self.secure else 'http'
self.api_url = '%s://%s' % (self.schema, self.host)
if isinstance(self.port, int):
self.api_url += ':%d' % self.port
return
def url(self, privacy=False, *args, **kwargs):
"""
Returns the URL built dynamically based on specified arguments.
"""
params = {
'visibility': self.visibility,
}
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
host = self.host
if isinstance(self.port, int):
host += ':%d' % self.port
return '{schema}://{token}@{host}/?{params}'.format(
schema=self.secure_protocol if self.secure else self.protocol,
host=host,
token=self.pprint(self.token, privacy, safe=''),
params=NotifyMisskey.urlencode(params),
)
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
wrapper to _send since we can alert more then one channel
"""
# prepare our headers
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json',
}
# Prepare our payload
payload = {
'i': self.token,
'text': body,
'visibility': self.visibility,
}
api_url = f'{self.api_url}/api/notes/create'
self.logger.debug('Misskey GET URL: %s (cert_verify=%r)' % (
api_url, self.verify_certificate))
self.logger.debug('Misskey Payload: %s' % str(payload))
# Always call throttle before any remote server i/o is made
self.throttle()
try:
r = requests.post(
api_url,
headers=headers,
data=dumps(payload),
verify=self.verify_certificate,
timeout=self.request_timeout,
)
if r.status_code != requests.codes.ok:
# We had a problem
status_str = \
NotifyMisskey.http_response_code_lookup(r.status_code)
self.logger.warning(
'Failed to send Misskey notification: '
'{}{}error={}.'.format(
status_str,
', ' if status_str else '',
r.status_code))
self.logger.debug('Response Details:\r\n{}'.format(r.content))
# Return; we're done
return False
else:
self.logger.info('Sent Misskey notification.')
except requests.RequestException as e:
self.logger.warning(
'A Connection error occurred sending Misskey '
'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 re-instantiate this object.
"""
results = NotifyBase.parse_url(url)
if not results:
# We're done early as we couldn't load the results
return results
if 'token' in results['qsd'] and len(results['qsd']['token']):
results['token'] = NotifyMisskey.unquote(results['qsd']['token'])
elif not results['password'] and results['user']:
results['token'] = NotifyMisskey.unquote(results['user'])
# Capture visibility if specified
if 'visibility' in results['qsd'] and \
len(results['qsd']['visibility']):
results['visibility'] = \
NotifyMisskey.unquote(results['qsd']['visibility'])
return results

@ -1,26 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 CON
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
@ -125,7 +133,7 @@ class NotifyNextcloud(NotifyBase):
"""
Initialize Nextcloud Object
"""
super(NotifyNextcloud, self).__init__(**kwargs)
super().__init__(**kwargs)
self.targets = parse_list(targets)
if len(self.targets) == 0:
@ -304,6 +312,12 @@ class NotifyNextcloud(NotifyBase):
params=NotifyNextcloud.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,29 +1,38 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 CON
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
from json import dumps
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..common import NotifyType
@ -106,7 +115,7 @@ class NotifyNextcloudTalk(NotifyBase):
"""
Initialize Nextcloud Talk Object
"""
super(NotifyNextcloudTalk, self).__init__(**kwargs)
super().__init__(**kwargs)
if self.user is None or self.password is None:
msg = 'User and password have to be specified.'
@ -134,7 +143,9 @@ class NotifyNextcloudTalk(NotifyBase):
# Prepare our Header
headers = {
'User-Agent': self.app_id,
'OCS-APIREQUEST': 'true',
'OCS-APIRequest': 'true',
'Accept': 'application/json',
'Content-Type': 'application/json',
}
# Apply any/all header over-rides defined
@ -183,7 +194,7 @@ class NotifyNextcloudTalk(NotifyBase):
try:
r = requests.post(
notify_url,
data=payload,
data=dumps(payload),
headers=headers,
auth=(self.user, self.password),
verify=self.verify_certificate,
@ -252,6 +263,12 @@ class NotifyNextcloudTalk(NotifyBase):
for x in self.targets]),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,26 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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 CON
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 1. Simply visit https://notica.us
# 2. You'll be provided a new variation of the website which will look
@ -160,7 +168,7 @@ class NotifyNotica(NotifyBase):
"""
Initialize Notica Object
"""
super(NotifyNotica, self).__init__(**kwargs)
super().__init__(**kwargs)
# Token (associated with project)
self.token = validate_regex(token)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Notifico allows you to relay notifications into IRC channels.
#
@ -160,7 +167,7 @@ class NotifyNotifico(NotifyBase):
"""
Initialize Notifico Object
"""
super(NotifyNotifico, self).__init__(**kwargs)
super().__init__(**kwargs)
# Assign our message hook
self.project_id = validate_regex(

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Great sources
# - https://github.com/matrix-org/matrix-python-sdk
@ -40,8 +47,10 @@ from os.path import basename
from .NotifyBase import NotifyBase
from ..common import NotifyType
from ..common import NotifyImageSize
from ..AppriseLocale import gettext_lazy as _
from ..utils import parse_list
from ..utils import parse_bool
from ..utils import is_hostname
from ..utils import is_ipaddr
from ..utils import validate_regex
@ -65,6 +74,27 @@ NTFY_MODES = (
NtfyMode.PRIVATE,
)
# A Simple regular expression used to auto detect Auth mode if it isn't
# otherwise specified:
NTFY_AUTH_DETECT_RE = re.compile('tk_[^ \t]+', re.IGNORECASE)
class NtfyAuth:
"""
Define ntfy Authentication Modes
"""
# Basic auth (user and password provided)
BASIC = "basic"
# Auth Token based
TOKEN = "token"
NTFY_AUTH = (
NtfyAuth.BASIC,
NtfyAuth.TOKEN,
)
class NtfyPriority:
"""
@ -142,6 +172,9 @@ class NotifyNtfy(NotifyBase):
# Default upstream/cloud host if none is defined
cloud_notify_url = 'https://ntfy.sh'
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_256
# Message time to live (if remote client isn't around to receive it)
time_to_live = 2419200
@ -158,6 +191,8 @@ class NotifyNtfy(NotifyBase):
'{schema}://{user}@{host}:{port}/{targets}',
'{schema}://{user}:{password}@{host}/{targets}',
'{schema}://{user}:{password}@{host}:{port}/{targets}',
'{schema}://{token}@{host}/{targets}',
'{schema}://{token}@{host}:{port}/{targets}',
)
# Define our template tokens
@ -181,6 +216,11 @@ class NotifyNtfy(NotifyBase):
'type': 'string',
'private': True,
},
'token': {
'name': _('Token'),
'type': 'string',
'private': True,
},
'topic': {
'name': _('Topic'),
'type': 'string',
@ -199,6 +239,16 @@ class NotifyNtfy(NotifyBase):
'name': _('Attach'),
'type': 'string',
},
'image': {
'name': _('Include Image'),
'type': 'bool',
'default': True,
'map_to': 'include_image',
},
'avatar_url': {
'name': _('Avatar URL'),
'type': 'string',
},
'filename': {
'name': _('Attach Filename'),
'type': 'string',
@ -231,6 +281,15 @@ class NotifyNtfy(NotifyBase):
'values': NTFY_MODES,
'default': NtfyMode.PRIVATE,
},
'token': {
'alias_of': 'token',
},
'auth': {
'name': _('Authentication Type'),
'type': 'choice:string',
'values': NTFY_AUTH,
'default': NtfyAuth.BASIC,
},
'to': {
'alias_of': 'targets',
},
@ -238,11 +297,12 @@ class NotifyNtfy(NotifyBase):
def __init__(self, targets=None, attach=None, filename=None, click=None,
delay=None, email=None, priority=None, tags=None, mode=None,
include_image=True, avatar_url=None, auth=None, token=None,
**kwargs):
"""
Initialize ntfy Object
"""
super(NotifyNtfy, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare our mode
self.mode = mode.strip().lower() \
@ -254,6 +314,20 @@ class NotifyNtfy(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
# Show image associated with notification
self.include_image = include_image
# Prepare our authentication type
self.auth = auth.strip().lower() \
if isinstance(auth, str) \
else self.template_args['auth']['default']
if self.auth not in NTFY_AUTH:
msg = 'An invalid ntfy Authentication type ({}) was specified.' \
.format(auth)
self.logger.warning(msg)
raise TypeError(msg)
# Attach a file (URL supported)
self.attach = attach
@ -269,6 +343,9 @@ class NotifyNtfy(NotifyBase):
# An email to forward notifications to
self.email = email
# Save our token
self.token = token
# The Priority of the message
self.priority = NotifyNtfy.template_args['priority']['default'] \
if not priority else \
@ -280,6 +357,11 @@ class NotifyNtfy(NotifyBase):
# Any optional tags to attach to the notification
self.__tags = parse_list(tags)
# Avatar URL
# This allows a user to provide an over-ride to the otherwise
# dynamically generated avatar url images
self.avatar_url = avatar_url
# Build list of topics
topics = parse_list(targets)
self.topics = []
@ -308,6 +390,15 @@ class NotifyNtfy(NotifyBase):
self.logger.warning('There are no ntfy topics to notify')
return False
# Acquire image_url
image_url = self.image_url(notify_type)
if self.include_image and (image_url or self.avatar_url):
image_url = \
self.avatar_url if self.avatar_url else image_url
else:
image_url = None
# Create a copy of the topics
topics = list(self.topics)
while len(topics) > 0:
@ -336,20 +427,23 @@ class NotifyNtfy(NotifyBase):
attachment.url(privacy=True)))
okay, response = self._send(
topic, body=_body, title=_title, attach=attachment)
topic, body=_body, title=_title, image_url=image_url,
attach=attachment)
if not okay:
# We can't post our attachment; abort immediately
return False
else:
# Send our Notification Message
okay, response = self._send(topic, body=body, title=title)
okay, response = self._send(
topic, body=body, title=title, image_url=image_url)
if not okay:
# Mark our failure, but contiue to move on
has_error = True
return not has_error
def _send(self, topic, body=None, title=None, attach=None, **kwargs):
def _send(self, topic, body=None, title=None, attach=None, image_url=None,
**kwargs):
"""
Wrapper to the requests (post) object
"""
@ -376,9 +470,17 @@ class NotifyNtfy(NotifyBase):
else: # NotifyNtfy.PRVATE
# Allow more settings to be applied now
if self.user:
if self.auth == NtfyAuth.BASIC and self.user:
auth = (self.user, self.password)
elif self.auth == NtfyAuth.TOKEN:
if not self.token:
self.logger.warning('No Ntfy Token was specified')
return False, None
# Set Token
headers['Authorization'] = f'Bearer {self.token}'
# Prepare our ntfy Template URL
schema = 'https' if self.secure else 'http'
@ -397,6 +499,9 @@ class NotifyNtfy(NotifyBase):
virt_payload = params
notify_url += '/{topic}'.format(topic=topic)
if image_url:
headers['X-Icon'] = image_url
if title:
virt_payload['title'] = title
@ -529,8 +634,13 @@ class NotifyNtfy(NotifyBase):
params = {
'priority': self.priority,
'mode': self.mode,
'image': 'yes' if self.include_image else 'no',
'auth': self.auth,
}
if self.avatar_url:
params['avatar_url'] = self.avatar_url
if self.attach is not None:
params['attach'] = self.attach
@ -550,15 +660,22 @@ class NotifyNtfy(NotifyBase):
# Determine Authentication
auth = ''
if self.user and self.password:
auth = '{user}:{password}@'.format(
user=NotifyNtfy.quote(self.user, safe=''),
password=self.pprint(
self.password, privacy, mode=PrivacyMode.Secret, safe=''),
)
elif self.user:
auth = '{user}@'.format(
user=NotifyNtfy.quote(self.user, safe=''),
if self.auth == NtfyAuth.BASIC:
if self.user and self.password:
auth = '{user}:{password}@'.format(
user=NotifyNtfy.quote(self.user, safe=''),
password=self.pprint(
self.password, privacy, mode=PrivacyMode.Secret,
safe=''),
)
elif self.user:
auth = '{user}@'.format(
user=NotifyNtfy.quote(self.user, safe=''),
)
elif self.token: # NtfyAuth.TOKEN also
auth = '{token}@'.format(
token=self.pprint(self.token, privacy, safe=''),
)
if self.mode == NtfyMode.PRIVATE:
@ -581,6 +698,12 @@ class NotifyNtfy(NotifyBase):
params=NotifyNtfy.urlencode(params)
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.topics)
@staticmethod
def parse_url(url):
"""
@ -623,6 +746,15 @@ class NotifyNtfy(NotifyBase):
results['tags'] = \
parse_list(NotifyNtfy.unquote(results['qsd']['tags']))
# Boolean to include an image or not
results['include_image'] = parse_bool(results['qsd'].get(
'image', NotifyNtfy.template_args['image']['default']))
# Extract avatar url if it was specified
if 'avatar_url' in results['qsd']:
results['avatar_url'] = \
NotifyNtfy.unquote(results['qsd']['avatar_url'])
# Acquire our targets/topics
results['targets'] = NotifyNtfy.split_path(results['fullpath'])
@ -631,6 +763,37 @@ class NotifyNtfy(NotifyBase):
results['targets'] += \
NotifyNtfy.parse_list(results['qsd']['to'])
# Token Specified
if 'token' in results['qsd'] and len(results['qsd']['token']):
# Token presumed to be the one in use
results['auth'] = NtfyAuth.TOKEN
results['token'] = NotifyNtfy.unquote(results['qsd']['token'])
# Auth override
if 'auth' in results['qsd'] and results['qsd']['auth']:
results['auth'] = NotifyNtfy.unquote(
results['qsd']['auth'].strip().lower())
if not results.get('auth') and results['user'] \
and not results['password']:
# We can try to detect the authentication type on the formatting of
# the username. Look for tk_.*
#
# This isn't a surfire way to do things though; it's best to
# specify the auth= flag
results['auth'] = NtfyAuth.TOKEN \
if NTFY_AUTH_DETECT_RE.match(results['user']) \
else NtfyAuth.BASIC
if results.get('auth') == NtfyAuth.TOKEN and not results.get('token'):
if results['user'] and not results['password']:
# Make sure we properly set our token
results['token'] = NotifyNtfy.unquote(results['user'])
elif results['password']:
# Make sure we properly set our token
results['token'] = NotifyNtfy.unquote(results['password'])
# Mode override
if 'mode' in results['qsd'] and results['qsd']['mode']:
results['mode'] = NotifyNtfy.unquote(

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# API Details:
# https://docs.microsoft.com/en-us/previous-versions/office/\
@ -173,7 +180,7 @@ class NotifyOffice365(NotifyBase):
"""
Initialize Office 365 Object
"""
super(NotifyOffice365, self).__init__(**kwargs)
super().__init__(**kwargs)
# Tenant identifier
self.tenant = validate_regex(
@ -589,6 +596,12 @@ class NotifyOffice365(NotifyBase):
safe='') for e in self.targets]),
params=NotifyOffice365.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# One Signal requires that you've signed up with the service and
# generated yourself an API Key and APP ID.
@ -44,7 +51,7 @@ from ..utils import is_email
from ..AppriseLocale import gettext_lazy as _
class OneSignalCategory(NotifyBase):
class OneSignalCategory:
"""
We define the different category types that we can notify via OneSignal
"""
@ -85,7 +92,7 @@ class NotifyOneSignal(NotifyBase):
image_size = NotifyImageSize.XY_72
# The maximum allowable batch sizes per message
maximum_batch_size = 2000
default_batch_size = 2000
# Define object templates
templates = (
@ -114,7 +121,7 @@ class NotifyOneSignal(NotifyBase):
'private': True,
'required': True,
},
'target_device': {
'target_player': {
'name': _('Target Player ID'),
'type': 'string',
'map_to': 'targets',
@ -178,7 +185,7 @@ class NotifyOneSignal(NotifyBase):
Initialize OneSignal
"""
super(NotifyOneSignal, self).__init__(**kwargs)
super().__init__(**kwargs)
# The apikey associated with the account
self.apikey = validate_regex(apikey)
@ -197,7 +204,7 @@ class NotifyOneSignal(NotifyBase):
raise TypeError(msg)
# Prepare Batch Mode Flag
self.batch_size = self.maximum_batch_size if batch else 1
self.batch_size = self.default_batch_size if batch else 1
# Place a thumbnail image inline with the message body
self.include_image = include_image
@ -425,6 +432,26 @@ class NotifyOneSignal(NotifyBase):
params=NotifyOneSignal.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
if self.batch_size > 1:
# Batches can only be sent by group (you can't combine groups into
# a single batch)
total_targets = 0
for k, m in self.targets.items():
targets = len(m)
total_targets += int(targets / self.batch_size) + \
(1 if targets % self.batch_size else 0)
return total_targets
# Normal batch count; just count the targets
return sum([len(m) for _, m in self.targets.items()])
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Signup @ https://www.opsgenie.com
#
@ -165,7 +172,7 @@ class NotifyOpsgenie(NotifyBase):
opsgenie_default_region = OpsgenieRegion.US
# The maximum allowable targets within a notification
maximum_batch_size = 50
default_batch_size = 50
# Define object templates
templates = (
@ -262,7 +269,7 @@ class NotifyOpsgenie(NotifyBase):
"""
Initialize Opsgenie Object
"""
super(NotifyOpsgenie, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(apikey)
@ -301,7 +308,7 @@ class NotifyOpsgenie(NotifyBase):
self.details.update(details)
# Prepare Batch Mode Flag
self.batch_size = self.maximum_batch_size if batch else 1
self.batch_size = self.default_batch_size if batch else 1
# Assign our tags (if defined)
self.__tags = parse_list(tags)
@ -382,7 +389,7 @@ class NotifyOpsgenie(NotifyBase):
has_error = False
# Use body if title not set
title_body = body if not title else body
title_body = body if not title else title
# Create a copy ouf our details object
details = self.details.copy()
@ -529,6 +536,20 @@ class NotifyOpsgenie(NotifyBase):
for x in self.targets]),
params=NotifyOpsgenie.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
targets = len(self.targets)
if self.batch_size > 1:
targets = int(targets / self.batch_size) + \
(1 if targets % self.batch_size else 0)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# API Refererence:
# - https://developer.pagerduty.com/api-reference/\
@ -61,6 +68,13 @@ PAGERDUTY_SEVERITY_MAP = {
NotifyType.FAILURE: PagerDutySeverity.CRITICAL,
}
PAGERDUTY_SEVERITIES = (
PagerDutySeverity.INFO,
PagerDutySeverity.WARNING,
PagerDutySeverity.CRITICAL,
PagerDutySeverity.ERROR,
)
# Priorities
class PagerDutyRegion:
@ -169,6 +183,14 @@ class NotifyPagerDuty(NotifyBase):
'default': PagerDutyRegion.US,
'map_to': 'region_name',
},
# The severity is automatically determined, however you can optionally
# over-ride its value and force it to be what you want
'severity': {
'name': _('Severity'),
'type': 'choice:string',
'values': PAGERDUTY_SEVERITIES,
'map_to': 'severity',
},
'image': {
'name': _('Include Image'),
'type': 'bool',
@ -188,11 +210,11 @@ class NotifyPagerDuty(NotifyBase):
def __init__(self, apikey, integrationkey=None, source=None,
component=None, group=None, class_id=None,
include_image=True, click=None, details=None,
region_name=None, **kwargs):
region_name=None, severity=None, **kwargs):
"""
Initialize Pager Duty Object
"""
super(NotifyPagerDuty, self).__init__(**kwargs)
super().__init__(**kwargs)
# Long-Lived Access token (generated from User Profile)
self.apikey = validate_regex(apikey)
@ -248,6 +270,19 @@ class NotifyPagerDuty(NotifyBase):
self.logger.warning(msg)
raise TypeError(msg)
# The severity (if specified)
self.severity = \
None if severity is None else next((
s for s in PAGERDUTY_SEVERITIES
if str(s).lower().startswith(severity)), False)
if self.severity is False:
# Invalid severity specified
msg = 'The PagerDuty severity specified ({}) is invalid.' \
.format(severity)
self.logger.warning(msg)
raise TypeError(msg)
# A clickthrough option for notifications
self.click = click
@ -289,8 +324,8 @@ class NotifyPagerDuty(NotifyBase):
'summary': body,
# Set our severity
'severity': PAGERDUTY_SEVERITY_MAP[notify_type],
'severity': PAGERDUTY_SEVERITY_MAP[notify_type]
if not self.severity else self.severity,
# Our Alerting Source/Component
'source': self.source,
@ -400,6 +435,9 @@ class NotifyPagerDuty(NotifyBase):
if self.click is not None:
params['click'] = self.click
if self.severity:
params['severity'] = self.severity
# Append our custom entries our parameters
params.update({'+{}'.format(k): v for k, v in self.details.items()})
@ -464,6 +502,10 @@ class NotifyPagerDuty(NotifyBase):
results['class_id'] = \
NotifyPagerDuty.unquote(results['qsd']['class'])
if 'severity' in results['qsd'] and len(results['qsd']['severity']):
results['severity'] = \
NotifyPagerDuty.unquote(results['qsd']['severity'])
# Acquire our full path
fullpath = NotifyPagerDuty.split_path(results['fullpath'])

@ -0,0 +1,424 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
from json import dumps
from uuid import uuid4
from .NotifyBase import NotifyBase
from ..common import NotifyType
from ..utils import parse_list
from ..utils import validate_regex
from ..AppriseLocale import gettext_lazy as _
# Actions
class PagerTreeAction:
CREATE = 'create'
ACKNOWLEDGE = 'acknowledge'
RESOLVE = 'resolve'
# Urgencies
class PagerTreeUrgency:
SILENT = "silent"
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
PAGERTREE_ACTIONS = {
PagerTreeAction.CREATE: 'create',
PagerTreeAction.ACKNOWLEDGE: 'acknowledge',
PagerTreeAction.RESOLVE: 'resolve',
}
PAGERTREE_URGENCIES = {
# Note: This also acts as a reverse lookup mapping
PagerTreeUrgency.SILENT: 'silent',
PagerTreeUrgency.LOW: 'low',
PagerTreeUrgency.MEDIUM: 'medium',
PagerTreeUrgency.HIGH: 'high',
PagerTreeUrgency.CRITICAL: 'critical',
}
# Extend HTTP Error Messages
PAGERTREE_HTTP_ERROR_MAP = {
402: 'Payment Required - Please subscribe or upgrade',
403: 'Forbidden - Blocked',
404: 'Not Found - Invalid Integration ID',
405: 'Method Not Allowed - Integration Disabled',
429: 'Too Many Requests - Rate Limit Exceeded',
}
class NotifyPagerTree(NotifyBase):
"""
A wrapper for PagerTree Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'PagerTree'
# The services URL
service_url = 'https://pagertree.com/'
# All PagerTree requests are secure
secure_protocol = 'pagertree'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pagertree'
# PagerTree uses the http protocol with JSON requests
notify_url = 'https://api.pagertree.com/integration/{}'
# Define object templates
templates = (
'{schema}://{integration}',
)
# Define our template tokens
template_tokens = dict(NotifyBase.template_tokens, **{
'integration': {
'name': _('Integration ID'),
'type': 'string',
'private': True,
'required': True,
}
})
# Define our template arguments
template_args = dict(NotifyBase.template_args, **{
'action': {
'name': _('Action'),
'type': 'choice:string',
'values': PAGERTREE_ACTIONS,
'default': PagerTreeAction.CREATE,
},
'thirdparty': {
'name': _('Third Party ID'),
'type': 'string',
},
'urgency': {
'name': _('Urgency'),
'type': 'choice:string',
'values': PAGERTREE_URGENCIES,
},
'tags': {
'name': _('Tags'),
'type': 'string',
},
})
# Define any kwargs we're using
template_kwargs = {
'headers': {
'name': _('HTTP Header'),
'prefix': '+',
},
'payload_extras': {
'name': _('Payload Extras'),
'prefix': ':',
},
'meta_extras': {
'name': _('Meta Extras'),
'prefix': '-',
},
}
def __init__(self, integration, action=None, thirdparty=None,
urgency=None, tags=None, headers=None,
payload_extras=None, meta_extras=None, **kwargs):
"""
Initialize PagerTree Object
"""
super().__init__(**kwargs)
# Integration ID (associated with account)
self.integration = \
validate_regex(integration, r'^int_[a-zA-Z0-9\-_]{7,14}$')
if not self.integration:
msg = 'An invalid PagerTree Integration ID ' \
'({}) was specified.'.format(integration)
self.logger.warning(msg)
raise TypeError(msg)
# thirdparty (optional, in case they want to pass the
# acknowledge or resolve action)
self.thirdparty = None
if thirdparty:
# An id was specified, we want to validate it
self.thirdparty = validate_regex(thirdparty)
if not self.thirdparty:
msg = 'An invalid PagerTree third party ID ' \
'({}) was specified.'.format(thirdparty)
self.logger.warning(msg)
raise TypeError(msg)
self.headers = {}
if headers:
# Store our extra headers
self.headers.update(headers)
self.payload_extras = {}
if payload_extras:
# Store our extra payload entries
self.payload_extras.update(payload_extras)
self.meta_extras = {}
if meta_extras:
# Store our extra payload entries
self.meta_extras.update(meta_extras)
# Setup our action
self.action = NotifyPagerTree.template_args['action']['default'] \
if action not in PAGERTREE_ACTIONS else \
PAGERTREE_ACTIONS[action]
# Setup our urgency
self.urgency = \
None if urgency not in PAGERTREE_URGENCIES else \
PAGERTREE_URGENCIES[urgency]
# Any optional tags to attach to the notification
self.__tags = parse_list(tags)
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
Perform PagerTree Notification
"""
# Prepare our headers
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json',
}
# Apply any/all header over-rides defined
# For things like PagerTree Token
headers.update(self.headers)
# prepare JSON Object
payload = {
# Generate an ID (unless one was explicitly forced to be used)
'id': self.thirdparty if self.thirdparty else str(uuid4()),
'event_type': self.action,
}
if self.action == PagerTreeAction.CREATE:
payload['title'] = title if title else self.app_desc
payload['description'] = body
payload['meta'] = self.meta_extras
payload['tags'] = self.__tags
if self.urgency is not None:
payload['urgency'] = self.urgency
# Apply any/all payload over-rides defined
payload.update(self.payload_extras)
# Prepare our URL based on integration
notify_url = self.notify_url.format(self.integration)
self.logger.debug('PagerTree POST URL: %s (cert_verify=%r)' % (
notify_url, self.verify_certificate,
))
self.logger.debug('PagerTree Payload: %s' % str(payload))
# Always call throttle before any remote server i/o is made
self.throttle()
try:
r = requests.post(
notify_url,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
timeout=self.request_timeout,
)
if r.status_code not in (
requests.codes.ok, requests.codes.created,
requests.codes.accepted):
# We had a problem
status_str = \
NotifyPagerTree.http_response_code_lookup(
r.status_code)
self.logger.warning(
'Failed to send PagerTree notification: '
'{}{}error={}.'.format(
status_str,
', ' if status_str else '',
r.status_code))
self.logger.debug('Response Details:\r\n{}'.format(r.content))
# Return; we're done
return False
else:
self.logger.info('Sent PagerTree notification.')
except requests.RequestException as e:
self.logger.warning(
'A Connection error occurred sending PagerTree '
'notification to %s.' % self.host)
self.logger.debug('Socket Exception: %s' % str(e))
# Return; we're done
return False
return True
def url(self, privacy=False, *args, **kwargs):
"""
Returns the URL built dynamically based on specified arguments.
"""
# Define any URL parameters
params = {
'action': self.action,
}
if self.thirdparty:
params['tid'] = self.thirdparty
if self.urgency:
params['urgency'] = self.urgency
if self.__tags:
params['tags'] = ','.join([x for x in self.__tags])
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
# Headers prefixed with a '+' sign
# Append our headers into our parameters
params.update({'+{}'.format(k): v for k, v in self.headers.items()})
# Meta: {} prefixed with a '-' sign
# Append our meta extras into our parameters
params.update(
{'-{}'.format(k): v for k, v in self.meta_extras.items()})
# Payload body extras prefixed with a ':' sign
# Append our payload extras into our parameters
params.update(
{':{}'.format(k): v for k, v in self.payload_extras.items()})
return '{schema}://{integration}?{params}'.format(
schema=self.secure_protocol,
# never encode hostname since we're expecting it to be a valid one
integration=self.pprint(self.integration, privacy, safe=''),
params=NotifyPagerTree.urlencode(params),
)
@staticmethod
def parse_url(url):
"""
Parses the URL and returns enough arguments that can allow
us to re-instantiate this object.
"""
results = NotifyBase.parse_url(url, verify_host=False)
if not results:
# We're done early as we couldn't load the results
return results
# Add our headers that the user can potentially over-ride if they wish
# to to our returned result set and tidy entries by unquoting them
results['headers'] = {
NotifyPagerTree.unquote(x): NotifyPagerTree.unquote(y)
for x, y in results['qsd+'].items()
}
# store any additional payload extra's defined
results['payload_extras'] = {
NotifyPagerTree.unquote(x): NotifyPagerTree.unquote(y)
for x, y in results['qsd:'].items()
}
# store any additional meta extra's defined
results['meta_extras'] = {
NotifyPagerTree.unquote(x): NotifyPagerTree.unquote(y)
for x, y in results['qsd-'].items()
}
# Integration ID
if 'id' in results['qsd'] and len(results['qsd']['id']):
# Shortened version of integration id
results['integration'] = \
NotifyPagerTree.unquote(results['qsd']['id'])
elif 'integration' in results['qsd'] and \
len(results['qsd']['integration']):
results['integration'] = \
NotifyPagerTree.unquote(results['qsd']['integration'])
else:
results['integration'] = \
NotifyPagerTree.unquote(results['host'])
# Set our thirdparty
if 'tid' in results['qsd'] and len(results['qsd']['tid']):
# Shortened version of thirdparty
results['thirdparty'] = \
NotifyPagerTree.unquote(results['qsd']['tid'])
elif 'thirdparty' in results['qsd'] and \
len(results['qsd']['thirdparty']):
results['thirdparty'] = \
NotifyPagerTree.unquote(results['qsd']['thirdparty'])
# Set our urgency
if 'action' in results['qsd'] and \
len(results['qsd']['action']):
results['action'] = \
NotifyPagerTree.unquote(results['qsd']['action'])
# Set our urgency
if 'urgency' in results['qsd'] and len(results['qsd']['urgency']):
results['urgency'] = \
NotifyPagerTree.unquote(results['qsd']['urgency'])
# Set our tags
if 'tags' in results['qsd'] and len(results['qsd']['tags']):
results['tags'] = \
parse_list(NotifyPagerTree.unquote(results['qsd']['tags']))
return results

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Official API reference: https://developer.gitter.im/docs/user-resource
@ -130,7 +137,7 @@ class NotifyParsePlatform(NotifyBase):
"""
Initialize Parse Platform Object
"""
super(NotifyParsePlatform, self).__init__(**kwargs)
super().__init__(**kwargs)
self.fullpath = kwargs.get('fullpath')
if not isinstance(self.fullpath, str):

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
@ -105,7 +112,7 @@ class NotifyPopcornNotify(NotifyBase):
"""
Initialize PopcornNotify Object
"""
super(NotifyPopcornNotify, self).__init__(**kwargs)
super().__init__(**kwargs)
# Access Token (associated with project)
self.apikey = validate_regex(
@ -258,6 +265,21 @@ class NotifyPopcornNotify(NotifyBase):
[NotifyPopcornNotify.quote(x, safe='') for x in self.targets]),
params=NotifyPopcornNotify.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
@ -143,7 +150,7 @@ class NotifyProwl(NotifyBase):
"""
Initialize Prowl Object
"""
super(NotifyProwl, self).__init__(**kwargs)
super().__init__(**kwargs)
# The Priority of the message
self.priority = NotifyProwl.template_args['priority']['default'] \

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
from json import dumps
@ -115,7 +122,7 @@ class NotifyPushBullet(NotifyBase):
"""
Initialize PushBullet Object
"""
super(NotifyPushBullet, self).__init__(**kwargs)
super().__init__(**kwargs)
# Access Token (associated with project)
self.accesstoken = validate_regex(accesstoken)
@ -399,6 +406,12 @@ class NotifyPushBullet(NotifyBase):
targets=targets,
params=NotifyPushBullet.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import base64
import requests
@ -400,7 +407,7 @@ class NotifyPushSafer(NotifyBase):
"""
Initialize PushSafer Object
"""
super(NotifyPushSafer, self).__init__(**kwargs)
super().__init__(**kwargs)
#
# Priority
@ -787,6 +794,12 @@ class NotifyPushSafer(NotifyBase):
targets=targets,
params=NotifyPushSafer.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -120,7 +127,7 @@ class NotifyPushed(NotifyBase):
Initialize Pushed Object
"""
super(NotifyPushed, self).__init__(**kwargs)
super().__init__(**kwargs)
# Application Key (associated with project)
self.app_key = validate_regex(app_key)
@ -322,6 +329,13 @@ class NotifyPushed(NotifyBase):
)]),
params=NotifyPushed.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.channels) + len(self.users)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import requests
from json import dumps
@ -102,7 +109,7 @@ class NotifyPushjet(NotifyBase):
"""
Initialize Pushjet Object
"""
super(NotifyPushjet, self).__init__(**kwargs)
super().__init__(**kwargs)
# Secret Key (associated with project)
self.secret_key = validate_regex(secret_key)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -158,7 +165,7 @@ class NotifyPushover(NotifyBase):
notify_url = 'https://api.pushover.net/1/messages.json'
# The maximum allowable characters allowed in the body per message
body_maxlen = 512
body_maxlen = 1024
# Default Pushover sound
default_pushover_sound = PushoverSound.PUSHOVER
@ -251,7 +258,7 @@ class NotifyPushover(NotifyBase):
"""
Initialize Pushover Object
"""
super(NotifyPushover, self).__init__(**kwargs)
super().__init__(**kwargs)
# Access Token (associated with project)
self.token = validate_regex(token)
@ -570,6 +577,12 @@ class NotifyPushover(NotifyBase):
devices=devices,
params=NotifyPushover.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# 1. Visit https://www.reddit.com/prefs/apps and scroll to the bottom
# 2. Click on the button that reads 'are you a developer? create an app...'
@ -240,7 +248,7 @@ class NotifyReddit(NotifyBase):
"""
Initialize Notify Reddit Object
"""
super(NotifyReddit, self).__init__(**kwargs)
super().__init__(**kwargs)
# Initialize subreddit list
self.subreddits = set()
@ -359,6 +367,12 @@ class NotifyReddit(NotifyBase):
params=NotifyReddit.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.subreddits)
def login(self):
"""
A simple wrapper to authenticate with the Reddit Server

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -48,10 +55,6 @@ RC_HTTP_ERROR_MAP = {
401: 'Authentication tokens provided is invalid or missing.',
}
# Used to break apart list of potential tags by their delimiter
# into a usable list.
LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+')
class RocketChatAuthMode:
"""
@ -188,7 +191,7 @@ class NotifyRocketChat(NotifyBase):
"""
Initialize Notify Rocket.Chat Object
"""
super(NotifyRocketChat, self).__init__(**kwargs)
super().__init__(**kwargs)
# Set our schema
self.schema = 'https' if self.secure else 'http'
@ -320,7 +323,8 @@ class NotifyRocketChat(NotifyBase):
auth = '{user}{webhook}@'.format(
user='{}:'.format(NotifyRocketChat.quote(self.user, safe=''))
if self.user else '',
webhook=self.pprint(self.webhook, privacy, safe=''),
webhook=self.pprint(self.webhook, privacy,
mode=PrivacyMode.Secret, safe=''),
)
default_port = 443 if self.secure else 80
@ -333,7 +337,7 @@ class NotifyRocketChat(NotifyBase):
port='' if self.port is None or self.port == default_port
else ':{}'.format(self.port),
targets='/'.join(
[NotifyRocketChat.quote(x, safe='') for x in chain(
[NotifyRocketChat.quote(x, safe='@#') for x in chain(
# Channels are prefixed with a pound/hashtag symbol
['#{}'.format(x) for x in self.channels],
# Rooms are as is
@ -344,6 +348,13 @@ class NotifyRocketChat(NotifyBase):
params=NotifyRocketChat.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.channels) + len(self.rooms) + len(self.users)
return targets if targets > 0 else 1
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
wrapper to _send since we can alert more then one channel

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this plugin, you need to first generate a webhook.
@ -129,7 +136,7 @@ class NotifyRyver(NotifyBase):
"""
Initialize Ryver Object
"""
super(NotifyRyver, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Token (associated with project)
self.token = validate_regex(

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# API Information:
# - https://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html
@ -217,7 +224,7 @@ class NotifySES(NotifyBase):
"""
Initialize Notify AWS SES Object
"""
super(NotifySES, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store our AWS API Access Key
self.aws_access_key_id = validate_regex(access_key_id)
@ -809,6 +816,13 @@ class NotifySES(NotifyBase):
params=NotifySES.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -66,6 +73,22 @@ SMSEAGLE_PRIORITY_MAP = {
}
class SMSEagleCategory:
"""
We define the different category types that we can notify via SMS Eagle
"""
PHONE = 'phone'
GROUP = 'group'
CONTACT = 'contact'
SMSEAGLE_CATEGORIES = (
SMSEagleCategory.PHONE,
SMSEagleCategory.GROUP,
SMSEagleCategory.CONTACT,
)
class NotifySMSEagle(NotifyBase):
"""
A wrapper for SMSEagle Notifications
@ -191,7 +214,7 @@ class NotifySMSEagle(NotifyBase):
"""
Initialize SMSEagle Object
"""
super(NotifySMSEagle, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare Flash Mode Flag
self.flash = flash
@ -396,15 +419,15 @@ class NotifySMSEagle(NotifyBase):
batch_size = 1 if not self.batch else self.default_batch_size
notify_by = {
'phone': {
SMSEagleCategory.PHONE: {
"method": "sms.send_sms",
'target': 'to',
},
'group': {
SMSEagleCategory.GROUP: {
"method": "sms.send_togroup",
'target': 'groupname',
},
'contact': {
SMSEagleCategory.CONTACT: {
"method": "sms.send_tocontact",
'target': 'contactname',
},
@ -413,7 +436,7 @@ class NotifySMSEagle(NotifyBase):
# categories separated into a tuple since notify_by.keys()
# returns an unpredicable list in Python 2.7 which causes
# tests to fail every so often
for category in ('phone', 'group', 'contact'):
for category in SMSEAGLE_CATEGORIES:
# Create a copy of our template
payload = {
'method': notify_by[category]['method'],
@ -583,10 +606,34 @@ class NotifySMSEagle(NotifyBase):
['@{}'.format(x) for x in self.target_contacts],
# Groups
['#{}'.format(x) for x in self.target_groups],
# Pass along the same invalid entries as were provided
self.invalid_targets,
)]),
params=NotifySMSEagle.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
if batch_size > 1:
# Batches can only be sent by group (you can't combine groups into
# a single batch)
total_targets = 0
for c in SMSEAGLE_CATEGORIES:
targets = len(getattr(self, f'target_{c}s'))
total_targets += int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return total_targets
# Normal batch count; just count the targets
return len(self.target_phones) + len(self.target_contacts) + \
len(self.target_groups)
@staticmethod
def parse_url(url):
"""
@ -633,6 +680,7 @@ class NotifySMSEagle(NotifyBase):
results['status'] = \
parse_bool(results['qsd'].get('status', False))
# Get priority
if 'priority' in results['qsd'] and len(results['qsd']['priority']):
results['priority'] = \
NotifySMSEagle.unquote(results['qsd']['priority'])

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2021 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Signup @ https://smtp2go.com (free accounts available)
#
@ -159,7 +166,7 @@ class NotifySMTP2Go(NotifyBase):
"""
Initialize SMTP2Go Object
"""
super(NotifySMTP2Go, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(apikey)
@ -506,6 +513,21 @@ class NotifySMTP2Go(NotifyBase):
safe='') for e in self.targets]),
params=NotifySMTP2Go.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import hmac
@ -159,7 +166,7 @@ class NotifySNS(NotifyBase):
"""
Initialize Notify AWS SNS Object
"""
super(NotifySNS, self).__init__(**kwargs)
super().__init__(**kwargs)
# Store our AWS API Access Key
self.aws_access_key_id = validate_regex(access_key_id)
@ -593,6 +600,12 @@ class NotifySNS(NotifyBase):
params=NotifySNS.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.phone) + len(self.topics)
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# You will need an API Key for this plugin to work.
# From the Settings -> API Keys you can click "Create API Key" if you don't
@ -159,7 +167,7 @@ class NotifySendGrid(NotifyBase):
"""
Initialize Notify SendGrid Object
"""
super(NotifySendGrid, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(
@ -279,6 +287,12 @@ class NotifySendGrid(NotifyBase):
params=NotifySendGrid.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
return len(self.targets)
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
Perform SendGrid Notification

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2020 Chris Caron <xuzheliang135@qq.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -79,7 +86,7 @@ class NotifyServerChan(NotifyBase):
"""
Initialize ServerChan Object
"""
super(NotifyServerChan, self).__init__(**kwargs)
super().__init__(**kwargs)
# Token (associated with project)
self.token = validate_regex(

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import re
import requests
@ -157,7 +164,7 @@ class NotifySignalAPI(NotifyBase):
"""
Initialize SignalAPI Object
"""
super(NotifySignalAPI, self).__init__(**kwargs)
super().__init__(**kwargs)
# Prepare Batch Mode Flag
self.batch = batch
@ -424,6 +431,21 @@ class NotifySignalAPI(NotifyBase):
params=NotifySignalAPI.urlencode(params),
)
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
#
# Factor batch into calculation
#
batch_size = 1 if not self.batch else self.default_batch_size
targets = len(self.targets)
if batch_size > 1:
targets = int(targets / batch_size) + \
(1 if targets % batch_size else 0)
return targets
@staticmethod
def parse_url(url):
"""

@ -1,27 +1,35 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from os import urandom
from json import loads
import requests
@ -125,7 +133,7 @@ class NotifySimplePush(NotifyBase):
"""
Initialize SimplePush Object
"""
super(NotifySimplePush, self).__init__(**kwargs)
super().__init__(**kwargs)
# API Key (associated with project)
self.apikey = validate_regex(apikey)

@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
# BSD 3-Clause License
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <lead2gold@gmail.com>
#
# This code is licensed under the MIT License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 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 :
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 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.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# To use this service you will need a Sinch account to which you can get your
# API_TOKEN and SERVICE_PLAN_ID right from your console/dashboard at:
@ -169,7 +176,7 @@ class NotifySinch(NotifyBase):
"""
Initialize Sinch Object
"""
super(NotifySinch, self).__init__(**kwargs)
super().__init__(**kwargs)
# The Account SID associated with the account
self.service_plan_id = validate_regex(
@ -401,6 +408,13 @@ class NotifySinch(NotifyBase):
[NotifySinch.quote(x, safe='') for x in self.targets]),
params=NotifySinch.urlencode(params))
def __len__(self):
"""
Returns the number of targets associated with this notification
"""
targets = len(self.targets)
return targets if targets > 0 else 1
@staticmethod
def parse_url(url):
"""

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save