Commit 0ae07011 authored by Roberto Rosario's avatar Roberto Rosario

Add support for HTTP methods

Add HTTP methods to the workflow HTTP request state action.
Signed-off-by: Roberto Rosario's avatarRoberto Rosario <[email protected]>
parent e3446ce2
Pipeline #126560588 skipped with stage
......@@ -26,6 +26,7 @@
- Update the document type and document models to avoid a double save
when creating a new document.
- Add quotas app.
- Add support for HTTP methods to the workflow HTTP request state action.
3.3.15 (2020-03-05)
===================
......
......@@ -63,6 +63,9 @@ class TestClientAdapter(requests.adapters.BaseAdapter):
"""Craft a Django request based on the attribute of
requests' request object.
"""
# Expose the timeout value so that the test case can assert it.
self.test_case.timeout = timeout
return self.build_response(
request=request, django_response=self.test_case.generic(
data=request.body,
......
from __future__ import unicode_literals
import requests
from .http_adapters import TestClientAdapter
def request_method_factory(test_case):
def request(method, url, **kwargs):
with requests.sessions.Session() as session:
session.mount(
prefix=test_case.testserver_prefix,
adapter=TestClientAdapter(test_case=test_case)
)
return session.request(method=method, url=url, **kwargs)
def get_adapter(url):
return TestClientAdapter(test_case=test_case)
return request
return get_adapter
......@@ -43,7 +43,26 @@ class WorkflowActionBase(object):
fields = ()
class WorkflowAction(six.with_metaclass(WorkflowActionMetaclass, WorkflowActionBase)):
class WorkflowAction(
six.with_metaclass(WorkflowActionMetaclass, WorkflowActionBase)
):
previous_dotted_paths = ()
@staticmethod
def initialize():
for app in apps.get_app_configs():
try:
import_module('{}.workflow_actions'.format(app.name))
except ImportError as exception:
if force_text(exception) not in ('No module named workflow_actions', 'No module named \'{}.workflow_actions\''.format(app.name)):
logger.error(
'Error importing %s workflow_actions.py file; %s',
app.name, exception
)
for action_class in WorkflowAction.get_all():
action_class.migrate()
@classmethod
def clean(cls, request, form_data=None):
return form_data
......@@ -60,17 +79,15 @@ class WorkflowAction(six.with_metaclass(WorkflowActionMetaclass, WorkflowActionB
def id(cls):
return '{}.{}'.format(cls.__module__, cls.__name__)
@staticmethod
def initialize():
for app in apps.get_app_configs():
try:
import_module('{}.workflow_actions'.format(app.name))
except ImportError as exception:
if force_text(exception) not in ('No module named workflow_actions', 'No module named \'{}.workflow_actions\''.format(app.name)):
logger.error(
'Error importing %s workflow_actions.py file; %s',
app.name, exception
)
@classmethod
def migrate(cls):
WorkflowStateAction = apps.get_model(
app_label='document_states', model_name='WorkflowStateAction'
)
for previous_dotted_path in cls.previous_dotted_paths:
WorkflowStateAction.objects.filter(
action_path=previous_dotted_path
).update(action_path=cls.id())
def __init__(self, form_data=None):
self.form_data = form_data
......
......@@ -8,7 +8,7 @@ from mayan.apps.common.tests.mocks import request_method_factory
from mayan.apps.document_states.tests.mixins import WorkflowTestMixin
from mayan.apps.documents.tests.base import GenericDocumentViewTestCase
from ..workflow_actions import HTTPPostAction
from ..workflow_actions import HTTPAction
from .literals import (
TEST_HEADERS_AUTHENTICATION_KEY, TEST_HEADERS_AUTHENTICATION_VALUE,
......@@ -19,33 +19,35 @@ from .literals import (
)
class HTTPPostWorkflowActionTestCase(
class HTTPWorkflowActionTestCase(
TestServerTestCaseMixin, GenericDocumentViewTestCase, WorkflowTestMixin,
):
auto_upload_test_document = False
auto_add_test_view = True
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_simple(self, mock_object):
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'method': 'POST',
'url': self.testserver_url
}
)
action.execute(context={})
self.assertFalse(self.test_view_request is None)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_payload_simple(self, mock_object):
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'payload': TEST_PAYLOAD_JSON,
'url': self.testserver_url,
'method': 'POST'
}
)
action.execute(context={})
......@@ -55,15 +57,16 @@ class HTTPPostWorkflowActionTestCase(
{'label': 'label'}
)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_payload_template(self, mock_object):
self._upload_test_document()
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'payload': TEST_PAYLOAD_TEMPLATE_DOCUMENT_LABEL,
'url': self.testserver_url,
'method': 'POST'
}
)
action.execute(context={'document': self.test_document})
......@@ -73,14 +76,15 @@ class HTTPPostWorkflowActionTestCase(
{'label': self.test_document.label}
)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_headers_simple(self, mock_object):
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'headers': TEST_HEADERS_JSON,
'url': self.testserver_url,
'method': 'POST'
}
)
action.execute(context={})
......@@ -92,15 +96,16 @@ class HTTPPostWorkflowActionTestCase(
self.test_view_request.META[TEST_HEADERS_KEY], TEST_HEADERS_VALUE
)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_headers_template(self, mock_object):
self._upload_test_document()
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'headers': TEST_HEADERS_JSON_TEMPLATE,
'url': self.testserver_url,
'method': 'POST'
}
)
action.execute(context={'document': self.test_document})
......@@ -113,15 +118,16 @@ class HTTPPostWorkflowActionTestCase(
self.test_document.label
)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_authentication(self, mock_object):
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'password': TEST_SERVER_PASSWORD,
'url': self.testserver_url,
'username': TEST_SERVER_USERNAME,
'password': TEST_SERVER_PASSWORD
'method': 'POST'
}
)
action.execute(context={})
......@@ -134,50 +140,44 @@ class HTTPPostWorkflowActionTestCase(
TEST_HEADERS_AUTHENTICATION_VALUE
)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_timeout_value_int(self, mock_object):
def mock_request(method, url, **kwargs):
self.timeout = kwargs.get('timeout')
mock_object.side_effect = mock_request
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'timeout': '1',
'url': self.testserver_url,
'timeout': '1'
'method': 'POST'
}
)
action.execute(context={})
self.assertEqual(self.timeout, 1)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_timeout_value_float(self, mock_object):
def mock_request(method, url, **kwargs):
self.timeout = kwargs.get('timeout')
mock_object.side_effect = mock_request
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'timeout': '1.5',
'url': self.testserver_url,
'timeout': '1.5'
'method': 'POST'
}
)
action.execute(context={})
self.assertEqual(self.timeout, 1.5)
@mock.patch('requests.api.request')
@mock.patch('requests.sessions.Session.get_adapter')
def test_http_post_action_timeout_value_none(self, mock_object):
def mock_request(method, url, **kwargs):
self.timeout = kwargs.get('timeout')
mock_object.side_effect = mock_request
mock_object.side_effect = request_method_factory(test_case=self)
action = HTTPPostAction(
action = HTTPAction(
form_data={
'url': self.testserver_url,
'method': 'POST'
}
)
action.execute(context={})
......
......@@ -83,7 +83,7 @@ class DocumentPropertiesEditAction(WorkflowAction):
document.save()
class HTTPPostAction(WorkflowAction):
class HTTPAction(WorkflowAction):
fields = {
'url': {
'label': _('URL'),
......@@ -146,6 +146,20 @@ class HTTPPostAction(WorkflowAction):
'and "comment" attributes.'
), 'max_length': 192, 'required': False
},
}, 'method': {
'label': _('Method'),
'class': 'django.forms.CharField', 'kwargs': {
'help_text': _(
'The HTTP method to use for the request. Typical choices '
'are OPTIONS, HEAD, POST, GET, PUT, PATCH, DELETE. '
'Can be a static value or a template that returns the '
'method text. Templates receive the workflow log entry '
'instance as part of their context via the '
'variable "entry_log". The "entry_log" in turn '
'provides the "workflow_instance", "datetime", '
'"transition", "user", and "comment" attributes.'
), 'required': True
}
}, 'headers': {
'label': _('Headers'),
'class': 'django.forms.CharField', 'kwargs': {
......@@ -162,9 +176,12 @@ class HTTPPostAction(WorkflowAction):
}
}
field_order = (
'url', 'username', 'password', 'headers', 'timeout', 'payload'
'url', 'username', 'password', 'headers', 'timeout', 'verb', 'payload'
)
label = _('Perform an HTTP request')
previous_dotted_paths = (
'mayan.apps.document_states.workflow_actions.HTTPPostAction',
)
label = _('Perform a POST request')
widgets = {
'payload': {
'class': 'django.forms.widgets.Textarea', 'kwargs': {
......@@ -216,12 +233,13 @@ class HTTPPostAction(WorkflowAction):
return result
def execute(self, context):
url = self.render(field_name='url', context=context)
username = self.render(field_name='username', context=context)
password = self.render(field_name='password', context=context)
timeout = self.render(field_name='timeout', context=context)
headers = self.render_load(field_name='headers', context=context)
method = self.render(field_name='method', context=context)
password = self.render(field_name='password', context=context)
payload = self.render_load(field_name='payload', context=context)
timeout = self.render(field_name='timeout', context=context)
url = self.render(field_name='url', context=context)
username = self.render(field_name='username', context=context)
if '.' in timeout:
timeout = float(timeout)
......@@ -236,7 +254,7 @@ class HTTPPostAction(WorkflowAction):
username=username, password=password
)
requests.post(
url=url, json=payload, timeout=timeout,
requests.request(
method=method, url=url, json=payload, timeout=timeout,
auth=authentication, headers=headers
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment