See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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 /** 83 * Create a mapping. 84 * 85 * @param string $action The action of this method. 86 * @param string $url The base url of this backpack. 87 * @param mixed $postparams List of parameters for this method. 88 * @param string $requestexporter Name of a class to export parameters for this method. 89 * @param string $responseexporter Name of a class to export response for this method. 90 * @param boolean $multiple This method returns an array of responses. 91 * @param string $method get or post methods. 92 * @param boolean $json json decode the response. 93 * @param boolean $authrequired Authentication is required for this request. 94 * @param boolean $isuserbackpack user backpack or a site backpack. 95 * @param integer $backpackapiversion OpenBadges version 1 or 2. 96 */ 97 public function __construct($action, $url, $postparams, $requestexporter, $responseexporter, 98 $multiple, $method, $json, $authrequired, $isuserbackpack, $backpackapiversion) { 99 $this->action = $action; 100 $this->url = $url; 101 $this->postparams = $postparams; 102 $this->requestexporter = $requestexporter; 103 $this->responseexporter = $responseexporter; 104 $this->multiple = $multiple; 105 $this->method = $method; 106 $this->json = $json; 107 $this->authrequired = $authrequired; 108 $this->isuserbackpack = $isuserbackpack; 109 $this->backpackapiversion = $backpackapiversion; 110 } 111 112 /** 113 * Get the unique key for the token. 114 * 115 * @param string $type The type of token. 116 * @return string 117 */ 118 private function get_token_key($type) { 119 $prefix = 'badges_'; 120 if ($this->isuserbackpack) { 121 $prefix .= 'user_backpack_'; 122 } else { 123 $prefix .= 'site_backpack_'; 124 } 125 $prefix .= $type . '_token'; 126 return $prefix; 127 } 128 129 /** 130 * Remember the error message in a static variable. 131 * 132 * @param string $msg The message. 133 */ 134 public static function set_authentication_error($msg) { 135 self::$authenticationerror = $msg; 136 } 137 138 /** 139 * Get the last authentication error in this request. 140 * 141 * @return string 142 */ 143 public static function get_authentication_error() { 144 return self::$authenticationerror; 145 } 146 147 /** 148 * Does the action match this mapping? 149 * 150 * @param string $action The action. 151 * @return boolean 152 */ 153 public function is_match($action) { 154 return $this->action == $action; 155 } 156 157 /** 158 * Parse the method url and insert parameters. 159 * 160 * @param string $apiurl The raw apiurl. 161 * @param string $param1 The first parameter. 162 * @param string $param2 The second parameter. 163 * @return string 164 */ 165 private function get_url($apiurl, $param1, $param2) { 166 $urlscheme = parse_url($apiurl, PHP_URL_SCHEME); 167 $urlhost = parse_url($apiurl, PHP_URL_HOST); 168 169 $url = $this->url; 170 $url = str_replace('[SCHEME]', $urlscheme, $url); 171 $url = str_replace('[HOST]', $urlhost, $url); 172 $url = str_replace('[URL]', $apiurl, $url); 173 $url = str_replace('[PARAM1]', $param1 ?? '', $url); 174 $url = str_replace('[PARAM2]', $param2 ?? '', $url); 175 176 return $url; 177 } 178 179 /** 180 * Parse the post parameters and insert replacements. 181 * 182 * @param string $email The api username. 183 * @param string $password The api password. 184 * @param string $param The parameter. 185 * @return mixed 186 */ 187 private function get_post_params($email, $password, $param) { 188 global $PAGE; 189 190 if ($this->method == 'get') { 191 return ''; 192 } 193 194 $request = $this->postparams; 195 if ($request === '[PARAM]') { 196 $value = $param; 197 foreach ($value as $key => $keyvalue) { 198 if (gettype($value[$key]) == 'array') { 199 $newkey = 'related_' . $key; 200 $value[$newkey] = $value[$key]; 201 unset($value[$key]); 202 } 203 } 204 } else if (is_array($request)) { 205 foreach ($request as $key => $value) { 206 if ($value == '[EMAIL]') { 207 $value = $email; 208 $request[$key] = $value; 209 } else if ($value == '[PASSWORD]') { 210 $value = $password; 211 $request[$key] = $value; 212 } else if ($value == '[PARAM]') { 213 $request[$key] = is_array($param) ? $param[0] : $param; 214 } 215 } 216 } 217 $context = context_system::instance(); 218 $exporter = $this->requestexporter; 219 $output = $PAGE->get_renderer('core', 'badges'); 220 if (!empty($exporter)) { 221 $exporterinstance = new $exporter($value, ['context' => $context]); 222 $request = $exporterinstance->export($output); 223 } 224 if ($this->json) { 225 return json_encode($request); 226 } 227 return $request; 228 } 229 230 /** 231 * Read the response from a V1 user request and save the userID. 232 * 233 * @param string $response The request response. 234 * @param integer $backpackid The backpack id. 235 * @return mixed 236 */ 237 private function convert_email_response($response, $backpackid) { 238 global $SESSION; 239 240 if (isset($response->status) && $response->status == 'okay') { 241 242 // Remember the tokens. 243 $useridkey = $this->get_token_key(BADGE_USER_ID_TOKEN); 244 $backpackidkey = $this->get_token_key(BADGE_BACKPACK_ID_TOKEN); 245 246 $SESSION->$useridkey = $response->userId; 247 $SESSION->$backpackidkey = $backpackid; 248 return $response->userId; 249 } 250 if (!empty($response->error)) { 251 self::set_authentication_error($response->error); 252 } 253 return false; 254 } 255 256 /** 257 * Get the user id from a previous user request. 258 * 259 * @return integer 260 */ 261 private function get_auth_user_id() { 262 global $USER; 263 264 if ($this->isuserbackpack) { 265 return $USER->id; 266 } else { 267 // The access tokens for the system backpack are shared. 268 return -1; 269 } 270 } 271 272 /** 273 * Parse the response from an openbadges 2 login. 274 * 275 * @param string $response The request response data. 276 * @param integer $backpackid The id of the backpack. 277 * @return mixed 278 */ 279 private function oauth_token_response($response, $backpackid) { 280 global $SESSION; 281 282 if (isset($response->access_token) && isset($response->refresh_token)) { 283 // Remember the tokens. 284 $accesskey = $this->get_token_key(BADGE_ACCESS_TOKEN); 285 $refreshkey = $this->get_token_key(BADGE_REFRESH_TOKEN); 286 $expireskey = $this->get_token_key(BADGE_EXPIRES_TOKEN); 287 $useridkey = $this->get_token_key(BADGE_USER_ID_TOKEN); 288 $backpackidkey = $this->get_token_key(BADGE_BACKPACK_ID_TOKEN); 289 if (isset($response->expires_in)) { 290 $timeout = $response->expires_in; 291 } else { 292 $timeout = 15 * 60; // 15 minute timeout if none set. 293 } 294 $expires = $timeout + time(); 295 296 $SESSION->$expireskey = $expires; 297 $SESSION->$useridkey = $this->get_auth_user_id(); 298 $SESSION->$accesskey = $response->access_token; 299 $SESSION->$refreshkey = $response->refresh_token; 300 $SESSION->$backpackidkey = $backpackid; 301 return -1; 302 } else if (isset($response->error_description)) { 303 self::set_authentication_error($response->error_description); 304 } 305 return $response; 306 } 307 308 /** 309 * Standard options used for all curl requests. 310 * 311 * @return array 312 */ 313 private function get_curl_options() { 314 return array( 315 'FRESH_CONNECT' => true, 316 'RETURNTRANSFER' => true, 317 'FOLLOWLOCATION' => true, 318 'FORBID_REUSE' => true, 319 'HEADER' => 0, 320 'CONNECTTIMEOUT' => 3, 321 'CONNECTTIMEOUT' => 3, 322 // Follow redirects with the same type of request when sent 301, or 302 redirects. 323 'CURLOPT_POSTREDIR' => 3, 324 ); 325 } 326 327 /** 328 * Make an api request and parse the response. 329 * 330 * @param string $apiurl Raw request url. 331 * @param string $urlparam1 Parameter for the request. 332 * @param string $urlparam2 Parameter for the request. 333 * @param string $email User email for authentication. 334 * @param string $password for authentication. 335 * @param mixed $postparam Raw data for the post body. 336 * @param string $backpackid the id of the backpack to use. 337 * @return mixed 338 */ 339 public function request($apiurl, $urlparam1, $urlparam2, $email, $password, $postparam, $backpackid) { 340 global $SESSION, $PAGE; 341 342 $curl = new curl(); 343 344 $url = $this->get_url($apiurl, $urlparam1, $urlparam2); 345 346 if ($this->authrequired) { 347 $accesskey = $this->get_token_key(BADGE_ACCESS_TOKEN); 348 if (isset($SESSION->$accesskey)) { 349 $token = $SESSION->$accesskey; 350 $curl->setHeader('Authorization: Bearer ' . $token); 351 } 352 } 353 if ($this->json) { 354 $curl->setHeader(array('Content-type: application/json')); 355 } 356 $curl->setHeader(array('Accept: application/json', 'Expect:')); 357 $options = $this->get_curl_options(); 358 359 $post = $this->get_post_params($email, $password, $postparam); 360 361 if ($this->method == 'get') { 362 $response = $curl->get($url, $post, $options); 363 } else if ($this->method == 'post') { 364 $response = $curl->post($url, $post, $options); 365 } else if ($this->method == 'put') { 366 $response = $curl->put($url, $post, $options); 367 } 368 $response = json_decode($response); 369 if (isset($response->result)) { 370 $response = $response->result; 371 } 372 $context = context_system::instance(); 373 $exporter = $this->responseexporter; 374 if (class_exists($exporter)) { 375 $output = $PAGE->get_renderer('core', 'badges'); 376 if (!$this->multiple) { 377 if (count($response)) { 378 $response = $response[0]; 379 } 380 if (empty($response)) { 381 return null; 382 } 383 $apidata = $exporter::map_external_data($response, $this->backpackapiversion); 384 $exporterinstance = new $exporter($apidata, ['context' => $context]); 385 $data = $exporterinstance->export($output); 386 return $data; 387 } else { 388 $multiple = []; 389 if (empty($response)) { 390 return $multiple; 391 } 392 foreach ($response as $data) { 393 $apidata = $exporter::map_external_data($data, $this->backpackapiversion); 394 $exporterinstance = new $exporter($apidata, ['context' => $context]); 395 $multiple[] = $exporterinstance->export($output); 396 } 397 return $multiple; 398 } 399 } else if (method_exists($this, $exporter)) { 400 return $this->$exporter($response, $backpackid); 401 } 402 return $response; 403 } 404 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body