2011-09-09 16:16:27 -04:00
|
|
|
<?php
|
2011-11-06 21:51:06 -05:00
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
//
|
|
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
/**
|
2011-11-16 12:31:15 -05:00
|
|
|
* LTI web service endpoints
|
2011-11-06 21:51:06 -05:00
|
|
|
*
|
2014-02-16 11:52:18 +13:00
|
|
|
* @package mod_lti
|
2011-11-16 12:31:15 -05:00
|
|
|
* @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
|
2011-11-06 21:51:06 -05:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2011-11-16 12:31:15 -05:00
|
|
|
* @author Chris Scribner
|
2011-11-06 21:51:06 -05:00
|
|
|
*/
|
|
|
|
|
2012-11-27 09:26:01 -08:00
|
|
|
define('NO_DEBUG_DISPLAY', true);
|
2014-09-03 23:35:39 +01:00
|
|
|
define('NO_MOODLE_COOKIES', true);
|
2012-11-27 09:26:01 -08:00
|
|
|
|
2016-02-26 17:47:58 +11:00
|
|
|
require_once(__DIR__ . "/../../config.php");
|
2011-09-09 16:16:27 -04:00
|
|
|
require_once($CFG->dirroot.'/mod/lti/locallib.php');
|
2011-09-16 18:37:43 -04:00
|
|
|
require_once($CFG->dirroot.'/mod/lti/servicelib.php');
|
2011-09-09 16:16:27 -04:00
|
|
|
|
2014-09-03 23:35:39 +01:00
|
|
|
// TODO: Switch to core oauthlib once implemented - MDL-30149.
|
2015-09-25 13:44:14 -07:00
|
|
|
use mod_lti\service_exception_handler;
|
2011-10-10 18:27:53 -04:00
|
|
|
use moodle\mod\lti as lti;
|
|
|
|
|
2011-09-16 18:37:43 -04:00
|
|
|
$rawbody = file_get_contents("php://input");
|
2011-10-10 18:27:53 -04:00
|
|
|
|
2015-09-25 13:44:14 -07:00
|
|
|
$logrequests = lti_should_log_request($rawbody);
|
|
|
|
$errorhandler = new service_exception_handler($logrequests);
|
|
|
|
|
|
|
|
// Register our own error handler so we can always send valid XML response.
|
|
|
|
set_exception_handler(array($errorhandler, 'handle'));
|
|
|
|
|
|
|
|
if ($logrequests) {
|
2014-04-01 15:07:54 -07:00
|
|
|
lti_log_request($rawbody);
|
|
|
|
}
|
|
|
|
|
2013-07-24 09:07:14 -07:00
|
|
|
foreach (lti\OAuthUtil::get_headers() as $name => $value) {
|
2011-11-07 00:10:24 +01:00
|
|
|
if ($name === 'Authorization') {
|
2014-09-03 23:35:39 +01:00
|
|
|
// TODO: Switch to core oauthlib once implemented - MDL-30149.
|
2011-10-10 18:27:53 -04:00
|
|
|
$oauthparams = lti\OAuthUtil::split_header($value);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-10-10 18:27:53 -04:00
|
|
|
$consumerkey = $oauthparams['oauth_consumer_key'];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-07 00:10:24 +01:00
|
|
|
if (empty($consumerkey)) {
|
2011-10-10 18:27:53 -04:00
|
|
|
throw new Exception('Consumer key is missing.');
|
|
|
|
}
|
|
|
|
|
|
|
|
$sharedsecret = lti_verify_message($consumerkey, lti_get_shared_secrets_by_key($consumerkey), $rawbody);
|
|
|
|
|
2011-11-07 00:10:24 +01:00
|
|
|
if ($sharedsecret === false) {
|
2011-10-10 18:27:53 -04:00
|
|
|
throw new Exception('Message signature not valid');
|
|
|
|
}
|
|
|
|
|
2014-06-10 12:53:43 +08:00
|
|
|
// TODO MDL-46023 Replace this code with a call to the new library.
|
|
|
|
$origentity = libxml_disable_entity_loader(true);
|
|
|
|
$xml = simplexml_load_string($rawbody);
|
|
|
|
if (!$xml) {
|
|
|
|
libxml_disable_entity_loader($origentity);
|
|
|
|
throw new Exception('Invalid XML content');
|
|
|
|
}
|
|
|
|
libxml_disable_entity_loader($origentity);
|
2011-09-09 16:16:27 -04:00
|
|
|
|
|
|
|
$body = $xml->imsx_POXBody;
|
2011-11-07 00:10:24 +01:00
|
|
|
foreach ($body->children() as $child) {
|
2011-09-09 16:16:27 -04:00
|
|
|
$messagetype = $child->getName();
|
|
|
|
}
|
|
|
|
|
2015-09-25 13:44:14 -07:00
|
|
|
// We know more about the message, update error handler to send better errors.
|
|
|
|
$errorhandler->set_message_id(lti_parse_message_id($xml));
|
|
|
|
$errorhandler->set_message_type($messagetype);
|
|
|
|
|
2011-11-07 00:10:24 +01:00
|
|
|
switch ($messagetype) {
|
2011-09-09 16:16:27 -04:00
|
|
|
case 'replaceResultRequest':
|
2015-09-25 13:44:14 -07:00
|
|
|
$parsed = lti_parse_grade_replace_message($xml);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2014-04-01 15:07:54 -07:00
|
|
|
if (!lti_accepts_grades($ltiinstance)) {
|
|
|
|
throw new Exception('Tool does not accept grades');
|
|
|
|
}
|
|
|
|
|
2011-09-16 18:37:43 -04:00
|
|
|
lti_verify_sourcedid($ltiinstance, $parsed);
|
2014-04-01 15:07:54 -07:00
|
|
|
lti_set_session_user($parsed->userid);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-28 11:11:20 -04:00
|
|
|
$gradestatus = lti_update_grade($ltiinstance, $parsed->userid, $parsed->launchid, $parsed->gradeval);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2015-09-25 13:44:14 -07:00
|
|
|
if (!$gradestatus) {
|
|
|
|
throw new Exception('Grade replace response');
|
|
|
|
}
|
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$responsexml = lti_get_response_xml(
|
2015-09-25 13:44:14 -07:00
|
|
|
'success',
|
2011-09-09 16:16:27 -04:00
|
|
|
'Grade replace response',
|
|
|
|
$parsed->messageid,
|
|
|
|
'replaceResultResponse'
|
|
|
|
);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
echo $responsexml->asXML();
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
break;
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
case 'readResultRequest':
|
|
|
|
$parsed = lti_parse_grade_read_message($xml);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2014-04-01 15:07:54 -07:00
|
|
|
if (!lti_accepts_grades($ltiinstance)) {
|
|
|
|
throw new Exception('Tool does not accept grades');
|
|
|
|
}
|
|
|
|
|
2014-09-03 23:35:39 +01:00
|
|
|
// Getting the grade requires the context is set.
|
2012-07-27 13:27:13 +08:00
|
|
|
$context = context_course::instance($ltiinstance->course);
|
2011-10-05 17:58:30 -04:00
|
|
|
$PAGE->set_context($context);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-16 18:37:43 -04:00
|
|
|
lti_verify_sourcedid($ltiinstance, $parsed);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$grade = lti_read_grade($ltiinstance, $parsed->userid);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$responsexml = lti_get_response_xml(
|
2014-09-03 23:35:39 +01:00
|
|
|
'success', // Empty grade is also 'success'.
|
2011-09-09 16:16:27 -04:00
|
|
|
'Result read',
|
|
|
|
$parsed->messageid,
|
|
|
|
'readResultResponse'
|
|
|
|
);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$node = $responsexml->imsx_POXBody->readResultResponse;
|
2011-11-15 12:46:48 -05:00
|
|
|
$node = $node->addChild('result')->addChild('resultScore');
|
|
|
|
$node->addChild('language', 'en');
|
|
|
|
$node->addChild('textString', isset($grade) ? $grade : '');
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
echo $responsexml->asXML();
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
break;
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
case 'deleteResultRequest':
|
|
|
|
$parsed = lti_parse_grade_delete_message($xml);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2014-04-01 15:07:54 -07:00
|
|
|
if (!lti_accepts_grades($ltiinstance)) {
|
|
|
|
throw new Exception('Tool does not accept grades');
|
|
|
|
}
|
|
|
|
|
2011-09-16 18:37:43 -04:00
|
|
|
lti_verify_sourcedid($ltiinstance, $parsed);
|
2014-04-01 15:07:54 -07:00
|
|
|
lti_set_session_user($parsed->userid);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$gradestatus = lti_delete_grade($ltiinstance, $parsed->userid);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2015-09-25 13:44:14 -07:00
|
|
|
if (!$gradestatus) {
|
|
|
|
throw new Exception('Grade delete request');
|
|
|
|
}
|
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
$responsexml = lti_get_response_xml(
|
2015-09-25 13:44:14 -07:00
|
|
|
'success',
|
2011-11-06 22:00:40 -05:00
|
|
|
'Grade delete request',
|
|
|
|
$parsed->messageid,
|
2011-09-09 16:16:27 -04:00
|
|
|
'deleteResultResponse'
|
|
|
|
);
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
echo $responsexml->asXML();
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-10-10 18:27:53 -04:00
|
|
|
break;
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-10-10 18:27:53 -04:00
|
|
|
default:
|
2014-09-03 23:35:39 +01:00
|
|
|
// Fire an event if we get a web service request which we don't support directly.
|
|
|
|
// This will allow others to extend the LTI services, which I expect to be a common
|
|
|
|
// use case, at least until the spec matures.
|
2014-02-28 16:15:26 +08:00
|
|
|
$data = new stdClass();
|
|
|
|
$data->body = $rawbody;
|
|
|
|
$data->xml = $xml;
|
2014-07-31 10:49:03 -07:00
|
|
|
$data->messageid = lti_parse_message_id($xml);
|
2014-02-28 16:15:26 +08:00
|
|
|
$data->messagetype = $messagetype;
|
|
|
|
$data->consumerkey = $consumerkey;
|
|
|
|
$data->sharedsecret = $sharedsecret;
|
2013-08-12 11:38:39 +08:00
|
|
|
$eventdata = array();
|
|
|
|
$eventdata['other'] = array();
|
2014-07-31 10:49:03 -07:00
|
|
|
$eventdata['other']['messageid'] = $data->messageid;
|
2013-08-12 11:38:39 +08:00
|
|
|
$eventdata['other']['messagetype'] = $messagetype;
|
|
|
|
$eventdata['other']['consumerkey'] = $consumerkey;
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2012-10-29 10:10:50 -04:00
|
|
|
// Before firing the event, allow subplugins a chance to handle.
|
2014-07-31 10:49:03 -07:00
|
|
|
if (lti_extend_lti_services($data)) {
|
2012-10-29 10:10:50 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-09-03 23:35:39 +01:00
|
|
|
// If an event handler handles the web service, it should set this global to true
|
|
|
|
// So this code knows whether to send an "operation not supported" or not.
|
|
|
|
global $ltiwebservicehandled;
|
|
|
|
$ltiwebservicehandled = false;
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2013-10-19 02:57:12 +02:00
|
|
|
try {
|
|
|
|
$event = \mod_lti\event\unknown_service_api_called::create($eventdata);
|
2014-02-28 16:15:26 +08:00
|
|
|
$event->set_message_data($data);
|
2013-10-19 02:57:12 +02:00
|
|
|
$event->trigger();
|
|
|
|
} catch (Exception $e) {
|
2014-09-03 23:35:39 +01:00
|
|
|
$ltiwebservicehandled = false;
|
2013-10-19 02:57:12 +02:00
|
|
|
}
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2014-09-03 23:35:39 +01:00
|
|
|
if (!$ltiwebservicehandled) {
|
2011-10-19 14:35:40 -04:00
|
|
|
$responsexml = lti_get_response_xml(
|
2011-11-06 22:00:40 -05:00
|
|
|
'unsupported',
|
|
|
|
'unsupported',
|
2011-10-19 14:35:40 -04:00
|
|
|
lti_parse_message_id($xml),
|
|
|
|
$messagetype
|
|
|
|
);
|
|
|
|
|
|
|
|
echo $responsexml->asXML();
|
|
|
|
}
|
2011-11-06 22:00:40 -05:00
|
|
|
|
2011-09-09 16:16:27 -04:00
|
|
|
break;
|
|
|
|
}
|