PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/mod/lti/service.php

https://github.com/totara/moodle
PHP | 218 lines | 139 code | 47 blank | 32 comment | 11 complexity | 4c50a6f7125da50e207add50c545945e MD5 | raw file
  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. * LTI web service endpoints
  18. *
  19. * @package mod_lti
  20. * @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. * @author Chris Scribner
  23. */
  24. define('NO_DEBUG_DISPLAY', true);
  25. define('NO_MOODLE_COOKIES', true);
  26. require_once(dirname(__FILE__) . "/../../config.php");
  27. require_once($CFG->dirroot.'/mod/lti/locallib.php');
  28. require_once($CFG->dirroot.'/mod/lti/servicelib.php');
  29. // TODO: Switch to core oauthlib once implemented - MDL-30149.
  30. use moodle\mod\lti as lti;
  31. $rawbody = file_get_contents("php://input");
  32. if (lti_should_log_request($rawbody)) {
  33. lti_log_request($rawbody);
  34. }
  35. foreach (lti\OAuthUtil::get_headers() as $name => $value) {
  36. if ($name === 'Authorization') {
  37. // TODO: Switch to core oauthlib once implemented - MDL-30149.
  38. $oauthparams = lti\OAuthUtil::split_header($value);
  39. $consumerkey = $oauthparams['oauth_consumer_key'];
  40. break;
  41. }
  42. }
  43. if (empty($consumerkey)) {
  44. throw new Exception('Consumer key is missing.');
  45. }
  46. $sharedsecret = lti_verify_message($consumerkey, lti_get_shared_secrets_by_key($consumerkey), $rawbody);
  47. if ($sharedsecret === false) {
  48. throw new Exception('Message signature not valid');
  49. }
  50. // TODO MDL-46023 Replace this code with a call to the new library.
  51. $origentity = libxml_disable_entity_loader(true);
  52. $xml = simplexml_load_string($rawbody);
  53. if (!$xml) {
  54. libxml_disable_entity_loader($origentity);
  55. throw new Exception('Invalid XML content');
  56. }
  57. libxml_disable_entity_loader($origentity);
  58. $body = $xml->imsx_POXBody;
  59. foreach ($body->children() as $child) {
  60. $messagetype = $child->getName();
  61. }
  62. switch ($messagetype) {
  63. case 'replaceResultRequest':
  64. try {
  65. $parsed = lti_parse_grade_replace_message($xml);
  66. } catch (Exception $e) {
  67. $responsexml = lti_get_response_xml(
  68. 'failure',
  69. $e->getMessage(),
  70. uniqid(),
  71. 'replaceResultResponse');
  72. echo $responsexml->asXML();
  73. break;
  74. }
  75. $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
  76. if (!lti_accepts_grades($ltiinstance)) {
  77. throw new Exception('Tool does not accept grades');
  78. }
  79. lti_verify_sourcedid($ltiinstance, $parsed);
  80. lti_set_session_user($parsed->userid);
  81. $gradestatus = lti_update_grade($ltiinstance, $parsed->userid, $parsed->launchid, $parsed->gradeval);
  82. $responsexml = lti_get_response_xml(
  83. $gradestatus ? 'success' : 'failure',
  84. 'Grade replace response',
  85. $parsed->messageid,
  86. 'replaceResultResponse'
  87. );
  88. echo $responsexml->asXML();
  89. break;
  90. case 'readResultRequest':
  91. $parsed = lti_parse_grade_read_message($xml);
  92. $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
  93. if (!lti_accepts_grades($ltiinstance)) {
  94. throw new Exception('Tool does not accept grades');
  95. }
  96. // Getting the grade requires the context is set.
  97. $context = context_course::instance($ltiinstance->course);
  98. $PAGE->set_context($context);
  99. lti_verify_sourcedid($ltiinstance, $parsed);
  100. $grade = lti_read_grade($ltiinstance, $parsed->userid);
  101. $responsexml = lti_get_response_xml(
  102. 'success', // Empty grade is also 'success'.
  103. 'Result read',
  104. $parsed->messageid,
  105. 'readResultResponse'
  106. );
  107. $node = $responsexml->imsx_POXBody->readResultResponse;
  108. $node = $node->addChild('result')->addChild('resultScore');
  109. $node->addChild('language', 'en');
  110. $node->addChild('textString', isset($grade) ? $grade : '');
  111. echo $responsexml->asXML();
  112. break;
  113. case 'deleteResultRequest':
  114. $parsed = lti_parse_grade_delete_message($xml);
  115. $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
  116. if (!lti_accepts_grades($ltiinstance)) {
  117. throw new Exception('Tool does not accept grades');
  118. }
  119. lti_verify_sourcedid($ltiinstance, $parsed);
  120. lti_set_session_user($parsed->userid);
  121. $gradestatus = lti_delete_grade($ltiinstance, $parsed->userid);
  122. $responsexml = lti_get_response_xml(
  123. $gradestatus ? 'success' : 'failure',
  124. 'Grade delete request',
  125. $parsed->messageid,
  126. 'deleteResultResponse'
  127. );
  128. echo $responsexml->asXML();
  129. break;
  130. default:
  131. // Fire an event if we get a web service request which we don't support directly.
  132. // This will allow others to extend the LTI services, which I expect to be a common
  133. // use case, at least until the spec matures.
  134. $data = new stdClass();
  135. $data->body = $rawbody;
  136. $data->xml = $xml;
  137. $data->messageid = lti_parse_message_id($xml);
  138. $data->messagetype = $messagetype;
  139. $data->consumerkey = $consumerkey;
  140. $data->sharedsecret = $sharedsecret;
  141. $eventdata = array();
  142. $eventdata['other'] = array();
  143. $eventdata['other']['messageid'] = $data->messageid;
  144. $eventdata['other']['messagetype'] = $messagetype;
  145. $eventdata['other']['consumerkey'] = $consumerkey;
  146. // Before firing the event, allow subplugins a chance to handle.
  147. if (lti_extend_lti_services($data)) {
  148. break;
  149. }
  150. // If an event handler handles the web service, it should set this global to true
  151. // So this code knows whether to send an "operation not supported" or not.
  152. global $ltiwebservicehandled;
  153. $ltiwebservicehandled = false;
  154. try {
  155. $event = \mod_lti\event\unknown_service_api_called::create($eventdata);
  156. $event->set_message_data($data);
  157. $event->trigger();
  158. } catch (Exception $e) {
  159. $ltiwebservicehandled = false;
  160. }
  161. if (!$ltiwebservicehandled) {
  162. $responsexml = lti_get_response_xml(
  163. 'unsupported',
  164. 'unsupported',
  165. lti_parse_message_id($xml),
  166. $messagetype
  167. );
  168. echo $responsexml->asXML();
  169. }
  170. break;
  171. }