Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Represent the url for each method and the encoding of the parameters and response. 19 * 20 * @package core_badges 21 * @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @author Yuliya Bozhko <yuliya.bozhko@totaralms.com> 24 */ 25 26 namespace core_badges; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 global $CFG; 31 require_once($CFG->libdir . '/filelib.php'); 32 33 use context_system; 34 use core_badges\external\assertion_exporter; 35 use core_badges\external\collection_exporter; 36 use core_badges\external\issuer_exporter; 37 use core_badges\external\badgeclass_exporter; 38 use curl; 39 40 /** 41 * Represent a single method for the remote api. 42 * 43 * @package core_badges 44 * @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 46 */ 47 class backpack_api_mapping { 48 49 /** @var string The action of this method. */ 50 public $action; 51 52 /** @var string The base url of this backpack. */ 53 private $url; 54 55 /** @var array List of parameters for this method. */ 56 public $params; 57 58 /** @var string Name of a class to export parameters for this method. */ 59 public $requestexporter; 60 61 /** @var string Name of a class to export response for this method. */ 62 public $responseexporter; 63 64 /** @var boolean This method returns an array of responses. */ 65 public $multiple; 66 67 /** @var string get or post methods. */ 68 public $method; 69 70 /** @var boolean json decode the response. */ 71 public $json; 72 73 /** @var boolean Authentication is required for this request. */ 74 public $authrequired; 75 76 /** @var boolean Differentiate the function that can be called on a user backpack or a site backpack. */ 77 private $isuserbackpack; 78 79 /** @var string Error string from authentication request. */ 80 private static $authenticationerror = ''; 81 82 /** @var mixed List of parameters for this method. */ 83 protected $postparams; 84 85 /** @var int OpenBadges version 1 or 2. */ 86 protected $backpackapiversion; 87 88 /** 89 * Create a mapping. 90 * 91 * @param string $action The action of this method. 92 * @param string $url The base url of this backpack. 93 * @param mixed $postparams List of parameters for this method. 94 * @param string $requestexporter Name of a class to export parameters for this method. 95 * @param string $responseexporter Name of a class to export response for this method. 96 * @param boolean $multiple This method returns an array of responses. 97 * @param string $method get or post methods. 98 * @param boolean $json json decode the response. 99 * @param boolean $authrequired Authentication is required for this request. 100 * @param boolean $isuserbackpack user backpack or a site backpack. 101 * @param integer $backpackapiversion OpenBadges version 1 or 2. 102 */ 103 public function __construct($action, $url, $postparams, $requestexporter, $responseexporter, 104 $multiple, $method, $json, $authrequired, $isuserbackpack, $backpackapiversion) { 105 $this->action = $action; 106 $this->url = $url; 107 $this->postparams = $postparams; 108 $this->requestexporter = $requestexporter; 109 $this->responseexporter = $responseexporter; 110 $this->multiple = $multiple; 111 $this->method = $method; 112 $this->json = $json; 113 $this->authrequired = $authrequired; 114 $this->isuserbackpack = $isuserbackpack; 115 $this->backpackapiversion = $backpackapiversion; 116 } 117 118 /** 119 * Get the unique key for the token. 120 * 121 * @param string $type The type of token. 122 * @return string 123 */ 124 private function get_token_key($type) { 125 $prefix = 'badges_'; 126 if ($this->isuserbackpack) { 127 $prefix .= 'user_backpack_'; 128 } else { 129 $prefix .= 'site_backpack_'; 130 } 131 $prefix .= $type . '_token'; 132 return $prefix; 133 } 134 135 /** 136 * Remember the error message in a static variable. 137 * 138 * @param string $msg The message. 139 */ 140 public static function set_authentication_error($msg) { 141 self::$authenticationerror = $msg; 142 } 143 144 /** 145 * Get the last authentication error in this request. 146 * 147 * @return string 148 */ 149 public static function get_authentication_error() { 150 return self::$authenticationerror; 151 } 152 153 /** 154 * Does the action match this mapping? 155 * 156 * @param string $action The action. 157 * @return boolean 158 */ 159 public function is_match($action) { 160 return $this->action == $action; 161 } 162 163 /** 164 * Parse the method url and insert parameters. 165 * 166 * @param string $apiurl The raw apiurl. 167 * @param string $param1 The first parameter. 168 * @param string $param2 The second parameter. 169 * @return string 170 */ 171 private function get_url($apiurl, $param1, $param2) { 172 $urlscheme = parse_url($apiurl, PHP_URL_SCHEME); 173 $urlhost = parse_url($apiurl, PHP_URL_HOST); 174 175 $url = $this->url; 176 $url = str_replace('[SCHEME]', $urlscheme, $url); 177 $url = str_replace('[HOST]', $urlhost, $url); 178 $url = str_replace('[URL]', $apiurl, $url); 179 $url = str_replace('[PARAM1]', $param1 ?? '', $url); 180 $url = str_replace('[PARAM2]', $param2 ?? '', $url); 181 182 return $url; 183 } 184 185 /** 186 * Parse the post parameters and insert replacements. 187 * 188 * @param string $email The api username. 189 * @param string $password The api password. 190 * @param string $param The parameter. 191 * @return mixed 192 */ 193 private function get_post_params($email, $password, $param) { 194 global $PAGE; 195 196 if ($this->method == 'get') { 197 return ''; 198 } 199 200 $request = $this->postparams; 201 if ($request === '[PARAM]') { 202 $value = $param; 203 foreach ($value as $key => $keyvalue) { 204 if (gettype($value[$key]) == 'array') { 205 $newkey = 'related_' . $key; 206 $value[$newkey] = $value[$key]; 207 unset($value[$key]); 208 } 209 } 210 } else if (is_array($request)) { 211 foreach ($request as $key => $value) { 212 if ($value == '[EMAIL]') { 213 $value = $email; 214 $request[$key] = $value; 215 } else if ($value == '[PASSWORD]') { 216 $value = $password; 217 $request[$key] = $value; 218 } else if ($value == '[PARAM]') { 219 $request[$key] = is_array($param) ? $param[0] : $param; 220 } 221 } 222 } 223 $context = context_system::instance(); 224 $exporter = $this->requestexporter; 225 $output = $PAGE->get_renderer('core', 'badges'); 226 if (!empty($exporter)) { 227 $exporterinstance = new $exporter($value, ['context' => $context]); 228 $request = $exporterinstance->export($output); 229 } 230 if ($this->json) { 231 return json_encode($request); 232 } 233 return $request; 234 } 235 236 /** 237 * Read the response from a V1 user request and save the userID. 238 * 239 * @param string $response The request response. 240 * @param integer $backpackid The backpack id. 241 * @return mixed 242 */ 243 private function convert_email_response($response, $backpackid) { 244 global $SESSION; 245 246 if (isset($response->status) && $response->status == 'okay') { 247 248 // Remember the tokens. 249 $useridkey = $this->get_token_key(BADGE_USER_ID_TOKEN); 250 $backpackidkey = $this->get_token_key(BADGE_BACKPACK_ID_TOKEN); 251 252 $SESSION->$useridkey = $response->userId; 253 $SESSION->$backpackidkey = $backpackid; 254 return $response->userId; 255 } 256 if (!empty($response->error)) { 257 self::set_authentication_error($response->error); 258 } 259 return false; 260 } 261 262 /** 263 * Get the user id from a previous user request. 264 * 265 * @return integer 266 */ 267 private function get_auth_user_id() { 268 global $USER; 269 270 if ($this->isuserbackpack) { 271 return $USER->id; 272 } else { 273 // The access tokens for the system backpack are shared. 274 return -1; 275 } 276 } 277 278 /** 279 * Parse the response from an openbadges 2 login. 280 * 281 * @param string $response The request response data. 282 * @param integer $backpackid The id of the backpack. 283 * @return mixed 284 */ 285 private function oauth_token_response($response, $backpackid) { 286 global $SESSION; 287 288 if (isset($response->access_token) && isset($response->refresh_token)) { 289 // Remember the tokens. 290 $accesskey = $this->get_token_key(BADGE_ACCESS_TOKEN); 291 $refreshkey = $this->get_token_key(BADGE_REFRESH_TOKEN); 292 $expireskey = $this->get_token_key(BADGE_EXPIRES_TOKEN); 293 $useridkey = $this->get_token_key(BADGE_USER_ID_TOKEN); 294 $backpackidkey = $this->get_token_key(BADGE_BACKPACK_ID_TOKEN); 295 if (isset($response->expires_in)) { 296 $timeout = $response->expires_in; 297 } else { 298 $timeout = 15 * 60; // 15 minute timeout if none set. 299 } 300 $expires = $timeout + time(); 301 302 $SESSION->$expireskey = $expires; 303 $SESSION->$useridkey = $this->get_auth_user_id(); 304 $SESSION->$accesskey = $response->access_token; 305 $SESSION->$refreshkey = $response->refresh_token; 306 $SESSION->$backpackidkey = $backpackid; 307 return -1; 308 } else if (isset($response->error_description)) { 309 self::set_authentication_error($response->error_description); 310 } 311 return $response; 312 } 313 314 /** 315 * Standard options used for all curl requests. 316 * 317 * @return array 318 */ 319 private function get_curl_options() { 320 return array( 321 'FRESH_CONNECT' => true, 322 'RETURNTRANSFER' => true, 323 'FOLLOWLOCATION' => true, 324 'FORBID_REUSE' => true, 325 'HEADER' => 0, 326 'CONNECTTIMEOUT' => 3, 327 'CONNECTTIMEOUT' => 3, 328 // Follow redirects with the same type of request when sent 301, or 302 redirects. 329 'CURLOPT_POSTREDIR' => 3, 330 ); 331 } 332 333 /** 334 * Make an api request and parse the response. 335 * 336 * @param string $apiurl Raw request url. 337 * @param string $urlparam1 Parameter for the request. 338 * @param string $urlparam2 Parameter for the request. 339 * @param string $email User email for authentication. 340 * @param string $password for authentication. 341 * @param mixed $postparam Raw data for the post body. 342 * @param string $backpackid the id of the backpack to use. 343 * @return mixed 344 */ 345 public function request($apiurl, $urlparam1, $urlparam2, $email, $password, $postparam, $backpackid) { 346 global $SESSION, $PAGE; 347 348 $curl = new curl(); 349 350 $url = $this->get_url($apiurl, $urlparam1, $urlparam2); 351 352 if ($this->authrequired) { 353 $accesskey = $this->get_token_key(BADGE_ACCESS_TOKEN); 354 if (isset($SESSION->$accesskey)) { 355 $token = $SESSION->$accesskey; 356 $curl->setHeader('Authorization: Bearer ' . $token); 357 } 358 } 359 if ($this->json) { 360 $curl->setHeader(array('Content-type: application/json')); 361 } 362 $curl->setHeader(array('Accept: application/json', 'Expect:')); 363 $options = $this->get_curl_options(); 364 365 $post = $this->get_post_params($email, $password, $postparam); 366 367 if ($this->method == 'get') { 368 $response = $curl->get($url, $post, $options); 369 } else if ($this->method == 'post') { 370 $response = $curl->post($url, $post, $options); 371 } else if ($this->method == 'put') { 372 $response = $curl->put($url, $post, $options); 373 } 374 $response = json_decode($response); 375 if (isset($response->result)) { 376 $response = $response->result; 377 } 378 $context = context_system::instance(); 379 $exporter = $this->responseexporter; 380 if (class_exists($exporter)) { 381 $output = $PAGE->get_renderer('core', 'badges'); 382 if (!$this->multiple) { 383 if (count($response)) { 384 $response = $response[0]; 385 } 386 if (empty($response)) { 387 return null; 388 } 389 $apidata = $exporter::map_external_data($response, $this->backpackapiversion); 390 $exporterinstance = new $exporter($apidata, ['context' => $context]); 391 $data = $exporterinstance->export($output); 392 return $data; 393 } else { 394 $multiple = []; 395 if (empty($response)) { 396 return $multiple; 397 } 398 foreach ($response as $data) { 399 $apidata = $exporter::map_external_data($data, $this->backpackapiversion); 400 $exporterinstance = new $exporter($apidata, ['context' => $context]); 401 $multiple[] = $exporterinstance->export($output); 402 } 403 return $multiple; 404 } 405 } else if (method_exists($this, $exporter)) { 406 return $this->$exporter($response, $backpackid); 407 } 408 return $response; 409 } 410 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body