Bark Notification Support Added (#582)

This commit is contained in:
Chris Caron 2022-05-11 11:09:50 -04:00 committed by GitHub
parent d9b2ed5eee
commit ca0c8460f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 778 additions and 23 deletions

View File

@ -7,7 +7,7 @@
<!-- This section is only applicable if you're adding a new service -->
* [ ] apprise/plugins/Notify<!--ServiceName goes here-->.py
* [ ] setup.py
- add new service into the `keywords` section of the `setup()` declaration
- add new service into the `KEYWORDS` file located in the root directory
* [ ] README.md
- add entry for new service to table (as a quick reference)
* [ ] packaging/redhat/python-apprise.spec
@ -19,3 +19,27 @@
* [ ] There is no commented out code in this PR.
* [ ] No lint errors (use `flake8`)
* [ ] 100% test coverage
## Testing
<!-- If this your code is testable by other users of the program
it would be really helpful to define this here -->
Anyone can help test this source code as follows:
```bash
# Create a virtual environment to work in as follows:
python3 -m venv apprise
# Change into our new directory
cd apprise
# Activate our virtual environment
source bin/activate
# Install the branch
pip install git+https://github.com/caronc/apprise.git@<this.branch-name>
# Be sure you're running your Signal API Server and query it like so
apprise -t "Test Title" -b "Test Message" \
<apprise url related to ticket>
```

81
KEYWORDS Normal file
View File

@ -0,0 +1,81 @@
Alerts
API
AWS
Boxcar
Chat
CLI
ClickSend
DAPNET
Dbus
Dingtalk
Discord
Email
Emby
Faast
FCM
Flock
Gitter
Gnome
Google
Gotify
Growl
Guilded
Home Assistant
IFTTT
Join
Kavenegar
KODI
Kumulos
LaMetric
MacOS
Mailgun
Matrix
Mattermost
MessageBird
Microsoft
MQTT
MSG91
MSTeams
Nexmo
Nextcloud
NextcloudTalk
Notica
Notifico
Ntfy
Office365
OneSignal
Opsgenie
ParsePlatform
PopcornNotify
Prowl
PushBullet
Pushed
Pushjet
Push Notifications
Pushover
PushSafer
Reddit
Rocket.Chat
Ryver
SendGrid
ServerChan
SES
Signal
SimplePush
Sinch
Slack
SMTP2Go
SNS
SparkPost
Spontit
Streamlabs
Stride
Syslog
Techulus
Telegram
Twilio
Twist
Twitter
Webex
Windows
XBMC

View File

@ -1,4 +1,5 @@
include LICENSE
include KEYWORDS
include README.md
include requirements.txt
include win-requirements.txt

View File

@ -36,7 +36,8 @@ The table below identifies the services this tool supports and some example serv
| -------------------- | ---------- | ------------ | -------------- |
| [Apprise API](https://github.com/caronc/apprise/wiki/Notify_apprise_api) | apprise:// or apprises:// | (TCP) 80 or 443 | apprise://hostname/Token
| [AWS SES](https://github.com/caronc/apprise/wiki/Notify_ses) | ses:// | (TCP) 443 | ses://user@domain/AccessKeyID/AccessSecretKey/RegionName<br/>ses://user@domain/AccessKeyID/AccessSecretKey/RegionName/email1/email2/emailN
| [Boxcar](https://github.com/caronc/apprise/wiki/Notify_boxcar) | boxcar:// | (TCP) 443 | boxcar://hostname<br />boxcar://hostname/@tag<br/>boxcar://hostname/device_token<br />boxcar://hostname/device_token1/device_token2/device_tokenN<br />boxcar://hostname/@tag/@tag2/device_token
| [Bark](https://github.com/caronc/apprise/wiki/Notify_bark) | bark:// | (TCP) 80 or 443 | bark://hostname<br />bark://hostname/device_key<br />bark://hostname/device_key1/device_key2/device_keyN
| [Boxcar](https://github.com/caronc/apprise/wiki/Notify_bark) | boxcar:// | (TCP) 443 | boxcar://hostname<br />boxcar://hostname/@tag<br/>boxcar://hostname/device_token<br />boxcar://hostname/device_token1/device_token2/device_tokenN<br />boxcar://hostname/@tag/@tag2/device_token
| [Discord](https://github.com/caronc/apprise/wiki/Notify_discord) | discord:// | (TCP) 443 | discord://webhook_id/webhook_token<br />discord://avatar@webhook_id/webhook_token
| [Emby](https://github.com/caronc/apprise/wiki/Notify_emby) | emby:// or embys:// | (TCP) 8096 | emby://user@hostname/<br />emby://user:password@hostname
| [Enigma2](https://github.com/caronc/apprise/wiki/Notify_enigma2) | enigma2:// or enigma2s:// | (TCP) 80 or 443 | enigma2://hostname

View File

@ -0,0 +1,508 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
#
# This code is licensed under the MIT License.
#
# 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 :
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# 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.
#
# API: https://github.com/Finb/bark-server/blob/master/docs/API_V2.md#python
#
import six
import requests
import json
from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..common import NotifyImageSize
from ..common import NotifyType
from ..utils import parse_list
from ..utils import parse_bool
from ..AppriseLocale import gettext_lazy as _
# Sounds generated off of: https://github.com/Finb/Bark/tree/master/Sounds
BARK_SOUNDS = (
"alarm.caf",
"anticipate.caf",
"bell.caf",
"birdsong.caf",
"bloom.caf",
"calypso.caf",
"chime.caf",
"choo.caf",
"descent.caf",
"electronic.caf",
"fanfare.caf",
"glass.caf",
"gotosleep.caf",
"healthnotification.caf",
"horn.caf",
"ladder.caf",
"mailsent.caf",
"minuet.caf",
"multiwayinvitation.caf",
"newmail.caf",
"newsflash.caf",
"noir.caf",
"paymentsuccess.caf",
"shake.caf",
"sherwoodforest.caf",
"silence.caf",
"spell.caf",
"suspense.caf",
"telegraph.caf",
"tiptoes.caf",
"typewriters.caf",
"update.caf",
)
# Supported Level Entries
class NotifyBarkLevel(object):
"""
Defines the Bark Level options
"""
ACTIVE = 'active'
TIME_SENSITIVE = 'timeSensitive'
PASSIVE = 'passive'
BARK_LEVELS = (
NotifyBarkLevel.ACTIVE,
NotifyBarkLevel.TIME_SENSITIVE,
NotifyBarkLevel.PASSIVE,
)
class NotifyBark(NotifyBase):
"""
A wrapper for Notify Bark Notifications
"""
# The default descriptive name associated with the Notification
service_name = 'Bark'
# The services URL
service_url = 'https://github.com/Finb/Bark'
# The default protocol
protocol = 'bark'
# The default secure protocol
secure_protocol = 'barks'
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_bark'
# Allows the user to specify the NotifyImageSize object; this is supported
# through the webhook
image_size = NotifyImageSize.XY_128
# Define object templates
templates = (
'{schema}://{host}:{port}/{targets}',
'{schema}://{user}:{password}@{host}/{targets}',
'{schema}://{user}:{password}@{host}:{port}/{targets}',
'{schema}://{user}:{password}@{host}/{targets}',
)
# Define our template arguments
template_tokens = dict(NotifyBase.template_tokens, **{
'host': {
'name': _('Hostname'),
'type': 'string',
'required': True,
},
'port': {
'name': _('Port'),
'type': 'int',
'min': 1,
'max': 65535,
},
'user': {
'name': _('Username'),
'type': 'string',
},
'password': {
'name': _('Password'),
'type': 'string',
'private': True,
},
'target_device': {
'name': _('Target Device'),
'type': 'string',
'map_to': 'targets',
},
'targets': {
'name': _('Targets'),
'type': 'list:string',
},
})
# Define our template arguments
template_args = dict(NotifyBase.template_args, **{
'to': {
'alias_of': 'targets',
},
'sound': {
'name': _('Sound'),
'type': 'choice:string',
'values': BARK_SOUNDS,
},
'level': {
'name': _('Level'),
'type': 'choice:string',
'values': BARK_LEVELS,
},
'click': {
'name': _('Click'),
'type': 'string',
},
'badge': {
'name': _('Badge'),
'type': 'int',
'min': 0,
},
'category': {
'name': _('Category'),
'type': 'string',
},
'group': {
'name': _('Group'),
'type': 'string',
},
'image': {
'name': _('Include Image'),
'type': 'bool',
'default': True,
'map_to': 'include_image',
},
})
def __init__(self, targets=None, include_image=True, sound=None,
category=None, group=None, level=None, click=None,
badge=None, **kwargs):
"""
Initialize Notify Bark Object
"""
super(NotifyBark, self).__init__(**kwargs)
# Prepare our URL
self.notify_url = '%s://%s/push' % (
'https' if self.secure else 'http',
self.host,
)
if isinstance(self.port, int):
self.notify_url += ':%d' % self.port
# Assign our category
self.category = \
category if isinstance(category, six.string_types) else None
# Assign our group
self.group = group if isinstance(group, six.string_types) else None
# Initialize device list
self.targets = parse_list(targets)
# Place an image inline with the message body
self.include_image = include_image
# A clickthrough option for notifications
self.click = click
# Badge
try:
# Acquire our badge count if we can:
# - We accept both the integer form as well as a string
# representation
self.badge = int(badge)
if self.badge < 0:
raise ValueError()
except TypeError:
# NoneType means use Default; this is an okay exception
self.badge = None
except ValueError:
self.badge = None
self.logger.warning(
'The specified Bark badge ({}) is not valid ', badge)
# Sound (easy-lookup)
self.sound = None if not sound else next(
(f for f in BARK_SOUNDS if f.startswith(sound.lower())), None)
if sound and not self.sound:
self.logger.warning(
'The specified Bark sound ({}) was not found ', sound)
# Level
self.level = None if not level else next(
(f for f in BARK_LEVELS if f[0] == level[0]), None)
if level and not self.level:
self.logger.warning(
'The specified Bark level ({}) is not valid ', level)
return
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
"""
Perform Bark Notification
"""
# error tracking (used for function return)
has_error = False
if not len(self.targets):
# We have nothing to notify; we're done
self.logger.warning('There are no Bark devices to notify')
return False
# Prepare our headers
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json; charset=utf-8',
}
# Prepare our payload (sample below)
# {
# "body": "Test Bark Server",
# "device_key": "nysrshcqielvoxsa",
# "title": "bleem",
# "category": "category",
# "sound": "minuet.caf",
# "badge": 1,
# "icon": "https://day.app/assets/images/avatar.jpg",
# "group": "test",
# "url": "https://mritd.com"
# }
payload = {
'title': title if title else self.app_desc,
'body': body,
}
# Acquire our image url if configured to do so
image_url = None if not self.include_image else \
self.image_url(notify_type)
if image_url:
payload['icon'] = image_url
if self.sound:
payload['sound'] = self.sound
if self.click:
payload['url'] = self.click
if self.badge:
payload['badge'] = self.badge
if self.level:
payload['level'] = self.level
if self.category:
payload['category'] = self.category
if self.group:
payload['group'] = self.group
auth = None
if self.user:
auth = (self.user, self.password)
# Create a copy of the targets
targets = list(self.targets)
while len(targets) > 0:
# Retrieve our device key
target = targets.pop()
payload['device_key'] = target
self.logger.debug('Bark POST URL: %s (cert_verify=%r)' % (
self.notify_url, self.verify_certificate,
))
self.logger.debug('Bark Payload: %s' % str(payload))
# Always call throttle before any remote server i/o is made
self.throttle()
try:
r = requests.post(
self.notify_url,
data=json.dumps(payload),
headers=headers,
auth=auth,
verify=self.verify_certificate,
timeout=self.request_timeout,
)
if r.status_code != requests.codes.ok:
# We had a problem
status_str = \
NotifyBark.http_response_code_lookup(
r.status_code)
self.logger.warning(
'Failed to send Bark notification to {}: '
'{}{}error={}.'.format(
target,
status_str,
', ' if status_str else '',
r.status_code))
self.logger.debug(
'Response Details:\r\n{}'.format(r.content))
# Mark our failure
has_error = True
continue
else:
self.logger.info(
'Sent Bark notification to {}.'.format(target))
except requests.RequestException as e:
self.logger.warning(
'A Connection error occurred sending Bark '
'notification to {}.'.format(target))
self.logger.debug('Socket Exception: %s' % str(e))
# Mark our failure
has_error = True
continue
return not has_error
def url(self, privacy=False, *args, **kwargs):
"""
Returns the URL built dynamically based on specified arguments.
"""
# Define any URL parameters
params = {
'image': 'yes' if self.include_image else 'no',
}
if self.sound:
params['sound'] = self.sound
if self.click:
params['click'] = self.click
if self.badge:
params['badge'] = str(self.badge)
if self.level:
params['level'] = self.level
if self.category:
params['category'] = self.category
if self.group:
params['group'] = self.group
# Extend our parameters
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
# Determine Authentication
auth = ''
if self.user and self.password:
auth = '{user}:{password}@'.format(
user=NotifyBark.quote(self.user, safe=''),
password=self.pprint(
self.password, privacy, mode=PrivacyMode.Secret, safe=''),
)
elif self.user:
auth = '{user}@'.format(
user=NotifyBark.quote(self.user, safe=''),
)
default_port = 443 if self.secure else 80
return '{schema}://{auth}{hostname}{port}/{targets}?{params}'.format(
schema=self.secure_protocol if self.secure else self.protocol,
auth=auth,
# never encode hostname since we're expecting it to be a valid one
hostname=self.host,
port='' if self.port is None or self.port == default_port
else ':{}'.format(self.port),
targets='/'.join(
[NotifyBark.quote('{}'.format(x)) for x in self.targets]),
params=NotifyBark.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)
if not results:
# We're done early as we couldn't load the results
return results
# Apply our targets
results['targets'] = NotifyBark.split_path(results['fullpath'])
# Category
if 'category' in results['qsd'] and results['qsd']['category']:
results['category'] = NotifyBark.unquote(
results['qsd']['category'].strip())
# Group
if 'group' in results['qsd'] and results['qsd']['group']:
results['group'] = NotifyBark.unquote(
results['qsd']['group'].strip())
# Badge
if 'badge' in results['qsd'] and results['qsd']['badge']:
results['badge'] = NotifyBark.unquote(
results['qsd']['badge'].strip())
# Level
if 'level' in results['qsd'] and results['qsd']['level']:
results['level'] = NotifyBark.unquote(
results['qsd']['level'].strip())
# Click (URL)
if 'click' in results['qsd'] and results['qsd']['click']:
results['click'] = NotifyBark.unquote(
results['qsd']['click'].strip())
# Sound
if 'sound' in results['qsd'] and results['qsd']['sound']:
results['sound'] = NotifyBark.unquote(
results['qsd']['sound'].strip())
# The 'to' makes it easier to use yaml configuration
if 'to' in results['qsd'] and len(results['qsd']['to']):
results['targets'] += \
NotifyBark.parse_list(results['qsd']['to'])
# use image= for consistency with the other plugins
results['include_image'] = \
parse_bool(results['qsd'].get('image', True))
return results

View File

@ -274,7 +274,7 @@ class NotifyNtfy(NotifyBase):
self.logger.warning('There are no ntfy topics to notify')
return False
# Create a copy of the subreddits list
# Create a copy of the topics
topics = list(self.topics)
while len(topics) > 0:
# Retrieve our topic

View File

@ -47,16 +47,16 @@ Apprise is a Python package for simplifying access to all of the different
notification services that are out there. Apprise opens the door and makes
it easy to access:
Apprise API, AWS SES, AWS SNS, Boxcar, ClickSend, DAPNET, DingTalk, Discord,
E-Mail, Emby, Faast, FCM, Flock, Gitter, Google Chat, Gotify, Growl, Guilded, Home
Assistant, IFTTT, Join, Kavenegar, KODI, Kumulos, LaMetric, MacOSX, Mailgun,
Mattermost, Matrix, Microsoft Windows, Microsoft Teams, MessageBird, MQTT, MSG91,
MyAndroid, Nexmo, Nextcloud, NextcloudTalk, Notica, Notifico, ntfy, Office365,
OneSignal, Opsgenie, ParsePlatform, PopcornNotify, Prowl, Pushalot,
PushBullet, Pushjet, Pushover, PushSafer, Reddit, Rocket.Chat, SendGrid,
ServerChan, Signal, SimplePush, Sinch, Slack, SMTP2Go, Spontit, SparkPost,
Super Toasty, Streamlabs, Stride, Syslog, Techulus Push, Telegram, Twilio,
Twitter, Twist, XBMC, XMPP, Webex Teams}
Apprise API, AWS SES, AWS SNS, Bark, Boxcar, ClickSend, DAPNET, DingTalk,
Discord, E-Mail, Emby, Faast, FCM, Flock, Gitter, Google Chat, Gotify, Growl,
Guilded, Home Assistant, IFTTT, Join, Kavenegar, KODI, Kumulos, LaMetric,
MacOSX, Mailgun, Mattermost, Matrix, Microsoft Windows, Microsoft Teams,
MessageBird, MQTT, MSG91, MyAndroid, Nexmo, Nextcloud, NextcloudTalk, Notica,
Notifico, ntfy, Office365, OneSignal, Opsgenie, ParsePlatform, PopcornNotify,
Prowl, Pushalot, PushBullet, Pushjet, Pushover, PushSafer, Reddit,
Rocket.Chat, SendGrid, ServerChan, Signal, SimplePush, Sinch, Slack, SMTP2Go,
Spontit, SparkPost, Super Toasty, Streamlabs, Stride, Syslog, Techulus Push,
Telegram, Twilio, Twitter, Twist, XBMC, XMPP, Webex Teams}
Name: python-%{pypi_name}
Version: 0.9.8.3

View File

@ -24,6 +24,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import re
import os
import platform
try:
@ -69,16 +70,7 @@ setup(
long_description_content_type='text/markdown',
cmdclass=cmdclass,
url='https://github.com/caronc/apprise',
keywords='Push Notifications Alerts Email AWS SES SNS Boxcar ClickSend '
'DAPNET Dingtalk Discord Dbus Emby Faast FCM Flock Gitter Gnome '
'Google Chat Gotify Growl Guilded Home Assistant IFTTT Join Kavenegar '
'KODI Kumulos LaMetric MacOS Mailgun Matrix Mattermost MessageBird '
'MQTT MSG91 Nexmo Nextcloud NextcloudTalk Notica Notifico Ntfy '
'Office365 OneSignal Opsgenie ParsePlatform PopcornNotify Prowl '
'PushBullet Pushjet Pushed Pushover PushSafer Reddit Rocket.Chat '
'Ryver SendGrid ServerChan Signal SimplePush Sinch Slack SMTP2Go '
'SparkPost Spontit Streamlabs Stride Syslog Techulus Telegram Twilio '
'Twist Twitter XBMC MSTeams Microsoft Windows Webex CLI API',
keywords=' '.join(re.split(r'\s+', open('KEYWORDS').read())),
author='Chris Caron',
author_email='lead2gold@gmail.com',
packages=find_packages(),

148
test/test_plugin_bark.py Normal file
View File

@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2022 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
#
# This code is licensed under the MIT License.
#
# 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 :
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from apprise import plugins
from helpers import AppriseURLTester
# Disable logging for a cleaner testing output
import logging
logging.disable(logging.CRITICAL)
# Our Testing URLs
apprise_url_tests = (
('bark://', {
# No no host
'instance': None,
}),
('bark://:@/', {
# just invalid all around
'instance': None,
}),
('bark://localhost', {
# No Device Key specified
'instance': plugins.NotifyBark,
# Expected notify() response False (because we won't be able
# to actually notify anything if no device_key was specified
'notify_response': False,
}),
('bark://192.168.0.6:8081/device_key', {
# Everything is okay
'instance': plugins.NotifyBark,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'bark://192.168.0.6:8081/',
}),
('bark://user@192.168.0.6:8081/device_key', {
# Everything is okay (test with user)
'instance': plugins.NotifyBark,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'bark://user@192.168.0.6:8081/',
}),
('bark://192.168.0.6:8081/device_key/?sound=invalid', {
# bad sound, but we go ahead anyway
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?sound=alarm', {
# alarm.caf sound loaded
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?sound=NOiR.cAf', {
# noir.caf sound loaded
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?badge=100', {
# set badge
'instance': plugins.NotifyBark,
}),
('barks://192.168.0.6:8081/device_key/?badge=invalid', {
# set invalid badge
'instance': plugins.NotifyBark,
}),
('barks://192.168.0.6:8081/device_key/?badge=-12', {
# set invalid badge
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?category=apprise', {
# set category
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?image=no', {
# do not display image
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?group=apprise', {
# set group
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?level=invalid', {
# bad level, but we go ahead anyway
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/?to=device_key', {
# test use of to= argument
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?click=http://localhost', {
# Our click link
'instance': plugins.NotifyBark,
}),
('bark://192.168.0.6:8081/device_key/?level=active', {
# active level
'instance': plugins.NotifyBark,
}),
('bark://user:pass@192.168.0.5:8086/device_key/device_key2/', {
# Everything is okay
'instance': plugins.NotifyBark,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'bark://user:****@192.168.0.5:8086/',
}),
('barks://192.168.0.7/device_key/', {
'instance': plugins.NotifyBark,
# throw a bizzare code forcing us to fail to look it up
'response': False,
'requests_response_code': 999,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'barks://192.168.0.7/device_key',
}),
('bark://192.168.0.7/device_key', {
'instance': plugins.NotifyBark,
# Throws a series of connection and transfer exceptions when this flag
# is set and tests that we gracfully handle them
'test_requests_exceptions': True,
}),
)
def test_plugin_bark_urls():
"""
NotifyBark() Apprise URLs
"""
# Run our general tests
AppriseURLTester(tests=apprise_url_tests).run_all()