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]
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 * Extends the IMS Tool provider library data connector for moodle. 19 * 20 * @package enrol_lti 21 * @copyright 2016 John Okely <john@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace enrol_lti; 26 27 defined('MOODLE_INTERNAL') || die; 28 29 use IMSGlobal\LTI\ToolProvider; 30 use IMSGlobal\LTI\ToolProvider\ConsumerNonce; 31 use IMSGlobal\LTI\ToolProvider\Context; 32 use IMSGlobal\LTI\ToolProvider\DataConnector\DataConnector; 33 use IMSGlobal\LTI\ToolProvider\ResourceLink; 34 use IMSGlobal\LTI\ToolProvider\ResourceLinkShare; 35 use IMSGlobal\LTI\ToolProvider\ResourceLinkShareKey; 36 use IMSGlobal\LTI\ToolProvider\ToolConsumer; 37 use IMSGlobal\LTI\ToolProvider\ToolProxy; 38 use IMSGlobal\LTI\ToolProvider\User; 39 use stdClass; 40 41 /** 42 * Extends the IMS Tool provider library data connector for moodle. 43 * 44 * @package enrol_lti 45 * @copyright 2016 John Okely <john@moodle.com> 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48 class data_connector extends DataConnector { 49 50 /** @var string Tool consumer table name. */ 51 protected $consumertable; 52 /** @var string Context table name. */ 53 protected $contexttable; 54 /** @var string Consumer nonce table name. */ 55 protected $noncetable; 56 /** @var string Resource link table name. */ 57 protected $resourcelinktable; 58 /** @var string Resource link share key table name. */ 59 protected $sharekeytable; 60 /** @var string Tool proxy table name. */ 61 protected $toolproxytable; 62 /** @var string User result table name. */ 63 protected $userresulttable; 64 65 /** 66 * data_connector constructor. 67 */ 68 public function __construct() { 69 parent::__construct(null, 'enrol_lti_'); 70 71 // Set up table names. 72 $this->consumertable = $this->dbTableNamePrefix . DataConnector::CONSUMER_TABLE_NAME; 73 $this->contexttable = $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME; 74 $this->noncetable = $this->dbTableNamePrefix . DataConnector::NONCE_TABLE_NAME; 75 $this->resourcelinktable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_TABLE_NAME; 76 $this->sharekeytable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME; 77 $this->toolproxytable = $this->dbTableNamePrefix . DataConnector::TOOL_PROXY_TABLE_NAME; 78 $this->userresulttable = $this->dbTableNamePrefix . DataConnector::USER_RESULT_TABLE_NAME; 79 } 80 81 /** 82 * Load tool consumer object. 83 * 84 * @param ToolConsumer $consumer ToolConsumer object 85 * @return boolean True if the tool consumer object was successfully loaded 86 */ 87 public function loadToolConsumer($consumer) { 88 global $DB; 89 90 $id = $consumer->getRecordId(); 91 $key = $consumer->getKey(); 92 $result = false; 93 94 if (!empty($id)) { 95 $result = $DB->get_record($this->consumertable, ['id' => $id]); 96 } else if (!empty($key)) { 97 $key256 = DataConnector::getConsumerKey($key); 98 $result = $DB->get_record($this->consumertable, ['consumerkey256' => $key256]); 99 } 100 101 if ($result) { 102 if (empty($key256) || empty($result->consumerkey) || ($key === $result->consumerkey)) { 103 $this->build_tool_consumer_object($result, $consumer); 104 return true; 105 } 106 } 107 108 return false; 109 } 110 111 /** 112 * Save tool consumer object. 113 * 114 * @param ToolConsumer $consumer Consumer object 115 * @return boolean True if the tool consumer object was successfully saved 116 */ 117 public function saveToolConsumer($consumer) { 118 global $DB; 119 120 $key = $consumer->getKey(); 121 $key256 = DataConnector::getConsumerKey($key); 122 if ($key === $key256) { 123 $key = null; 124 } 125 $protected = ($consumer->protected) ? 1 : 0; 126 $enabled = ($consumer->enabled) ? 1 : 0; 127 $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null; 128 $settingsvalue = serialize($consumer->getSettings()); 129 $now = time(); 130 $consumer->updated = $now; 131 $data = [ 132 'consumerkey256' => $key256, 133 'consumerkey' => $key, 134 'name' => $consumer->name, 135 'secret' => $consumer->secret, 136 'ltiversion' => $consumer->ltiVersion, 137 'consumername' => $consumer->consumerName, 138 'consumerversion' => $consumer->consumerVersion, 139 'consumerguid' => $consumer->consumerGuid, 140 'profile' => $profile, 141 'toolproxy' => $consumer->toolProxy, 142 'settings' => $settingsvalue, 143 'protected' => $protected, 144 'enabled' => $enabled, 145 'enablefrom' => $consumer->enableFrom, 146 'enableuntil' => $consumer->enableUntil, 147 'lastaccess' => $consumer->lastAccess, 148 'updated' => $consumer->updated, 149 ]; 150 151 $id = $consumer->getRecordId(); 152 153 if (empty($id)) { 154 $consumer->created = $now; 155 $data['created'] = $consumer->created; 156 $id = $DB->insert_record($this->consumertable, (object) $data); 157 if ($id) { 158 $consumer->setRecordId($id); 159 return true; 160 } 161 } else { 162 $data['id'] = $id; 163 return $DB->update_record($this->consumertable, (object) $data); 164 } 165 166 return false; 167 } 168 169 /** 170 * Delete tool consumer object and related records. 171 * 172 * @param ToolConsumer $consumer Consumer object 173 * @return boolean True if the tool consumer object was successfully deleted 174 */ 175 public function deleteToolConsumer($consumer) { 176 global $DB; 177 178 $consumerpk = $consumer->getRecordId(); 179 $deletecondition = ['consumerid' => $consumerpk]; 180 181 // Delete any nonce values for this consumer. 182 $DB->delete_records($this->noncetable, $deletecondition); 183 184 // Delete any outstanding share keys for resource links for this consumer. 185 $where = "resourcelinkid IN ( 186 SELECT rl.id 187 FROM {{$this->resourcelinktable}} rl 188 WHERE rl.consumerid = :consumerid 189 )"; 190 $DB->delete_records_select($this->sharekeytable, $where, $deletecondition); 191 192 // Delete any outstanding share keys for resource links for contexts in this consumer. 193 $where = "resourcelinkid IN ( 194 SELECT rl.id 195 FROM {{$this->resourcelinktable}} rl 196 INNER JOIN {{$this->contexttable}} c 197 ON rl.contextid = c.id 198 WHERE c.consumerid = :consumerid 199 )"; 200 $DB->delete_records_select($this->sharekeytable, $where, $deletecondition); 201 202 // Delete any users in resource links for this consumer. 203 $where = "resourcelinkid IN ( 204 SELECT rl.id 205 FROM {{$this->resourcelinktable}} rl 206 WHERE rl.consumerid = :consumerid 207 )"; 208 $DB->delete_records_select($this->userresulttable, $where, $deletecondition); 209 210 // Delete any users in resource links for contexts in this consumer. 211 $where = "resourcelinkid IN ( 212 SELECT rl.id 213 FROM {{$this->resourcelinktable}} rl 214 INNER JOIN {{$this->contexttable}} c 215 ON rl.contextid = c.id 216 WHERE c.consumerid = :consumerid 217 )"; 218 $DB->delete_records_select($this->userresulttable, $where, $deletecondition); 219 220 // Update any resource links for which this consumer is acting as a primary resource link. 221 $where = "primaryresourcelinkid IN ( 222 SELECT rl.id 223 FROM {{$this->resourcelinktable}} rl 224 WHERE rl.consumerid = :consumerid 225 )"; 226 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition); 227 foreach ($updaterecords as $record) { 228 $record->primaryresourcelinkid = null; 229 $record->shareapproved = null; 230 $DB->update_record($this->resourcelinktable, $record); 231 } 232 233 // Update any resource links for contexts in which this consumer is acting as a primary resource link. 234 $where = "primaryresourcelinkid IN ( 235 SELECT rl.id 236 FROM {{$this->resourcelinktable}} rl 237 INNER JOIN {{$this->contexttable}} c 238 ON rl.contextid = c.id 239 WHERE c.consumerid = :consumerid 240 )"; 241 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition); 242 foreach ($updaterecords as $record) { 243 $record->primaryresourcelinkid = null; 244 $record->shareapproved = null; 245 $DB->update_record($this->resourcelinktable, $record); 246 } 247 248 // Delete any resource links for contexts in this consumer. 249 $where = "contextid IN ( 250 SELECT c.id 251 FROM {{$this->contexttable}} c 252 WHERE c.consumerid = :consumerid 253 )"; 254 $DB->delete_records_select($this->resourcelinktable, $where, $deletecondition); 255 256 // Delete any resource links for this consumer. 257 $DB->delete_records($this->resourcelinktable, $deletecondition); 258 259 // Delete any contexts for this consumer. 260 $DB->delete_records($this->contexttable, $deletecondition); 261 262 // Delete consumer. 263 $DB->delete_records($this->consumertable, ['id' => $consumerpk]); 264 265 $consumer->initialize(); 266 267 return true; 268 } 269 270 /** 271 * Load all tool consumers from the database. 272 * @return array 273 */ 274 public function getToolConsumers() { 275 global $DB; 276 $consumers = []; 277 278 $rsconsumers = $DB->get_recordset($this->consumertable, null, 'name'); 279 foreach ($rsconsumers as $row) { 280 $consumer = new ToolProvider\ToolConsumer($row->consumerkey, $this); 281 $this->build_tool_consumer_object($row, $consumer); 282 $consumers[] = $consumer; 283 } 284 $rsconsumers->close(); 285 286 return $consumers; 287 } 288 289 /* 290 * ToolProxy methods. 291 */ 292 293 /** 294 * Load the tool proxy from the database. 295 * 296 * @param ToolProxy $toolproxy 297 * @return bool 298 */ 299 public function loadToolProxy($toolproxy) { 300 return false; 301 } 302 303 /** 304 * Save the tool proxy to the database. 305 * 306 * @param ToolProxy $toolproxy 307 * @return bool 308 */ 309 public function saveToolProxy($toolproxy) { 310 return false; 311 } 312 313 /** 314 * Delete the tool proxy from the database. 315 * 316 * @param ToolProxy $toolproxy 317 * @return bool 318 */ 319 public function deleteToolProxy($toolproxy) { 320 return false; 321 } 322 323 /* 324 * Context methods. 325 */ 326 327 /** 328 * Load context object. 329 * 330 * @param Context $context Context object 331 * @return boolean True if the context object was successfully loaded 332 */ 333 public function loadContext($context) { 334 global $DB; 335 336 if (!empty($context->getRecordId())) { 337 $params = ['id' => $context->getRecordId()]; 338 } else { 339 $params = [ 340 'consumerid' => $context->getConsumer()->getRecordId(), 341 'lticontextkey' => $context->ltiContextId 342 ]; 343 } 344 if ($row = $DB->get_record($this->contexttable, $params)) { 345 $context->setRecordId($row->id); 346 $context->setConsumerId($row->consumerid); 347 $context->ltiContextId = $row->lticontextkey; 348 $context->type = $row->type; 349 $settings = unserialize($row->settings); 350 if (!is_array($settings)) { 351 $settings = array(); 352 } 353 $context->setSettings($settings); 354 $context->created = $row->created; 355 $context->updated = $row->updated; 356 return true; 357 } 358 359 return false; 360 } 361 362 /** 363 * Save context object. 364 * 365 * @param Context $context Context object 366 * @return boolean True if the context object was successfully saved 367 */ 368 public function saveContext($context) { 369 global $DB; 370 $now = time(); 371 $context->updated = $now; 372 $settingsvalue = serialize($context->getSettings()); 373 $id = $context->getRecordId(); 374 $consumerpk = $context->getConsumer()->getRecordId(); 375 376 $isinsert = empty($id); 377 if ($isinsert) { 378 $context->created = $now; 379 $params = [ 380 'consumerid' => $consumerpk, 381 'lticontextkey' => $context->ltiContextId, 382 'type' => $context->type, 383 'settings' => $settingsvalue, 384 'created' => $context->created, 385 'updated' => $context->updated, 386 ]; 387 $id = $DB->insert_record($this->contexttable, (object) $params); 388 if ($id) { 389 $context->setRecordId($id); 390 return true; 391 } 392 } else { 393 $data = (object) [ 394 'id' => $id, 395 'contextid' => $consumerpk, 396 'lticontextkey' => $context->ltiContextId, 397 'type' => $context->type, 398 'settings' => $settingsvalue, 399 'updated' => $context->updated, 400 ]; 401 return $DB->update_record($this->contexttable, $data); 402 } 403 404 return false; 405 } 406 407 /** 408 * Delete context object. 409 * 410 * @param Context $context Context object 411 * @return boolean True if the Context object was successfully deleted 412 */ 413 public function deleteContext($context) { 414 global $DB; 415 416 $contextid = $context->getRecordId(); 417 418 $params = ['id' => $contextid]; 419 420 // Delete any outstanding share keys for resource links for this context. 421 $where = "resourcelinkid IN ( 422 SELECT rl.id 423 FROM {{$this->resourcelinktable}} rl 424 WHERE rl.contextid = :id 425 )"; 426 $DB->delete_records_select($this->sharekeytable, $where, $params); 427 428 // Delete any users in resource links for this context. 429 $DB->delete_records_select($this->userresulttable, $where, $params); 430 431 // Update any resource links for which this consumer is acting as a primary resource link. 432 $where = "primaryresourcelinkid IN ( 433 SELECT rl.id 434 FROM {{$this->resourcelinktable}} rl 435 WHERE rl.contextid = :id 436 )"; 437 $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $params); 438 foreach ($updaterecords as $record) { 439 $record->primaryresourcelinkid = null; 440 $record->shareapproved = null; 441 $DB->update_record($this->resourcelinktable, $record); 442 } 443 444 // Delete any resource links for this context. 445 $DB->delete_records($this->resourcelinktable, ['contextid' => $contextid]); 446 447 // Delete context. 448 $DB->delete_records($this->contexttable, $params); 449 450 $context->initialize(); 451 452 return true; 453 } 454 455 /* 456 * ResourceLink methods 457 */ 458 459 /** 460 * Load resource link object. 461 * 462 * @param ResourceLink $resourcelink ResourceLink object 463 * @return boolean True if the resource link object was successfully loaded 464 */ 465 public function loadResourceLink($resourcelink) { 466 global $DB; 467 468 $resourceid = $resourcelink->getRecordId(); 469 if (!empty($resourceid)) { 470 $params = ['id' => $resourceid]; 471 $row = $DB->get_record($this->resourcelinktable, $params); 472 } else if (!empty($resourcelink->getContext())) { 473 $params = [ 474 'contextid' => $resourcelink->getContext()->getRecordId(), 475 'ltiresourcelinkkey' => $resourcelink->getId() 476 ]; 477 $row = $DB->get_record($this->resourcelinktable, $params); 478 } else { 479 $sql = "SELECT r.* 480 FROM {{$this->resourcelinktable}} r 481 LEFT OUTER JOIN {{$this->contexttable}} c 482 ON r.contextid = c.id 483 WHERE (r.consumerid = ? OR c.consumerid = ?) 484 AND ltiresourcelinkkey = ?"; 485 $params = [ 486 $resourcelink->getConsumer()->getRecordId(), 487 $resourcelink->getConsumer()->getRecordId(), 488 $resourcelink->getId() 489 ]; 490 $row = $DB->get_record_sql($sql, $params); 491 } 492 if ($row) { 493 $resourcelink->setRecordId($row->id); 494 if (!is_null($row->contextid)) { 495 $resourcelink->setContextId($row->contextid); 496 } else { 497 $resourcelink->setContextId(null); 498 } 499 if (!is_null($row->consumerid)) { 500 $resourcelink->setConsumerId($row->consumerid); 501 } else { 502 $resourcelink->setConsumerId(null); 503 } 504 $resourcelink->ltiResourceLinkId = $row->ltiresourcelinkkey; 505 $settings = unserialize($row->settings); 506 if (!is_array($settings)) { 507 $settings = array(); 508 } 509 $resourcelink->setSettings($settings); 510 if (!is_null($row->primaryresourcelinkid)) { 511 $resourcelink->primaryResourceLinkId = $row->primaryresourcelinkid; 512 } else { 513 $resourcelink->primaryResourceLinkId = null; 514 } 515 $resourcelink->shareApproved = (is_null($row->shareapproved)) ? null : ($row->shareapproved == 1); 516 $resourcelink->created = $row->created; 517 $resourcelink->updated = $row->updated; 518 return true; 519 } 520 521 return false; 522 } 523 524 /** 525 * Save resource link object. 526 * 527 * @param ResourceLink $resourcelink Resource_Link object 528 * @return boolean True if the resource link object was successfully saved 529 */ 530 public function saveResourceLink($resourcelink) { 531 global $DB; 532 533 if (is_null($resourcelink->shareApproved)) { 534 $approved = null; 535 } else if ($resourcelink->shareApproved) { 536 $approved = 1; 537 } else { 538 $approved = 0; 539 } 540 if (empty($resourcelink->primaryResourceLinkId)) { 541 $primaryresourcelinkid = null; 542 } else { 543 $primaryresourcelinkid = $resourcelink->primaryResourceLinkId; 544 } 545 $now = time(); 546 $resourcelink->updated = $now; 547 $settingsvalue = serialize($resourcelink->getSettings()); 548 if (!empty($resourcelink->getContext())) { 549 $consumerid = null; 550 $contextid = $resourcelink->getContext()->getRecordId(); 551 } else if (!empty($resourcelink->getContextId())) { 552 $consumerid = null; 553 $contextid = $resourcelink->getContextId(); 554 } else { 555 $consumerid = $resourcelink->getConsumer()->getRecordId(); 556 $contextid = null; 557 } 558 $id = $resourcelink->getRecordId(); 559 560 $data = [ 561 'consumerid' => $consumerid, 562 'contextid' => $contextid, 563 'ltiresourcelinkkey' => $resourcelink->getId(), 564 'settings' => $settingsvalue, 565 'primaryresourcelinkid' => $primaryresourcelinkid, 566 'shareapproved' => $approved, 567 'updated' => $resourcelink->updated, 568 ]; 569 570 $returnid = null; 571 572 if (empty($id)) { 573 $resourcelink->created = $now; 574 $data['created'] = $resourcelink->created; 575 $id = $DB->insert_record($this->resourcelinktable, (object) $data); 576 if ($id) { 577 $resourcelink->setRecordId($id); 578 return true; 579 } 580 581 } else { 582 $data['id'] = $id; 583 return $DB->update_record($this->resourcelinktable, (object) $data); 584 } 585 586 return false; 587 } 588 589 /** 590 * Delete resource link object. 591 * 592 * @param ResourceLink $resourcelink ResourceLink object 593 * @return boolean True if the resource link object and its related records were successfully deleted. 594 * Otherwise, a DML exception is thrown. 595 */ 596 public function deleteResourceLink($resourcelink) { 597 global $DB; 598 599 $resourcelinkid = $resourcelink->getRecordId(); 600 601 // Delete any outstanding share keys for resource links for this consumer. 602 $DB->delete_records($this->sharekeytable, ['resourcelinkid' => $resourcelinkid]); 603 604 // Delete users. 605 $DB->delete_records($this->userresulttable, ['resourcelinkid' => $resourcelinkid]); 606 607 // Update any resource links for which this is the primary resource link. 608 $records = $DB->get_records($this->resourcelinktable, ['primaryresourcelinkid' => $resourcelinkid]); 609 foreach ($records as $record) { 610 $record->primaryresourcelinkid = null; 611 $DB->update_record($this->resourcelinktable, $record); 612 } 613 614 // Delete resource link. 615 $DB->delete_records($this->resourcelinktable, ['id' => $resourcelinkid]); 616 617 $resourcelink->initialize(); 618 619 return true; 620 } 621 622 /** 623 * Get array of user objects. 624 * 625 * Obtain an array of User objects for users with a result sourcedId. The array may include users from other 626 * resource links which are sharing this resource link. It may also be optionally indexed by the user ID of a specified scope. 627 * 628 * @param ResourceLink $resourcelink Resource link object 629 * @param boolean $localonly True if only users within the resource link are to be returned 630 * (excluding users sharing this resource link) 631 * @param int $idscope Scope value to use for user IDs 632 * @return array Array of User objects 633 */ 634 public function getUserResultSourcedIDsResourceLink($resourcelink, $localonly, $idscope) { 635 global $DB; 636 637 $users = []; 638 639 $params = ['resourcelinkid' => $resourcelink->getRecordId()]; 640 641 // Where clause for the subquery. 642 $subwhere = "(id = :resourcelinkid AND primaryresourcelinkid IS NULL)"; 643 if (!$localonly) { 644 $subwhere .= " OR (primaryresourcelinkid = :resourcelinkid2 AND shareapproved = 1)"; 645 $params['resourcelinkid2'] = $resourcelink->getRecordId(); 646 } 647 648 // The subquery. 649 $subsql = "SELECT id 650 FROM {{$this->resourcelinktable}} 651 WHERE {$subwhere}"; 652 653 // Our main where clause. 654 $where = "resourcelinkid IN ($subsql)"; 655 656 // Fields to be queried. 657 $fields = 'id, ltiresultsourcedid, ltiuserkey, created, updated'; 658 659 // Fetch records. 660 $rs = $DB->get_recordset_select($this->userresulttable, $where, $params, '', $fields); 661 foreach ($rs as $row) { 662 $user = User::fromResourceLink($resourcelink, $row->ltiuserkey); 663 $user->setRecordId($row->id); 664 $user->ltiResultSourcedId = $row->ltiresultsourcedid; 665 $user->created = $row->created; 666 $user->updated = $row->updated; 667 if (is_null($idscope)) { 668 $users[] = $user; 669 } else { 670 $users[$user->getId($idscope)] = $user; 671 } 672 } 673 $rs->close(); 674 675 return $users; 676 } 677 678 /** 679 * Get array of shares defined for this resource link. 680 * 681 * @param ResourceLink $resourcelink ResourceLink object 682 * @return array Array of ResourceLinkShare objects 683 */ 684 public function getSharesResourceLink($resourcelink) { 685 global $DB; 686 687 $shares = []; 688 689 $params = ['primaryresourcelinkid' => $resourcelink->getRecordId()]; 690 $fields = 'id, shareapproved, consumerid'; 691 $records = $DB->get_records($this->resourcelinktable, $params, 'consumerid', $fields); 692 foreach ($records as $record) { 693 $share = new ResourceLinkShare(); 694 $share->resourceLinkId = $record->id; 695 $share->approved = $record->shareapproved == 1; 696 $shares[] = $share; 697 } 698 699 return $shares; 700 } 701 702 /* 703 * ConsumerNonce methods 704 */ 705 706 /** 707 * Load nonce object. 708 * 709 * @param ConsumerNonce $nonce Nonce object 710 * @return boolean True if the nonce object was successfully loaded 711 */ 712 public function loadConsumerNonce($nonce) { 713 global $DB; 714 715 // Delete any expired nonce values. 716 $now = time(); 717 $DB->delete_records_select($this->noncetable, "expires <= ?", [$now]); 718 719 // Load the nonce. 720 $params = [ 721 'consumerid' => $nonce->getConsumer()->getRecordId(), 722 'value' => $nonce->getValue() 723 ]; 724 $result = $DB->get_field($this->noncetable, 'value', $params); 725 726 return !empty($result); 727 } 728 729 /** 730 * Save nonce object. 731 * 732 * @param ConsumerNonce $nonce Nonce object 733 * @return boolean True if the nonce object was successfully saved 734 */ 735 public function saveConsumerNonce($nonce) { 736 global $DB; 737 738 $data = [ 739 'consumerid' => $nonce->getConsumer()->getRecordId(), 740 'value' => $nonce->getValue(), 741 'expires' => $nonce->expires 742 ]; 743 744 return $DB->insert_record($this->noncetable, (object) $data, false); 745 } 746 747 /* 748 * ResourceLinkShareKey methods. 749 */ 750 751 /** 752 * Load resource link share key object. 753 * 754 * @param ResourceLinkShareKey $sharekey ResourceLink share key object 755 * @return boolean True if the resource link share key object was successfully loaded 756 */ 757 public function loadResourceLinkShareKey($sharekey) { 758 global $DB; 759 760 // Clear expired share keys. 761 $now = time(); 762 $where = "expires <= :expires"; 763 764 $DB->delete_records_select($this->sharekeytable, $where, ['expires' => $now]); 765 766 // Load share key. 767 $fields = 'resourcelinkid, autoapprove, expires'; 768 if ($sharekeyrecord = $DB->get_record($this->sharekeytable, ['sharekey' => $sharekey->getId()], $fields)) { 769 if ($sharekeyrecord->resourcelinkid == $sharekey->resourceLinkId) { 770 $sharekey->autoApprove = $sharekeyrecord->autoapprove == 1; 771 $sharekey->expires = $sharekeyrecord->expires; 772 return true; 773 } 774 } 775 776 return false; 777 } 778 779 /** 780 * Save resource link share key object. 781 * 782 * @param ResourceLinkShareKey $sharekey Resource link share key object 783 * @return boolean True if the resource link share key object was successfully saved 784 */ 785 public function saveResourceLinkShareKey($sharekey) { 786 global $DB; 787 788 if ($sharekey->autoApprove) { 789 $approve = 1; 790 } else { 791 $approve = 0; 792 } 793 794 $expires = $sharekey->expires; 795 796 $params = [ 797 'sharekey' => $sharekey->getId(), 798 'resourcelinkid' => $sharekey->resourceLinkId, 799 'autoapprove' => $approve, 800 'expires' => $expires 801 ]; 802 803 return $DB->insert_record($this->sharekeytable, (object) $params, false); 804 } 805 806 /** 807 * Delete resource link share key object. 808 * 809 * @param ResourceLinkShareKey $sharekey Resource link share key object 810 * @return boolean True if the resource link share key object was successfully deleted 811 */ 812 public function deleteResourceLinkShareKey($sharekey) { 813 global $DB; 814 815 $DB->delete_records($this->sharekeytable, ['sharekey' => $sharekey->getId()]); 816 $sharekey->initialize(); 817 818 return true; 819 } 820 821 /* 822 * User methods 823 */ 824 825 /** 826 * Load user object. 827 * 828 * @param User $user User object 829 * @return boolean True if the user object was successfully loaded 830 */ 831 public function loadUser($user) { 832 global $DB; 833 834 $userid = $user->getRecordId(); 835 $fields = 'id, resourcelinkid, ltiuserkey, ltiresultsourcedid, created, updated'; 836 if (!empty($userid)) { 837 $row = $DB->get_record($this->userresulttable, ['id' => $userid], $fields); 838 } else { 839 $resourcelinkid = $user->getResourceLink()->getRecordId(); 840 $userid = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY); 841 $row = $DB->get_record_select( 842 $this->userresulttable, 843 "resourcelinkid = ? AND ltiuserkey = ?", 844 [$resourcelinkid, $userid], 845 $fields 846 ); 847 } 848 if ($row) { 849 $user->setRecordId($row->id); 850 $user->setResourceLinkId($row->resourcelinkid); 851 $user->ltiUserId = $row->ltiuserkey; 852 $user->ltiResultSourcedId = $row->ltiresultsourcedid; 853 $user->created = $row->created; 854 $user->updated = $row->updated; 855 return true; 856 } 857 858 return false; 859 } 860 861 /** 862 * Save user object. 863 * 864 * @param User $user User object 865 * @return boolean True if the user object was successfully saved 866 */ 867 public function saveUser($user) { 868 global $DB; 869 870 $now = time(); 871 $isinsert = is_null($user->created); 872 $user->updated = $now; 873 874 $params = [ 875 'ltiresultsourcedid' => $user->ltiResultSourcedId, 876 'updated' => $user->updated 877 ]; 878 879 if ($isinsert) { 880 $params['resourcelinkid'] = $user->getResourceLink()->getRecordId(); 881 $params['ltiuserkey'] = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY); 882 $user->created = $now; 883 $params['created'] = $user->created; 884 $id = $DB->insert_record($this->userresulttable, (object) $params); 885 if ($id) { 886 $user->setRecordId($id); 887 return true; 888 } 889 890 } else { 891 $params['id'] = $user->getRecordId(); 892 return $DB->update_record($this->userresulttable, (object) $params); 893 } 894 895 return false; 896 } 897 898 /** 899 * Delete user object. 900 * 901 * @param User $user User object 902 * @return boolean True if the user object was successfully deleted 903 */ 904 public function deleteUser($user) { 905 global $DB; 906 907 $DB->delete_records($this->userresulttable, ['id' => $user->getRecordId()]); 908 $user->initialize(); 909 910 return true; 911 } 912 913 /** 914 * Fetches the list of Context objects that are linked to a ToolConsumer. 915 * 916 * @param ToolConsumer $consumer 917 * @return Context[] 918 */ 919 public function get_contexts_from_consumer(ToolConsumer $consumer) { 920 global $DB; 921 922 $contexts = []; 923 $contextrecords = $DB->get_records($this->contexttable, ['consumerid' => $consumer->getRecordId()], '', 'lticontextkey'); 924 foreach ($contextrecords as $record) { 925 $context = Context::fromConsumer($consumer, $record->lticontextkey); 926 $contexts[] = $context; 927 } 928 929 return $contexts; 930 } 931 932 /** 933 * Fetches a resource link record that is associated with a ToolConsumer. 934 * 935 * @param ToolConsumer $consumer 936 * @return ResourceLink 937 */ 938 public function get_resourcelink_from_consumer(ToolConsumer $consumer) { 939 global $DB; 940 941 $resourcelink = null; 942 if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['consumerid' => $consumer->getRecordId()], 943 'ltiresourcelinkkey')) { 944 $resourcelink = ResourceLink::fromConsumer($consumer, $resourcelinkrecord->ltiresourcelinkkey); 945 } 946 947 return $resourcelink; 948 } 949 950 /** 951 * Fetches a resource link record that is associated with a Context object. 952 * 953 * @param Context $context 954 * @return ResourceLink 955 */ 956 public function get_resourcelink_from_context(Context $context) { 957 global $DB; 958 959 $resourcelink = null; 960 if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['contextid' => $context->getRecordId()], 961 'ltiresourcelinkkey')) { 962 $resourcelink = ResourceLink::fromContext($context, $resourcelinkrecord->ltiresourcelinkkey); 963 } 964 965 return $resourcelink; 966 } 967 968 969 /** 970 * Fetches the list of ToolConsumer objects that are linked to a tool. 971 * 972 * @param int $toolid 973 * @return ToolConsumer[] 974 */ 975 public function get_consumers_mapped_to_tool($toolid) { 976 global $DB; 977 978 $consumers = []; 979 $consumerrecords = $DB->get_records('enrol_lti_tool_consumer_map', ['toolid' => $toolid], '', 'consumerid'); 980 foreach ($consumerrecords as $record) { 981 $consumers[] = ToolConsumer::fromRecordId($record->consumerid, $this); 982 } 983 return $consumers; 984 } 985 986 /** 987 * Builds a ToolConsumer object from a record object from the DB. 988 * 989 * @param stdClass $record The DB record object. 990 * @param ToolConsumer $consumer 991 */ 992 protected function build_tool_consumer_object($record, ToolConsumer $consumer) { 993 $consumer->setRecordId($record->id); 994 $consumer->name = $record->name; 995 $key = empty($record->consumerkey) ? $record->consumerkey256 : $record->consumerkey; 996 $consumer->setKey($key); 997 $consumer->secret = $record->secret; 998 $consumer->ltiVersion = $record->ltiversion; 999 $consumer->consumerName = $record->consumername; 1000 $consumer->consumerVersion = $record->consumerversion; 1001 $consumer->consumerGuid = $record->consumerguid; 1002 $consumer->profile = json_decode($record->profile ?? ''); 1003 $consumer->toolProxy = $record->toolproxy; 1004 $settings = unserialize($record->settings); 1005 if (!is_array($settings)) { 1006 $settings = array(); 1007 } 1008 $consumer->setSettings($settings); 1009 $consumer->protected = $record->protected == 1; 1010 $consumer->enabled = $record->enabled == 1; 1011 $consumer->enableFrom = null; 1012 if (!is_null($record->enablefrom)) { 1013 $consumer->enableFrom = $record->enablefrom; 1014 } 1015 $consumer->enableUntil = null; 1016 if (!is_null($record->enableuntil)) { 1017 $consumer->enableUntil = $record->enableuntil; 1018 } 1019 $consumer->lastAccess = null; 1020 if (!is_null($record->lastaccess)) { 1021 $consumer->lastAccess = $record->lastaccess; 1022 } 1023 $consumer->created = $record->created; 1024 $consumer->updated = $record->updated; 1025 } 1026 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body