matrix42: add a generic object/action POST endpoint (#84636)
gitea/passerelle/pipeline/head This commit looks good Details

This commit is contained in:
Thomas NOËL 2023-12-15 17:03:36 +01:00
parent ec8dd0a43c
commit 40c3c6affb
2 changed files with 61 additions and 1 deletions

View File

@ -38,6 +38,8 @@ class Matrix42(BaseResource, HTTPResource):
log_requests_errors = False
_category_ordering = [_('Fragments'), _('Objects')]
class Meta:
verbose_name = _('Matrix42 Public API')
@ -59,7 +61,9 @@ class Matrix42(BaseResource, HTTPResource):
'Authorization': 'Bearer ' + token['RawToken'],
}
def request(self, uri, params=None, json=None, headers=None, method=None, dict_response=True):
def request(
self, uri, params=None, json=None, headers=None, method=None, dict_response=True, allow_empty=False
):
if headers is None:
headers = self.get_authorization_headers()
if method is None:
@ -67,6 +71,10 @@ class Matrix42(BaseResource, HTTPResource):
url = urljoin(self.base_url, uri)
response = self.requests.request(method, url, params=params, json=json, headers=headers)
status_code = response.status_code
if status_code == 204:
if allow_empty:
return None
raise APIError('Matrix42 returned an empty response (status 204)')
try:
response = response.json()
except ValueError:
@ -210,3 +218,24 @@ class Matrix42(BaseResource, HTTPResource):
):
uri = urljoin(self.base_url, 'data/objects/%s' % ciname)
return {'data': self.request(uri, json=post_data, dict_response=False)}
@endpoint(
name='generic',
display_category=_('Generic: ticket, task, change, problem, …'),
methods=['post'],
pattern=r'^(?P<object_type>.+)/(?P<action>.+)$',
example_pattern='ticket/Transform',
post={
'description': _('Perform action on object(s)'),
'request_body': {'schema': {'application/json': DICT_SCHEMA}},
},
)
def generic(
self,
request,
object_type,
action,
post_data,
):
uri = urljoin(self.base_url, '%s/%s' % (object_type, action))
return {'data': self.request(uri, json=post_data, dict_response=False, allow_empty=True)}

View File

@ -1,6 +1,8 @@
import json
from unittest import mock
import pytest
import responses
from django.contrib.contenttypes.models import ContentType
from passerelle.apps.matrix42.models import Matrix42
@ -213,6 +215,15 @@ def test_matrix42_bad_rawtoken(mocked_request, app, matrix42):
assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
assert 'not returned a dict' in resp.json['err_desc']
# empty response: error when not allowed
mocked_request.side_effect = [
FakedResponse(content='', status_code=204),
]
resp = app.get(endpoint, params=params, status=200)
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
assert 'returned an empty response' in resp.json['err_desc']
# Matrix42 error
mocked_request.side_effect = [
FakedResponse(content='{"ExceptionName":"NotFound","Message":"4o4"}', status_code=404),
@ -302,3 +313,23 @@ def test_matrix42_object(mocked_request, app, matrix42):
'ID': '424242',
'SPSActivityClassBase': {'TicketNumber': 'TCK0000153', 'TimeStamp': 'AAAAAAHlWr4='},
}
def test_matrix42_generic(app, matrix42):
api = ApiUser.objects.create(username='all', keytype='', key='')
obj_type = ContentType.objects.get_for_model(matrix42)
AccessRight.objects.create(
codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=matrix42.pk
)
endpoint = generic_endpoint_url('matrix42', 'generic', slug=matrix42.slug)
with responses.RequestsMock() as rsps:
rsps.post(
'https://matrix42.example.net/api/ApiToken/GenerateAccessTokenFromApiToken',
status=200,
body=TOKEN,
)
rsps.post('https://matrix42.example.net/api/ticket/Transform', status=204)
resp = app.post_json(endpoint + '/ticket/Transform', params={'foo/bar': 'coin'}, status=200)
assert json.loads(rsps.calls[1].request.body) == {'foo': {'bar': 'coin'}}
assert resp.json == {'err': 0, 'data': None} # empty response 204 is ok here