From 4055bf0a57902d30d527e66aacfd208bdd2b635c Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Mon, 16 Oct 2023 17:15:19 +1100 Subject: [PATCH] issue #209: allow different HTTP methods for http_post_action_step --- .../steps/actions/http_post_action_step.php | 31 ++++++++-- lang/en/tool_trigger.php | 4 +- tests/http_post_action_step_test.php | 61 ++++++++++++++++++- version.php | 4 +- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/classes/steps/actions/http_post_action_step.php b/classes/steps/actions/http_post_action_step.php index aca43c0..2b6c2c8 100644 --- a/classes/steps/actions/http_post_action_step.php +++ b/classes/steps/actions/http_post_action_step.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * HTTP Post action step class. + * HTTP action step class. * * @package tool_trigger * @copyright Matt Porritt @@ -25,7 +25,7 @@ namespace tool_trigger\steps\actions; /** - * HTTP Post action step class. + * HTTP action step class. * * @package tool_trigger * @copyright Matt Porritt @@ -35,9 +35,22 @@ class http_post_action_step extends base_action_step { use \tool_trigger\helper\datafield_manager; + /** + * Supported HTTP methods. + */ + const SUPPORTED_HTTP_METHODS = [ + 'POST' => 'POST', + 'GET' => 'GET', + 'PUT' => 'PUT', + 'DELETE' => 'DELETE', + 'PATCH' => 'PATCH', + ]; + protected $url; + protected $httpmethod; protected $headers; protected $params; + private $httphandler = null; /** * The fields supplied by this step. @@ -52,6 +65,7 @@ class http_post_action_step extends base_action_step { protected function init() { $this->url = $this->data['url']; + $this->httpmethod = !empty($this->data['httpmethod']) ? $this->data['httpmethod'] : 'POST'; $this->headers = $this->data['httpheaders']; $this->params = $this->data['httpparams']; $this->jsonencode = $this->data['jsonencode']; @@ -81,8 +95,6 @@ public static function get_step_desc() { return get_string('httppostactionstepdesc', 'tool_trigger'); } - private $httphandler = null; - /** * Kinda hacky... unit testing requires us to specify a different http handler for guzzle to use. * That's really the only reason we need this method! @@ -143,7 +155,7 @@ public function execute($step, $trigger, $event, $stepresults) { $params = json_encode($output); } - $request = new \GuzzleHttp\Psr7\Request('POST', $url, $headers, $params); + $request = new \GuzzleHttp\Psr7\Request($this->httpmethod, $url, $headers, $params); $client = $this->get_http_client(); try { @@ -159,7 +171,9 @@ public function execute($step, $trigger, $event, $stepresults) { if ($response->getStatusCode() != $this->expectedresponse) { // If we weren't expecting this response, throw an exception. // The error will be caught and rerun. - throw new \invalid_response_exception("HTTP Response code expected was {$this->expectedresponse}, received {$response->getStatusCode()}"); + throw new \invalid_response_exception( + "HTTP Response code expected was {$this->expectedresponse}, received {$response->getStatusCode()}" + ); } return array(true, $stepresults); @@ -180,6 +194,11 @@ public function form_definition_extra($form, $mform, $customdata) { $mform->addRule('url', get_string('required'), 'required'); $mform->addHelpButton('url', 'httpostactionurl', 'tool_trigger'); + // HTTP method. + $mform->addElement('select', 'httpmethod', get_string ('httpostmethod', 'tool_trigger'), self::SUPPORTED_HTTP_METHODS); + $mform->setType('httpmethod', PARAM_TEXT); + $mform->addHelpButton('httpmethod', 'httpostmethod', 'tool_trigger'); + // Headers. $attributes = array('cols' => '50', 'rows' => '2'); $mform->addElement('textarea', 'httpheaders', get_string ('httpostactionheaders', 'tool_trigger'), $attributes); diff --git a/lang/en/tool_trigger.php b/lang/en/tool_trigger.php index 5e61453..e689ae9 100644 --- a/lang/en/tool_trigger.php +++ b/lang/en/tool_trigger.php @@ -120,11 +120,13 @@ $string['historysettingsdesc'] = 'These settings provide control over how the history of a workflow is stored.'; $string['httpostactionurl'] = 'URL'; $string['httpostactionurl_help'] = 'The URL to post the data to.'; +$string['httpostmethod'] = 'HTTP method'; +$string['httpostmethod_help'] = 'HTTP method for the given request.'; $string['httpostactionheaders'] = 'Headers'; $string['httpostactionheaders_help'] = 'The requests headers to send.'; $string['httpostactionparams'] = 'Parameters'; $string['httpostactionparams_help'] = 'The parameters to send with the request.'; -$string['httppostactionstepname'] = 'HTTP Post'; +$string['httppostactionstepname'] = 'HTTP request'; $string['httppostactionstepdesc'] = 'A step to allow Moodle workflows to send data to a HTTP/S endpoint.'; $string['importmodaltitle'] = 'Import workflow from file'; $string['importworkflow'] = 'Import a workflow'; diff --git a/tests/http_post_action_step_test.php b/tests/http_post_action_step_test.php index 5f0a767..24add51 100644 --- a/tests/http_post_action_step_test.php +++ b/tests/http_post_action_step_test.php @@ -62,12 +62,65 @@ private function make_mock_http_handler($response) { return $stack; } + /** + * Test supported HTTP methods. + */ + public function test_supported_http_methods() { + $expected = [ + 'POST' => 'POST', + 'GET' => 'GET', + 'PUT' => 'PUT', + 'DELETE' => 'DELETE', + 'PATCH' => 'PATCH', + ]; + $this->assertSame($expected, \tool_trigger\steps\actions\http_post_action_step::SUPPORTED_HTTP_METHODS); + } + + /** + * Test that POST method is set as default if no httpmethod set for the step class. + * This is to make sure that steps created before httpmethod was introduced will get it by default. + */ + public function test_if_httpmethod_is_not_set_post_method_set_as_default() { + $stepsettings = [ + 'url' => 'http://http_post_action_step.example.com', + 'httpheaders' => 'My-Special-Header: {headervalue}', + 'httpparams' => '', + 'jsonencode' => '0' + ]; + + $step = new \tool_trigger\steps\actions\http_post_action_step(json_encode($stepsettings)); + + $reflector = new \ReflectionClass(\tool_trigger\steps\actions\http_post_action_step::class); + $property = $reflector->getProperty('httpmethod'); + $property->setAccessible(true); + + $this->assertEquals('POST', $property->getValue($step)); + } + + /** + * Data provider for all supported HTTP methods. + * @return array[] + */ + public function http_methods_data_provider(): array { + return [ + ['POST'], + ['GET'], + ['PUT'], + ['DELETE'], + ['PATCH'], + ]; + } + /** * Simple test, with a successful response + * + * @dataProvider http_methods_data_provider + * @param string $httpmethod */ - public function test_execute_200() { + public function test_execute_200(string $httpmethod) { $stepsettings = [ 'url' => 'http://http_post_action_step.example.com', + 'httpmethod' => $httpmethod, 'httpheaders' => 'My-Special-Header: {headervalue}', 'httpparams' => '', 'jsonencode' => '0' @@ -89,10 +142,14 @@ public function test_execute_200() { /** * Test that we properly handle a 404 response. Guzzle will throw an exception in this * case, but the action step should catch the exception and handle it. + * + * @dataProvider http_methods_data_provider + * @param string $httpmethod */ - public function test_execute_404() { + public function test_execute_404(string $httpmethod) { $stepsettings = [ 'url' => 'http://http_post_action_step.example.com/badurl', + 'httpmethod' => $httpmethod, 'httpheaders' => 'My-Special-Header: {headervalue}', 'httpparams' => '', 'jsonencode' => '0', diff --git a/version.php b/version.php index 00fb10f..c618efc 100755 --- a/version.php +++ b/version.php @@ -25,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'tool_trigger'; -$plugin->release = 2021030408; -$plugin->version = 2021030408; +$plugin->release = 2021030409; +$plugin->version = 2021030409; $plugin->requires = 2016052300; $plugin->supported = [35, 310]; $plugin->maturity = MATURITY_STABLE;