Matrix login URL updated to accommodate newer API (#970)

This commit is contained in:
Chris Caron 2023-10-15 15:03:08 -04:00 committed by GitHub
parent f6b53ac556
commit 97c7af4c4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 167 additions and 76 deletions

View File

@ -586,7 +586,7 @@ class NotifyMatrix(NotifyBase):
attachments = None
if attach and self.attachment_support:
attachments = self._send_attachments(attach)
if not attachments:
if attachments is False:
# take an early exit
return False
@ -611,31 +611,46 @@ class NotifyMatrix(NotifyBase):
self.image_url(notify_type)
# Build our path
path = '/rooms/{}/send/m.room.message'.format(
NotifyMatrix.quote(room_id))
if self.version == MatrixVersion.V3:
path = '/rooms/{}/send/m.room.message/0'.format(
NotifyMatrix.quote(room_id))
if image_url:
# Define our payload
image_payload = {
'msgtype': 'm.image',
'url': image_url,
'body': '{}'.format(notify_type if not title else title),
}
else:
path = '/rooms/{}/send/m.room.message'.format(
NotifyMatrix.quote(room_id))
# Post our content
postokay, response = self._fetch(path, payload=image_payload)
if not postokay:
# Mark our failure
has_error = True
continue
if self.version == MatrixVersion.V2:
#
# Attachments don't work beyond V2 at this time
#
if image_url:
# Define our payload
image_payload = {
'msgtype': 'm.image',
'url': image_url,
'body': '{}'.format(
notify_type if not title else title),
}
if attachments:
for attachment in attachments:
postokay, response = self._fetch(path, payload=attachment)
if not postokay:
# Mark our failure
has_error = True
continue
# Post our content
postokay, response = self._fetch(
path, payload=image_payload)
if not postokay:
# Mark our failure
has_error = True
continue
if attachments:
for attachment in attachments:
attachment['room_id'] = room_id
attachment['type'] = 'm.room.message'
postokay, response = self._fetch(
path, payload=attachment)
if not postokay:
# Mark our failure
has_error = True
continue
# Define our payload
payload = {
@ -667,7 +682,9 @@ class NotifyMatrix(NotifyBase):
})
# Post our content
postokay, response = self._fetch(path, payload=payload)
method = 'PUT' if self.version == MatrixVersion.V3 else 'POST'
postokay, response = self._fetch(
path, payload=payload, method=method)
if not postokay:
# Notify our user
self.logger.warning(
@ -685,6 +702,11 @@ class NotifyMatrix(NotifyBase):
"""
payloads = []
if self.version != MatrixVersion.V2:
self.logger.warning(
'Add ?v=2 to Apprise URL to support Attachments')
return next((False for a in attach if not a), [])
for attachment in attach:
if not attachment:
# invalid attachment (bad file)
@ -705,15 +727,28 @@ class NotifyMatrix(NotifyBase):
# "content_uri": "mxc://example.com/a-unique-key"
# }
# Prepare our payload
payloads.append({
"info": {
"mimetype": attachment.mimetype,
},
"msgtype": "m.image",
"body": "tta.webp",
"url": response.get('content_uri'),
})
if self.version == MatrixVersion.V3:
# Prepare our payload
payloads.append({
"body": attachment.name,
"info": {
"mimetype": attachment.mimetype,
"size": len(attachment),
},
"msgtype": "m.image",
"url": response.get('content_uri'),
})
else:
# Prepare our payload
payloads.append({
"info": {
"mimetype": attachment.mimetype,
},
"msgtype": "m.image",
"body": "tta.webp",
"url": response.get('content_uri'),
})
return payloads
@ -780,12 +815,23 @@ class NotifyMatrix(NotifyBase):
'user/pass combo is missing.')
return False
# Prepare our Registration Payload
payload = {
'type': 'm.login.password',
'user': self.user,
'password': self.password,
}
# Prepare our Authentication Payload
if self.version == MatrixVersion.V3:
payload = {
'type': 'm.login.password',
'identifier': {
'type': 'm.id.user',
'user': self.user,
},
'password': self.password,
}
else:
payload = {
'type': 'm.login.password',
'user': self.user,
'password': self.password,
}
# Build our URL
postokay, response = self._fetch('/login', payload=payload)
@ -1109,7 +1155,8 @@ class NotifyMatrix(NotifyBase):
response = {}
# fetch function
fn = requests.post if method == 'POST' else requests.get
fn = requests.post if method == 'POST' else (
requests.put if method == 'PUT' else requests.get)
# Define how many attempts we'll make if we get caught in a throttle
# event
@ -1137,7 +1184,9 @@ class NotifyMatrix(NotifyBase):
timeout=self.request_timeout,
)
self.logger.debug('Matrix Response: %s' % str(r.content))
self.logger.debug(
'Matrix Response: code=%d, %s' % (
r.status_code, str(r.content)))
response = loads(r.content)
if r.status_code == 429:

View File

@ -27,7 +27,6 @@
# POSSIBILITY OF SUCH DAMAGE.
from unittest import mock
import os
import requests
import pytest
@ -228,9 +227,10 @@ def test_plugin_matrix_urls():
AppriseURLTester(tests=apprise_url_tests).run_all()
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_general(mock_post, mock_get):
def test_plugin_matrix_general(mock_post, mock_get, mock_put):
"""
NotifyMatrix() General Tests
@ -250,6 +250,7 @@ def test_plugin_matrix_general(mock_post, mock_get):
# Prepare Mock
mock_get.return_value = request
mock_post.return_value = request
mock_put.return_value = request
# Variation Initializations
obj = NotifyMatrix(host='host', targets='#abcd')
@ -383,9 +384,10 @@ def test_plugin_matrix_general(mock_post, mock_get):
assert obj.send(user='test', password='passwd', body="test") is True
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_fetch(mock_post, mock_get):
def test_plugin_matrix_fetch(mock_post, mock_get, mock_put):
"""
NotifyMatrix() Server Fetch/API Tests
@ -419,6 +421,7 @@ def test_plugin_matrix_fetch(mock_post, mock_get):
return request
mock_put.side_effect = fetch_failed
mock_get.side_effect = fetch_failed
mock_post.side_effect = fetch_failed
@ -449,12 +452,14 @@ def test_plugin_matrix_fetch(mock_post, mock_get):
# Default configuration
mock_get.side_effect = None
mock_post.side_effect = None
mock_put.side_effect = None
request = mock.Mock()
request.status_code = requests.codes.ok
request.content = dumps(response_obj)
mock_post.return_value = request
mock_get.return_value = request
mock_put.return_value = request
obj = NotifyMatrix(host='host', include_image=True)
assert isinstance(obj, NotifyMatrix) is True
@ -467,6 +472,7 @@ def test_plugin_matrix_fetch(mock_post, mock_get):
request.content = dumps({
'retry_after_ms': 1,
})
code, response = obj._fetch('/retry/apprise/unit/test')
assert code is False
@ -485,9 +491,10 @@ def test_plugin_matrix_fetch(mock_post, mock_get):
assert code is False
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_auth(mock_post, mock_get):
def test_plugin_matrix_auth(mock_post, mock_get, mock_put):
"""
NotifyMatrix() Server Authentication
@ -506,6 +513,7 @@ def test_plugin_matrix_auth(mock_post, mock_get):
request.content = dumps(response_obj)
mock_post.return_value = request
mock_get.return_value = request
mock_put.return_value = request
obj = NotifyMatrix(host='localhost')
assert isinstance(obj, NotifyMatrix) is True
@ -579,9 +587,10 @@ def test_plugin_matrix_auth(mock_post, mock_get):
assert obj.access_token is None
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_rooms(mock_post, mock_get):
def test_plugin_matrix_rooms(mock_post, mock_get, mock_put):
"""
NotifyMatrix() Room Testing
@ -606,6 +615,7 @@ def test_plugin_matrix_rooms(mock_post, mock_get):
request.content = dumps(response_obj)
mock_post.return_value = request
mock_get.return_value = request
mock_put.return_value = request
obj = NotifyMatrix(host='host')
assert isinstance(obj, NotifyMatrix) is True
@ -789,9 +799,10 @@ def test_plugin_matrix_url_parsing():
assert '#room3' in result['targets']
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_image_errors(mock_post, mock_get):
def test_plugin_matrix_image_errors(mock_post, mock_get, mock_put):
"""
NotifyMatrix() Image Error Handling
@ -822,8 +833,9 @@ def test_plugin_matrix_image_errors(mock_post, mock_get):
# Prepare Mock
mock_get.side_effect = mock_function_handing
mock_post.side_effect = mock_function_handing
mock_put.side_effect = mock_function_handing
obj = NotifyMatrix(host='host', include_image=True)
obj = NotifyMatrix(host='host', include_image=True, version='2')
assert isinstance(obj, NotifyMatrix) is True
assert obj.access_token is None
@ -831,7 +843,7 @@ def test_plugin_matrix_image_errors(mock_post, mock_get):
# we had post errors (of any kind) we still report a failure.
assert obj.notify('test', 'test') is False
obj = NotifyMatrix(host='host', include_image=False)
obj = NotifyMatrix(host='host', include_image=False, version='2')
assert isinstance(obj, NotifyMatrix) is True
assert obj.access_token is None
@ -862,6 +874,7 @@ def test_plugin_matrix_image_errors(mock_post, mock_get):
# Prepare Mock
mock_get.side_effect = mock_function_handing
mock_put.side_effect = mock_function_handing
mock_post.side_effect = mock_function_handing
obj = NotifyMatrix(host='host', include_image=True)
assert isinstance(obj, NotifyMatrix) is True
@ -879,9 +892,10 @@ def test_plugin_matrix_image_errors(mock_post, mock_get):
del obj
@mock.patch('requests.put')
@mock.patch('requests.get')
@mock.patch('requests.post')
def test_plugin_matrix_attachments_api_v3(mock_post, mock_get):
def test_plugin_matrix_attachments_api_v3(mock_post, mock_get, mock_put):
"""
NotifyMatrix() Attachment Checks (v3)
@ -899,6 +913,7 @@ def test_plugin_matrix_attachments_api_v3(mock_post, mock_get):
# Prepare Mock return object
mock_post.return_value = response
mock_get.return_value = response
mock_put.return_value = response
# Instantiate our object
obj = Apprise.instantiate('matrix://user:pass@localhost/#general?v=3')
@ -913,26 +928,22 @@ def test_plugin_matrix_attachments_api_v3(mock_post, mock_get):
attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
# Test our call count
assert mock_post.call_count == 5
assert mock_put.call_count == 1
assert mock_post.call_count == 2
assert mock_post.call_args_list[0][0][0] == \
'http://localhost/_matrix/client/v3/login'
assert mock_post.call_args_list[1][0][0] == \
'http://localhost/_matrix/media/v3/upload'
assert mock_post.call_args_list[2][0][0] == \
'http://localhost/_matrix/client/v3/join/%23general%3Alocalhost'
assert mock_post.call_args_list[3][0][0] == \
assert mock_put.call_args_list[0][0][0] == \
'http://localhost/_matrix/client/v3/rooms/%21abc123%3Alocalhost/' \
'send/m.room.message'
assert mock_post.call_args_list[4][0][0] == \
'http://localhost/_matrix/client/v3/rooms/%21abc123%3Alocalhost/' \
'send/m.room.message'
'send/m.room.message/0'
# Attach an unsupported file type
# Attach an unsupported file type (it's just skipped)
attach = AppriseAttachment(
os.path.join(TEST_VAR_DIR, 'apprise-archive.zip'))
assert obj.notify(
body='body', title='title', notify_type=NotifyType.INFO,
attach=attach) is False
attach=attach) is True
# An invalid attachment will cause a failure
path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
@ -949,23 +960,23 @@ def test_plugin_matrix_attachments_api_v3(mock_post, mock_get):
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# We'll never fail because files are not attached
assert obj.send(body="test", attach=attach) is True
# Throw an exception on the second call to requests.post()
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [response, side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# Attachment support does not exist vor v3 at time, so this will
# work nicely
assert obj.send(body="test", attach=attach) is True
# handle a bad response
bad_response = mock.Mock()
bad_response.status_code = requests.codes.internal_server_error
mock_post.side_effect = [response, bad_response, response]
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False
# Attachment support does not exist vor v3 at time, so this will
# work nicely
assert obj.send(body="test", attach=attach) is True
# Force a object removal (thus a logout call)
del obj
@ -993,7 +1004,7 @@ def test_plugin_matrix_attachments_api_v2(mock_post, mock_get):
mock_get.return_value = response
# Instantiate our object
obj = Apprise.instantiate('matrix://user:pass@localhost/#general?v=3')
obj = Apprise.instantiate('matrix://user:pass@localhost/#general?v=2')
# attach our content
attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
@ -1013,13 +1024,13 @@ def test_plugin_matrix_attachments_api_v2(mock_post, mock_get):
# Force a object removal (thus a logout call)
del obj
# Instantiate our object
obj = Apprise.instantiate('matrixs://user:pass@localhost/#general?v=2')
# Reset our object
mock_post.reset_mock()
mock_get.reset_mock()
# Instantiate our object
obj = Apprise.instantiate('matrixs://user:pass@localhost/#general?v=2')
assert obj.notify(
body='body', title='title', notify_type=NotifyType.INFO,
attach=attach) is True
@ -1039,12 +1050,12 @@ def test_plugin_matrix_attachments_api_v2(mock_post, mock_get):
'https://localhost/_matrix/client/r0/rooms/%21abc123%3Alocalhost/' \
'send/m.room.message'
# Attach an unsupported file type
# Attach an unsupported file type; these are skipped
attach = AppriseAttachment(
os.path.join(TEST_VAR_DIR, 'apprise-archive.zip'))
assert obj.notify(
body='body', title='title', notify_type=NotifyType.INFO,
attach=attach) is False
attach=attach) is True
# An invalid attachment will cause a failure
path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
@ -1083,8 +1094,6 @@ def test_plugin_matrix_attachments_api_v2(mock_post, mock_get):
assert obj.send(body="test", attach=attach) is False
# handle a bad response
bad_response = mock.Mock()
bad_response.status_code = requests.codes.internal_server_error
mock_post.side_effect = \
[response, bad_response, response, response, response, response]
mock_get.side_effect = \
@ -1093,5 +1102,38 @@ def test_plugin_matrix_attachments_api_v2(mock_post, mock_get):
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False
# Force a object removal (thus a logout call)
del obj
# Instantiate our object
obj = Apprise.instantiate(
'matrixs://user:pass@localhost/#general?v=2&image=y')
# Reset our object
mock_post.reset_mock()
mock_get.reset_mock()
mock_post.return_value = None
mock_get.return_value = None
mock_post.side_effect = \
[response, response, bad_response, response, response, response,
response]
mock_get.side_effect = \
[response, response, bad_response, response, response, response,
response]
# image attachment didn't succeed
assert obj.notify(
body='body', title='title', notify_type=NotifyType.INFO) is False
# Error during image post
mock_post.return_value = response
mock_get.return_value = response
mock_post.side_effect = None
mock_get.side_effect = None
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is True
# Force __del__() call
del obj