mirror of
https://github.com/caronc/apprise.git
synced 2025-06-23 19:23:18 +02:00
config files now correctly parse native urls (#164)
This commit is contained in:
parent
ccc9aba55a
commit
82683230a5
@ -34,7 +34,6 @@ from .common import MATCH_ALL_TAG
|
|||||||
from .utils import is_exclusive_match
|
from .utils import is_exclusive_match
|
||||||
from .utils import parse_list
|
from .utils import parse_list
|
||||||
from .utils import split_urls
|
from .utils import split_urls
|
||||||
from .utils import GET_SCHEMA_RE
|
|
||||||
from .logger import logger
|
from .logger import logger
|
||||||
|
|
||||||
from .AppriseAsset import AppriseAsset
|
from .AppriseAsset import AppriseAsset
|
||||||
@ -108,38 +107,8 @@ class Apprise(object):
|
|||||||
results = None
|
results = None
|
||||||
|
|
||||||
if isinstance(url, six.string_types):
|
if isinstance(url, six.string_types):
|
||||||
# swap hash (#) tag values with their html version
|
# Acquire our url tokens
|
||||||
_url = url.replace('/#', '/%23')
|
results = plugins.url_to_dict(url)
|
||||||
|
|
||||||
# Attempt to acquire the schema at the very least to allow our
|
|
||||||
# plugins to determine if they can make a better interpretation of
|
|
||||||
# a URL geared for them
|
|
||||||
schema = GET_SCHEMA_RE.match(_url)
|
|
||||||
if schema is None:
|
|
||||||
logger.error(
|
|
||||||
'Unparseable schema:// found in URL {}.'.format(url))
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Ensure our schema is always in lower case
|
|
||||||
schema = schema.group('schema').lower()
|
|
||||||
|
|
||||||
# Some basic validation
|
|
||||||
if schema not in plugins.SCHEMA_MAP:
|
|
||||||
# Give the user the benefit of the doubt that the user may be
|
|
||||||
# using one of the URLs provided to them by their notification
|
|
||||||
# service. Before we fail for good, just scan all the plugins
|
|
||||||
# that support he native_url() parse function
|
|
||||||
results = \
|
|
||||||
next((r['plugin'].parse_native_url(_url)
|
|
||||||
for r in plugins.MODULE_MAP.values()
|
|
||||||
if r['plugin'].parse_native_url(_url) is not None),
|
|
||||||
None)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Parse our url details of the server object as dictionary
|
|
||||||
# containing all of the information parsed from our URL
|
|
||||||
results = plugins.SCHEMA_MAP[schema].parse_url(_url)
|
|
||||||
|
|
||||||
if results is None:
|
if results is None:
|
||||||
# Failed to parse the server URL
|
# Failed to parse the server URL
|
||||||
logger.error('Unparseable URL {}.'.format(url))
|
logger.error('Unparseable URL {}.'.format(url))
|
||||||
|
@ -236,35 +236,14 @@ class ConfigBase(URLBase):
|
|||||||
# otherwise.
|
# otherwise.
|
||||||
return list()
|
return list()
|
||||||
|
|
||||||
if not result.group('url'):
|
# Store our url read in
|
||||||
|
url = result.group('url')
|
||||||
|
if not url:
|
||||||
# Comment/empty line; do nothing
|
# Comment/empty line; do nothing
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Store our url read in
|
# Acquire our url tokens
|
||||||
url = result.group('url')
|
results = plugins.url_to_dict(url)
|
||||||
|
|
||||||
# swap hash (#) tag values with their html version
|
|
||||||
_url = url.replace('/#', '/%23')
|
|
||||||
|
|
||||||
# Attempt to acquire the schema at the very least to allow our
|
|
||||||
# plugins to determine if they can make a better
|
|
||||||
# interpretation of a URL geared for them
|
|
||||||
schema = GET_SCHEMA_RE.match(_url)
|
|
||||||
|
|
||||||
# Ensure our schema is always in lower case
|
|
||||||
schema = schema.group('schema').lower()
|
|
||||||
|
|
||||||
# Some basic validation
|
|
||||||
if schema not in plugins.SCHEMA_MAP:
|
|
||||||
ConfigBase.logger.warning(
|
|
||||||
'Unsupported schema {} on line {}.'.format(
|
|
||||||
schema, line))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Parse our url details of the server object as dictionary
|
|
||||||
# containing all of the information parsed from our URL
|
|
||||||
results = plugins.SCHEMA_MAP[schema].parse_url(_url)
|
|
||||||
|
|
||||||
if results is None:
|
if results is None:
|
||||||
# Failed to parse the server URL
|
# Failed to parse the server URL
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
@ -407,63 +386,46 @@ class ConfigBase(URLBase):
|
|||||||
results = list()
|
results = list()
|
||||||
|
|
||||||
if isinstance(url, six.string_types):
|
if isinstance(url, six.string_types):
|
||||||
# We're just a simple URL string
|
# We're just a simple URL string...
|
||||||
|
schema = GET_SCHEMA_RE.match(url)
|
||||||
# swap hash (#) tag values with their html version
|
|
||||||
_url = url.replace('/#', '/%23')
|
|
||||||
|
|
||||||
# Attempt to acquire the schema at the very least to allow our
|
|
||||||
# plugins to determine if they can make a better
|
|
||||||
# interpretation of a URL geared for them
|
|
||||||
schema = GET_SCHEMA_RE.match(_url)
|
|
||||||
if schema is None:
|
if schema is None:
|
||||||
# Log invalid entries so that maintainer of config
|
# Log invalid entries so that maintainer of config
|
||||||
# config file at least has something to take action
|
# config file at least has something to take action
|
||||||
# with.
|
# with.
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
'Ignored entry {} found under urls, entry #{}'
|
'Invalid URL {}, entry #{}'.format(url, no + 1))
|
||||||
.format(_url, no + 1))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Ensure our schema is always in lower case
|
# We found a valid schema worthy of tracking; store it's
|
||||||
schema = schema.group('schema').lower()
|
# details:
|
||||||
|
_results = plugins.url_to_dict(url)
|
||||||
# Some basic validation
|
|
||||||
if schema not in plugins.SCHEMA_MAP:
|
|
||||||
ConfigBase.logger.warning(
|
|
||||||
'Unsupported schema {} under urls, entry #{}'.format(
|
|
||||||
schema, no + 1))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Parse our url details of the server object as dictionary
|
|
||||||
# containing all of the information parsed from our URL
|
|
||||||
_results = plugins.SCHEMA_MAP[schema].parse_url(_url)
|
|
||||||
if _results is None:
|
if _results is None:
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
'Unparseable {} based url, entry #{}'.format(
|
'Unparseable URL {}, entry #{}'.format(
|
||||||
schema, no + 1))
|
url, no + 1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# add our results to our global set
|
# add our results to our global set
|
||||||
results.append(_results)
|
results.append(_results)
|
||||||
|
|
||||||
elif isinstance(url, dict):
|
elif isinstance(url, dict):
|
||||||
# We are a url string with additional unescaped options
|
# We are a url string with additional unescaped options. In
|
||||||
|
# this case we want to iterate over all of our options so we
|
||||||
|
# can at least tell the end user what entries were ignored
|
||||||
|
# due to errors
|
||||||
|
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
it = url.iteritems()
|
it = url.iteritems()
|
||||||
else: # six.PY3
|
else: # six.PY3
|
||||||
it = iter(url.items())
|
it = iter(url.items())
|
||||||
|
|
||||||
# Track whether a schema was found
|
|
||||||
schema = None
|
|
||||||
|
|
||||||
# Track the URL to-load
|
# Track the URL to-load
|
||||||
_url = None
|
_url = None
|
||||||
for _key, tokens in it:
|
|
||||||
# swap hash (#) tag values with their html version
|
|
||||||
key = _key.replace('/#', '/%23')
|
|
||||||
|
|
||||||
# Get our schema
|
# Track last acquired schema
|
||||||
|
schema = None
|
||||||
|
for key, tokens in it:
|
||||||
|
# Test our schema
|
||||||
_schema = GET_SCHEMA_RE.match(key)
|
_schema = GET_SCHEMA_RE.match(key)
|
||||||
if _schema is None:
|
if _schema is None:
|
||||||
# Log invalid entries so that maintainer of config
|
# Log invalid entries so that maintainer of config
|
||||||
@ -471,32 +433,22 @@ class ConfigBase(URLBase):
|
|||||||
# with.
|
# with.
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
'Ignored entry {} found under urls, entry #{}'
|
'Ignored entry {} found under urls, entry #{}'
|
||||||
.format(_key, no + 1))
|
.format(key, no + 1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Store our URL and Schema Regex
|
# Store our URL and Schema Regex
|
||||||
_url = key
|
_url = key
|
||||||
schema = _schema
|
|
||||||
|
|
||||||
if schema is None:
|
# Store our schema
|
||||||
|
schema = _schema.group('schema').lower()
|
||||||
|
|
||||||
|
if _url is None:
|
||||||
# the loop above failed to match anything
|
# the loop above failed to match anything
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
'Unsupported schema in urls, entry #{}'.format(no + 1))
|
'Unsupported schema in urls, entry #{}'.format(no + 1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Ensure our schema is always in lower case
|
_results = plugins.url_to_dict(_url)
|
||||||
schema = schema.group('schema').lower()
|
|
||||||
|
|
||||||
# Some basic validation
|
|
||||||
if schema not in plugins.SCHEMA_MAP:
|
|
||||||
ConfigBase.logger.warning(
|
|
||||||
'Unsupported schema {} in urls, entry #{}'.format(
|
|
||||||
schema, no + 1))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Parse our url details of the server object as dictionary
|
|
||||||
# containing all of the information parsed from our URL
|
|
||||||
_results = plugins.SCHEMA_MAP[schema].parse_url(_url)
|
|
||||||
if _results is None:
|
if _results is None:
|
||||||
# Setup dictionary
|
# Setup dictionary
|
||||||
_results = {
|
_results = {
|
||||||
|
@ -43,6 +43,7 @@ from ..common import NOTIFY_IMAGE_SIZES
|
|||||||
from ..common import NotifyType
|
from ..common import NotifyType
|
||||||
from ..common import NOTIFY_TYPES
|
from ..common import NOTIFY_TYPES
|
||||||
from ..utils import parse_list
|
from ..utils import parse_list
|
||||||
|
from ..utils import GET_SCHEMA_RE
|
||||||
from ..AppriseLocale import gettext_lazy as _
|
from ..AppriseLocale import gettext_lazy as _
|
||||||
from ..AppriseLocale import LazyTranslation
|
from ..AppriseLocale import LazyTranslation
|
||||||
|
|
||||||
@ -57,6 +58,9 @@ __all__ = [
|
|||||||
# NotifyEmail Base Module (used for NotifyEmail testing)
|
# NotifyEmail Base Module (used for NotifyEmail testing)
|
||||||
'NotifyEmailBase',
|
'NotifyEmailBase',
|
||||||
|
|
||||||
|
# Tokenizer
|
||||||
|
'url_to_dict',
|
||||||
|
|
||||||
# gntp (used for NotifyGrowl Testing)
|
# gntp (used for NotifyGrowl Testing)
|
||||||
'gntp',
|
'gntp',
|
||||||
]
|
]
|
||||||
@ -414,3 +418,47 @@ def details(plugin):
|
|||||||
'args': template_args,
|
'args': template_args,
|
||||||
'kwargs': template_kwargs,
|
'kwargs': template_kwargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def url_to_dict(url):
|
||||||
|
"""
|
||||||
|
Takes an apprise URL and returns the tokens associated with it
|
||||||
|
if they can be acquired based on the plugins available.
|
||||||
|
|
||||||
|
None is returned if the URL could not be parsed, otherwise the
|
||||||
|
tokens are returned.
|
||||||
|
|
||||||
|
These tokens can be loaded into apprise through it's add()
|
||||||
|
function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# swap hash (#) tag values with their html version
|
||||||
|
_url = url.replace('/#', '/%23')
|
||||||
|
|
||||||
|
# Attempt to acquire the schema at the very least to allow our plugins to
|
||||||
|
# determine if they can make a better interpretation of a URL geared for
|
||||||
|
# them.
|
||||||
|
schema = GET_SCHEMA_RE.match(_url)
|
||||||
|
if schema is None:
|
||||||
|
# Not a valid URL; take an early exit
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Ensure our schema is always in lower case
|
||||||
|
schema = schema.group('schema').lower()
|
||||||
|
if schema not in SCHEMA_MAP:
|
||||||
|
# Give the user the benefit of the doubt that the user may be using
|
||||||
|
# one of the URLs provided to them by their notification service.
|
||||||
|
# Before we fail for good, just scan all the plugins that support the
|
||||||
|
# native_url() parse function
|
||||||
|
results = \
|
||||||
|
next((r['plugin'].parse_native_url(_url)
|
||||||
|
for r in MODULE_MAP.values()
|
||||||
|
if r['plugin'].parse_native_url(_url) is not None),
|
||||||
|
None)
|
||||||
|
else:
|
||||||
|
# Parse our url details of the server object as dictionary
|
||||||
|
# containing all of the information parsed from our URL
|
||||||
|
results = SCHEMA_MAP[schema].parse_url(_url)
|
||||||
|
|
||||||
|
# Return our results
|
||||||
|
return results
|
||||||
|
@ -111,19 +111,26 @@ def test_config_base_config_parse_text():
|
|||||||
# A comment line over top of a URL
|
# A comment line over top of a URL
|
||||||
mailto://userb:pass@gmail.com
|
mailto://userb:pass@gmail.com
|
||||||
|
|
||||||
|
# Test a URL using it's native format; in this case Ryver
|
||||||
|
https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG
|
||||||
|
|
||||||
|
# Invalid URL as it's not associated with a plugin
|
||||||
|
# or a native url
|
||||||
|
https://not.a.native.url/
|
||||||
|
|
||||||
# A line with mulitiple tag assignments to it
|
# A line with mulitiple tag assignments to it
|
||||||
taga,tagb=kde://
|
taga,tagb=kde://
|
||||||
""", asset=AppriseAsset())
|
""", asset=AppriseAsset())
|
||||||
|
|
||||||
# We expect to parse 2 entries from the above
|
# We expect to parse 3 entries from the above
|
||||||
assert isinstance(result, list)
|
assert isinstance(result, list)
|
||||||
assert len(result) == 2
|
assert len(result) == 3
|
||||||
assert len(result[0].tags) == 0
|
assert len(result[0].tags) == 0
|
||||||
|
|
||||||
# Our second element will have tags associated with it
|
# Our last element will have 2 tags associated with it
|
||||||
assert len(result[1].tags) == 2
|
assert len(result[-1].tags) == 2
|
||||||
assert 'taga' in result[1].tags
|
assert 'taga' in result[-1].tags
|
||||||
assert 'tagb' in result[1].tags
|
assert 'tagb' in result[-1].tags
|
||||||
|
|
||||||
# Here is a similar result set however this one has an invalid line
|
# Here is a similar result set however this one has an invalid line
|
||||||
# in it which invalidates the entire file
|
# in it which invalidates the entire file
|
||||||
@ -347,11 +354,14 @@ version: 1
|
|||||||
urls:
|
urls:
|
||||||
- pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b
|
- pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b
|
||||||
- mailto://test:password@gmail.com
|
- mailto://test:password@gmail.com
|
||||||
|
- https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG
|
||||||
|
- https://not.a.native.url/
|
||||||
""", asset=asset)
|
""", asset=asset)
|
||||||
|
|
||||||
# We expect to parse 2 entries from the above
|
# We expect to parse 3 entries from the above
|
||||||
|
# The Ryver one is in a native form and the 4th one is invalid
|
||||||
assert isinstance(result, list)
|
assert isinstance(result, list)
|
||||||
assert len(result) == 2
|
assert len(result) == 3
|
||||||
assert len(result[0].tags) == 0
|
assert len(result[0].tags) == 0
|
||||||
|
|
||||||
# Valid Configuration
|
# Valid Configuration
|
||||||
@ -372,6 +382,12 @@ urls:
|
|||||||
# we'll accept it
|
# we'll accept it
|
||||||
- mailto://oscar:pass@gmail.com:
|
- mailto://oscar:pass@gmail.com:
|
||||||
|
|
||||||
|
# A Ryver URL (using Native format); still accepted
|
||||||
|
- https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG:
|
||||||
|
|
||||||
|
# An invalid URL with colon (ignored)
|
||||||
|
- https://not.a.native.url/:
|
||||||
|
|
||||||
# A telegram entry (returns a None in parse_url())
|
# A telegram entry (returns a None in parse_url())
|
||||||
- tgram://invalid
|
- tgram://invalid
|
||||||
|
|
||||||
@ -380,7 +396,7 @@ urls:
|
|||||||
# We expect to parse 4 entries from the above because the tgram:// entry
|
# We expect to parse 4 entries from the above because the tgram:// entry
|
||||||
# would have failed to be loaded
|
# would have failed to be loaded
|
||||||
assert isinstance(result, list)
|
assert isinstance(result, list)
|
||||||
assert len(result) == 4
|
assert len(result) == 5
|
||||||
assert len(result[0].tags) == 2
|
assert len(result[0].tags) == 2
|
||||||
|
|
||||||
# Global Tags
|
# Global Tags
|
||||||
|
Loading…
x
Reference in New Issue
Block a user