Skip to content

Commit

Permalink
Issue #167: curl step
Browse files Browse the repository at this point in the history
  • Loading branch information
marcghaly committed Jun 30, 2022
1 parent a6462fc commit d31019d
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 4 deletions.
151 changes: 149 additions & 2 deletions classes/local/step/connector_curl.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,166 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class connector_curl extends connector_step {
/** @var int[] number of input flows (min, max). */
protected $inputflows = [0, 0];

/** @var int[] number of output connectors (min, max). */
protected $inputconnectors = [0, 1];

/** @var bool whether or not this step type (potentially) contains a side effect or not */
protected $hassideeffect = true;

/** @var int Time after which curl request is aborted */
protected $timeout = 60;

/**
* Return the definition of the fields available in this form.
*
* @return array
*/
protected static function form_define_fields(): array {
return [
'curl' => ['type' => PARAM_URL],
'destination' => ['type' => PARAM_PATH],
'headers' => ['type' => PARAM_RAW],
'method' => ['type' => PARAM_INT],
'rawpostdata' => ['type' => PARAM_RAW],
'sideeffects' => ['type' => PARAM_RAW],
'timeout' => ['type' => PARAM_INT],
];
}

/**
* Allows each step type to determine a list of optional/required form
* inputs for their configuration
*
* It's recommended you prefix the additional config related fields to avoid
* conflicts with any existing fields.
*
* @param \MoodleQuickForm &$mform
*/
public function form_add_custom_inputs(\MoodleQuickForm &$mform) {
$mform->addElement('text', 'config_curl', get_string('connector_curl:curl', 'tool_dataflows'),
['cols' => 50, 'rows' => 7]);
$mform->addElement('text', 'config_destination', get_string('connector_curl:destination', 'tool_dataflows'));
$mform->addElement('textarea', 'config_headers', get_string('connector_curl:headers', 'tool_dataflows'),
['cols' => 50, 'rows' => 7]);
$mform->addElement('select', 'config_method', get_string('connector_curl:method', 'tool_dataflows'),
['GET', 'POST', 'PUT']);
$mform->addElement('textarea' , 'config_rawpostdata', get_string('connector_curl:rawpostdata', 'tool_dataflows'),
['cols' => 50, 'rows' => 7]);
$mform->addElement('checkbox', 'config_sideeffects', get_string('connector_curl:sideeffects', 'tool_dataflows'),
get_string('yes'));
$mform->hideIf('config_rawpostdata', 'config_method', 'eq', 0);
$mform->disabledIf('config_rawpostdata', 'config_method', 'eq', 0);
$mform->addElement('text', 'config_timeout', get_string('connector_curl:timeout', 'tool_dataflows'));
$mform->addHelpButton('config_timeout', 'connector_curl:timeout', 'tool_dataflows');
}

/**
* Validate the configuration settings.
*
* @param object $config
* @return true|\lang_string[] true if valid, an array of errors otherwise
*/
public function validate_config($config) {
$errors = [];
if (empty($config->curl)) {
$errors['config_curl'] = get_string('config_field_missing', 'tool_dataflows', 'curl', true);
}
if (($config->method == 1 || $config->method == 2) && empty($config->rawpostdata)) {
$errors['config_rawpostdata'] = get_string('config_field_missing', 'tool_dataflows', 'rawpostdata', true);
}
return empty($errors) ? true : $errors;
}

/**
* Executes the step
*
* TODO: This will perform a curl call
* Performs a curl call according to given parameters.
*
* @return bool Returns true if successful, false otherwise.
*/
public function execute(): bool {
// TODO: Implement.
global $CFG, $PAGE;
// Get variables.
$config = $this->enginestep->stepdef->config;
$requesttype = [0 => 'get', 1 => 'post', 2 => 'put'];
$method = $requesttype[$config->method];
$postdata = null;

if (isset($config->timeout)) {
$this->timeout = (int)$config->timeout;
}
$options = ['CURLOPT_TIMEOUT' => $this->timeout];
$curl = new \curl();

if (!empty($config->sideeffects)) {
$this->hassideeffect = true;
} else {
$this->hassideeffect = false;
}

if (isset($config->headers) && !empty($config->headers)) {
$headers = $config->headers;
if (!is_array($headers)) {
$headers = json_decode($headers, true);
}
$curl->setHeader($headers);
}
if (isset($config->rawpostdata)) {
$postdata = json_decode($config->rawpostdata, true);
}
// Perform call or download/call.
if (!empty($config->destination)) {
// Download.
if ($config->destination[0] === '/') {
$config->destination = substr($config->destination, 1);
}
if (isset($config->rawpostdata)) {
$options['CURLOPT_POSTFIELDS'] = $postdata;
if ($method == 'post') {
$options['CURLOPT_POST'] = 1;
}
if ($method == 'put') {
$options['CURLOPT_PUT'] = 1;
}
}
$file = fopen($CFG->dirroot . '/' . $config->destination, 'w');
$result = $curl->$method($config->curl, $postdata, $options);
fwrite($file, $result);
fclose($file);
} else {
// Simple call without download.
if ($config->method != 0) {
$result = $curl->$method($config->curl, $postdata, $options);
$this->hassideeffect = true;
} else {
$result = $curl->get($config->curl, [], $options);
}
}

$info = $curl->get_info();
// Stores response to be reusable by other steps.
$response = $curl->getResponse();
$this->enginestep->stepdef->config->response = $response;

$httpcode = $info['http_code'] ?? null;
$connecttime = $info['connect_time'] ?? null;
$totaltime = $info['total_time'] ?? null;
$sizeupload = $info['size_upload'] ?? null;
$errno = $curl->get_errno();
if ($httpcode >= 400 || empty($response) || $errno == 28) {
if (is_string($result)) {
$resultarr = json_decode($result, true);
if (isset($resultarr['error'])) {
$codestatustext = $httpcode . '/' . $resultarr['error'];
} else {
$codestatustext = $httpcode . '/' . $result;
}
}
$this->enginestep->engine->abort(new \moodle_exception($codestatustext));
}
return true;
}
}
10 changes: 10 additions & 0 deletions lang/en/tool_dataflows.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,13 @@
$string['trigger_cron:crontab_desc'] = 'The schedule is edited as five values: minute, hour, day, month and day of month, in that order. The values are in crontab format.';
$string['trigger_cron:strftime_datetime'] = '%d %b %Y, %H:%M';
$string['trigger_cron:next_run_time'] = 'Next run time: {$a}';

// Connector cURL.
$string['connector_curl:curl'] = 'Client URL';
$string['connector_curl:destination'] = 'File destination';
$string['connector_curl:headers'] = 'Headers';
$string['connector_curl:method'] = 'HTTP request methods';
$string['connector_curl:rawpostdata'] = 'Raw post data';
$string['connector_curl:sideeffects'] = 'Has this request side effects ?';
$string['connector_curl:timeout'] = 'Timeout';
$string['connector_curl:timeout_help'] = 'Time after which curl request will abort, default is 60 seconds';
4 changes: 2 additions & 2 deletions version.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@

defined('MOODLE_INTERNAL') || die();

$plugin->version = 2022062900;
$plugin->release = 2022062900;
$plugin->version = 2022063000;
$plugin->release = 2022063000;

$plugin->requires = 2017051500; // Our lowest supported Moodle (3.3.0).

Expand Down

0 comments on commit d31019d

Please sign in to comment.