Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding oauth body code (from Chuck), implemented outcome services (on…

…ly replaceResult tested)
  • Loading branch information...
commit b9b2e7bbf821a9b451f5ac84b7b7f00c8365ae94 1 parent aa6eca6
@scriby scriby authored
View
158 mod/lti/OAuthBody.php
@@ -0,0 +1,158 @@
+<?php
+// This file is part of BasicLTI4Moodle
+//
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
+// are already supporting or going to support BasicLTI. This project Implements the consumer
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
+// at the GESSI research group at UPC.
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
+//
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
+//
+// OAuthBody.php is distributed under the MIT License
+//
+// The MIT License
+//
+// Copyright (c) 2007 Andy Smith
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// 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/>.
+
+require_once($CFG->dirroot . '/mod/lti/OAuth.php');
+require_once($CFG->dirroot . '/mod/lti/TrivialStore.php');
+
+function getOAuthKeyFromHeaders()
+{
+ $request_headers = OAuthUtil::get_headers();
+ // print_r($request_headers);
+
+ if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
+ $header_parameters = OAuthUtil::split_header($request_headers['Authorization']);
+
+ // echo("HEADER PARMS=\n");
+ // print_r($header_parameters);
+ return $header_parameters['oauth_consumer_key'];
+ }
+ return false;
+}
+
+function handleOAuthBodyPOST($oauth_consumer_key, $oauth_consumer_secret)
+{
+ $request_headers = OAuthUtil::get_headers();
+ // print_r($request_headers);
+
+ // Must reject application/x-www-form-urlencoded
+ if ($request_headers['Content-type'] == 'application/x-www-form-urlencoded' ) {
+ throw new Exception("OAuth request body signing must not use application/x-www-form-urlencoded");
+ }
+
+ if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
+ $header_parameters = OAuthUtil::split_header($request_headers['Authorization']);
+
+ // echo("HEADER PARMS=\n");
+ // print_r($header_parameters);
+ $oauth_body_hash = $header_parameters['oauth_body_hash'];
+ // echo("OBH=".$oauth_body_hash."\n");
+ }
+
+ if ( ! isset($oauth_body_hash) ) {
+ throw new Exception("OAuth request body signing requires oauth_body_hash body");
+ }
+
+ // Verify the message signature
+ $store = new TrivialOAuthDataStore();
+ $store->add_consumer($oauth_consumer_key, $oauth_consumer_secret);
+
+ $server = new OAuthServer($store);
+
+ $method = new OAuthSignatureMethod_HMAC_SHA1();
+ $server->add_signature_method($method);
+ $request = OAuthRequest::from_request();
+
+ try {
+ $server->verify_request($request);
+ } catch (Exception $e) {
+ $message = $e->getMessage();
+ throw new Exception("OAuth signature failed: " . $message);
+ }
+
+ $postdata = file_get_contents('php://input');
+ // echo($postdata);
+
+ $hash = base64_encode(sha1($postdata, TRUE));
+
+ if ( $hash != $oauth_body_hash ) {
+ throw new Exception("OAuth oauth_body_hash mismatch");
+ }
+
+ return $postdata;
+}
+
+function sendOAuthBodyPOST($method, $endpoint, $oauth_consumer_key, $oauth_consumer_secret, $content_type, $body)
+{
+ $hash = base64_encode(sha1($body, TRUE));
+
+ $parms = array('oauth_body_hash' => $hash);
+
+ $test_token = '';
+ $hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+ $test_consumer = new OAuthConsumer($oauth_consumer_key, $oauth_consumer_secret, NULL);
+
+ $acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $test_token, $method, $endpoint, $parms);
+ $acc_req->sign_request($hmac_method, $test_consumer, $test_token);
+
+ $header = $acc_req->to_header();
+ $header = $header . "\r\nContent-type: " . $content_type . "\r\n";
+
+ $params = array('http' => array(
+ 'method' => 'POST',
+ 'content' => $body,
+ 'header' => $header
+ ));
+ $ctx = stream_context_create($params);
+ $fp = @fopen($endpoint, 'rb', false, $ctx);
+ if (!$fp) {
+ throw new Exception("Problem with $endpoint, $php_errormsg");
+ }
+ $response = @stream_get_contents($fp);
+ if ($response === false) {
+ throw new Exception("Problem reading data from $endpoint, $php_errormsg");
+ }
+ return $response;
+}
View
1,835 mod/lti/locallib.php
@@ -1,910 +1,925 @@
-<?php
-// This file is part of BasicLTI4Moodle
-//
-// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
-// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
-// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
-// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
-// are already supporting or going to support BasicLTI. This project Implements the consumer
-// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
-// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
-// at the GESSI research group at UPC.
-// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
-// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
-// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
-//
-// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
-// of the Universitat Politecnica de Catalunya http://www.upc.edu
-// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
-//
-// 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/>.
-
-/**
- * This file contains the library of functions and constants for the basiclti module
- *
- * @package lti
- * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
- * marc.alier@upc.edu
- * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
- *
- * @author Marc Alier
- * @author Jordi Piguillem
- * @author Nikolas Galanis
- *
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die;
-
-require_once($CFG->dirroot.'/mod/lti/OAuth.php');
-
-define('LTI_URL_DOMAIN_REGEX', '/(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i');
-
-define('LTI_LAUNCH_CONTAINER_DEFAULT', 1);
-define('LTI_LAUNCH_CONTAINER_EMBED', 2);
-define('LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS', 3);
-define('LTI_LAUNCH_CONTAINER_WINDOW', 4);
-
-define('LTI_TOOL_STATE_ANY', 0);
-define('LTI_TOOL_STATE_CONFIGURED', 1);
-define('LTI_TOOL_STATE_PENDING', 2);
-define('LTI_TOOL_STATE_REJECTED', 3);
-
-define('LTI_SETTING_NEVER', 0);
-define('LTI_SETTING_ALWAYS', 1);
-define('LTI_SETTING_DEFAULT', 2);
-
-/**
- * Prints a Basic LTI activity
- *
- * $param int $basicltiid Basic LTI activity id
- */
-function lti_view($instance, $makeobject=false) {
- global $PAGE, $CFG;
-
- if(empty($instance->typeid)){
- $tool = lti_get_tool_by_url_match($instance->toolurl);
- if($tool){
- $typeid = $tool->id;
- } else {
- $typeid = null;
- }
- } else {
- $typeid = $instance->typeid;
- }
-
- if($typeid){
- $typeconfig = lti_get_type_config($typeid);
- } else {
- //There is no admin configuration for this tool. Use configuration in the lti instance record plus some defaults.
- $typeconfig = (array)$instance;
-
- $typeconfig['sendname'] = $instance->instructorchoicesendname;
- $typeconfig['sendemailaddr'] = $instance->instructorchoicesendemailaddr;
- $typeconfig['customparameters'] = $instance->instructorcustomparameters;
- }
-
- //Default the organizationid if not specified
- if(empty($typeconfig['organizationid'])){
- $urlparts = parse_url($CFG->wwwroot);
-
- $typeconfig['organizationid'] = $urlparts['host'];
- }
-
- $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];
- $key = !empty($instance->resourcekey) ? $instance->resourcekey : $typeconfig['resourcekey'];
- $secret = !empty($instance->password) ? $instance->password : $typeconfig['password'];
- $orgid = $typeconfig['organizationid'];
- /* Suppress this for now - Chuck
- $orgdesc = $typeconfig['organizationdescr'];
- */
-
- $course = $PAGE->course;
- $requestparams = lti_build_request($instance, $typeconfig, $course);
-
- // Make sure we let the tool know what LMS they are being called from
- $requestparams["ext_lms"] = "moodle-2";
-
- // Add oauth_callback to be compliant with the 1.0A spec
- $requestparams["oauth_callback"] = "about:blank";
-
- $submittext = get_string('press_to_submit', 'lti');
- $parms = sign_parameters($requestparams, $endpoint, "POST", $key, $secret, $submittext, $orgid /*, $orgdesc*/);
-
- $debuglaunch = ( $instance->debuglaunch == 1 );
-
- $content = post_launch_html($parms, $endpoint, $debuglaunch);
-
- echo $content;
-}
-
-/**
- * This function builds the request that must be sent to the tool producer
- *
- * @param object $instance Basic LTI instance object
- * @param object $typeconfig Basic LTI tool configuration
- * @param object $course Course object
- *
- * @return array $request Request details
- */
-function lti_build_request($instance, $typeconfig, $course) {
- global $USER, $CFG;
-
- $context = get_context_instance(CONTEXT_COURSE, $course->id);
- $role = lti_get_ims_role($USER, $context);
-
- $locale = $course->lang;
- if ( strlen($locale) < 1 ) {
- $locale = $CFG->lang;
- }
-
- $requestparams = array(
- "resource_link_id" => $instance->id,
- "resource_link_title" => $instance->name,
- "resource_link_description" => $instance->intro,
- "user_id" => $USER->id,
- "roles" => $role,
- "context_id" => $course->id,
- "context_label" => $course->shortname,
- "context_title" => $course->fullname,
- "launch_presentation_locale" => $locale,
- );
-
- $placementsecret = $typeconfig['servicesalt'];
- if ( isset($placementsecret) ) {
- $suffix = ':::' . $USER->id . ':::' . $instance->id;
- $plaintext = $placementsecret . $suffix;
- $hashsig = hash('sha256', $plaintext, false);
- $sourcedid = $hashsig . $suffix;
- }
-
- if ( isset($placementsecret) &&
- ( $typeconfig['acceptgrades'] == 1 ||
- ( $typeconfig['acceptgrades'] == 2 && $instance->instructorchoiceacceptgrades == 1 ) ) ) {
- $requestparams["lis_result_sourcedid"] = $sourcedid;
- $requestparams["ext_ims_lis_basic_outcome_url"] = $CFG->wwwroot.'/mod/lti/service.php';
- }
-
- if ( isset($placementsecret) &&
- ( $typeconfig['allowroster'] == 1 ||
- ( $typeconfig['allowroster'] == 2 && $instance->instructorchoiceallowroster == 1 ) ) ) {
- $requestparams["ext_ims_lis_memberships_id"] = $sourcedid;
- $requestparams["ext_ims_lis_memberships_url"] = $CFG->wwwroot.'/mod/lti/service.php';
- }
-
- // Send user's name and email data if appropriate
- if ( $typeconfig['sendname'] == 1 ||
- ( $typeconfig['sendname'] == 2 && $instance->instructorchoicesendname == 1 ) ) {
- $requestparams["lis_person_name_given"] = $USER->firstname;
- $requestparams["lis_person_name_family"] = $USER->lastname;
- $requestparams["lis_person_name_full"] = $USER->firstname." ".$USER->lastname;
- }
-
- if ( $typeconfig['sendemailaddr'] == 1 ||
- ( $typeconfig['sendemailaddr'] == 2 && $instance->instructorchoicesendemailaddr == 1 ) ) {
- $requestparams["lis_person_contact_email_primary"] = $USER->email;
- }
-
- // Concatenate the custom parameters from the administrator and the instructor
- // Instructor parameters are only taken into consideration if the administrator
- // has giver permission
- $customstr = $typeconfig['customparameters'];
- $instructorcustomstr = $instance->instructorcustomparameters;
- $custom = array();
- $instructorcustom = array();
- if ($customstr) {
- $custom = split_custom_parameters($customstr);
- }
- if (!isset($typeconfig['allowinstructorcustom']) || $typeconfig['allowinstructorcustom'] == 0) {
- $requestparams = array_merge($custom, $requestparams);
- } else {
- if ($instructorcustomstr) {
- $instructorcustom = split_custom_parameters($instructorcustomstr);
- }
- foreach ($instructorcustom as $key => $val) {
- if (array_key_exists($key, $custom)) {
- // Ignore the instructor's parameter
- } else {
- $custom[$key] = $val;
- }
- }
- $requestparams = array_merge($custom, $requestparams);
- }
-
- return $requestparams;
-}
-
-/**
- * Splits the custom parameters field to the various parameters
- *
- * @param string $customstr String containing the parameters
- *
- * @return Array of custom parameters
- */
-function split_custom_parameters($customstr) {
- $textlib = textlib_get_instance();
-
- $lines = preg_split("/[\n;]/", $customstr);
- $retval = array();
- foreach ($lines as $line) {
- $pos = strpos($line, "=");
- if ( $pos === false || $pos < 1 ) {
- continue;
- }
- $key = trim($textlib->substr($line, 0, $pos));
- $val = trim($textlib->substr($line, $pos+1));
- $key = map_keyname($key);
- $retval['custom_'.$key] = $val;
- }
- return $retval;
-}
-
-/**
- * Used for building the names of the different custom parameters
- *
- * @param string $key Parameter name
- *
- * @return string Processed name
- */
-function map_keyname($key) {
- $textlib = textlib_get_instance();
-
- $newkey = "";
- $key = $textlib->strtolower(trim($key));
- foreach (str_split($key) as $ch) {
- if ( ($ch >= 'a' && $ch <= 'z') || ($ch >= '0' && $ch <= '9') ) {
- $newkey .= $ch;
- } else {
- $newkey .= '_';
- }
- }
- return $newkey;
-}
-
-/**
- * Returns the IMS user role in a given context
- *
- * This function queries Moodle for an user role and
- * returns the correspondant IMS role
- *
- * @param StdClass $user Moodle user instance
- * @param StdClass $context Moodle context
- *
- * @return string IMS Role
- *
- */
-function lti_get_ims_role($user, $context) {
-
- $roles = get_user_roles($context, $user->id);
- $rolesname = array();
- foreach ($roles as $role) {
- $rolesname[] = $role->shortname;
- }
-
- if (in_array('admin', $rolesname) || in_array('coursecreator', $rolesname)) {
- return get_string('imsroleadmin', 'lti');
- }
-
- if (in_array('editingteacher', $rolesname) || in_array('teacher', $rolesname)) {
- return get_string('imsroleinstructor', 'lti');
- }
-
- return get_string('imsrolelearner', 'lti');
-}
-
-/**
- * Returns configuration details for the tool
- *
- * @param int $typeid Basic LTI tool typeid
- *
- * @return array Tool Configuration
- */
-function lti_get_type_config($typeid) {
- global $DB;
-
- $typeconfig = array();
- $configs = $DB->get_records('lti_types_config', array('typeid' => $typeid));
- if (!empty($configs)) {
- foreach ($configs as $config) {
- $typeconfig[$config->name] = $config->value;
- }
- }
- return $typeconfig;
-}
-
-function lti_get_tools_by_url($url, $state){
- $domain = lti_get_domain_from_url($url);
-
- return lti_get_tools_by_domain($domain, $state);
-}
-
-function lti_get_tools_by_domain($domain, $state = null, $courseid = null){
- global $DB, $SITE;
-
- $filters = array('tooldomain' => $domain);
-
- $statefilter = '';
- $coursefilter = '';
-
- if($state){
- $statefilter = 'AND state = :state';
- }
-
- if($courseid && $courseid != $SITE->id){
- $coursefilter = 'OR course = :courseid';
- }
-
- $query = <<<QUERY
- SELECT * FROM {lti_types}
- WHERE
- tooldomain = :tooldomain
- AND (course = :siteid $coursefilter)
- $statefilter
-QUERY;
-
- return $DB->get_records_sql($query, array(
- 'courseid' => $courseid,
- 'siteid' => $SITE->id,
- 'tooldomain' => $domain,
- 'state' => $state
- ));
-}
-
-/**
- * Returns all basicLTI tools configured by the administrator
- *
- */
-function lti_filter_get_types() {
- global $DB;
-
- return $DB->get_records('lti_types');
-}
-
-function lti_get_types_for_add_instance(){
- global $DB;
- $admintypes = $DB->get_records('lti_types', array('coursevisible' => 1));
-
- $types = array();
- $types[0] = get_string('automatic', 'lti');
-
- foreach($admintypes as $type) {
- $types[$type->id] = $type->name;
- }
-
- return $types;
-}
-
-function lti_get_domain_from_url($url){
- $matches = array();
-
- if(preg_match(LTI_URL_DOMAIN_REGEX, $url, $matches)){
- return $matches[1];
- }
-}
-
-function lti_get_tool_by_url_match($url, $courseid = null, $state = LTI_TOOL_STATE_CONFIGURED){
- $possibletools = lti_get_tools_by_url($url, $state, $courseid);
-
- return lti_get_best_tool_by_url($url, $possibletools);
-}
-
-function lti_get_url_thumbprint($url){
- $urlparts = parse_url(strtolower($url));
- if(!isset($urlparts['path'])){
- $urlparts['path'] = '';
- }
-
- if(substr($urlparts['host'], 0, 3) === 'www'){
- $urllparts['host'] = substr(3);
- }
-
- return $urllower = $urlparts['host'] . '/' . $urlparts['path'];
-}
-
-function lti_get_best_tool_by_url($url, $tools){
- if(count($tools) === 0){
- return null;
- }
-
- $urllower = lti_get_url_thumbprint($url);
-
- foreach($tools as $tool){
- $tool->_matchscore = 0;
-
- $toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);
-
- if($urllower === $toolbaseurllower){
- //100 points for exact match
- $tool->_matchscore += 100;
- } else if(substr($urllower, 0, strlen($toolbaseurllower)) === $toolbaseurllower){
- //50 points if it starts with the base URL
- $tool->_matchscore += 50;
- }
- }
-
- $bestmatch = array_reduce($tools, function($value, $tool){
- if($tool->_matchscore > $value->_matchscore){
- return $tool;
- } else {
- return $value;
- }
-
- }, (object)array('_matchscore' => -1));
-
- //None of the tools are suitable for this URL
- if($bestmatch->_matchscore <= 0){
- return null;
- }
-
- return $bestmatch;
-}
-
-/**
- * Prints the various configured tool types
- *
- */
-function lti_filter_print_types() {
- global $CFG;
-
- $types = lti_filter_get_types();
- if (!empty($types)) {
- echo '<ul>';
- foreach ($types as $type) {
- echo '<li>'.
- $type->name.
- '<span class="commands">'.
- '<a class="editing_update" href="typessettings.php?action=update&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Update">'.
- '<img class="iconsmall" alt="Update" src="'.$CFG->wwwroot.'/pix/t/edit.gif"/>'.
- '</a>'.
- '<a class="editing_delete" href="typessettings.php?action=delete&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Delete">'.
- '<img class="iconsmall" alt="Delete" src="'.$CFG->wwwroot.'/pix/t/delete.gif"/>'.
- '</a>'.
- '</span>'.
- '</li>';
-
- }
- echo '</ul>';
- } else {
- echo '<div class="message">';
- echo get_string('notypes', 'lti');
- echo '</div>';
- }
-}
-
-/**
- * Delete a Basic LTI configuration
- *
- * @param int $id Configuration id
- */
-function lti_delete_type($id) {
- global $DB;
-
- //We should probably just copy the launch URL to the tool instances in this case... using a single query
- /*
- $instances = $DB->get_records('lti', array('typeid' => $id));
- foreach ($instances as $instance) {
- $instance->typeid = 0;
- $DB->update_record('lti', $instance);
- }*/
-
- $DB->delete_records('lti_types', array('id' => $id));
- $DB->delete_records('lti_types_config', array('typeid' => $id));
-}
-
-function lti_set_state_for_type($id, $state){
- global $DB;
-
- $DB->update_record('lti_types', array('id' => $id, 'state' => $state));
-}
-
-/**
- * Transforms a basic LTI object to an array
- *
- * @param object $ltiobject Basic LTI object
- *
- * @return array Basic LTI configuration details
- */
-function lti_get_config($ltiobject) {
- $typeconfig = array();
- $typeconfig = (array)$ltiobject;
- $additionalconfig = lti_get_type_config($ltiobject->typeid);
- $typeconfig = array_merge($typeconfig, $additionalconfig);
- return $typeconfig;
-}
-
-/**
- *
- * Generates some of the tool configuration based on the instance details
- *
- * @param int $id
- *
- * @return Instance configuration
- *
- */
-function lti_get_type_config_from_instance($id) {
- global $DB;
-
- $instance = $DB->get_record('lti', array('id' => $id));
- $config = lti_get_config($instance);
-
- $type = new stdClass();
- $type->lti_fix = $id;
- if (isset($config['toolurl'])) {
- $type->lti_toolurl = $config['toolurl'];
- }
- if (isset($config['instructorchoicesendname'])) {
- $type->lti_sendname = $config['instructorchoicesendname'];
- }
- if (isset($config['instructorchoicesendemailaddr'])) {
- $type->lti_sendemailaddr = $config['instructorchoicesendemailaddr'];
- }
- if (isset($config['instructorchoiceacceptgrades'])) {
- $type->lti_acceptgrades = $config['instructorchoiceacceptgrades'];
- }
- if (isset($config['instructorchoiceallowroster'])) {
- $type->lti_allowroster = $config['instructorchoiceallowroster'];
- }
-
- if (isset($config['instructorcustomparameters'])) {
- $type->lti_allowsetting = $config['instructorcustomparameters'];
- }
- return $type;
-}
-
-/**
- * Generates some of the tool configuration based on the admin configuration details
- *
- * @param int $id
- *
- * @return Configuration details
- */
-function lti_get_type_type_config($id) {
- global $DB;
-
- $basicltitype = $DB->get_record('lti_types', array('id' => $id));
- $config = lti_get_type_config($id);
-
- $type->lti_typename = $basicltitype->name;
-
- $type->lti_toolurl = $basicltitype->baseurl;
-
- if (isset($config['resourcekey'])) {
- $type->lti_resourcekey = $config['resourcekey'];
- }
- if (isset($config['password'])) {
- $type->lti_password = $config['password'];
- }
-
- if (isset($config['sendname'])) {
- $type->lti_sendname = $config['sendname'];
- }
- if (isset($config['instructorchoicesendname'])){
- $type->lti_instructorchoicesendname = $config['instructorchoicesendname'];
- }
- if (isset($config['sendemailaddr'])){
- $type->lti_sendemailaddr = $config['sendemailaddr'];
- }
- if (isset($config['instructorchoicesendemailaddr'])){
- $type->lti_instructorchoicesendemailaddr = $config['instructorchoicesendemailaddr'];
- }
- if (isset($config['acceptgrades'])){
- $type->lti_acceptgrades = $config['acceptgrades'];
- }
- if (isset($config['instructorchoiceacceptgrades'])){
- $type->lti_instructorchoiceacceptgrades = $config['instructorchoiceacceptgrades'];
- }
- if (isset($config['allowroster'])){
- $type->lti_allowroster = $config['allowroster'];
- }
- if (isset($config['instructorchoiceallowroster'])){
- $type->lti_instructorchoiceallowroster = $config['instructorchoiceallowroster'];
- }
-
- if (isset($config['customparameters'])) {
- $type->lti_customparameters = $config['customparameters'];
- }
-
- if (isset($config['organizationid'])) {
- $type->lti_organizationid = $config['organizationid'];
- }
- if (isset($config['organizationurl'])) {
- $type->lti_organizationurl = $config['organizationurl'];
- }
- if (isset($config['organizationdescr'])) {
- $type->lti_organizationdescr = $config['organizationdescr'];
- }
- if (isset($config['launchcontainer'])) {
- $type->lti_launchcontainer = $config['launchcontainer'];
- }
-
- if (isset($config['coursevisible'])) {
- $type->lti_coursevisible = $config['coursevisible'];
- }
-
- if (isset($config['debuglaunch'])) {
- $type->lti_debuglaunch = $config['debuglaunch'];
- }
-
- if (isset($config['module_class_type'])) {
- $type->lti_module_class_type = $config['module_class_type'];
- }
-
- return $type;
-}
-
-function lti_prepare_type_for_save($type, $config){
- $type->baseurl = $config->lti_toolurl;
- $type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
- $type->name = $config->lti_typename;
-
- $type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;
- $config->lti_coursevisible = $type->coursevisible;
-
- $type->timemodified = time();
-
- unset ($config->lti_typename);
- unset ($config->lti_toolurl);
-}
-
-function lti_update_type($type, $config){
- global $DB;
-
- lti_prepare_type_for_save($type, $config);
-
- if ($DB->update_record('lti_types', $type)) {
- foreach ($config as $key => $value) {
- if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
- $record = new StdClass();
- $record->typeid = $type->id;
- $record->name = substr($key, 4);
- $record->value = $value;
-
- lti_update_config($record);
- }
- }
- }
-}
-
-function lti_add_type($type, $config){
- global $USER, $SITE, $DB;
-
- lti_prepare_type_for_save($type, $config);
-
- if(!isset($type->state)){
- $type->state = LTI_TOOL_STATE_PENDING;
- }
-
- if(!isset($type->timecreated)){
- $type->timecreated = time();
- }
-
- if(!isset($type->createdby)){
- $type->createdby = $USER->id;
- }
-
- if(!isset($type->course)){
- $type->course = $SITE->id;
- }
-
- //Create a salt value to be used for signing passed data to extension services
- $config->lti_servicesalt = uniqid('', true);
-
- $id = $DB->insert_record('lti_types', $type);
-
- if ($id) {
- foreach ($config as $key => $value) {
- if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
- $record = new StdClass();
- $record->typeid = $id;
- $record->name = substr($key, 4);
- $record->value = $value;
-
- lti_add_config($record);
- }
- }
- }
-}
-
-/**
- * Add a tool configuration in the database
- *
- * @param $config Tool configuration
- *
- * @return int Record id number
- */
-function lti_add_config($config) {
- global $DB;
-
- return $DB->insert_record('lti_types_config', $config);
-}
-
-/**
- * Updates a tool configuration in the database
- *
- * @param $config Tool configuration
- *
- * @return Record id number
- */
-function lti_update_config($config) {
- global $DB;
-
- $return = true;
- $old = $DB->get_record('lti_types_config', array('typeid' => $config->typeid, 'name' => $config->name));
-
- if ($old) {
- $config->id = $old->id;
- $return = $DB->update_record('lti_types_config', $config);
- } else {
- $return = $DB->insert_record('lti_types_config', $config);
- }
- return $return;
-}
-
-/**
- * Signs the petition to launch the external tool using OAuth
- *
- * @param $oldparms Parameters to be passed for signing
- * @param $endpoint url of the external tool
- * @param $method Method for sending the parameters (e.g. POST)
- * @param $oauth_consumoer_key Key
- * @param $oauth_consumoer_secret Secret
- * @param $submittext The text for the submit button
- * @param $orgid LMS name
- * @param $orgdesc LMS key
- */
-function sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $oauthconsumersecret, $submittext, $orgid /*, $orgdesc*/) {
- global $lastbasestring;
- $parms = $oldparms;
- $parms["lti_version"] = "LTI-1p0";
- $parms["lti_message_type"] = "basic-lti-launch-request";
- if ( $orgid ) {
- $parms["tool_consumer_instance_guid"] = $orgid;
- }
- /* Suppress this for now - Chuck
- if ( $orgdesc ) $parms["tool_consumer_instance_description"] = $orgdesc;
- */
- $parms["ext_submit"] = $submittext;
-
- $testtoken = '';
-
- $hmacmethod = new OAuthSignatureMethod_HMAC_SHA1();
- $testconsumer = new OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);
-
- $accreq = OAuthRequest::from_consumer_and_token($testconsumer, $testtoken, $method, $endpoint, $parms);
- $accreq->sign_request($hmacmethod, $testconsumer, $testtoken);
-
- // Pass this back up "out of band" for debugging
- $lastbasestring = $accreq->get_signature_base_string();
-
- $newparms = $accreq->get_parameters();
-
- return $newparms;
-}
-
-/**
- * Posts the launch petition HTML
- *
- * @param $newparms Signed parameters
- * @param $endpoint URL of the external tool
- * @param $debug Debug (true/false)
- */
-function post_launch_html($newparms, $endpoint, $debug=false) {
- global $lastbasestring;
-
- $r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";
-
- $submittext = $newparms['ext_submit'];
-
- // Contruct html for the launch parameters
- foreach ($newparms as $key => $value) {
- $key = htmlspecialchars($key);
- $value = htmlspecialchars($value);
- if ( $key == "ext_submit" ) {
- $r .= "<input type=\"submit\" name=\"";
- } else {
- $r .= "<input type=\"hidden\" name=\"";
- }
- $r .= $key;
- $r .= "\" value=\"";
- $r .= $value;
- $r .= "\"/>\n";
- }
-
- if ( $debug ) {
- $r .= "<script language=\"javascript\"> \n";
- $r .= " //<![CDATA[ \n";
- $r .= "function basicltiDebugToggle() {\n";
- $r .= " var ele = document.getElementById(\"basicltiDebug\");\n";
- $r .= " if(ele.style.display == \"block\") {\n";
- $r .= " ele.style.display = \"none\";\n";
- $r .= " }\n";
- $r .= " else {\n";
- $r .= " ele.style.display = \"block\";\n";
- $r .= " }\n";
- $r .= "} \n";
- $r .= " //]]> \n";
- $r .= "</script>\n";
- $r .= "<a id=\"displayText\" href=\"javascript:basicltiDebugToggle();\">";
- $r .= get_string("toggle_debug_data", "lti")."</a>\n";
- $r .= "<div id=\"basicltiDebug\" style=\"display:none\">\n";
- $r .= "<b>".get_string("basiclti_endpoint", "lti")."</b><br/>\n";
- $r .= $endpoint . "<br/>\n&nbsp;<br/>\n";
- $r .= "<b>".get_string("basiclti_parameters", "lti")."</b><br/>\n";
- foreach ($newparms as $key => $value) {
- $key = htmlspecialchars($key);
- $value = htmlspecialchars($value);
- $r .= "$key = $value<br/>\n";
- }
- $r .= "&nbsp;<br/>\n";
- $r .= "<p><b>".get_string("basiclti_base_string", "lti")."</b><br/>\n".$lastbasestring."</p>\n";
- $r .= "</div>\n";
- }
- $r .= "</form>\n";
-
- if ( ! $debug ) {
- $ext_submit = "ext_submit";
- $ext_submit_text = $submittext;
- $r .= " <script type=\"text/javascript\"> \n" .
- " //<![CDATA[ \n" .
- " document.getElementById(\"ltiLaunchForm\").style.display = \"none\";\n" .
- " nei = document.createElement('input');\n" .
- " nei.setAttribute('type', 'hidden');\n" .
- " nei.setAttribute('name', '".$ext_submit."');\n" .
- " nei.setAttribute('value', '".$ext_submit_text."');\n" .
- " document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n" .
- " document.ltiLaunchForm.submit(); \n" .
- " //]]> \n" .
- " </script> \n";
- }
- return $r;
-}
-
-/**
- * Returns a link with info about the state of the basiclti submissions
- *
- * This is used by view_header to put this link at the top right of the page.
- * For teachers it gives the number of submitted assignments with a link
- * For students it gives the time of their submission.
- * This will be suitable for most assignment types.
- *
- * @global object
- * @global object
- * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php
- * @return string
- */
-function submittedlink($cm, $allgroups=false) {
- global $CFG;
-
- $submitted = '';
- $urlbase = "{$CFG->wwwroot}/mod/lti/";
-
- $context = get_context_instance(CONTEXT_MODULE, $cm->id);
- if (has_capability('mod/lti:grade', $context)) {
- if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) {
- $group = 0;
- } else {
- $group = groups_get_activity_group($cm);
- }
-
- $submitted = '<a href="'.$urlbase.'submissions.php?id='.$cm->id.'">'.
- get_string('viewsubmissions', 'lti').'</a>';
- } else {
- if (isloggedin()) {
- // TODO Insert code for students if needed
- }
- }
-
- return $submitted;
-}
-
+<?php
+// This file is part of BasicLTI4Moodle
+//
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
+// are already supporting or going to support BasicLTI. This project Implements the consumer
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
+// at the GESSI research group at UPC.
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
+//
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
+//
+// 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/>.
+
+/**
+ * This file contains the library of functions and constants for the basiclti module
+ *
+ * @package lti
+ * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
+ * marc.alier@upc.edu
+ * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
+ *
+ * @author Marc Alier
+ * @author Jordi Piguillem
+ * @author Nikolas Galanis
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->dirroot.'/mod/lti/OAuth.php');
+
+define('LTI_URL_DOMAIN_REGEX', '/(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i');
+
+define('LTI_LAUNCH_CONTAINER_DEFAULT', 1);
+define('LTI_LAUNCH_CONTAINER_EMBED', 2);
+define('LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS', 3);
+define('LTI_LAUNCH_CONTAINER_WINDOW', 4);
+
+define('LTI_TOOL_STATE_ANY', 0);
+define('LTI_TOOL_STATE_CONFIGURED', 1);
+define('LTI_TOOL_STATE_PENDING', 2);
+define('LTI_TOOL_STATE_REJECTED', 3);
+
+define('LTI_SETTING_NEVER', 0);
+define('LTI_SETTING_ALWAYS', 1);
+define('LTI_SETTING_DEFAULT', 2);
+
+/**
+ * Prints a Basic LTI activity
+ *
+ * $param int $basicltiid Basic LTI activity id
+ */
+function lti_view($instance, $makeobject=false) {
+ global $PAGE, $CFG;
+
+ if(empty($instance->typeid)){
+ $tool = lti_get_tool_by_url_match($instance->toolurl);
+ if($tool){
+ $typeid = $tool->id;
+ } else {
+ $typeid = null;
+ }
+ } else {
+ $typeid = $instance->typeid;
+ }
+
+ if($typeid){
+ $typeconfig = lti_get_type_config($typeid);
+ } else {
+ //There is no admin configuration for this tool. Use configuration in the lti instance record plus some defaults.
+ $typeconfig = (array)$instance;
+
+ $typeconfig['sendname'] = $instance->instructorchoicesendname;
+ $typeconfig['sendemailaddr'] = $instance->instructorchoicesendemailaddr;
+ $typeconfig['customparameters'] = $instance->instructorcustomparameters;
+ }
+
+ //Default the organizationid if not specified
+ if(empty($typeconfig['organizationid'])){
+ $urlparts = parse_url($CFG->wwwroot);
+
+ $typeconfig['organizationid'] = $urlparts['host'];
+ }
+
+ $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];
+ $key = !empty($instance->resourcekey) ? $instance->resourcekey : $typeconfig['resourcekey'];
+ $secret = !empty($instance->password) ? $instance->password : $typeconfig['password'];
+ $orgid = $typeconfig['organizationid'];
+ /* Suppress this for now - Chuck
+ $orgdesc = $typeconfig['organizationdescr'];
+ */
+
+ $course = $PAGE->course;
+ $requestparams = lti_build_request($instance, $typeconfig, $course);
+
+ // Make sure we let the tool know what LMS they are being called from
+ $requestparams["ext_lms"] = "moodle-2";
+
+ // Add oauth_callback to be compliant with the 1.0A spec
+ $requestparams["oauth_callback"] = "about:blank";
+
+ $submittext = get_string('press_to_submit', 'lti');
+ $parms = sign_parameters($requestparams, $endpoint, "POST", $key, $secret, $submittext, $orgid /*, $orgdesc*/);
+
+ $debuglaunch = ( $instance->debuglaunch == 1 );
+
+ $content = post_launch_html($parms, $endpoint, $debuglaunch);
+
+ echo $content;
+}
+
+/**
+ * This function builds the request that must be sent to the tool producer
+ *
+ * @param object $instance Basic LTI instance object
+ * @param object $typeconfig Basic LTI tool configuration
+ * @param object $course Course object
+ *
+ * @return array $request Request details
+ */
+function lti_build_request($instance, $typeconfig, $course) {
+ global $USER, $CFG;
+
+ $context = get_context_instance(CONTEXT_COURSE, $course->id);
+ $role = lti_get_ims_role($USER, $context);
+
+ $locale = $course->lang;
+ if ( strlen($locale) < 1 ) {
+ $locale = $CFG->lang;
+ }
+
+ $requestparams = array(
+ "resource_link_id" => $instance->id,
+ "resource_link_title" => $instance->name,
+ "resource_link_description" => $instance->intro,
+ "user_id" => $USER->id,
+ "roles" => $role,
+ "context_id" => $course->id,
+ "context_label" => $course->shortname,
+ "context_title" => $course->fullname,
+ "launch_presentation_locale" => $locale,
+ );
+
+ //$placementsecret = $typeconfig['servicesalt'];
+
+ //Always use the servicesalt on the instance.
+ //TODO: Remove from type settings
+ $placementsecret = $instance->servicesalt;
+
+ if ( isset($placementsecret) ) {
+ $data = new stdClass();
+
+ $data->instanceid = $instance->id;
+ $data->userid = $USER->id;
+
+ $json = json_encode($data);
+
+ $hash = hash('sha256', $json . $placementsecret, false);
+
+ $container = new stdClass();
+ $container->data = $data;
+ $container->hash = $hash;
+
+ $sourcedid = json_encode($container);
+ }
+
+ if ( isset($placementsecret) &&
+ ( $typeconfig['acceptgrades'] == 1 ||
+ ( $typeconfig['acceptgrades'] == 2 && $instance->instructorchoiceacceptgrades == 1 ) ) ) {
+ $requestparams["lis_result_sourcedid"] = $sourcedid;
+ $requestparams["ext_ims_lis_basic_outcome_url"] = $CFG->wwwroot.'/mod/lti/service.php';
+ }
+
+ if ( isset($placementsecret) &&
+ ( $typeconfig['allowroster'] == 1 ||
+ ( $typeconfig['allowroster'] == 2 && $instance->instructorchoiceallowroster == 1 ) ) ) {
+ $requestparams["ext_ims_lis_memberships_id"] = $sourcedid;
+ $requestparams["ext_ims_lis_memberships_url"] = $CFG->wwwroot.'/mod/lti/service.php';
+ }
+
+ // Send user's name and email data if appropriate
+ if ( $typeconfig['sendname'] == 1 ||
+ ( $typeconfig['sendname'] == 2 && $instance->instructorchoicesendname == 1 ) ) {
+ $requestparams["lis_person_name_given"] = $USER->firstname;
+ $requestparams["lis_person_name_family"] = $USER->lastname;
+ $requestparams["lis_person_name_full"] = $USER->firstname." ".$USER->lastname;
+ }
+
+ if ( $typeconfig['sendemailaddr'] == 1 ||
+ ( $typeconfig['sendemailaddr'] == 2 && $instance->instructorchoicesendemailaddr == 1 ) ) {
+ $requestparams["lis_person_contact_email_primary"] = $USER->email;
+ }
+
+ // Concatenate the custom parameters from the administrator and the instructor
+ // Instructor parameters are only taken into consideration if the administrator
+ // has giver permission
+ $customstr = $typeconfig['customparameters'];
+ $instructorcustomstr = $instance->instructorcustomparameters;
+ $custom = array();
+ $instructorcustom = array();
+ if ($customstr) {
+ $custom = split_custom_parameters($customstr);
+ }
+ if (!isset($typeconfig['allowinstructorcustom']) || $typeconfig['allowinstructorcustom'] == 0) {
+ $requestparams = array_merge($custom, $requestparams);
+ } else {
+ if ($instructorcustomstr) {
+ $instructorcustom = split_custom_parameters($instructorcustomstr);
+ }
+ foreach ($instructorcustom as $key => $val) {
+ if (array_key_exists($key, $custom)) {
+ // Ignore the instructor's parameter
+ } else {
+ $custom[$key] = $val;
+ }
+ }
+ $requestparams = array_merge($custom, $requestparams);
+ }
+
+ return $requestparams;
+}
+
+/**
+ * Splits the custom parameters field to the various parameters
+ *
+ * @param string $customstr String containing the parameters
+ *
+ * @return Array of custom parameters
+ */
+function split_custom_parameters($customstr) {
+ $textlib = textlib_get_instance();
+
+ $lines = preg_split("/[\n;]/", $customstr);
+ $retval = array();
+ foreach ($lines as $line) {
+ $pos = strpos($line, "=");
+ if ( $pos === false || $pos < 1 ) {
+ continue;
+ }
+ $key = trim($textlib->substr($line, 0, $pos));
+ $val = trim($textlib->substr($line, $pos+1));
+ $key = map_keyname($key);
+ $retval['custom_'.$key] = $val;
+ }
+ return $retval;
+}
+
+/**
+ * Used for building the names of the different custom parameters
+ *
+ * @param string $key Parameter name
+ *
+ * @return string Processed name
+ */
+function map_keyname($key) {
+ $textlib = textlib_get_instance();
+
+ $newkey = "";
+ $key = $textlib->strtolower(trim($key));
+ foreach (str_split($key) as $ch) {
+ if ( ($ch >= 'a' && $ch <= 'z') || ($ch >= '0' && $ch <= '9') ) {
+ $newkey .= $ch;
+ } else {
+ $newkey .= '_';
+ }
+ }
+ return $newkey;
+}
+
+/**
+ * Returns the IMS user role in a given context
+ *
+ * This function queries Moodle for an user role and
+ * returns the correspondant IMS role
+ *
+ * @param StdClass $user Moodle user instance
+ * @param StdClass $context Moodle context
+ *
+ * @return string IMS Role
+ *
+ */
+function lti_get_ims_role($user, $context) {
+
+ $roles = get_user_roles($context, $user->id);
+ $rolesname = array();
+ foreach ($roles as $role) {
+ $rolesname[] = $role->shortname;
+ }
+
+ if (in_array('admin', $rolesname) || in_array('coursecreator', $rolesname)) {
+ return get_string('imsroleadmin', 'lti');
+ }
+
+ if (in_array('editingteacher', $rolesname) || in_array('teacher', $rolesname)) {
+ return get_string('imsroleinstructor', 'lti');
+ }
+
+ return get_string('imsrolelearner', 'lti');
+}
+
+/**
+ * Returns configuration details for the tool
+ *
+ * @param int $typeid Basic LTI tool typeid
+ *
+ * @return array Tool Configuration
+ */
+function lti_get_type_config($typeid) {
+ global $DB;
+
+ $typeconfig = array();
+ $configs = $DB->get_records('lti_types_config', array('typeid' => $typeid));
+ if (!empty($configs)) {
+ foreach ($configs as $config) {
+ $typeconfig[$config->name] = $config->value;
+ }
+ }
+ return $typeconfig;
+}
+
+function lti_get_tools_by_url($url, $state){
+ $domain = lti_get_domain_from_url($url);
+
+ return lti_get_tools_by_domain($domain, $state);
+}
+
+function lti_get_tools_by_domain($domain, $state = null, $courseid = null){
+ global $DB, $SITE;
+
+ $filters = array('tooldomain' => $domain);
+
+ $statefilter = '';
+ $coursefilter = '';
+
+ if($state){
+ $statefilter = 'AND state = :state';
+ }
+
+ if($courseid && $courseid != $SITE->id){
+ $coursefilter = 'OR course = :courseid';
+ }
+
+ $query = <<<QUERY
+ SELECT * FROM {lti_types}
+ WHERE
+ tooldomain = :tooldomain
+ AND (course = :siteid $coursefilter)
+ $statefilter
+QUERY;
+
+ return $DB->get_records_sql($query, array(
+ 'courseid' => $courseid,
+ 'siteid' => $SITE->id,
+ 'tooldomain' => $domain,
+ 'state' => $state
+ ));
+}
+
+/**
+ * Returns all basicLTI tools configured by the administrator
+ *
+ */
+function lti_filter_get_types() {
+ global $DB;
+
+ return $DB->get_records('lti_types');
+}
+
+function lti_get_types_for_add_instance(){
+ global $DB;
+ $admintypes = $DB->get_records('lti_types', array('coursevisible' => 1));
+
+ $types = array();
+ $types[0] = get_string('automatic', 'lti');
+
+ foreach($admintypes as $type) {
+ $types[$type->id] = $type->name;
+ }
+
+ return $types;
+}
+
+function lti_get_domain_from_url($url){
+ $matches = array();
+
+ if(preg_match(LTI_URL_DOMAIN_REGEX, $url, $matches)){
+ return $matches[1];
+ }
+}
+
+function lti_get_tool_by_url_match($url, $courseid = null, $state = LTI_TOOL_STATE_CONFIGURED){
+ $possibletools = lti_get_tools_by_url($url, $state, $courseid);
+
+ return lti_get_best_tool_by_url($url, $possibletools);
+}
+
+function lti_get_url_thumbprint($url){
+ $urlparts = parse_url(strtolower($url));
+ if(!isset($urlparts['path'])){
+ $urlparts['path'] = '';
+ }
+
+ if(substr($urlparts['host'], 0, 3) === 'www'){
+ $urllparts['host'] = substr(3);
+ }
+
+ return $urllower = $urlparts['host'] . '/' . $urlparts['path'];
+}
+
+function lti_get_best_tool_by_url($url, $tools){
+ if(count($tools) === 0){
+ return null;
+ }
+
+ $urllower = lti_get_url_thumbprint($url);
+
+ foreach($tools as $tool){
+ $tool->_matchscore = 0;
+
+ $toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);
+
+ if($urllower === $toolbaseurllower){
+ //100 points for exact match
+ $tool->_matchscore += 100;
+ } else if(substr($urllower, 0, strlen($toolbaseurllower)) === $toolbaseurllower){
+ //50 points if it starts with the base URL
+ $tool->_matchscore += 50;
+ }
+ }
+
+ $bestmatch = array_reduce($tools, function($value, $tool){
+ if($tool->_matchscore > $value->_matchscore){
+ return $tool;
+ } else {
+ return $value;
+ }
+
+ }, (object)array('_matchscore' => -1));
+
+ //None of the tools are suitable for this URL
+ if($bestmatch->_matchscore <= 0){
+ return null;
+ }
+
+ return $bestmatch;
+}
+
+/**
+ * Prints the various configured tool types
+ *
+ */
+function lti_filter_print_types() {
+ global $CFG;
+
+ $types = lti_filter_get_types();
+ if (!empty($types)) {
+ echo '<ul>';
+ foreach ($types as $type) {
+ echo '<li>'.
+ $type->name.
+ '<span class="commands">'.
+ '<a class="editing_update" href="typessettings.php?action=update&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Update">'.
+ '<img class="iconsmall" alt="Update" src="'.$CFG->wwwroot.'/pix/t/edit.gif"/>'.
+ '</a>'.
+ '<a class="editing_delete" href="typessettings.php?action=delete&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Delete">'.
+ '<img class="iconsmall" alt="Delete" src="'.$CFG->wwwroot.'/pix/t/delete.gif"/>'.
+ '</a>'.
+ '</span>'.
+ '</li>';
+
+ }
+ echo '</ul>';
+ } else {
+ echo '<div class="message">';
+ echo get_string('notypes', 'lti');
+ echo '</div>';
+ }
+}
+
+/**
+ * Delete a Basic LTI configuration
+ *
+ * @param int $id Configuration id
+ */
+function lti_delete_type($id) {
+ global $DB;
+
+ //We should probably just copy the launch URL to the tool instances in this case... using a single query
+ /*
+ $instances = $DB->get_records('lti', array('typeid' => $id));
+ foreach ($instances as $instance) {
+ $instance->typeid = 0;
+ $DB->update_record('lti', $instance);
+ }*/
+
+ $DB->delete_records('lti_types', array('id' => $id));
+ $DB->delete_records('lti_types_config', array('typeid' => $id));
+}
+
+function lti_set_state_for_type($id, $state){
+ global $DB;
+
+ $DB->update_record('lti_types', array('id' => $id, 'state' => $state));
+}
+
+/**
+ * Transforms a basic LTI object to an array
+ *
+ * @param object $ltiobject Basic LTI object
+ *
+ * @return array Basic LTI configuration details
+ */
+function lti_get_config($ltiobject) {
+ $typeconfig = array();
+ $typeconfig = (array)$ltiobject;
+ $additionalconfig = lti_get_type_config($ltiobject->typeid);
+ $typeconfig = array_merge($typeconfig, $additionalconfig);
+ return $typeconfig;
+}
+
+/**
+ *
+ * Generates some of the tool configuration based on the instance details
+ *
+ * @param int $id
+ *
+ * @return Instance configuration
+ *
+ */
+function lti_get_type_config_from_instance($id) {
+ global $DB;
+
+ $instance = $DB->get_record('lti', array('id' => $id));
+ $config = lti_get_config($instance);
+
+ $type = new stdClass();
+ $type->lti_fix = $id;
+ if (isset($config['toolurl'])) {
+ $type->lti_toolurl = $config['toolurl'];
+ }
+ if (isset($config['instructorchoicesendname'])) {
+ $type->lti_sendname = $config['instructorchoicesendname'];
+ }
+ if (isset($config['instructorchoicesendemailaddr'])) {
+ $type->lti_sendemailaddr = $config['instructorchoicesendemailaddr'];
+ }
+ if (isset($config['instructorchoiceacceptgrades'])) {
+ $type->lti_acceptgrades = $config['instructorchoiceacceptgrades'];
+ }
+ if (isset($config['instructorchoiceallowroster'])) {
+ $type->lti_allowroster = $config['instructorchoiceallowroster'];
+ }
+
+ if (isset($config['instructorcustomparameters'])) {
+ $type->lti_allowsetting = $config['instructorcustomparameters'];
+ }
+ return $type;
+}
+
+/**
+ * Generates some of the tool configuration based on the admin configuration details
+ *
+ * @param int $id
+ *
+ * @return Configuration details
+ */
+function lti_get_type_type_config($id) {
+ global $DB;
+
+ $basicltitype = $DB->get_record('lti_types', array('id' => $id));
+ $config = lti_get_type_config($id);
+
+ $type->lti_typename = $basicltitype->name;
+
+ $type->lti_toolurl = $basicltitype->baseurl;
+
+ if (isset($config['resourcekey'])) {
+ $type->lti_resourcekey = $config['resourcekey'];
+ }
+ if (isset($config['password'])) {
+ $type->lti_password = $config['password'];
+ }
+
+ if (isset($config['sendname'])) {
+ $type->lti_sendname = $config['sendname'];
+ }
+ if (isset($config['instructorchoicesendname'])){
+ $type->lti_instructorchoicesendname = $config['instructorchoicesendname'];
+ }
+ if (isset($config['sendemailaddr'])){
+ $type->lti_sendemailaddr = $config['sendemailaddr'];
+ }
+ if (isset($config['instructorchoicesendemailaddr'])){
+ $type->lti_instructorchoicesendemailaddr = $config['instructorchoicesendemailaddr'];
+ }
+ if (isset($config['acceptgrades'])){
+ $type->lti_acceptgrades = $config['acceptgrades'];
+ }
+ if (isset($config['instructorchoiceacceptgrades'])){
+ $type->lti_instructorchoiceacceptgrades = $config['instructorchoiceacceptgrades'];
+ }
+ if (isset($config['allowroster'])){
+ $type->lti_allowroster = $config['allowroster'];
+ }
+ if (isset($config['instructorchoiceallowroster'])){
+ $type->lti_instructorchoiceallowroster = $config['instructorchoiceallowroster'];
+ }
+
+ if (isset($config['customparameters'])) {
+ $type->lti_customparameters = $config['customparameters'];
+ }
+
+ if (isset($config['organizationid'])) {
+ $type->lti_organizationid = $config['organizationid'];
+ }
+ if (isset($config['organizationurl'])) {
+ $type->lti_organizationurl = $config['organizationurl'];
+ }
+ if (isset($config['organizationdescr'])) {
+ $type->lti_organizationdescr = $config['organizationdescr'];
+ }
+ if (isset($config['launchcontainer'])) {
+ $type->lti_launchcontainer = $config['launchcontainer'];
+ }
+
+ if (isset($config['coursevisible'])) {
+ $type->lti_coursevisible = $config['coursevisible'];
+ }
+
+ if (isset($config['debuglaunch'])) {
+ $type->lti_debuglaunch = $config['debuglaunch'];
+ }
+
+ if (isset($config['module_class_type'])) {
+ $type->lti_module_class_type = $config['module_class_type'];
+ }
+
+ return $type;
+}
+
+function lti_prepare_type_for_save($type, $config){
+ $type->baseurl = $config->lti_toolurl;
+ $type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
+ $type->name = $config->lti_typename;
+
+ $type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;
+ $config->lti_coursevisible = $type->coursevisible;
+
+ $type->timemodified = time();
+
+ unset ($config->lti_typename);
+ unset ($config->lti_toolurl);
+}
+
+function lti_update_type($type, $config){
+ global $DB;
+
+ lti_prepare_type_for_save($type, $config);
+
+ if ($DB->update_record('lti_types', $type)) {
+ foreach ($config as $key => $value) {
+ if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
+ $record = new StdClass();
+ $record->typeid = $type->id;
+ $record->name = substr($key, 4);
+ $record->value = $value;
+
+ lti_update_config($record);
+ }
+ }
+ }
+}
+
+function lti_add_type($type, $config){
+ global $USER, $SITE, $DB;
+
+ lti_prepare_type_for_save($type, $config);
+
+ if(!isset($type->state)){
+ $type->state = LTI_TOOL_STATE_PENDING;
+ }
+
+ if(!isset($type->timecreated)){
+ $type->timecreated = time();
+ }
+
+ if(!isset($type->createdby)){
+ $type->createdby = $USER->id;
+ }
+
+ if(!isset($type->course)){
+ $type->course = $SITE->id;
+ }
+
+ //Create a salt value to be used for signing passed data to extension services
+ $config->lti_servicesalt = uniqid('', true);
+
+ $id = $DB->insert_record('lti_types', $type);
+
+ if ($id) {
+ foreach ($config as $key => $value) {
+ if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
+ $record = new StdClass();
+ $record->typeid = $id;
+ $record->name = substr($key, 4);
+ $record->value = $value;
+
+ lti_add_config($record);
+ }
+ }
+ }
+}
+
+/**
+ * Add a tool configuration in the database
+ *
+ * @param $config Tool configuration
+ *
+ * @return int Record id number
+ */
+function lti_add_config($config) {
+ global $DB;
+
+ return $DB->insert_record('lti_types_config', $config);
+}
+
+/**
+ * Updates a tool configuration in the database
+ *
+ * @param $config Tool configuration
+ *
+ * @return Record id number
+ */
+function lti_update_config($config) {
+ global $DB;
+
+ $return = true;
+ $old = $DB->get_record('lti_types_config', array('typeid' => $config->typeid, 'name' => $config->name));
+
+ if ($old) {
+ $config->id = $old->id;
+ $return = $DB->update_record('lti_types_config', $config);
+ } else {
+ $return = $DB->insert_record('lti_types_config', $config);
+ }
+ return $return;
+}
+
+/**
+ * Signs the petition to launch the external tool using OAuth
+ *
+ * @param $oldparms Parameters to be passed for signing
+ * @param $endpoint url of the external tool
+ * @param $method Method for sending the parameters (e.g. POST)
+ * @param $oauth_consumoer_key Key
+ * @param $oauth_consumoer_secret Secret
+ * @param $submittext The text for the submit button
+ * @param $orgid LMS name
+ * @param $orgdesc LMS key
+ */
+function sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $oauthconsumersecret, $submittext, $orgid /*, $orgdesc*/) {
+ global $lastbasestring;
+ $parms = $oldparms;
+ $parms["lti_version"] = "LTI-1p0";
+ $parms["lti_message_type"] = "basic-lti-launch-request";
+ if ( $orgid ) {
+ $parms["tool_consumer_instance_guid"] = $orgid;
+ }
+ /* Suppress this for now - Chuck
+ if ( $orgdesc ) $parms["tool_consumer_instance_description"] = $orgdesc;
+ */
+ $parms["ext_submit"] = $submittext;
+
+ $testtoken = '';
+
+ $hmacmethod = new OAuthSignatureMethod_HMAC_SHA1();
+ $testconsumer = new OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);
+
+ $accreq = OAuthRequest::from_consumer_and_token($testconsumer, $testtoken, $method, $endpoint, $parms);
+ $accreq->sign_request($hmacmethod, $testconsumer, $testtoken);
+
+ // Pass this back up "out of band" for debugging
+ $lastbasestring = $accreq->get_signature_base_string();
+
+ $newparms = $accreq->get_parameters();
+
+ return $newparms;
+}
+
+/**
+ * Posts the launch petition HTML
+ *
+ * @param $newparms Signed parameters
+ * @param $endpoint URL of the external tool
+ * @param $debug Debug (true/false)
+ */
+function post_launch_html($newparms, $endpoint, $debug=false) {
+ global $lastbasestring;
+
+ $r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";
+
+ $submittext = $newparms['ext_submit'];
+
+ // Contruct html for the launch parameters
+ foreach ($newparms as $key => $value) {
+ $key = htmlspecialchars($key);
+ $value = htmlspecialchars($value);
+ if ( $key == "ext_submit" ) {
+ $r .= "<input type=\"submit\" name=\"";
+ } else {
+ $r .= "<input type=\"hidden\" name=\"";
+ }
+ $r .= $key;
+ $r .= "\" value=\"";
+ $r .= $value;
+ $r .= "\"/>\n";
+ }
+
+ if ( $debug ) {
+ $r .= "<script language=\"javascript\"> \n";
+ $r .= " //<![CDATA[ \n";
+ $r .= "function basicltiDebugToggle() {\n";
+ $r .= " var ele = document.getElementById(\"basicltiDebug\");\n";
+ $r .= " if(ele.style.display == \"block\") {\n";
+ $r .= " ele.style.display = \"none\";\n";
+ $r .= " }\n";
+ $r .= " else {\n";
+ $r .= " ele.style.display = \"block\";\n";
+ $r .= " }\n";
+ $r .= "} \n";
+ $r .= " //]]> \n";
+ $r .= "</script>\n";
+ $r .= "<a id=\"displayText\" href=\"javascript:basicltiDebugToggle();\">";
+ $r .= get_string("toggle_debug_data", "lti")."</a>\n";
+ $r .= "<div id=\"basicltiDebug\" style=\"display:none\">\n";
+ $r .= "<b>".get_string("basiclti_endpoint", "lti")."</b><br/>\n";
+ $r .= $endpoint . "<br/>\n&nbsp;<br/>\n";
+ $r .= "<b>".get_string("basiclti_parameters", "lti")."</b><br/>\n";
+ foreach ($newparms as $key => $value) {
+ $key = htmlspecialchars($key);
+ $value = htmlspecialchars($value);
+ $r .= "$key = $value<br/>\n";
+ }
+ $r .= "&nbsp;<br/>\n";
+ $r .= "<p><b>".get_string("basiclti_base_string", "lti")."</b><br/>\n".$lastbasestring."</p>\n";
+ $r .= "</div>\n";
+ }
+ $r .= "</form>\n";
+
+ if ( ! $debug ) {
+ $ext_submit = "ext_submit";
+ $ext_submit_text = $submittext;
+ $r .= " <script type=\"text/javascript\"> \n" .
+ " //<![CDATA[ \n" .
+ " document.getElementById(\"ltiLaunchForm\").style.display = \"none\";\n" .
+ " nei = document.createElement('input');\n" .
+ " nei.setAttribute('type', 'hidden');\n" .
+ " nei.setAttribute('name', '".$ext_submit."');\n" .
+ " nei.setAttribute('value', '".$ext_submit_text."');\n" .
+ " document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n" .
+ " document.ltiLaunchForm.submit(); \n" .
+ " //]]> \n" .
+ " </script> \n";
+ }
+ return $r;
+}
+
+/**
+ * Returns a link with info about the state of the basiclti submissions
+ *
+ * This is used by view_header to put this link at the top right of the page.
+ * For teachers it gives the number of submitted assignments with a link
+ * For students it gives the time of their submission.
+ * This will be suitable for most assignment types.
+ *
+ * @global object
+ * @global object
+ * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php
+ * @return string
+ */
+function submittedlink($cm, $allgroups=false) {
+ global $CFG;
+
+ $submitted = '';
+ $urlbase = "{$CFG->wwwroot}/mod/lti/";
+
+ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+ if (has_capability('mod/lti:grade', $context)) {
+ if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) {
+ $group = 0;
+ } else {
+ $group = groups_get_activity_group($cm);
+ }
+
+ $submitted = '<a href="'.$urlbase.'submissions.php?id='.$cm->id.'">'.
+ get_string('viewsubmissions', 'lti').'</a>';
+ } else {
+ if (isloggedin()) {
+ // TODO Insert code for students if needed
+ }
+ }
+
+ return $submitted;
+}
+
View
391 mod/lti/oldservice.php
@@ -0,0 +1,391 @@
+<?php
+// This file is part of BasicLTI4Moodle
+//
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
+// are already supporting or going to support BasicLTI. This project Implements the consumer
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
+// at the GESSI research group at UPC.
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
+//
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
+//
+// 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/>.
+
+/**
+ * This file contains all necessary code to support basiclti services
+ * like outcomes and roster access.
+ *
+ * @package lti
+ * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
+ * marc.alier@upc.edu
+ * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
+ *
+ * @author Marc Alier
+ * @author Jordi Piguillem
+ * @author Nikolas Galanis
+ * @author Charles Severance
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once("../../config.php");
+require_once($CFG->dirroot.'/mod/lti/lib.php');
+require_once($CFG->dirroot.'/mod/lti/locallib.php');
+require_once($CFG->dirroot.'/mod/lti/OAuth.php');
+require_once($CFG->dirroot.'/mod/lti/TrivialStore.php');
+
+error_reporting(E_ALL & ~E_NOTICE);
+ini_set("display_errors", 1);
+
+$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
+$PAGE->set_url('/mod/lti/service.php');
+$PAGE->set_pagetype('admin-setting-' . $section);
+$PAGE->set_pagelayout('admin');
+$PAGE->navigation->clear_cache();
+
+function message_response($major, $severity, $minor=false, $message=false, $xml=false) {
+ $lti_message_type = $_REQUEST['lti_message_type'];
+ $retval = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"."\n" .
+ "<message_response>\n" .
+ " <lti_message_type>$lti_message_type</lti_message_type>\n" .
+ " <statusinfo>\n" .
+ " <codemajor>$major</codemajor>\n" .
+ " <severity>$severity</severity>\n";
+ if (! $codeminor === false) {
+ $retval = $retval . " <codeminor>$minor</codeminor>\n";
+ }
+ $retval = $retval .
+ " <description>$message</description>\n" .
+ " </statusinfo>\n";
+ if (! $xml === false) {
+ $retval = $retval . $xml;
+ }
+ $retval = $retval . "</message_response>\n";
+ return $retval;
+}
+
+function do_error($message) {
+ print message_response('Fail', 'Error', false, $message);
+ exit();
+}
+
+$lti_version = $_REQUEST['lti_version'];
+if ($lti_version != "LTI-1p0") {
+ do_error("Improperly formed message: wrong lti version: ".$lti_version);
+}
+
+$lti_message_type = $_REQUEST['lti_message_type'];
+if (! isset($lti_message_type)) {
+ do_error("Improperly formed message: no lti_message_type parameter");
+}
+
+$message_type = false;
+if ($lti_message_type == "basic-lis-replaceresult" ||
+ $lti_message_type == "basic-lis-createresult" ||
+ $lti_message_type == "basic-lis-updateresult" ||
+ $lti_message_type == "basic-lis-deleteresult" ||
+ $lti_message_type == "basic-lis-readresult") {
+ $sourcedid = $_REQUEST['sourcedid'];
+ $message_type = "basicoutcome";
+} else if ($lti_message_type == "basic-lti-loadsetting" ||
+ $lti_message_type == "basic-lti-savesetting" ||
+ $lti_message_type == "basic-lti-deletesetting") {
+ $sourcedid = $_REQUEST['id'];
+ $message_type = "toolsetting";
+} else if ($lti_message_type == "basic-lis-readmembershipsforcontext") {
+ $sourcedid = $_REQUEST['id'];
+ $message_type = "roster";
+}
+
+if ($message_type == false) {
+ do_error("Illegal lti_message_type");
+}
+
+if (!isset($sourcedid)) {
+ do_error("sourcedid missing");
+}
+// Truncate to maximum length
+$sourcedid = substr($sourcedid, 0, 2048);
+
+try {
+ $info = explode(':::', $sourcedid);
+ if (! is_array($info)) {
+ do_error("Bad sourcedid (1)");
+ }
+ $signature = $info[0];
+ $userid = intval($info[1]);
+ $placement = $info[2];
+} catch (Exception $e) {
+ do_error("Bad sourcedid (2)");
+}
+
+if (isset($signature) && isset($userid) && isset($placement)) {
+ // OK
+} else {
+ do_error("Bad sourcedid (3)");
+}
+
+// Retrieve the Basic LTI placement
+if (! $basiclti = $DB->get_record('lti', array('id'=>$placement))) {
+ do_error("Bad sourcedid (4)");
+}
+
+$basiclti_types_config = (object)$basiclti_types_config;
+
+$typeconfig = lti_get_type_config($basiclti->typeid);
+
+if (isset($typeconfig) && isset($typeconfig['password'])) {
+ // OK
+} else {
+ do_error("Unable to load type");
+}
+
+if ($message_type == "basicoutcome") {
+ if ($typeconfig["acceptgrades"] == 1 ||
+ ($typeconfig["acceptgrades"] == 2 && $basiclti->instructorchoiceacceptgrades == 1)) {
+ // The placement is configured to accept grades
+ } else {
+ do_error("Not permitted (1)");
+ }
+} else if ($message_type == "toolsetting") {
+ if ($typeconfig["allowsetting"] == 1 ||
+ ($typeconfig["allowsetting"] == 2 && $basiclti->instructorchoiceallowsetting == 1)) {
+ // OK
+ } else {
+ do_error("Not permitted (2)");
+ }
+} else if ($message_type == "roster") {
+ if ($typeconfig["allowroster"] == 1 ||
+ ($typeconfig["allowroster"] == 2 && $basiclti->instructorchoiceallowroster == 1)) {
+ // OK
+ } else {
+ do_error("Not permitted (3)");
+ }
+}
+
+// Retrieve the secret we use to sign lis_result_sourcedid
+$placementsecret = $basiclti->placementsecret;
+$oldplacementsecret = $basiclti->oldplacementsecret;
+if (! isset($placementsecret)) {
+ do_error("Not permitted (4)");
+}
+
+$suffix = ':::' . $userid . ':::' . $placement;
+$plaintext = $placementsecret . $suffix;
+$hashsig = hash('sha256', $plaintext, false);
+if (($hashsig != $signature) && isset($oldplacementsecret) && (strlen($oldplacementsecret) > 1)) {
+ $plaintext = $oldplacementsecret . $suffix;
+ $hashsig = hash('sha256', $plaintext, false);
+}
+
+if ($hashsig != $signature) {
+ do_error("Invalid sourcedid");
+}
+
+// Check the OAuth Signature
+$oauth_secret = $typeconfig["password"];
+$oauth_consumer_key = $typeconfig["resourcekey"];
+if (! isset($oauth_secret)) {
+ do_error("Not permitted (5)");
+}
+if (! isset($oauth_consumer_key)) {
+ do_error("Not permitted (6)");
+}
+
+// Verify the message signature
+$store = new TrivialOAuthDataStore();
+$store->add_consumer($oauth_consumer_key, $oauth_secret);
+
+$server = new OAuthServer($store);
+
+$method = new OAuthSignatureMethod_HMAC_SHA1();
+$server->add_signature_method($method);
+$request = OAuthRequest::from_request();
+
+$basestring = $request->get_signature_base_string();
+try {
+ $server->verify_request($request);
+} catch (Exception $e) {
+ do_error($e->getMessage());
+}
+
+if (! $course = $DB->get_record('course', array('id'=>$basiclti->course))) {
+ do_error("Could not retrieve course");
+}
+
+// TODO: Check that user is in course
+
+if (! $cm = get_coursemodule_from_instance("lti", $basiclti->id, $course->id)) {
+ do_error("Course Module ID was incorrect");
+}
+
+// Lets store the grade
+require_once($CFG->libdir.'/gradelib.php');
+
+// Beginning of actual grade processing
+if ($message_type == "basicoutcome") {
+ $source = 'mod/lti';
+ $courseid = $course->id;
+ $itemtype = 'mod';
+ $itemmodule = 'lti';
+ $iteminstance = $basiclti->id;
+
+ if ($lti_message_type == "basic-lis-readresult") {
+ unset($grade);
+ $thegrade = grade_get_grades($courseid, $itemtype, $itemmodule, $iteminstance, $userid);
+ // print_r($thegrade->items[0]->grades);
+ if (isset($thegrade) && is_array($thegrade->items[0]->grades)) {
+ foreach ($thegrade->items[0]->grades as $agrade) {
+ $grade = $agrade->grade;
+ break;
+ }
+ }
+ if (! isset($grade)) {
+ do_error("Unable to read grade");
+ }
+
+ $result = " <result>\n" .
+ " <resultscore>\n" .
+ " <textstring>" .
+ htmlspecialchars($grade/100.0) .
+ "</textstring>\n" .
+ " </resultscore>\n" .
+ " </result>\n";
+ print message_response('Success', 'Status', false, "Grade read", $result);
+ exit();
+ }
+
+ if ($lti_message_type == "basic-lis-deleteresult") {
+ $params = array();
+ $params['itemname'] = $basiclti->name;
+
+ $grade = new stdClass();
+ $grade->userid = $userid;
+ $grade->rawgrade = null;
+
+ grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, 0, $grade, array('deleted'=>1));
+ } else {
+ if (isset($_REQUEST['result_resultscore_textstring'])) {
+ $gradeval = floatval($_REQUEST['result_resultscore_textstring']);