See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [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 * LTI web service endpoints 19 * 20 * @package mod_lti 21 * @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com) 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @author Chris Scribner 24 */ 25 26 define('NO_DEBUG_DISPLAY', true); 27 define('NO_MOODLE_COOKIES', true); 28 29 require_once(__DIR__ . "/../../config.php"); 30 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 31 require_once($CFG->dirroot.'/mod/lti/servicelib.php'); 32 33 // TODO: Switch to core oauthlib once implemented - MDL-30149. 34 use mod_lti\service_exception_handler; 35 use moodle\mod\lti as lti; 36 use ltiservice_basicoutcomes\local\service\basicoutcomes; 37 38 $rawbody = file_get_contents("php://input"); 39 40 $logrequests = lti_should_log_request($rawbody); 41 $errorhandler = new service_exception_handler($logrequests); 42 43 // Register our own error handler so we can always send valid XML response. 44 set_exception_handler(array($errorhandler, 'handle')); 45 46 if ($logrequests) { 47 lti_log_request($rawbody); 48 } 49 50 $ok = true; 51 $type = null; 52 $toolproxy = false; 53 54 $consumerkey = lti\get_oauth_key_from_headers(null, array(basicoutcomes::SCOPE_BASIC_OUTCOMES)); 55 if ($consumerkey === false) { 56 throw new Exception('Missing or invalid consumer key or access token.'); 57 } else if (is_string($consumerkey)) { 58 $toolproxy = lti_get_tool_proxy_from_guid($consumerkey); 59 if ($toolproxy !== false) { 60 $secrets = array($toolproxy->secret); 61 } else if (!empty($tool)) { 62 $secrets = array($typeconfig['password']); 63 } else { 64 $secrets = lti_get_shared_secrets_by_key($consumerkey); 65 } 66 $sharedsecret = lti_verify_message($consumerkey, lti_get_shared_secrets_by_key($consumerkey), $rawbody); 67 if ($sharedsecret === false) { 68 throw new Exception('Message signature not valid'); 69 } 70 } 71 72 // TODO MDL-46023 Replace this code with a call to the new library. 73 $origentity = lti_libxml_disable_entity_loader(true); 74 $xml = simplexml_load_string($rawbody); 75 if (!$xml) { 76 lti_libxml_disable_entity_loader($origentity); 77 throw new Exception('Invalid XML content'); 78 } 79 lti_libxml_disable_entity_loader($origentity); 80 81 $body = $xml->imsx_POXBody; 82 foreach ($body->children() as $child) { 83 $messagetype = $child->getName(); 84 } 85 86 // We know more about the message, update error handler to send better errors. 87 $errorhandler->set_message_id(lti_parse_message_id($xml)); 88 $errorhandler->set_message_type($messagetype); 89 90 switch ($messagetype) { 91 case 'replaceResultRequest': 92 $parsed = lti_parse_grade_replace_message($xml); 93 94 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid)); 95 96 if (!lti_accepts_grades($ltiinstance)) { 97 throw new Exception('Tool does not accept grades'); 98 } 99 100 lti_verify_sourcedid($ltiinstance, $parsed); 101 lti_set_session_user($parsed->userid); 102 103 $gradestatus = lti_update_grade($ltiinstance, $parsed->userid, $parsed->launchid, $parsed->gradeval); 104 105 if (!$gradestatus) { 106 throw new Exception('Grade replace response'); 107 } 108 109 $responsexml = lti_get_response_xml( 110 'success', 111 'Grade replace response', 112 $parsed->messageid, 113 'replaceResultResponse' 114 ); 115 116 echo $responsexml->asXML(); 117 118 break; 119 120 case 'readResultRequest': 121 $parsed = lti_parse_grade_read_message($xml); 122 123 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid)); 124 125 if (!lti_accepts_grades($ltiinstance)) { 126 throw new Exception('Tool does not accept grades'); 127 } 128 129 // Getting the grade requires the context is set. 130 $context = context_course::instance($ltiinstance->course); 131 $PAGE->set_context($context); 132 133 lti_verify_sourcedid($ltiinstance, $parsed); 134 135 $grade = lti_read_grade($ltiinstance, $parsed->userid); 136 137 $responsexml = lti_get_response_xml( 138 'success', // Empty grade is also 'success'. 139 'Result read', 140 $parsed->messageid, 141 'readResultResponse' 142 ); 143 144 $node = $responsexml->imsx_POXBody->readResultResponse; 145 $node = $node->addChild('result')->addChild('resultScore'); 146 $node->addChild('language', 'en'); 147 $node->addChild('textString', isset($grade) ? $grade : ''); 148 149 echo $responsexml->asXML(); 150 151 break; 152 153 case 'deleteResultRequest': 154 $parsed = lti_parse_grade_delete_message($xml); 155 156 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid)); 157 158 if (!lti_accepts_grades($ltiinstance)) { 159 throw new Exception('Tool does not accept grades'); 160 } 161 162 lti_verify_sourcedid($ltiinstance, $parsed); 163 lti_set_session_user($parsed->userid); 164 165 $gradestatus = lti_delete_grade($ltiinstance, $parsed->userid); 166 167 if (!$gradestatus) { 168 throw new Exception('Grade delete request'); 169 } 170 171 $responsexml = lti_get_response_xml( 172 'success', 173 'Grade delete request', 174 $parsed->messageid, 175 'deleteResultResponse' 176 ); 177 178 echo $responsexml->asXML(); 179 180 break; 181 182 default: 183 // Fire an event if we get a web service request which we don't support directly. 184 // This will allow others to extend the LTI services, which I expect to be a common 185 // use case, at least until the spec matures. 186 $data = new stdClass(); 187 $data->body = $rawbody; 188 $data->xml = $xml; 189 $data->messageid = lti_parse_message_id($xml); 190 $data->messagetype = $messagetype; 191 $data->consumerkey = $consumerkey; 192 $data->sharedsecret = $sharedsecret; 193 $eventdata = array(); 194 $eventdata['other'] = array(); 195 $eventdata['other']['messageid'] = $data->messageid; 196 $eventdata['other']['messagetype'] = $messagetype; 197 $eventdata['other']['consumerkey'] = $consumerkey; 198 199 // Before firing the event, allow subplugins a chance to handle. 200 if (lti_extend_lti_services($data)) { 201 break; 202 } 203 204 // If an event handler handles the web service, it should set this global to true 205 // So this code knows whether to send an "operation not supported" or not. 206 global $ltiwebservicehandled; 207 $ltiwebservicehandled = false; 208 209 try { 210 $event = \mod_lti\event\unknown_service_api_called::create($eventdata); 211 $event->set_message_data($data); 212 $event->trigger(); 213 } catch (Exception $e) { 214 $ltiwebservicehandled = false; 215 } 216 217 if (!$ltiwebservicehandled) { 218 $responsexml = lti_get_response_xml( 219 'unsupported', 220 'unsupported', 221 lti_parse_message_id($xml), 222 $messagetype 223 ); 224 225 echo $responsexml->asXML(); 226 } 227 228 break; 229 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body