mirror of
https://github.com/caronc/apprise.git
synced 2025-02-06 05:19:15 +01:00
Google Chat Thread-Key support (#753)
This commit is contained in:
parent
2912dfd1e3
commit
fc16c7bf0b
@ -80,8 +80,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 +95,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 +118,11 @@ class NotifyGoogleChat(NotifyBase):
|
||||
'private': True,
|
||||
'required': True,
|
||||
},
|
||||
'thread_key': {
|
||||
'name': _('Thread Key'),
|
||||
'type': 'string',
|
||||
'private': True,
|
||||
},
|
||||
})
|
||||
|
||||
# Define our template arguments
|
||||
@ -131,9 +136,13 @@ 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
|
||||
|
||||
@ -164,6 +173,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 +204,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 +226,7 @@ class NotifyGoogleChat(NotifyBase):
|
||||
try:
|
||||
r = requests.post(
|
||||
notify_url,
|
||||
params=params,
|
||||
data=dumps(payload),
|
||||
headers=headers,
|
||||
verify=self.verify_certificate,
|
||||
@ -242,11 +270,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 +288,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 +308,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 +324,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 +343,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(
|
||||
|
@ -23,9 +23,13 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
import requests
|
||||
|
||||
import pytest
|
||||
from apprise import Apprise
|
||||
from apprise.plugins.NotifyGoogleChat import NotifyGoogleChat
|
||||
from helpers import AppriseURLTester
|
||||
from unittest import mock
|
||||
from apprise import NotifyType
|
||||
from json import loads
|
||||
|
||||
# Disable logging for a cleaner testing output
|
||||
import logging
|
||||
@ -57,12 +61,25 @@ apprise_url_tests = (
|
||||
'instance': NotifyGoogleChat,
|
||||
'privacy_url': 'gchat://w...s/m...y/m...n',
|
||||
}),
|
||||
# Google Native Webhohok URL
|
||||
('gchat://?workspace=ws&key=mykey&token=mytoken&thread=abc123', {
|
||||
# Test our thread key
|
||||
'instance': NotifyGoogleChat,
|
||||
'privacy_url': 'gchat://w...s/m...y/m...n/a...3',
|
||||
}),
|
||||
('gchat://?workspace=ws&key=mykey&token=mytoken&threadKey=abc345', {
|
||||
# Test our thread key
|
||||
'instance': NotifyGoogleChat,
|
||||
'privacy_url': 'gchat://w...s/m...y/m...n/a...5',
|
||||
}),
|
||||
# Google Native Webhook URL
|
||||
('https://chat.googleapis.com/v1/spaces/myworkspace/messages'
|
||||
'?key=mykey&token=mytoken', {
|
||||
'instance': NotifyGoogleChat,
|
||||
'privacy_url': 'gchat://m...e/m...y/m...n'}),
|
||||
|
||||
('https://chat.googleapis.com/v1/spaces/myworkspace/messages'
|
||||
'?key=mykey&token=mytoken&threadKey=mythreadkey', {
|
||||
'instance': NotifyGoogleChat,
|
||||
'privacy_url': 'gchat://m...e/m...y/m...n/m...y'}),
|
||||
('gchat://workspace/key/token', {
|
||||
'instance': NotifyGoogleChat,
|
||||
# force a failure
|
||||
@ -92,3 +109,70 @@ def test_plugin_google_chat_urls():
|
||||
|
||||
# Run our general tests
|
||||
AppriseURLTester(tests=apprise_url_tests).run_all()
|
||||
|
||||
|
||||
@mock.patch('requests.post')
|
||||
def test_plugin_google_chat_general(mock_post):
|
||||
"""
|
||||
NotifyGoogleChat() General Checks
|
||||
|
||||
"""
|
||||
|
||||
# Initialize some generic (but valid) tokens
|
||||
workspace = 'ws'
|
||||
key = 'key'
|
||||
threadkey = 'threadkey'
|
||||
token = 'token'
|
||||
|
||||
# Prepare Mock
|
||||
mock_post.return_value = requests.Request()
|
||||
mock_post.return_value.status_code = requests.codes.ok
|
||||
|
||||
# Test our messaging
|
||||
obj = Apprise.instantiate(
|
||||
'gchat://{}/{}/{}'.format(workspace, key, token))
|
||||
assert isinstance(obj, NotifyGoogleChat)
|
||||
assert obj.notify(
|
||||
body="test body", title='title',
|
||||
notify_type=NotifyType.INFO) is True
|
||||
|
||||
# Test our call count
|
||||
assert mock_post.call_count == 1
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://chat.googleapis.com/v1/spaces/ws/messages'
|
||||
params = mock_post.call_args_list[0][1]['params']
|
||||
assert params.get('token') == token
|
||||
assert params.get('key') == key
|
||||
assert 'threadKey' not in params
|
||||
payload = loads(mock_post.call_args_list[0][1]['data'])
|
||||
assert payload['text'] == "title\r\ntest body"
|
||||
|
||||
mock_post.reset_mock()
|
||||
|
||||
# Test our messaging with the threadKey
|
||||
obj = Apprise.instantiate(
|
||||
'gchat://{}/{}/{}/{}'.format(workspace, key, token, threadkey))
|
||||
assert isinstance(obj, NotifyGoogleChat)
|
||||
assert obj.notify(
|
||||
body="test body", title='title',
|
||||
notify_type=NotifyType.INFO) is True
|
||||
|
||||
# Test our call count
|
||||
assert mock_post.call_count == 1
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://chat.googleapis.com/v1/spaces/ws/messages'
|
||||
params = mock_post.call_args_list[0][1]['params']
|
||||
assert params.get('token') == token
|
||||
assert params.get('key') == key
|
||||
assert params.get('threadKey') == threadkey
|
||||
payload = loads(mock_post.call_args_list[0][1]['data'])
|
||||
assert payload['text'] == "title\r\ntest body"
|
||||
|
||||
|
||||
def test_plugin_google_chat_edge_case():
|
||||
"""
|
||||
NotifyGoogleChat() Edge Cases
|
||||
|
||||
"""
|
||||
with pytest.raises(TypeError):
|
||||
NotifyGoogleChat('workspace', 'webhook', 'token', thread_key=object())
|
||||
|
Loading…
Reference in New Issue
Block a user