MDL-44616 behat: Adding steps to test MDLQA-1709 and MDLQA-62
[moodle.git] / mod / lti / service.php
blobbeae870997efe65b1a92af75f8c85bc1eeb919df
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.
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/>.
17 /**
18 * LTI web service endpoints
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
26 define('NO_DEBUG_DISPLAY', true);
28 require_once(dirname(__FILE__) . "/../../config.php");
29 require_once($CFG->dirroot.'/mod/lti/locallib.php');
30 require_once($CFG->dirroot.'/mod/lti/servicelib.php');
32 // TODO: Switch to core oauthlib once implemented - MDL-30149
33 use moodle\mod\lti as lti;
35 $rawbody = file_get_contents("php://input");
37 foreach (lti\OAuthUtil::get_headers() as $name => $value) {
38 if ($name === 'Authorization') {
39 // TODO: Switch to core oauthlib once implemented - MDL-30149
40 $oauthparams = lti\OAuthUtil::split_header($value);
42 $consumerkey = $oauthparams['oauth_consumer_key'];
43 break;
47 if (empty($consumerkey)) {
48 throw new Exception('Consumer key is missing.');
51 $sharedsecret = lti_verify_message($consumerkey, lti_get_shared_secrets_by_key($consumerkey), $rawbody);
53 if ($sharedsecret === false) {
54 throw new Exception('Message signature not valid');
57 $xml = new SimpleXMLElement($rawbody);
59 $body = $xml->imsx_POXBody;
60 foreach ($body->children() as $child) {
61 $messagetype = $child->getName();
64 switch ($messagetype) {
65 case 'replaceResultRequest':
66 try {
67 $parsed = lti_parse_grade_replace_message($xml);
68 } catch (Exception $e) {
69 $responsexml = lti_get_response_xml(
70 'failure',
71 $e->getMessage(),
72 uniqid(),
73 'replaceResultResponse');
75 echo $responsexml->asXML();
76 break;
79 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
81 lti_verify_sourcedid($ltiinstance, $parsed);
83 $gradestatus = lti_update_grade($ltiinstance, $parsed->userid, $parsed->launchid, $parsed->gradeval);
85 $responsexml = lti_get_response_xml(
86 $gradestatus ? 'success' : 'failure',
87 'Grade replace response',
88 $parsed->messageid,
89 'replaceResultResponse'
92 echo $responsexml->asXML();
94 break;
96 case 'readResultRequest':
97 $parsed = lti_parse_grade_read_message($xml);
99 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
101 //Getting the grade requires the context is set
102 $context = context_course::instance($ltiinstance->course);
103 $PAGE->set_context($context);
105 lti_verify_sourcedid($ltiinstance, $parsed);
107 $grade = lti_read_grade($ltiinstance, $parsed->userid);
109 $responsexml = lti_get_response_xml(
110 'success', // Empty grade is also 'success'
111 'Result read',
112 $parsed->messageid,
113 'readResultResponse'
116 $node = $responsexml->imsx_POXBody->readResultResponse;
117 $node = $node->addChild('result')->addChild('resultScore');
118 $node->addChild('language', 'en');
119 $node->addChild('textString', isset($grade) ? $grade : '');
121 echo $responsexml->asXML();
123 break;
125 case 'deleteResultRequest':
126 $parsed = lti_parse_grade_delete_message($xml);
128 $ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
130 lti_verify_sourcedid($ltiinstance, $parsed);
132 $gradestatus = lti_delete_grade($ltiinstance, $parsed->userid);
134 $responsexml = lti_get_response_xml(
135 $gradestatus ? 'success' : 'failure',
136 'Grade delete request',
137 $parsed->messageid,
138 'deleteResultResponse'
141 echo $responsexml->asXML();
143 break;
145 default:
146 //Fire an event if we get a web service request which we don't support directly.
147 //This will allow others to extend the LTI services, which I expect to be a common
148 //use case, at least until the spec matures.
149 $data = new stdClass();
150 $data->body = $rawbody;
151 $data->xml = $xml;
152 $data->messagetype = $messagetype;
153 $data->consumerkey = $consumerkey;
154 $data->sharedsecret = $sharedsecret;
155 $eventdata = array();
156 $eventdata['other'] = array();
157 $eventdata['other']['messageid'] = lti_parse_message_id($xml);
158 $eventdata['other']['messagetype'] = $messagetype;
159 $eventdata['other']['consumerkey'] = $consumerkey;
161 // Before firing the event, allow subplugins a chance to handle.
162 if (lti_extend_lti_services((object) $eventdata['other'])) {
163 break;
166 //If an event handler handles the web service, it should set this global to true
167 //So this code knows whether to send an "operation not supported" or not.
168 global $lti_web_service_handled;
169 $lti_web_service_handled = false;
171 try {
172 $event = \mod_lti\event\unknown_service_api_called::create($eventdata);
173 $event->set_message_data($data);
174 $event->trigger();
175 } catch (Exception $e) {
176 $lti_web_service_handled = false;
179 if (!$lti_web_service_handled) {
180 $responsexml = lti_get_response_xml(
181 'unsupported',
182 'unsupported',
183 lti_parse_message_id($xml),
184 $messagetype
187 echo $responsexml->asXML();
190 break;
194 //echo print_r(apache_request_headers(), true);
196 //echo '<br />';
198 //echo file_get_contents("php://input");