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