Lametric Time cloud mode support fixed (#293)

This commit is contained in:
Chris Caron 2020-09-13 22:13:27 -04:00 committed by GitHub
parent f1bd97a259
commit 49faa9a201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 285 additions and 147 deletions

View File

@ -47,7 +47,7 @@ The table below identifies the services this tool supports and some example serv
| [Join](https://github.com/caronc/apprise/wiki/Notify_join) | join:// | (TCP) 443 | join://apikey/device<br />join://apikey/device1/device2/deviceN/<br />join://apikey/group<br />join://apikey/groupA/groupB/groupN<br />join://apikey/DeviceA/groupA/groupN/DeviceN/ | [Join](https://github.com/caronc/apprise/wiki/Notify_join) | join:// | (TCP) 443 | join://apikey/device<br />join://apikey/device1/device2/deviceN/<br />join://apikey/group<br />join://apikey/groupA/groupB/groupN<br />join://apikey/DeviceA/groupA/groupN/DeviceN/
| [KODI](https://github.com/caronc/apprise/wiki/Notify_kodi) | kodi:// or kodis:// | (TCP) 8080 or 443 | kodi://hostname<br />kodi://user@hostname<br />kodi://user:password@hostname:port | [KODI](https://github.com/caronc/apprise/wiki/Notify_kodi) | kodi:// or kodis:// | (TCP) 8080 or 443 | kodi://hostname<br />kodi://user@hostname<br />kodi://user:password@hostname:port
| [Kumulos](https://github.com/caronc/apprise/wiki/Notify_kumulos) | kumulos:// | (TCP) 443 | kumulos://apikey/serverkey | [Kumulos](https://github.com/caronc/apprise/wiki/Notify_kumulos) | kumulos:// | (TCP) 443 | kumulos://apikey/serverkey
| [LaMetric](https://github.com/caronc/apprise/wiki/Notify_lametric) | lametric:// | (TCP) 443 | lametric://apikey@device_ipaddr<br/>lametric://apikey@hostname:port<br/>lametric://client_id@client_secret | [LaMetric Time](https://github.com/caronc/apprise/wiki/Notify_lametric) | lametric:// | (TCP) 443 | lametric://apikey@device_ipaddr<br/>lametric://apikey@hostname:port<br/>lametric://client_id@client_secret
| [Mailgun](https://github.com/caronc/apprise/wiki/Notify_mailgun) | mailgun:// | (TCP) 443 | mailgun://user@hostname/apikey<br />mailgun://user@hostname/apikey/email<br />mailgun://user@hostname/apikey/email1/email2/emailN<br />mailgun://user@hostname/apikey/?name="From%20User" | [Mailgun](https://github.com/caronc/apprise/wiki/Notify_mailgun) | mailgun:// | (TCP) 443 | mailgun://user@hostname/apikey<br />mailgun://user@hostname/apikey/email<br />mailgun://user@hostname/apikey/email1/email2/emailN<br />mailgun://user@hostname/apikey/?name="From%20User"
| [Matrix](https://github.com/caronc/apprise/wiki/Notify_matrix) | matrix:// or matrixs:// | (TCP) 80 or 443 | matrix://hostname<br />matrix://user@hostname<br />matrixs://user:pass@hostname:port/#room_alias<br />matrixs://user:pass@hostname:port/!room_id<br />matrixs://user:pass@hostname:port/#room_alias/!room_id/#room2<br />matrixs://token@hostname:port/?webhook=matrix<br />matrix://user:token@hostname/?webhook=slack&format=markdown | [Matrix](https://github.com/caronc/apprise/wiki/Notify_matrix) | matrix:// or matrixs:// | (TCP) 80 or 443 | matrix://hostname<br />matrix://user@hostname<br />matrixs://user:pass@hostname:port/#room_alias<br />matrixs://user:pass@hostname:port/!room_id<br />matrixs://user:pass@hostname:port/#room_alias/!room_id/#room2<br />matrixs://token@hostname:port/?webhook=matrix<br />matrix://user:token@hostname/?webhook=slack&format=markdown
| [Mattermost](https://github.com/caronc/apprise/wiki/Notify_mattermost) | mmost:// | (TCP) 8065 | mmost://hostname/authkey<br />mmost://hostname:80/authkey<br />mmost://user@hostname:80/authkey<br />mmost://hostname/authkey?channel=channel<br />mmosts://hostname/authkey<br />mmosts://user@hostname/authkey<br /> | [Mattermost](https://github.com/caronc/apprise/wiki/Notify_mattermost) | mmost:// | (TCP) 8065 | mmost://hostname/authkey<br />mmost://hostname:80/authkey<br />mmost://user@hostname:80/authkey<br />mmost://hostname/authkey?channel=channel<br />mmosts://hostname/authkey<br />mmosts://user@hostname/authkey<br />

View File

@ -27,15 +27,39 @@
# website. it can be done as follows: # website. it can be done as follows:
# Cloud Mode: # Cloud Mode:
# 1. Sign Up and login to the developer webpage https://developer.lametric.com # - Sign Up and login to the developer webpage https://developer.lametric.com
# 2. Create a **Notification App** if you haven't already done so from: #
# https://developer.lametric.com/applications/sources # - Create a **Indicator App** if you haven't already done so from here:
# 3. Provide it an app name, a description and privacy URL (which can point to # https://developer.lametric.com/applications/sources
# anywhere; I set mine to `http://localhost`). No permissions are #
# required. # There is a great official tutorial on how to do this here:
# 4. Access your newly created app so that you can acquire both the # https://lametric-documentation.readthedocs.io/en/latest/\
# **Client ID** and the **Client Secret** here: # guides/first-steps/first-lametric-indicator-app.html
# https://developer.lametric.com/applications/sources #
# - Make sure to set the **Communication Type** to **PUSH**.
#
# - You will be able to **Publish** your app once you've finished setting it
# up. This will allow it to be accessible from the internet using the
# `cloud` mode of this Apprise Plugin. The **Publish** button shows up
# from within the settings of your Lametric App upon clicking on the
# **Draft Vx** folder (where `x` is the version - usually a 1)
#
# When you've completed, the site would have provided you a **PUSH URL** that
# looks like this:
# https://developer.lametric.com/api/v1/dev/widget/update/\
# com.lametric.{app_id}/{app_ver}
#
# You will need to record the `{app_id}` and `{app_ver}` to use the `cloud`
# mode.
#
# The same page should also provide you with an **Access Token**. It's
# approximately 86 characters with two equal (`=`) characters at the end of it.
# This becomes your `{app_token}`. Here is an example of what one might
# look like:
# K2MxWI0NzU0ZmI2NjJlZYTgViMDgDRiN8YjlmZjRmNTc4NDVhJzk0RiNjNh0EyKWW==`
#
# The syntax for the cloud mode is:
# * `lametric://{app_token}@{app_id}/{app_ver}?mode=cloud`
# Device Mode: # Device Mode:
# - Sign Up and login to the developer webpage https://developer.lametric.com # - Sign Up and login to the developer webpage https://developer.lametric.com
@ -44,11 +68,14 @@
# - From here you can get your your API Key for the device you plan to notify. # - From here you can get your your API Key for the device you plan to notify.
# - Your devices IP Address can be found in LaMetric Time app at: # - Your devices IP Address can be found in LaMetric Time app at:
# Settings -> Wi-Fi -> IP Address # Settings -> Wi-Fi -> IP Address
#
# The syntax for the device mode is:
# * `lametric://{apikey}@{host}`
# A great source for API examples (Device Mode): # A great source for API examples (Device Mode):
# - https://lametric-documentation.readthedocs.io/en/latest/reference-docs\ # - https://lametric-documentation.readthedocs.io/en/latest/reference-docs\
# /device-notifications.html # /device-notifications.html
#
# A great source for API examples (Cloud Mode): # A great source for API examples (Cloud Mode):
# - https://lametric-documentation.readthedocs.io/en/latest/reference-docs\ # - https://lametric-documentation.readthedocs.io/en/latest/reference-docs\
# /lametric-cloud-reference.html # /lametric-cloud-reference.html
@ -56,18 +83,26 @@
# A great source for the icon reference: # A great source for the icon reference:
# - https://developer.lametric.com/icons # - https://developer.lametric.com/icons
import re import re
import six import six
import requests import requests
from json import dumps from json import dumps
from .NotifyBase import NotifyBase from .NotifyBase import NotifyBase
from ..URLBase import PrivacyMode
from ..common import NotifyType from ..common import NotifyType
from ..utils import validate_regex from ..utils import validate_regex
from ..AppriseLocale import gettext_lazy as _ from ..AppriseLocale import gettext_lazy as _
from ..utils import is_hostname from ..utils import is_hostname
from ..utils import is_ipaddr from ..utils import is_ipaddr
# A URL Parser to detect App ID
LAMETRIC_APP_ID_DETECTOR_RE = re.compile(
r'(com\.lametric\.)?(?P<app_id>[0-9a-z.-]{1,64})'
r'(/(?P<app_ver>[1-9][0-9]*))?', re.I)
# Tokens are huge
LAMETRIC_IS_APP_TOKEN = re.compile(r'^[a-z0-9]{80,}==$', re.I)
class LametricMode(object): class LametricMode(object):
""" """
@ -295,7 +330,7 @@ class NotifyLametric(NotifyBase):
# URL used for notifying Lametric App's created in the Dev Portal # URL used for notifying Lametric App's created in the Dev Portal
cloud_notify_url = 'https://developer.lametric.com/api/v1' \ cloud_notify_url = 'https://developer.lametric.com/api/v1' \
'/dev/widget/update/com.lametric.{client_id}' '/dev/widget/update/com.lametric.{app_id}/{app_ver}'
# URL used for local notifications directly to the device # URL used for local notifications directly to the device
device_notify_url = '{schema}://{host}{port}/api/v2/device/notifications' device_notify_url = '{schema}://{host}{port}/api/v2/device/notifications'
@ -323,8 +358,9 @@ class NotifyLametric(NotifyBase):
# Define object templates # Define object templates
templates = ( templates = (
# App Mode # Cloud (App) Mode
'{schema}://{client_id}@{secret}', '{schema}://{app_token}@{app_id}',
'{schema}://{app_token}@{app_id}/{app_ver}',
# Device Mode # Device Mode
'{schema}://{apikey}@{host}', '{schema}://{apikey}@{host}',
@ -334,11 +370,31 @@ class NotifyLametric(NotifyBase):
# Define our template tokens # Define our template tokens
template_tokens = dict(NotifyBase.template_tokens, **{ template_tokens = dict(NotifyBase.template_tokens, **{
# Used for Local Device mode
'apikey': { 'apikey': {
'name': _('Device API Key'), 'name': _('Device API Key'),
'type': 'string', 'type': 'string',
'private': True, 'private': True,
}, },
# Used for Cloud mode
'app_id': {
'name': _('App ID'),
'type': 'string',
'private': True,
},
# Used for Cloud mode
'app_ver': {
'name': _('App Version'),
'type': 'string',
'regex': (r'^[1-9][0-9]*$', ''),
'default': '1',
},
# Used for Cloud mode
'app_token': {
'name': _('App Access Token'),
'type': 'string',
'regex': (r'^[A-Z0-9]{80,}==$', 'i'),
},
'host': { 'host': {
'name': _('Hostname'), 'name': _('Hostname'),
'type': 'string', 'type': 'string',
@ -355,30 +411,22 @@ class NotifyLametric(NotifyBase):
'name': _('Username'), 'name': _('Username'),
'type': 'string', 'type': 'string',
}, },
'client_id': {
'name': _('Client ID'),
'type': 'string',
'private': True,
'regex': (r'^[a-z0-9-]+$', 'i'),
},
'secret': {
'name': _('Client Secret'),
'type': 'string',
'private': True,
},
}) })
# Define our template arguments # Define our template arguments
template_args = dict(NotifyBase.template_args, **{ template_args = dict(NotifyBase.template_args, **{
'oauth_id': {
'alias_of': 'client_id',
},
'oauth_secret': {
'alias_of': 'secret',
},
'apikey': { 'apikey': {
'alias_of': 'apikey', 'alias_of': 'apikey',
}, },
'app_id': {
'alias_of': 'app_id',
},
'app_ver': {
'alias_of': 'app_ver',
},
'app_token': {
'alias_of': 'app_token',
},
'priority': { 'priority': {
'name': _('Priority'), 'name': _('Priority'),
'type': 'choice:string', 'type': 'choice:string',
@ -414,9 +462,9 @@ class NotifyLametric(NotifyBase):
}, },
}) })
def __init__(self, apikey=None, client_id=None, secret=None, priority=None, def __init__(self, apikey=None, app_token=None, app_id=None,
icon=None, icon_type=None, sound=None, mode=None, app_ver=None, priority=None, icon=None, icon_type=None,
cycles=None, **kwargs): sound=None, mode=None, cycles=None, **kwargs):
""" """
Initialize LaMetric Object Initialize LaMetric Object
""" """
@ -426,41 +474,61 @@ class NotifyLametric(NotifyBase):
if isinstance(mode, six.string_types) \ if isinstance(mode, six.string_types) \
else self.template_args['mode']['default'] else self.template_args['mode']['default']
# Default Cloud Argument
self.lametric_app_id = None
self.lametric_app_ver = None
self.lametric_app_access_token = None
# Default Device/Cloud Argument
self.lametric_apikey = None
if self.mode not in LAMETRIC_MODES: if self.mode not in LAMETRIC_MODES:
msg = 'An invalid LaMetric Mode ({}) was specified.'.format(mode) msg = 'An invalid LaMetric Mode ({}) was specified.'.format(mode)
self.logger.warning(msg) self.logger.warning(msg)
raise TypeError(msg) raise TypeError(msg)
# Default Cloud Arguments
self.secret = None
self.client_id = None
# Default Device Arguments
self.apikey = None
if self.mode == LametricMode.CLOUD: if self.mode == LametricMode.CLOUD:
# Client ID try:
self.client_id = validate_regex( results = LAMETRIC_APP_ID_DETECTOR_RE.match(app_id)
client_id, *self.template_tokens['client_id']['regex']) except TypeError:
if not self.client_id: msg = 'An invalid LaMetric Application ID ' \
msg = 'An invalid LaMetric Client OAuth2 ID ' \ '({}) was specified.'.format(app_id)
'({}) was specified.'.format(client_id)
self.logger.warning(msg) self.logger.warning(msg)
raise TypeError(msg) raise TypeError(msg)
# Client Secret # Detect our Access Token
self.secret = validate_regex(secret) self.lametric_app_access_token = validate_regex(
if not self.secret: app_token,
msg = 'An invalid LaMetric Client OAuth2 Secret ' \ *self.template_tokens['app_token']['regex'])
'({}) was specified.'.format(secret) if not self.lametric_app_access_token:
msg = 'An invalid LaMetric Application Access Token ' \
'({}) was specified.'.format(app_token)
self.logger.warning(msg) self.logger.warning(msg)
raise TypeError(msg) raise TypeError(msg)
else: # LametricMode.DEVICE # If app_ver is specified, it over-rides all
if app_ver:
self.lametric_app_ver = validate_regex(
app_ver, *self.template_tokens['app_ver']['regex'])
if not self.lametric_app_ver:
msg = 'An invalid LaMetric Application Version ' \
'({}) was specified.'.format(app_ver)
self.logger.warning(msg)
raise TypeError(msg)
# API Key else:
self.apikey = validate_regex(apikey) # If app_ver wasn't specified, we parse it from the
if not self.apikey: # Application ID
self.lametric_app_ver = results.group('app_ver') \
if results.group('app_ver') else \
self.template_tokens['app_ver']['default']
# Store our Application ID
self.lametric_app_id = results.group('app_id')
if self.mode == LametricMode.DEVICE:
self.lametric_apikey = validate_regex(apikey)
if not self.lametric_apikey:
msg = 'An invalid LaMetric Device API Key ' \ msg = 'An invalid LaMetric Device API Key ' \
'({}) was specified.'.format(apikey) '({}) was specified.'.format(apikey)
self.logger.warning(msg) self.logger.warning(msg)
@ -522,8 +590,7 @@ class NotifyLametric(NotifyBase):
# Update header entries # Update header entries
headers.update({ headers.update({
'X-Access-Token': self.secret, 'X-Access-Token': self.lametric_apikey,
'Cache-Control': 'no-cache',
}) })
if self.sound: if self.sound:
@ -555,12 +622,14 @@ class NotifyLametric(NotifyBase):
{ {
"icon": icon, "icon": icon,
"text": body, "text": body,
"index": 0,
} }
] ]
} }
# Prepare our Cloud Notify URL # Prepare our Cloud Notify URL
notify_url = self.cloud_notify_url.format(client_id=self.client_id) notify_url = self.cloud_notify_url.format(
app_id=self.lametric_app_id, app_ver=self.lametric_app_ver)
# Return request parameters # Return request parameters
return (notify_url, None, payload) return (notify_url, None, payload)
@ -646,6 +715,7 @@ class NotifyLametric(NotifyBase):
'User-Agent': self.app_id, 'User-Agent': self.app_id,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/json', 'Accept': 'application/json',
'Cache-Control': 'no-cache',
} }
# Depending on the mode, the payload is gathered by # Depending on the mode, the payload is gathered by
@ -730,11 +800,12 @@ class NotifyLametric(NotifyBase):
if self.mode == LametricMode.CLOUD: if self.mode == LametricMode.CLOUD:
# Upstream/LaMetric App Return # Upstream/LaMetric App Return
return '{schema}://{client_id}@{secret}/?{params}'.format( return '{schema}://{token}@{app_id}/{app_ver}/?{params}'.format(
schema=self.protocol, schema=self.protocol,
client_id=self.pprint(self.client_id, privacy, safe=''), token=self.pprint(
secret=self.pprint( self.lametric_app_access_token, privacy, safe=''),
self.secret, privacy, mode=PrivacyMode.Secret, safe=''), app_id=self.pprint(self.lametric_app_id, privacy, safe=''),
app_ver=NotifyLametric.quote(self.lametric_app_ver, safe=''),
params=NotifyLametric.urlencode(params)) params=NotifyLametric.urlencode(params))
# #
@ -758,11 +829,11 @@ class NotifyLametric(NotifyBase):
if self.user and self.password: if self.user and self.password:
auth = '{user}:{apikey}@'.format( auth = '{user}:{apikey}@'.format(
user=NotifyLametric.quote(self.user, safe=''), user=NotifyLametric.quote(self.user, safe=''),
apikey=self.pprint(self.apikey, privacy, safe=''), apikey=self.pprint(self.lametric_apikey, privacy, safe=''),
) )
else: # self.apikey is set else: # self.apikey is set
auth = '{apikey}@'.format( auth = '{apikey}@'.format(
apikey=self.pprint(self.apikey, privacy, safe=''), apikey=self.pprint(self.lametric_apikey, privacy, safe=''),
) )
# Local Return # Local Return
@ -799,64 +870,91 @@ class NotifyLametric(NotifyBase):
results['user'] = None results['user'] = None
# Priority Handling # Priority Handling
if 'priority' in results['qsd'] and len(results['qsd']['priority']): if 'priority' in results['qsd'] and results['qsd']['priority']:
results['priority'] = results['qsd']['priority'].strip().lower() results['priority'] = NotifyLametric.unquote(
results['qsd']['priority'].strip().lower())
# Icon Type # Icon Type
if 'icon' in results['qsd'] and len(results['qsd']['icon']): if 'icon' in results['qsd'] and results['qsd']['icon']:
results['icon'] = results['qsd']['icon'].strip().lower() results['icon'] = NotifyLametric.unquote(
results['qsd']['icon'].strip().lower())
# Icon Type # Icon Type
if 'icon_type' in results['qsd'] and len(results['qsd']['icon_type']): if 'icon_type' in results['qsd'] and results['qsd']['icon_type']:
results['icon_type'] = results['qsd']['icon_type'].strip().lower() results['icon_type'] = NotifyLametric.unquote(
results['qsd']['icon_type'].strip().lower())
# Sound # Sound
if 'sound' in results['qsd'] and len(results['qsd']['sound']): if 'sound' in results['qsd'] and results['qsd']['sound']:
results['sound'] = results['qsd']['sound'].strip().lower() results['sound'] = NotifyLametric.unquote(
results['qsd']['sound'].strip().lower())
# We can detect the mode based on the validity of the hostname
results['mode'] = LametricMode.DEVICE \
if (is_hostname(results['host']) or
is_ipaddr(results['host'])) else LametricMode.CLOUD
# Mode override
if 'mode' in results['qsd'] and len(results['qsd']['mode']):
results['mode'] = NotifyLametric.unquote(results['qsd']['mode'])
# API Key (Device Mode) # API Key (Device Mode)
if 'apikey' in results['qsd'] and results['qsd']['apikey']:
# Extract API Key from an argument
results['apikey'] = \
NotifyLametric.unquote(results['qsd']['apikey'])
# App ID
if 'app' in results['qsd'] \
and results['qsd']['app']:
# Extract the App ID from an argument
results['app_id'] = \
NotifyLametric.unquote(results['qsd']['app'])
# App Version
if 'app_ver' in results['qsd'] \
and results['qsd']['app_ver']:
# Extract the App ID from an argument
results['app_ver'] = \
NotifyLametric.unquote(results['qsd']['app_ver'])
if 'token' in results['qsd'] and results['qsd']['token']:
# Extract Application Access Token from an argument
results['app_token'] = \
NotifyLametric.unquote(results['qsd']['token'])
# Mode override
if 'mode' in results['qsd'] and results['qsd']['mode']:
results['mode'] = NotifyLametric.unquote(
results['qsd']['mode'].strip().lower())
else:
# We can try to detect the mode based on the validity of the
# hostname. We can also scan the validity of the Application
# Access token
#
# This isn't a surfire way to do things though; it's best to
# specify the mode= flag
results['mode'] = LametricMode.DEVICE \
if ((is_hostname(results['host']) or
is_ipaddr(results['host'])) and
# make sure password is not an Access Token
(results['password'] and not
LAMETRIC_IS_APP_TOKEN.match(results['password'])) and
# Scan for app_ flags
next((f for f in results.keys() \
if f.startswith('app_')), None) is None) \
else LametricMode.CLOUD
# Handle defaults if not set
if results['mode'] == LametricMode.DEVICE: if results['mode'] == LametricMode.DEVICE:
if 'apikey' in results['qsd'] and len(results['qsd']['apikey']): # Device Mode Defaults
# Extract API Key from an argument if 'apikey' not in results:
results['apikey'] = \
NotifyLametric.unquote(results['qsd']['apikey'])
else:
results['apikey'] = \ results['apikey'] = \
NotifyLametric.unquote(results['password']) NotifyLametric.unquote(results['password'])
elif results['mode'] == LametricMode.CLOUD: else:
# OAuth2 ID (Cloud Mode) # CLOUD Mode Defaults
if 'oauth_id' in results['qsd'] \ if 'app_id' not in results:
and len(results['qsd']['oauth_id']): results['app_id'] = \
# Extract the OAuth2 Key from an argument
results['client_id'] = \
NotifyLametric.unquote(results['qsd']['oauth_id'])
else:
results['client_id'] = \
NotifyLametric.unquote(results['password'])
# OAuth2 Secret (Cloud Mode)
if 'oauth_secret' in results['qsd'] and \
len(results['qsd']['oauth_secret']):
# Extract the API Secret from an argument
results['secret'] = \
NotifyLametric.unquote(results['qsd']['oauth_secret'])
else:
results['secret'] = \
NotifyLametric.unquote(results['host']) NotifyLametric.unquote(results['host'])
if 'app_token' not in results:
results['app_token'] = \
NotifyLametric.unquote(results['password'])
# Set cycles # Set cycles
try: try:
@ -867,3 +965,38 @@ class NotifyLametric(NotifyBase):
pass pass
return results return results
@staticmethod
def parse_native_url(url):
"""
Support
https://developer.lametric.com/api/v1/dev/\
widget/update/com.lametric.{APP_ID}/1
https://developer.lametric.com/api/v1/dev/\
widget/update/com.lametric.{APP_ID}/{APP_VER}
"""
# If users do provide the Native URL they wll also want to add
# ?token={APP_ACCESS_TOKEN} to the parameters at the end or the
# URL will fail to load in later stages.
result = re.match(
r'^http(?P<secure>s)?://(?P<host>[^/]+)'
r'/api/(?P<api_ver>v[1-9]*[0-9]+)'
r'/dev/widget/update/'
r'com\.lametric\.(?P<app_id>[0-9a-z.-]{1,64})'
r'(/(?P<app_ver>[1-9][0-9]*))?/?'
r'(?P<params>\?.+)?$', url, re.I)
if result:
return NotifyLametric.parse_url(
'{schema}://{app_id}{app_ver}/{params}'.format(
schema=NotifyLametric.secure_protocol
if result.group('secure') else NotifyLametric.protocol,
app_id=result.group('app_id'),
app_ver='/{}'.format(result.group('app_ver'))
if result.group('app_ver') else '',
params='' if not result.group('params')
else result.group('params')))
return None

View File

@ -1245,16 +1245,17 @@ TEST_URLS = (
# NotifyLametric # NotifyLametric
################################## ##################################
('lametric://', { ('lametric://', {
# No APIKey or Client ID/Secret specified # No APIKey or App ID specified
'instance': TypeError, 'instance': TypeError,
}), }),
('lametric://:@/', { ('lametric://:@/', {
# No APIKey or Client ID/Secret specified # No APIKey or App ID specified
'instance': TypeError, 'instance': TypeError,
}), }),
('lametric://{}/'.format(UUID4), { ('lametric://{}/'.format(
# No APIKey or Client ID specified 'com.lametric.941c51dff3135bd87aa72db9d855dd50'), {
'instance': TypeError, # No APIKey specified
'instance': TypeError,
}), }),
('lametric://root:{}@192.168.0.5:8080/'.format(UUID4), { ('lametric://root:{}@192.168.0.5:8080/'.format(UUID4), {
# Everything is okay; this would be picked up in Device Mode # Everything is okay; this would be picked up in Device Mode
@ -1286,6 +1287,16 @@ TEST_URLS = (
# Our expected url(privacy=True) startswith() response: # Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametrics://8...2@192.168.0.6/', 'privacy_url': 'lametrics://8...2@192.168.0.6/',
}), }),
# Support Native URL (with Access Token Argument)
('https://developer.lametric.com/api/v1/dev/widget/update/'
'com.lametric.ABCD123/1?token={}=='.format('D' * 88), {
# Everything is okay; Device mode forced
'instance': plugins.NotifyLametric,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://D...=@A...3/1/',
}),
('lametric://192.168.2.8/?mode=device&apikey=abc123', { ('lametric://192.168.2.8/?mode=device&apikey=abc123', {
# Everything is okay; Device mode forced # Everything is okay; Device mode forced
'instance': plugins.NotifyLametric, 'instance': plugins.NotifyLametric,
@ -1293,29 +1304,38 @@ TEST_URLS = (
# Our expected url(privacy=True) startswith() response: # Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://a...3@192.168.2.8/', 'privacy_url': 'lametric://a...3@192.168.2.8/',
}), }),
('lametrics://{}@abcd==/?mode=cloud'.format(UUID4), { ('lametrics://{}==@com.lametric.941c51dff3135bd87aa72db9d855dd50/'
# Everything is okay; Cloud mode forced '?mode=cloud&app_ver=2'.format('A' * 88), {
'instance': plugins.NotifyLametric, # Everything is okay; Cloud mode forced
# We gracefully strip off the com.lametric. part as well
# We also set an application version of 2
'instance': plugins.NotifyLametric,
# Our expected url(privacy=True) startswith() response: # Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://8...2@****/', 'privacy_url': 'lametric://A...=@9...0/',
}), }),
('lametric://_/?mode=cloud&oauth_id=abcd&oauth_secret=1234&cycles=3', { ('lametrics://{}==@com.lametric.941c51dff3135bd87aa72db9d855dd50/'
# Everything is okay; Cloud mode forced '?app_ver=invalid'.format('A' * 88), {
# arguments used on URL path # We set invalid app version
'instance': plugins.NotifyLametric, 'instance': TypeError,
}),
# our lametric object initialized via argument
('lametric://?app=com.lametric.941c51dff3135bd87aa72db9d855dd50&token={}=='
'&mode=cloud'.format('B' * 88), {
# Everything is okay; Cloud mode forced
'instance': plugins.NotifyLametric,
# Our expected url(privacy=True) startswith() response: # Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://a...d@****/', 'privacy_url': 'lametric://B...=@9...0/',
}), }),
('lametrics://{}@abcd==/?mode=cloud&sound=knock&icon_type=info' ('lametrics://{}==@abcd/?mode=cloud&sound=knock&icon_type=info'
'&priority=critical'.format(UUID4), { '&priority=critical&cycles=10'.format('C' * 88), {
# Cloud mode forced, sound, icon_type, and priority not supported # Cloud mode forced, sound, icon_type, and priority not supported
# with cloud mode so warnings are created # with cloud mode so warnings are created
'instance': plugins.NotifyLametric, 'instance': plugins.NotifyLametric,
# Our expected url(privacy=True) startswith() response: # Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://8...2@****/', 'privacy_url': 'lametric://C...=@a...d/',
}), }),
('lametrics://{}@192.168.0.7/?mode=invalid'.format(UUID4), { ('lametrics://{}@192.168.0.7/?mode=invalid'.format(UUID4), {
# Invalid Mode # Invalid Mode
@ -1385,21 +1405,6 @@ TEST_URLS = (
# Invalid priority just produce warnings... object still loads # Invalid priority just produce warnings... object still loads
'instance': plugins.NotifyLametric, 'instance': plugins.NotifyLametric,
}), }),
('lametric://{}@{}/'.format(
UUID4, 'YWosnkdnoYREsdogfoSDff734kjsfbweo7r434597FYODIoicosdonnreiuhvd'
'ciuhouerhohcd8sds89fdRw=='), {
# Everything is okay; this would be picked up in Cloud Mode
'instance': plugins.NotifyLametric,
# Our expected url(privacy=True) startswith() response:
'privacy_url': 'lametric://8...2@****/',
}),
('lametric://{}@{}/'.format(
UUID4, 'YWosnkdnoYREsdogfoSDff734kjsfbweo7r434597FYODIoicosdonnreiuhvd'
'ciuhouerhohcd8sds89fdRw==?icon=Heart'), {
# Cloude mode with the icon over-ride
'instance': plugins.NotifyLametric,
}),
('lametric://{}@example.com/'.format(UUID4), { ('lametric://{}@example.com/'.format(UUID4), {
'instance': plugins.NotifyLametric, 'instance': plugins.NotifyLametric,
# force a failure # force a failure