f7211a38aa25ad719c327871414f7bba75ec3bfc
[moodle.git] / mod / lti / servicelib.php
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/>.
17 /**
18  * MRTODO: Brief description of this file
19  *
20  * @package    mod
21  * @subpackage lti
22  * @copyright  2011 onwards MRTODO
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 require_once($CFG->dirroot.'/mod/lti/OAuthBody.php');
28 use moodle\mod\lti as lti;
30 define('LTI_ITEM_TYPE', 'mod');
31 define('LTI_ITEM_MODULE', 'lti');
32 define('LTI_SOURCE', 'mod/lti');
34 function lti_get_response_xml($codemajor, $description, $messageref, $messagetype) {
35     $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><imsx_POXEnvelopeResponse />');
36     $xml->addAttribute('xmlns', 'http://www.imsglobal.org/lis/oms1p0/pox');
38     $headerinfo = $xml->addChild('imsx_POXHeader')->addChild('imsx_POXResponseHeaderInfo');
40     $headerinfo->addChild('imsx_version', 'V1.0');
41     $headerinfo->addChild('imsx_messageIdentifier', (string)mt_rand());
43     $statusinfo = $headerinfo->addChild('imsx_statusInfo');
44     $statusinfo->addchild('imsx_codeMajor', $codemajor);
45     $statusinfo->addChild('imsx_severity', 'status');
46     $statusinfo->addChild('imsx_description', $description);
47     $statusinfo->addChild('imsx_messageRefIdentifier', $messageref);
49     $xml->addChild('imsx_POXBody')->addChild($messagetype);
51     return $xml;
52 }
54 function lti_parse_message_id($xml) {
55     $node = $xml->imsx_POXHeader->imsx_POXRequestHeaderInfo->imsx_messageIdentifier;
56     $messageid = (string)$node;
58     return $messageid;
59 }
61 function lti_parse_grade_replace_message($xml) {
62     $node = $xml->imsx_POXBody->replaceResultRequest->resultRecord->sourcedGUID->sourcedId;
63     $resultjson = json_decode((string)$node);
65     $node = $xml->imsx_POXBody->replaceResultRequest->resultRecord->result->resultScore->textString;
66     $grade = floatval((string)$node);
68     $parsed = new stdClass();
69     $parsed->gradeval = $grade * 100;
71     $parsed->instanceid = $resultjson->data->instanceid;
72     $parsed->userid = $resultjson->data->userid;
73     $parsed->launchid = $resultjson->data->launchid;
74     $parsed->sourcedidhash = $resultjson->hash;
76     $parsed->messageid = lti_parse_message_id($xml);
78     return $parsed;
79 }
81 function lti_parse_grade_read_message($xml) {
82     $node = $xml->imsx_POXBody->readResultRequest->resultRecord->sourcedGUID->sourcedId;
83     $resultjson = json_decode((string)$node);
85     $parsed = new stdClass();
86     $parsed->instanceid = $resultjson->data->instanceid;
87     $parsed->userid = $resultjson->data->userid;
88     $parsed->launchid = $resultjson->data->launchid;
89     $parsed->sourcedidhash = $resultjson->hash;
91     $parsed->messageid = lti_parse_message_id($xml);
93     return $parsed;
94 }
96 function lti_parse_grade_delete_message($xml) {
97     $node = $xml->imsx_POXBody->deleteResultRequest->resultRecord->sourcedGUID->sourcedId;
98     $resultjson = json_decode((string)$node);
100     $parsed = new stdClass();
101     $parsed->instanceid = $resultjson->data->instanceid;
102     $parsed->userid = $resultjson->data->userid;
103     $parsed->launchid = $resultjson->data->launchid;
104     $parsed->sourcedidhash = $resultjson->hash;
106     $parsed->messageid = lti_parse_message_id($xml);
108     return $parsed;
111 function lti_update_grade($ltiinstance, $userid, $launchid, $gradeval) {
112     global $CFG, $DB;
113     require_once($CFG->libdir . '/gradelib.php');
115     $params = array();
116     $params['itemname'] = $ltiinstance->name;
118     $grade = new stdClass();
119     $grade->userid   = $userid;
120     $grade->rawgrade = $gradeval;
122     $status = grade_update(LTI_SOURCE, $ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, 0, $grade, $params);
124     $record = $DB->get_record('lti_submission', array('ltiid' => $ltiinstance->id, 'userid' => $userid, 'launchid' => $launchid), 'id');
125     if ($record) {
126         $id = $record->id;
127     } else {
128         $id = null;
129     }
131     if (!empty($id)) {
132         $DB->update_record('lti_submission', array(
133             'id' => $id,
134             'dateupdated' => time(),
135             'gradepercent' => $gradeval,
136             'state' => 2
137         ));
138     } else {
139         $DB->insert_record('lti_submission', array(
140             'ltiid' => $ltiinstance->id,
141             'userid' => $userid,
142             'datesubmitted' => time(),
143             'dateupdated' => time(),
144             'gradepercent' => $gradeval,
145             'originalgrade' => $gradeval,
146             'launchid' => $launchid,
147             'state' => 1
148         ));
149     }
151     return $status == GRADE_UPDATE_OK;
154 function lti_read_grade($ltiinstance, $userid) {
155     global $CFG;
156     require_once($CFG->libdir . '/gradelib.php');
158     $grades = grade_get_grades($ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, $userid);
160     if (isset($grades) && isset($grades->items[0]) && is_array($grades->items[0]->grades)) {
161         foreach ($grades->items[0]->grades as $agrade) {
162             $grade = $agrade->grade;
163             break;
164         }
165     }
167     if (isset($grade)) {
168         return $grade;
169     }
172 function lti_delete_grade($ltiinstance, $userid) {
173     global $CFG;
174     require_once($CFG->libdir . '/gradelib.php');
176     $grade = new stdClass();
177     $grade->userid   = $userid;
178     $grade->rawgrade = null;
180     $status = grade_update(LTI_SOURCE, $ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, 0, $grade, array('deleted'=>1));
182     return $status == GRADE_UPDATE_OK || $status == GRADE_UPDATE_ITEM_DELETED; //grade_update seems to return ok now, but could reasonably return deleted in the future
185 function lti_verify_message($key, $sharedsecrets, $body, $headers = null) {
186     foreach ($sharedsecrets as $secret) {
187         $signaturefailed = false;
189         try {
190             lti\handleOAuthBodyPOST($key, $secret, $body, $headers);
191         } catch (Exception $e) {
192             $signaturefailed = true;
193         }
195         if (!$signaturefailed) {
196             return $secret;//Return the secret used to sign the message)
197         }
198     }
200     return false;
203 function lti_verify_sourcedid($ltiinstance, $parsed) {
204     $sourceid = lti_build_sourcedid($parsed->instanceid, $parsed->userid, $parsed->launchid, $ltiinstance->servicesalt);
206     if ($sourceid->hash != $parsed->sourcedidhash) {
207         throw new Exception('SourcedId hash not valid');
208     }