Merge branch 'event_monitor' of git://github.com/ankitagarwal/moodle
authorDamyon Wiese <damyon@moodle.com>
Thu, 16 Oct 2014 05:20:45 +0000 (13:20 +0800)
committerDamyon Wiese <damyon@moodle.com>
Thu, 16 Oct 2014 05:20:45 +0000 (13:20 +0800)
102 files changed:
admin/tool/behat/tests/behat/data_generators.feature
grade/edit/tree/outcomeitem.php
grade/edit/tree/outcomeitem_form.php
grade/lib.php
grade/report/grader/index.php
grade/report/grader/lib.php
grade/report/user/lib.php
grade/report/user/version.php
grade/tests/behat/grade_aggregation.feature
grade/tests/behat/grade_scales.feature
grade/tests/behat/grade_single_item_scales.feature [new file with mode: 0644]
grade/tests/report_graderlib_test.php
lang/en/grades.php
lib/accesslib.php
lib/classes/plugin_manager.php
lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js
lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js
lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js
lib/editor/atto/plugins/managefiles/yui/src/usedfiles/js/usedfiles.js
lib/editor/tinymce/plugins/managefiles/tinymce/editor_plugin.js
lib/grade/grade_category.php
lib/navigationlib.php
lib/outputrenderers.php
lib/testing/generator/data_generator.php
lib/tests/behat/behat_data_generators.php
lib/tests/cronlib_test.php
lib/tests/filelib_test.php
mod/lti/OAuthBody.php
mod/lti/TrivialStore.php
mod/lti/ajax.php
mod/lti/backup/moodle1/lib.php
mod/lti/backup/moodle2/backup_lti_activity_task.class.php
mod/lti/backup/moodle2/backup_lti_stepslib.php
mod/lti/backup/moodle2/restore_lti_activity_task.class.php
mod/lti/backup/moodle2/restore_lti_stepslib.php
mod/lti/basiclti.js [deleted file]
mod/lti/classes/local/ltiservice/resource_base.php [new file with mode: 0644]
mod/lti/classes/local/ltiservice/response.php [new file with mode: 0644]
mod/lti/classes/local/ltiservice/service_base.php [new file with mode: 0644]
mod/lti/classes/plugininfo/ltiservice.php [new file with mode: 0644]
mod/lti/db/access.php
mod/lti/db/install.xml
mod/lti/db/log.php
mod/lti/db/subplugins.php
mod/lti/db/upgrade.php
mod/lti/db/upgradelib.php [new file with mode: 0644]
mod/lti/edit_form.php
mod/lti/grade.php
mod/lti/index.php
mod/lti/instructor_edit_tool_type.php
mod/lti/lang/en/lti.php
mod/lti/launch.php
mod/lti/lib.php
mod/lti/localadminlib.php [deleted file]
mod/lti/locallib.php
mod/lti/mod_form.js
mod/lti/mod_form.php
mod/lti/register.php [new file with mode: 0644]
mod/lti/register_form.php [new file with mode: 0644]
mod/lti/registersettings.php [new file with mode: 0644]
mod/lti/registration.php [new file with mode: 0644]
mod/lti/registrationreturn.php [new file with mode: 0644]
mod/lti/request_tool.php
mod/lti/return.php
mod/lti/service.php
mod/lti/service/profile/classes/local/resource/profile.php [new file with mode: 0644]
mod/lti/service/profile/classes/local/service/profile.php [new file with mode: 0644]
mod/lti/service/profile/lang/en/ltiservice_profile.php [new file with mode: 0644]
mod/lti/service/profile/version.php [new file with mode: 0644]
mod/lti/service/readme.txt [new file with mode: 0644]
mod/lti/service/toolproxy/classes/local/resource/toolproxy.php [new file with mode: 0644]
mod/lti/service/toolproxy/classes/local/service/toolproxy.php [new file with mode: 0644]
mod/lti/service/toolproxy/lang/en/ltiservice_toolproxy.php [new file with mode: 0644]
mod/lti/service/toolproxy/version.php [new file with mode: 0644]
mod/lti/service/toolsettings/classes/local/resource/contextsettings.php [new file with mode: 0644]
mod/lti/service/toolsettings/classes/local/resource/linksettings.php [new file with mode: 0644]
mod/lti/service/toolsettings/classes/local/resource/systemsettings.php [new file with mode: 0644]
mod/lti/service/toolsettings/classes/local/service/toolsettings.php [new file with mode: 0644]
mod/lti/service/toolsettings/lang/en/ltiservice_toolsettings.php [new file with mode: 0644]
mod/lti/service/toolsettings/version.php [new file with mode: 0644]
mod/lti/servicelib.php
mod/lti/services.php [new file with mode: 0644]
mod/lti/settings.php
mod/lti/tests/event/unknown_service_api_called_test.php
mod/lti/tests/generator_test.php
mod/lti/tests/locallib_test.php
mod/lti/tests/upgradelib_test.php [new file with mode: 0644]
mod/lti/toolproxies.php [new file with mode: 0644]
mod/lti/toolssettings.php [new file with mode: 0644]
mod/lti/typessettings.php
mod/lti/upgrade.txt
mod/lti/version.php
mod/lti/view.php
mod/wiki/pagelib.php
mod/wiki/renderer.php
mod/wiki/search.php
mod/wiki/tests/behat/wiki_search.feature
question/type/multianswer/module.js
theme/bootstrapbase/less/moodle/grade.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/style/moodle.css
user/tests/profilelib_test.php

index c9758f2..2b32cb0 100644 (file)
@@ -185,6 +185,12 @@ Feature: Set up contextual data for tests
       | url        | Test url name          | Test url description          | C1     | url1        |
       | wiki       | Test wiki name         | Test wiki description         | C1     | wiki1       |
       | workshop   | Test workshop name     | Test workshop description     | C1     | workshop1   |
+    And the following "scales" exist:
+      | name | scale |
+      | Test Scale 1 | Disappointing, Good, Very good, Excellent |
+    And the following "activities" exist:
+      | activity   | name                            | intro                         | course | idnumber    | grade |
+      | assign     | Test assignment name with scale | Test assignment description   | C1     | assign1     | Test Scale 1 |
     When I log in as "admin"
     And I follow "Course 1"
     Then I should see "Test assignment name"
@@ -214,6 +220,10 @@ Feature: Set up contextual data for tests
     And I should see "Test workshop name"
     And I follow "Test assignment name"
     And I should see "Test assignment description"
+    And I follow "C1"
+    And I follow "Test assignment name with scale"
+    And I follow "Edit settings"
+    And the field "Type" matches value "Scale"
 
   @javascript
   Scenario: Add relations between users and groups
@@ -297,13 +307,124 @@ Feature: Set up contextual data for tests
       | Course 1 | C1 |
     And the following "grade categories" exist:
       | fullname | course |
-      | Grade category 1 | C1|
+      | Grade category 1 | C1 |
     And the following "grade categories" exist:
       | fullname | course | gradecategory |
-      | Grade sub category 2 | C1 | Grade category 1|
+      | Grade sub category 2 | C1 | Grade category 1 |
     When I log in as "admin"
     And I follow "Courses"
     And I follow "Course 1"
     And I navigate to "Grades" node in "Course administration"
     Then I should see "Grade category 1"
     And I should see "Grade sub category 2"
+
+  Scenario: Add a bunch of grade items
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1 |
+    And the following "grade categories" exist:
+      | fullname | course |
+      | Grade category 1 | C1 |
+    And the following "grade categories" exist:
+      | fullname | course | gradecategory |
+      | Grade sub category 2 | C1 | Grade category 1 |
+    And the following "grade items" exist:
+      | itemname    | course |
+      | Test Grade Item 1 | C1 |
+    And the following "grade items" exist:
+      | itemname    | course | gradecategory |
+      | Test Grade Item 2 | C1 | Grade category 1 |
+      | Test Grade Item 3 | C1 | Grade sub category 2 |
+    When I log in as "admin"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    Then I should see "Test Grade Item 1"
+    And I follow "Edit   Test Grade Item 1"
+    And I expand all fieldsets
+    And I should see "Course 1"
+    And I press "Cancel"
+    And I should see "Grade category 1"
+    And I should see "Test Grade Item 2"
+    And I follow "Edit   Test Grade Item 2"
+    And I expand all fieldsets
+    And I should see "Grade category 1"
+    And I press "Cancel"
+    And I should see "Grade sub category 2"
+    And I should see "Test Grade Item 3"
+    And I follow "Edit   Test Grade Item 3"
+    And I expand all fieldsets
+    And I should see "Grade sub category 2"
+    And I press "Cancel"
+
+  Scenario: Add a bunch of scales
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1 |
+    And the following "scales" exist:
+      | name | scale |
+      | Test Scale 1 | Disappointing, Good, Very good, Excellent |
+    When I log in as "admin"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I follow "Scales"
+    Then I should see "Test Scale 1"
+    And I should see "Disappointing,  Good,  Very good,  Excellent"
+
+  Scenario: Add a bunch of outcomes
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "scales" exist:
+      | name | scale |
+      | Test Scale 1 | Disappointing, Good, Very good, Excellent |
+    And the following "grade outcomes" exist:
+      | fullname        | shortname | scale        |
+      | Grade outcome 1 | OT1       | Test Scale 1 |
+    And the following "grade outcomes" exist:
+      | fullname        | shortname | course | scale        |
+      | Grade outcome 2 | OT2       | C1     | Test Scale 1 |
+    When I log in as "admin"
+    And I set the following administration settings values:
+      | Enable outcomes | 1 |
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Outcomes"
+    Then I should see "Grade outcome 1" in the "#addoutcomes" "css_element"
+    And I should see "Grade outcome 2" in the "#removeoutcomes" "css_element"
+    And I follow "Edit outcomes"
+    And the following should exist in the "generaltable" table:
+      | Full name       | Short name | Scale        |
+      | Grade outcome 2 | OT2        | Test Scale 1 |
+
+  Scenario: Add a bunch of outcome grade items
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "scales" exist:
+      | name         | scale                                     |
+      | Test Scale 1 | Disappointing, Good, Very good, Excellent |
+    And the following "grade outcomes" exist:
+      | fullname        | shortname | course | scale        |
+      | Grade outcome 1 | OT1       | C1     | Test Scale 1 |
+    And the following "grade categories" exist:
+      | fullname         | course |
+      | Grade category 1 | C1     |
+     And the following "grade items" exist:
+       | itemname                  | course | outcome | gradecategory    |
+       | Test Outcome Grade Item 1 | C1     | OT1     | Grade category 1 |
+    When I log in as "admin"
+    And I set the following administration settings values:
+      | Enable outcomes | 1 |
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    Then I should see "Test Outcome Grade Item 1"
+    And I follow "Edit   Test Outcome Grade Item 1"
+    And the field "Outcome" matches value "Grade outcome 1"
+    And I expand all fieldsets
+    And "//div[contains(@class, 'fitem')]/div[contains(@class, 'fitemtitle')]/div[contains(@class, fstaticlabel) and contains(., 'Grade category')]/../../div[contains(@class, 'felement') and contains(., 'Grade category 1')]" "xpath_element" should exist
+    And I press "Cancel"
index 6c5c330..52bc618 100644 (file)
@@ -104,6 +104,7 @@ if (empty($parent_category)) {
     $item->aggregationcoef = 0;
 } else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM) {
     $item->aggregationcoef = $item->aggregationcoef > 0 ? 1 : 0;
+    $item->aggregationcoef2 = format_float($item->aggregationcoef2 * 100.0);
 } else {
     $item->aggregationcoef = format_float($item->aggregationcoef, 4);
 }
@@ -131,12 +132,15 @@ if ($data = $mform->get_data()) {
     unset($data->locked);
     unset($data->locktime);
 
-    $convert = array('gradepass', 'aggregationcoef');
+    $convert = array('gradepass', 'aggregationcoef', 'aggregationcoef2');
     foreach ($convert as $param) {
         if (property_exists($data, $param)) {
             $data->$param = unformat_float($data->$param);
         }
     }
+    if (isset($data->aggregationcoef2) && $parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+        $data->aggregationcoef2 = $data->aggregationcoef2 / 100.0;
+    }
 
     $grade_item = new grade_item(array('id'=>$id, 'courseid'=>$courseid));
     grade_item::set_properties($grade_item, $data);
index 8ae803f..9428e5b 100644 (file)
@@ -73,6 +73,14 @@ class edit_outcomeitem_form extends moodleform {
         $mform->addHelpButton('cmid', 'linkedactivity', 'grades');
         $mform->setDefault('cmid', 0);
 
+        $mform->addElement('advcheckbox', 'weightoverride', get_string('adjustedweight', 'grades'));
+        $mform->addHelpButton('weightoverride', 'weightoverride', 'grades');
+
+        $mform->addElement('text', 'aggregationcoef2', get_string('weight', 'grades'));
+        $mform->addHelpButton('aggregationcoef2', 'weight', 'grades');
+        $mform->setType('aggregationcoef2', PARAM_RAW);
+        $mform->disabledIf('aggregationcoef2', 'weightoverride');
+
         /// hiding
         /// advcheckbox is not compatible with disabledIf !!
         $mform->addElement('checkbox', 'hidden', get_string('hidden', 'grades'));
@@ -125,8 +133,9 @@ class edit_outcomeitem_form extends moodleform {
         }
 
         if ($coefstring !== '') {
-            if ($coefstring == 'aggregationcoefextrasum') {
+            if ($coefstring == 'aggregationcoefextrasum' || $coefstring == 'aggregationcoefextraweightsum') {
                 // advcheckbox is not compatible with disabledIf!
+                $coefstring = 'aggregationcoefextrasum';
                 $mform->addElement('checkbox', 'aggregationcoef', get_string($coefstring, 'grades'));
             } else {
                 $mform->addElement('text', 'aggregationcoef', get_string($coefstring, 'grades'));
@@ -193,7 +202,7 @@ class edit_outcomeitem_form extends moodleform {
 
                 $parent_category->apply_forced_settings();
 
-                if (!$parent_category->is_aggregationcoef_used() or $parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+                if (!$parent_category->is_aggregationcoef_used()) {
                     if ($mform->elementExists('aggregationcoef')) {
                         $mform->removeElement('aggregationcoef');
                     }
@@ -219,6 +228,15 @@ class edit_outcomeitem_form extends moodleform {
                         $mform->addHelpButton('aggregationcoef', $aggcoef, 'grades');
                     }
                 }
+                // Remove fields used by natural weighting if the parent category is not using natural weighting.
+                if ($parent_category->aggregation != GRADE_AGGREGATE_SUM) {
+                    if ($mform->elementExists('weightoverride')) {
+                        $mform->removeElement('weightoverride');
+                    }
+                    if ($mform->elementExists('aggregationcoef2')) {
+                        $mform->removeElement('aggregationcoef2');
+                    }
+                }
             }
 
         }
index 50b1c55..d33be86 100644 (file)
@@ -464,7 +464,7 @@ function grade_get_graded_users_select($report, $course, $userid, $groupid, $inc
  * @param int $courseid The current course id.
  */
 function hide_natural_aggregation_upgrade_notice($courseid) {
-    set_config('show_sumofgrades_upgrade_' . $courseid, false);
+    unset_config('show_sumofgrades_upgrade_' . $courseid);
 }
 
 /**
index 1174375..2e7022b 100644 (file)
@@ -191,6 +191,7 @@ if ($USER->gradeediting[$course->id] && ($report->get_pref('showquickfeedback')
     echo '<div>';
     echo '<input type="hidden" value="'.s($courseid).'" name="id" />';
     echo '<input type="hidden" value="'.sesskey().'" name="sesskey" />';
+    echo '<input type="hidden" value="'.time().'" name="timepageload" />';
     echo '<input type="hidden" value="grader" name="report"/>';
     echo '<input type="hidden" value="'.$page.'" name="page"/>';
     echo $reporthtml;
index f9feea8..32577b8 100644 (file)
@@ -185,6 +185,7 @@ class grade_report_grader extends grade_report {
 
         // Were any changes made?
         $changedgrades = false;
+        $timepageload = clean_param($data->timepageload, PARAM_INT);
 
         foreach ($data as $varname => $students) {
 
@@ -259,8 +260,15 @@ class grade_report_grader extends grade_report {
                         }
 
                         $errorstr = '';
-                        // Warn if the grade is out of bounds.
-                        if (!is_null($finalgrade)) {
+                        $skip = false;
+
+                        $dategraded = $oldvalue->get_dategraded();
+                        if (!empty($dategraded) && $timepageload < $dategraded) {
+                            // Warn if the grade was updated while we were editing this form.
+                            $errorstr = 'gradewasmodifiedduringediting';
+                            $skip = true;
+                        } else if (!is_null($finalgrade)) {
+                            // Warn if the grade is out of bounds.
                             $bounded = $gradeitem->bounded_grade($finalgrade);
                             if ($bounded > $finalgrade) {
                                 $errorstr = 'lessthanmin';
@@ -268,6 +276,7 @@ class grade_report_grader extends grade_report {
                                 $errorstr = 'morethanmax';
                             }
                         }
+
                         if ($errorstr) {
                             $userfields = 'id, ' . get_all_user_name_fields(true);
                             $user = $DB->get_record('user', array('id' => $userid), $userfields);
@@ -275,6 +284,10 @@ class grade_report_grader extends grade_report {
                             $gradestr->username = fullname($user);
                             $gradestr->itemname = $gradeitem->get_name();
                             $warnings[] = get_string($errorstr, 'grades', $gradestr);
+                            if ($skip) {
+                                // Skipping the update of this grade it failed the tests above.
+                                continue;
+                            }
                         }
 
                     } else if ($datatype == 'feedback') {
@@ -729,7 +742,6 @@ class grade_report_grader extends grade_report {
         $strftimedatetimeshort = get_string('strftimedatetimeshort');
         $strexcludedgrades = get_string('excluded', 'grades');
         $strerror = get_string('error');
-        $strtypescale = get_string('typescale', 'grades');
 
         foreach ($this->gtree->get_levels() as $key => $row) {
             $headingrow = new html_table_row();
@@ -978,7 +990,9 @@ class grade_report_grader extends grade_report {
                                 $nogradestr = $this->get_lang_string('nooutcome', 'grades');
                             }
                             $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
-                            $itemcell->text .= html_writer::label($strtypescale, $attributes['id'], false,
+                            $gradelabel = $fullname . ' ' . $item->itemname;
+                            $itemcell->text .= html_writer::label(
+                                get_string('useractivitygrade', 'gradereport_grader', $gradelabel), $attributes['id'], false,
                                     array('class' => 'accesshide'));
                             $itemcell->text .= html_writer::select($scaleopt, 'grade['.$userid.']['.$item->id.']', $gradeval, array(-1=>$nogradestr), $attributes);
                         } else if (!empty($scale)) {
index 9c0660c..3d4c7e6 100644 (file)
@@ -118,10 +118,10 @@ class grade_report_user extends grade_report {
     public $showfeedback = true;
 
     /**
-     * Show grade weighting in the report, default false
+     * Show grade weighting in the report, default true.
      * @var bool
      */
-    public $showweight = false;
+    public $showweight = true;
 
     /**
      * Show letter grades in the report, default false
@@ -133,7 +133,7 @@ class grade_report_user extends grade_report {
      * Show the calculated contribution to the course total column.
      * @var bool
      */
-    public $showcontributiontocoursetotal = false;
+    public $showcontributiontocoursetotal = true;
 
     /**
      * Show average grades in the report, default false.
@@ -205,8 +205,13 @@ class grade_report_user extends grade_report {
         $this->showgrade       = grade_get_setting($this->courseid, 'report_user_showgrade',       !empty($CFG->grade_report_user_showgrade));
         $this->showrange       = grade_get_setting($this->courseid, 'report_user_showrange',       !empty($CFG->grade_report_user_showrange));
         $this->showfeedback    = grade_get_setting($this->courseid, 'report_user_showfeedback',    !empty($CFG->grade_report_user_showfeedback));
-        $this->showweight      = grade_get_setting($this->courseid, 'report_user_showweight',      !empty($CFG->grade_report_user_showweight));
-        $this->showcontributiontocoursetotal      = grade_get_setting($this->courseid, 'report_user_showcontributiontocoursetotal',      !empty($CFG->grade_report_user_showcontributiontocoursetotal));
+
+        $this->showweight = grade_get_setting($this->courseid, 'report_user_showweight',
+            empty($CFG->grade_report_user_showweight));
+
+        $this->showcontributiontocoursetotal = grade_get_setting($this->courseid, 'report_user_showcontributiontocoursetotal',
+            empty($CFG->grade_report_user_showcontributiontocoursetotal));
+
         $this->showlettergrade = grade_get_setting($this->courseid, 'report_user_showlettergrade', !empty($CFG->grade_report_user_showlettergrade));
         $this->showaverage     = grade_get_setting($this->courseid, 'report_user_showaverage',     !empty($CFG->grade_report_user_showaverage));
 
@@ -712,12 +717,12 @@ class grade_report_user extends grade_report {
                 // Normalise the gradeval.
                 $gradecat = $grade_object->load_parent_category();
                 if ($gradecat->aggregation == GRADE_AGGREGATE_SUM) {
-                    // Natural aggregation/Sum of grades does not consider the mingrade.
+                    // Natural aggregation/Sum of grades does not consider the mingrade, cannot traditionnally normalise it.
                     $graderange = $this->aggregationhints[$itemid]['grademax'];
                     $gradeval = $this->aggregationhints[$itemid]['grade'] / $graderange;
                 } else {
-                    $graderange = $this->aggregationhints[$itemid]['grademax'] - $this->aggregationhints[$itemid]['grademin'];
-                    $gradeval = ($this->aggregationhints[$itemid]['grade'] - $this->aggregationhints[$itemid]['grademin']) / $graderange;
+                    $gradeval = grade_grade::standardise_score($this->aggregationhints[$itemid]['grade'],
+                        $this->aggregationhints[$itemid]['grademin'], $this->aggregationhints[$itemid]['grademax'], 0, 1);
                 }
 
                 // Multiply the normalised value by the weight
@@ -1018,9 +1023,9 @@ function grade_report_user_settings_definition(&$mform) {
     $mform->addElement('select', 'report_user_showfeedback', get_string('showfeedback', 'grades'), $options);
 
     if (empty($CFG->grade_report_user_showweight)) {
-        $options[-1] = get_string('defaultprev', 'grades', $options[0]);
-    } else {
         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
+    } else {
+        $options[-1] = get_string('defaultprev', 'grades', $options[0]);
     }
 
     $mform->addElement('select', 'report_user_showweight', get_string('showweight', 'grades'), $options);
@@ -1042,7 +1047,7 @@ function grade_report_user_settings_definition(&$mform) {
 
     $mform->addElement('select', 'report_user_showlettergrade', get_string('showlettergrade', 'grades'), $options);
     if (empty($CFG->grade_report_user_showcontributiontocoursetotal)) {
-        $options[-1] = get_string('defaultprev', 'grades', $options[0]);
+        $options[-1] = get_string('defaultprev', 'grades', $options[1]);
     } else {
         $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showcontributiontocoursetotal]);
     }
index e9a88f7..8e44488 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2014101400;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2014050800;        // Requires this Moodle version
 $plugin->component = 'gradereport_user'; // Full name of the plugin (used for diagnostics)
index 6dffd30..40e7063 100644 (file)
@@ -246,6 +246,126 @@ Feature: We can use calculated grade totals
     And I set the field "Grade report" to "Overview report"
     And I should see "50.00 (50.00 %)" in the "overview-grade" "table"
 
+  @javascript
+  Scenario: Natural aggregation on outcome items with natural weights
+    And I log out
+    And I log in as "admin"
+    And I set the following administration settings values:
+      | Enable outcomes | 1 |
+    And the following "scales" exist:
+      | name       | scale                                     |
+      | Test Scale | Disappointing, Good, Very good, Excellent |
+    And the following "grade outcomes" exist:
+      | fullname  | shortname | course | scale      |
+      | Outcome 1 | OT1       | C1     | Test Scale |
+    And the following "grade items" exist:
+      | itemname              | course | outcome | gradetype | scale      |
+      | Test outcome item one | C1     | OT1     | Scale     | Test Scale |
+    And I log out
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    And I set the following settings for grade item "Course 1":
+      | Aggregation                     | Natural |
+      | Include outcomes in aggregation | 1       |
+      | Exclude empty grades            | 0       |
+    And I follow "Grader report"
+    And I turn editing mode on
+    And I press "Save changes"
+    And I give the grade "Excellent" to the user "Student 1" for the grade item "Test outcome item one"
+    And I press "Save changes"
+    And I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field "report_overview_showtotalsifcontainhidden" to "Show totals excluding hidden items"
+    And I set the field "report_user_showtotalsifcontainhidden" to "Show totals excluding hidden items"
+    And I press "Save changes"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Test outcome item one" row "Grade" column of "user-grade" table should contain "Excellent (100.00 %)"
+    And I set the field "Grade report" to "Overview report"
+    And I should see "114.82 (18.27 %)" in the "overview-grade" "table"
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    And I set the following settings for grade item "Test outcome item one":
+     | Extra credit     | 1   |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Test outcome item one" row "Grade" column of "user-grade" table should contain "Excellent (100.00 %)"
+    And I set the field "Grade report" to "Overview report"
+    And I should see "114.00 (18.39 %)" in the "overview-grade" "table"
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    And I set the following settings for grade item "Course 1":
+      | Aggregation                     | Natural |
+      | Include outcomes in aggregation | 0       |
+    And I set the following settings for grade item "Test outcome item one":
+     | Extra credit     | 0   |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Test outcome item one" row "Grade" column of "user-grade" table should contain "Excellent (100.00 %)"
+    And I set the field "Grade report" to "Overview report"
+    And I should see "110.00 (17.74 %)" in the "overview-grade" "table"
+
+  @javascript
+  Scenario: Natural aggregation on outcome items with modified weights
+    And I log out
+    And I log in as "admin"
+    And I set the following administration settings values:
+      | Enable outcomes | 1 |
+    And the following "scales" exist:
+      | name       | scale                                     |
+      | Test Scale | Disappointing, Good, Very good, Excellent |
+    And the following "grade outcomes" exist:
+      | fullname  | shortname | course | scale      |
+      | Outcome 1 | OT1       | C1     | Test Scale |
+    And the following "grade items" exist:
+      | itemname              | course | outcome | gradetype | scale      |
+      | Test outcome item one | C1     | OT1     | Scale     | Test Scale |
+    And I log out
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I expand "Setup" node
+    And I follow "Categories and items"
+    And I set the following settings for grade item "Course 1":
+      | Aggregation                     | Natural |
+      | Include outcomes in aggregation | 1       |
+      | Exclude empty grades            | 0       |
+    And I set the following settings for grade item "Test outcome item one":
+     | Weight adjusted  | 1   |
+     | aggregationcoef2 | 100 |
+    And I follow "Grader report"
+    And I turn editing mode on
+    And I press "Save changes"
+    And I give the grade "Excellent" to the user "Student 1" for the grade item "Test outcome item one"
+    And I press "Save changes"
+    And I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field "report_overview_showtotalsifcontainhidden" to "Show totals excluding hidden items"
+    And I set the field "report_user_showtotalsifcontainhidden" to "Show totals excluding hidden items"
+    And I press "Save changes"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Test outcome item one" row "Grade" column of "user-grade" table should contain "Excellent (100.00 %)"
+    And I set the field "Grade report" to "Overview report"
+    And I should see "4.00 (100.00 %)" in the "overview-grade" "table"
+
   @javascript
   Scenario: Natural aggregation
     And I set the following settings for grade item "Sub category 1":
index 1421da7..c884ba8 100644 (file)
@@ -63,6 +63,11 @@ Feature: View gradebook when scales are used
     And I press "Save changes"
     And I follow "Course 1"
     And I follow "Grades"
+    And I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field "Show weightings" to "Show"
+    And I set the field "Show contribution to course total" to "Show"
+    And I press "Save changes"
+    And I follow "Grader report"
     And I turn editing mode on
 
   @javascript
@@ -83,10 +88,10 @@ Feature: View gradebook when scales are used
     And I set the field "Select all or one user" to "Student 3"
     And I click on "Select all or one user" "select"
     And the following should exist in the "user-grade" table:
-      | Grade item          | Grade | Range | Percentage |
-      | Test assignment one | C     | F–A   | 50.00 %    |
-      | Category total      | 3.00  | 0–5   | 60.00 %    |
-      | Course total        | 3.00  | 0–5   | 60.00 %    |
+      | Grade item          | Grade | Range | Percentage | Contribution to course total |
+      | Test assignment one | C     | F–A   | 50.00 %    | 3.00                         |
+      | Category total      | 3.00  | 0–5   | 60.00 %    | -                            |
+      | Course total        | 3.00  | 0–5   | 60.00 %    | -                            |
     And I set the field "jump" to "Categories and items"
     And the following should exist in the "grade_edit_tree_table" table:
       | Name                | Max grade |
@@ -98,10 +103,10 @@ Feature: View gradebook when scales are used
     And I follow "Course 1"
     And I follow "Grades"
     And the following should exist in the "user-grade" table:
-      | Grade item          | Grade | Range | Percentage |
-      | Test assignment one | B     | F–A   | 75.00 %    |
-      | Category total      | 4.00  | 0–5   | 80.00 %    |
-      | Course total        | 4.00  | 0–5   | 80.00 %    |
+      | Grade item          | Grade | Range | Percentage | Contribution to course total |
+      | Test assignment one | B     | F–A   | 75.00 %    | 4.00                         |
+      | Category total      | 4.00  | 0–5   | 80.00 %    | -                            |
+      | Course total        | 4.00  | 0–5   | 80.00 %    | -                            |
 
   @javascript
   Scenario Outline: Test displaying scales in gradebook in all other aggregation methods
@@ -131,10 +136,10 @@ Feature: View gradebook when scales are used
     And I set the field "Select all or one user" to "Student 3"
     And I click on "Select all or one user" "select"
     And the following should exist in the "user-grade" table:
-      | Grade item          | Grade          | Range | Percentage    |
-      | Test assignment one | C              | F–A   | 50.00 %       |
-      | Category total<aggregation>.      | 3.00           | 1–5   | 50.00 %       |
-      | Course total<aggregation>.        | <coursetotal3> | 0–100 | <courseperc3> |
+      | Grade item                   | Grade          | Range | Percentage    | Contribution to course total |
+      | Test assignment one          | C              | F–A   | 50.00 %       | <contrib3>                   |
+      | Category total<aggregation>. | 3.00           | 1–5   | 50.00 %       | -                            |
+      | Course total<aggregation>.   | <coursetotal3> | 0–100 | <courseperc3> | -                            |
     And I set the field "jump" to "Categories and items"
     And the following should exist in the "grade_edit_tree_table" table:
       | Name                | Max grade |
@@ -146,18 +151,18 @@ Feature: View gradebook when scales are used
     And I follow "Course 1"
     And I follow "Grades"
     And the following should exist in the "user-grade" table:
-      | Grade item          | Grade          | Range | Percentage    |
-      | Test assignment one | B              | F–A   | 75.00 %       |
-      | Category total<aggregation>.      | 4.00           | 1–5   | 75.00 %       |
-      | Course total<aggregation>.        | <coursetotal2> | 0–100 | <courseperc2> |
+      | Grade item                   | Grade          | Range | Percentage    | Contribution to course total |
+      | Test assignment one          | B              | F–A   | 75.00 %       | <contrib2>                   |
+      | Category total<aggregation>. | 4.00           | 1–5   | 75.00 %       | -                            |
+      | Course total<aggregation>.   | <coursetotal2> | 0–100 | <courseperc2> | -                            |
 
-  Examples:
-      | aggregation                         | coursetotal1 | coursetotal2 | coursetotal3 | coursetotal4 | coursetotal5 |overallavg | courseperc2 | courseperc3 |
-      | Mean of grades                      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Weighted mean of grades             | -            | -            | -            | -            | -            | -         | -           | -           |
-      | Simple weighted mean of grades      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Mean of grades (with extra credits) | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Median of grades                    | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Lowest grade                        | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Highest grade                       | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
-      | Mode of grades                      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     |
+    Examples:
+      | aggregation                         | coursetotal1 | coursetotal2 | coursetotal3 | coursetotal4 | coursetotal5 |overallavg | courseperc2 | courseperc3 | contrib2 | contrib3 |
+      | Mean of grades                      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Weighted mean of grades             | -            | -            | -            | -            | -            | -         | -           | -           | 0.00     | 0.00     |
+      | Simple weighted mean of grades      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Mean of grades (with extra credits) | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Median of grades                    | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Lowest grade                        | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Highest grade                       | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
+      | Mode of grades                      | 100.00       | 75.00        | 50.00        | 25.00        | 0.00         | 50.00     | 75.00 %     | 50.00 %     | 75.00    | 50.00    |
diff --git a/grade/tests/behat/grade_single_item_scales.feature b/grade/tests/behat/grade_single_item_scales.feature
new file mode 100644 (file)
index 0000000..6692c49
--- /dev/null
@@ -0,0 +1,134 @@
+@core @core_grades
+Feature: View gradebook when single item scales are used
+  In order to use single item scales to grade activities
+  As an teacher
+  I need to be able to view gradebook with single item scales
+
+  Background:
+    Given I log in as "admin"
+    And I set the following administration settings values:
+      | grade_report_showranges    | 1 |
+      | grade_aggregations_visible | Mean of grades,Weighted mean of grades,Simple weighted mean of grades,Mean of grades (with extra credits),Median of grades,Lowest grade,Highest grade,Mode of grades,Natural |
+    And I navigate to "Scales" node in "Site administration > Grades"
+    And I press "Add a new scale"
+    And I set the following fields to these values:
+      | Name  | Singleitem |
+      | Scale | Ace!       |
+    And I press "Save changes"
+    And I log out
+    And the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "users" exist:
+      | username | firstname | lastname | email            | idnumber |
+      | teacher1 | Teacher   | 1        | teacher1@asd.com | t1       |
+      | student1 | Student   | 1        | student1@asd.com | s1       |
+      | student2 | Student   | 2        | student2@asd.com | s2       |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+      | student2 | C1     | student        |
+    And the following "grade categories" exist:
+      | fullname       | course |
+      | Sub category 1 | C1     |
+    And the following "activities" exist:
+      | activity | course | idnumber | name                | intro             | gradecategory  |
+      | assign   | C1     | a1       | Test assignment one | Submit something! | Sub category 1 |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Test assignment one"
+    And I follow "Edit settings"
+    And I expand all fieldsets
+    And I set the field "grade[modgrade_type]" to "Scale"
+    And I set the field "grade[modgrade_scale]" to "Singleitem"
+    And I press "Save and display"
+    And I follow "View/grade all submissions"
+    And I click on "Grade Student 1" "link" in the "Student 1" "table_row"
+    And I set the field "Grade" to "A"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field "Show weightings" to "Show"
+    And I set the field "Show contribution to course total" to "Show"
+    And I press "Save changes"
+    And I follow "Grader report"
+    And I turn editing mode on
+
+  @javascript
+  Scenario: Test displaying single item scales in gradebook in aggregation method Natural
+    When I turn editing mode off
+    Then the following should exist in the "user-grades" table:
+      | -1-                | -4-       | -5-            | -6-          |
+      | Student 1          | Ace!      | 1.00           | 1.00         |
+    And the following should exist in the "user-grades" table:
+      | -1-                | -2-       | -3-            | -4-          |
+      | Range              | Ace!–Ace! | 0.00–1.00      | 0.00–1.00    |
+      | Overall average    | Ace!      | 1.00           | 1.00         |
+    And I follow "User report"
+    And I set the field "Select all or one user" to "Student 1"
+    And the following should exist in the "user-grade" table:
+      | Grade item          | Grade | Range     | Contribution to course total |
+      | Test assignment one | Ace!  | Ace!–Ace! | 1.00                         |
+      | Category total      | 1.00  | 0–1       | -                            |
+      | Course total        | 1.00  | 0–1       | -                            |
+    And I set the field "Select all or one user" to "Student 2"
+    And the following should exist in the "user-grade" table:
+      | Grade item          | Grade | Range     | Contribution to course total |
+      | Test assignment one | -     | Ace!–Ace! | 0.00                         |
+      | Category total      | -     | 0–1       | -                            |
+      | Course total        | -     | 0–1       | -                            |
+    And I set the field "jump" to "Categories and items"
+    And the following should exist in the "grade_edit_tree_table" table:
+      | Name                | Max grade |
+      | Test assignment one | 1.00      |
+      | Category total      | 1.00      |
+      | Course total        | 1.00      |
+
+  @javascript
+  Scenario Outline: Test displaying single item scales in gradebook in all other aggregation methods
+    When I follow "Edit   Course 1"
+    And I set the field "Aggregation" to "<aggregation>"
+    And I press "Save changes"
+    And I follow "Edit   Sub category 1"
+    And I expand all fieldsets
+    And I set the field "Aggregation" to "<aggregation>"
+    And I set the field "Category name" to "Sub category (<aggregation>)"
+    # And I set the field "Maximum grade" to "5"
+    # And I set the field "Minimum grade" to "1"
+    And I press "Save changes"
+    And I turn editing mode off
+    Then the following should exist in the "user-grades" table:
+      | -1-                | -4-       | -5-            | -6-            |
+      | Student 1          | Ace!      | <cattotal1>    | <coursetotal1> |
+      | Student 2          | -         | -              | -              |
+    And the following should exist in the "user-grades" table:
+      | -1-                | -2-       | -3-            | -4-            |
+      | Range              | Ace!–Ace! | 0.00–100.0     | 0.00–100.00    |
+      | Overall average    | Ace!      | <catavg>       | <overallavg>   |
+    And I follow "User report"
+    And I set the field "Select all or one user" to "Student 1"
+    And I click on "Select all or one user" "select"
+    And the following should exist in the "user-grade" table:
+      | Grade item                        | Grade          | Range       | Contribution to course total |
+      | Test assignment one               | Ace!           | Ace!–Ace!   | <contrib1>                   |
+      | Category total<aggregation>.      | <cattotal1>    | 0–100       | -                            |
+      | Course total<aggregation>.        | <coursetotal1> | 0–100       | -                            |
+    And I set the field "jump" to "Categories and items"
+    And the following should exist in the "grade_edit_tree_table" table:
+      | Name                         | Max grade |
+      | Test assignment one          | Ace! (1)  |
+      | Category total<aggregation>. | 100.00    |
+      | Course total<aggregation>.   | 100.00    |
+
+    Examples:
+      | aggregation                         | contrib1 | cattotal1 | coursetotal1 | catavg | overallavg |
+      | Mean of grades                      | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
+      | Weighted mean of grades             | 0.00     | 100.00    | -            | 100.00 | -          |
+      | Simple weighted mean of grades      | 0.00     | -         | -            | -      | -          |
+      | Mean of grades (with extra credits) | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
+      | Median of grades                    | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
+      | Lowest grade                        | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
+      | Highest grade                       | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
+      | Mode of grades                      | 100.00   | 100.00    | 100.00       | 100.00 | 100.00     |
index 8c39066..cf3d498 100644 (file)
@@ -65,6 +65,7 @@ class core_grade_report_graderlib_testcase extends advanced_testcase {
         $data = new stdClass();
         $data->id = $course->id;
         $data->report = 'grader';
+        $data->timepageload = time();
 
         $data->grade = array();
         $data->grade[$student->id] = array();
index 118d366..16212a9 100644 (file)
@@ -322,6 +322,7 @@ $string['gradetype_help'] = 'There are 4 grade types:
 Only value and scale grade types may be aggregated. The grade type for an activity-based grade item is set on the activity settings page.';
 $string['gradevaluetoobig'] = 'One of the grade values is larger than the allowed grade maximum of {$a}';
 $string['gradeview'] = 'View grade';
+$string['gradewasmodifiedduringediting'] = 'The grade entered for {$a->itemname} for {$a->username} was ignored because it was more recently updated by someone else.';
 $string['gradeweighthelp'] = 'Grade weight help';
 $string['groupavg'] = 'Group average';
 $string['hidden'] = 'Hidden';
@@ -670,8 +671,8 @@ $string['studentsperpagereduced'] = 'Reduced maximum students per page from {$a-
 $string['subcategory'] = 'Normal category';
 $string['submissions'] = 'Submissions';
 $string['submittedon'] = 'Submitted: {$a}';
-$string['sumofgradesupgradedgrades'] = 'A recent upgrade has changed the aggregation method "Sum of grades" to "Natural". Please review the grades in this course as it was previously using "Sum of grades".';
-$string['sumofgradesupgradedgradeshidemessage'] = 'Got it';
+$string['sumofgradesupgradedgrades'] = 'Note: The aggregation method "Sum of grades" has been changed to "Natural" as part of a site upgrade. Since "Sum of grades" was previously used in this course, it is recommended that you review this change in the gradebook.';
+$string['sumofgradesupgradedgradeshidemessage'] = 'OK';
 $string['switchtofullview'] = 'Switch to full view';
 $string['switchtosimpleview'] = 'Switch to simple view';
 $string['tabs'] = 'Tabs';
index b3ed02a..abd8fdb 100644 (file)
@@ -3110,10 +3110,6 @@ function get_user_roles_in_course($userid, $courseid) {
         $context = context_course::instance($courseid);
     }
 
-    if (empty($CFG->profileroles)) {
-        return array();
-    }
-
     list($rallowed, $params) = $DB->get_in_or_equal(explode(',', $CFG->profileroles), SQL_PARAMS_NAMED, 'a');
     list($contextlist, $cparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'p');
     $params = array_merge($params, $cparams);
index 6e8ee69..818832d 100644 (file)
@@ -1052,6 +1052,10 @@ class core_plugin_manager {
                 'database', 'legacy', 'standard',
             ),
 
+            'ltiservice' => array(
+                'profile', 'toolproxy', 'toolsettings'
+            ),
+
             'message' => array(
                 'airnotifier', 'email', 'jabber', 'popup'
             ),
index 69a3695..91cdb17 100644 (file)
Binary files a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js and b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js differ
index 3894cba..016fc2c 100644 (file)
Binary files a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js and b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js differ
index 30447d6..ed1b8db 100644 (file)
Binary files a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js and b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js differ
index 79bfc2f..92778d0 100644 (file)
@@ -153,7 +153,7 @@ M.atto_managefiles.usedfiles = M.atto_managefiles.usedfiles || {
             usedFiles = {};
 
         while ((match = pattern.exec(content.get('innerHTML'))) !== null) {
-            filename = unescape(match[1]);
+            filename = decodeURI(match[1]);
             usedFiles[filename] = true;
         }
 
index f3bb3e9..5b3c102 100644 (file)
@@ -83,7 +83,7 @@
                     patt = new RegExp(base.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "(.+?)[\\?\"']", 'gm'),
                     arr = [], match, filename;
                 while ((match = patt.exec(text)) !== null) {
-                    filename = unescape(match[1]);
+                    filename = decodeURI(match[1]);
                     if (arr.indexOf(filename) === -1) {
                         arr[arr.length] = filename;
                     }
index 32fd6f5..3f64375 100644 (file)
@@ -628,6 +628,7 @@ class grade_category extends grade_object {
             $grade->finalgrade = null;
 
             if (!is_null($oldfinalgrade)) {
+                $grade->timemodified = time();
                 $success = $grade->update('aggregation');
 
                 // If successful trigger a user_graded event.
@@ -712,6 +713,7 @@ class grade_category extends grade_object {
             $grade->finalgrade = null;
 
             if (!is_null($oldfinalgrade)) {
+                $grade->timemodified = time();
                 $success = $grade->update('aggregation');
 
                 // If successful trigger a user_graded event.
@@ -754,6 +756,7 @@ class grade_category extends grade_object {
         if (grade_floats_different($grade->finalgrade, $oldfinalgrade) ||
                 grade_floats_different($grade->rawgrademax, $oldrawgrademax) ||
                 grade_floats_different($grade->rawgrademin, $oldrawgrademin)) {
+            $grade->timemodified = time();
             $success = $grade->update('aggregation');
 
             // If successful trigger a user_graded event.
@@ -966,15 +969,14 @@ class grade_category extends grade_object {
                 $sum       = 0;
 
                 foreach ($grade_values as $itemid=>$grade_value) {
-
+                    if ($weights !== null) {
+                        $weights[$itemid] = $items[$itemid]->aggregationcoef;
+                    }
                     if ($items[$itemid]->aggregationcoef <= 0) {
                         continue;
                     }
                     $weightsum += $items[$itemid]->aggregationcoef;
                     $sum       += $items[$itemid]->aggregationcoef * $grade_value;
-                    if ($weights !== null) {
-                        $weights[$itemid] = $items[$itemid]->aggregationcoef;
-                    }
                 }
                 if ($weightsum == 0) {
                     $agg_grade = null;
index 6f8a4dc..d21c5b1 100644 (file)
@@ -2092,7 +2092,7 @@ class global_navigation extends navigation_node {
         $featuresfunc = $cm->modname.'_supports';
         if (function_exists($featuresfunc) && $featuresfunc(FEATURE_ADVANCED_GRADING)) {
             require_once($CFG->dirroot.'/grade/grading/lib.php');
-            $gradingman = get_grading_manager($cm->context, $cm->modname);
+            $gradingman = get_grading_manager($cm->context,  'mod_'.$cm->modname);
             $gradingman->extend_navigation($this, $activity);
         }
 
@@ -3977,7 +3977,7 @@ class settings_navigation extends navigation_node {
         $featuresfunc = $this->page->activityname.'_supports';
         if (function_exists($featuresfunc) && $featuresfunc(FEATURE_ADVANCED_GRADING) && has_capability('moodle/grade:managegradingforms', $this->page->cm->context)) {
             require_once($CFG->dirroot.'/grade/grading/lib.php');
-            $gradingman = get_grading_manager($this->page->cm->context, $this->page->activityname);
+            $gradingman = get_grading_manager($this->page->cm->context, 'mod_'.$this->page->activityname);
             $gradingman->extend_settings_navigation($this, $modulenode);
         }
 
index 22728e2..b0deb72 100644 (file)
@@ -3040,10 +3040,9 @@ EOD;
 
         $am = new action_menu();
         $am->initialise_js($this->page);
-        $am->set_menu_trigger(html_writer::span(
-            get_string('usermenu', 'moodle'),
-            "accesshide"
-        ));
+        $am->set_menu_trigger(
+            $returnstr
+        );
         $am->set_alignment(action_menu::TR, action_menu::BR);
         if ($withlinks) {
             $navitemcount = count($opts->navitems);
@@ -3072,10 +3071,6 @@ EOD;
         }
 
         return html_writer::div(
-            html_writer::div(
-                $returnstr,
-                'userinfo'
-            ) .
             $this->render($am),
             $usermenuclasses
         );
index 55ef5df..2bca043 100644 (file)
@@ -34,7 +34,12 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class testing_data_generator {
+    /** @var int The number of grade categories created */
     protected $gradecategorycounter = 0;
+    /** @var int The number of grade items created */
+    protected $gradeitemcounter = 0;
+    /** @var int The number of grade outcomes created */
+    protected $gradeoutcomecounter = 0;
     protected $usercounter = 0;
     protected $categorycount = 0;
     protected $cohortcount = 0;
@@ -914,7 +919,6 @@ EOD;
         global $CFG;
 
         $this->gradecategorycounter++;
-        $i = $this->gradecategorycounter;
 
         $record = (array)$record;
 
@@ -923,7 +927,7 @@ EOD;
         }
 
         if (!isset($record['fullname'])) {
-            $record['fullname'] = 'Grade category ' . $i;
+            $record['fullname'] = 'Grade category ' . $this->gradecategorycounter;
         }
 
         // For gradelib classes.
@@ -941,4 +945,68 @@ EOD;
         $gradecategory->update_from_db();
         return $gradecategory->get_record_data();
     }
+
+    /**
+     * Create a grade_item.
+     *
+     * @param array|stdClass $record
+     * @return stdClass the grade item record
+     */
+    public function create_grade_item($record = null) {
+        global $CFG;
+        require_once("$CFG->libdir/gradelib.php");
+
+        $this->gradeitemcounter++;
+
+        if (!isset($record['itemtype'])) {
+            $record['itemtype'] = 'manual';
+        }
+
+        if (!isset($record['itemname'])) {
+            $record['itemname'] = 'Grade item ' . $this->gradeitemcounter;
+        }
+
+        if (isset($record['outcomeid'])) {
+            $outcome = new grade_outcome(array('id' => $record['outcomeid']));
+            $record['scaleid'] = $outcome->scaleid;
+        }
+        if (isset($record['scaleid'])) {
+            $record['gradetype'] = GRADE_TYPE_SCALE;
+        } else if (!isset($record['gradetype'])) {
+            $record['gradetype'] = GRADE_TYPE_VALUE;
+        }
+
+        // Create new grade item in this course.
+        $gradeitem = new grade_item($record, false);
+        $gradeitem->insert();
+
+        $gradeitem->update_from_db();
+        return $gradeitem->get_record_data();
+    }
+
+    /**
+     * Create a grade_outcome.
+     *
+     * @param array|stdClass $record
+     * @return stdClass the grade outcome record
+     */
+    public function create_grade_outcome($record = null) {
+        global $CFG;
+
+        $this->gradeoutcomecounter++;
+        $i = $this->gradeoutcomecounter;
+
+        if (!isset($record['fullname'])) {
+            $record['fullname'] = 'Grade outcome ' . $i;
+        }
+
+        // For gradelib classes.
+        require_once($CFG->libdir . '/gradelib.php');
+        // Create new grading outcome in this course.
+        $gradeoutcome = new grade_outcome($record, false);
+        $gradeoutcome->insert();
+
+        $gradeoutcome->update_from_db();
+        return $gradeoutcome->get_record_data();
+    }
 }
index 2ce1a86..3a957dc 100644 (file)
@@ -140,6 +140,22 @@ class behat_data_generators extends behat_base {
             'datagenerator' => 'grade_category',
             'required' => array('fullname', 'course'),
             'switchids' => array('course' => 'courseid', 'gradecategory' => 'parent')
+        ),
+        'grade items' => array(
+            'datagenerator' => 'grade_item',
+            'required' => array('course'),
+            'switchids' => array('scale' => 'scaleid', 'outcome' => 'outcomeid', 'course' => 'courseid',
+                                 'gradecategory' => 'categoryid')
+        ),
+        'grade outcomes' => array(
+            'datagenerator' => 'grade_outcome',
+            'required' => array('shortname', 'scale'),
+            'switchids' => array('course' => 'courseid', 'gradecategory' => 'categoryid', 'scale' => 'scaleid')
+        ),
+        'scales' => array(
+            'datagenerator' => 'scale',
+            'required' => array('name', 'scale'),
+            'switchids' => array('course' => 'courseid')
         )
     );
 
@@ -246,6 +262,21 @@ class behat_data_generators extends behat_base {
         return $data;
     }
 
+    /**
+     * Preprocesses the creation of a grade item. Converts gradetype text to a number.
+     * @param array $data
+     * @return array
+     */
+    protected function preprocess_grade_item($data) {
+        global $CFG;
+        require_once("$CFG->libdir/grade/constants.php");
+
+        if (isset($data['gradetype'])) {
+            $data['gradetype'] = constant("GRADE_TYPE_" . strtoupper($data['gradetype']));
+        }
+        return $data;
+    }
+
     /**
      * Adapter to modules generator
      * @throws Exception Custom exception for test writers
@@ -253,12 +284,22 @@ class behat_data_generators extends behat_base {
      * @return void
      */
     protected function process_activity($data) {
-        global $DB;
+        global $DB, $CFG;
 
         // The the_following_exists() method checks that the field exists.
         $activityname = $data['activity'];
         unset($data['activity']);
 
+        // Convert scale name into scale id (negative number indicates using scale).
+        if (isset($data['grade']) && strlen($data['grade']) && !is_number($data['grade'])) {
+            $data['grade'] = - $this->get_scale_id($data['grade']);
+            require_once("$CFG->libdir/grade/constants.php");
+
+            if (!isset($data['gradetype'])) {
+                $data['gradetype'] = GRADE_TYPE_SCALE;
+            }
+        }
+
         // We split $data in the activity $record and the course module $options.
         $cmoptions = array();
         $cmcolumns = $DB->get_columns('course_modules');
@@ -559,6 +600,36 @@ class behat_data_generators extends behat_base {
         return $id;
     }
 
+    /**
+     * Gets the outcome item id from its shortname.
+     * @throws Exception
+     * @param string $shortname
+     * @return int
+     */
+    protected function get_outcome_id($shortname) {
+        global $DB;
+
+        if (!$id = $DB->get_field('grade_outcomes', 'id', array('shortname' => $shortname))) {
+            throw new Exception('The specified outcome with shortname "' . $shortname . '" does not exist');
+        }
+        return $id;
+    }
+
+    /**
+     * Gets the course id from its name.
+     * @throws Exception
+     * @param string $name
+     * @return int
+     */
+    protected function get_scale_id($name) {
+        global $DB;
+
+        if (!$id = $DB->get_field('scale', 'id', array('name' => $name))) {
+            throw new Exception('The specified scale with name "' . $name . '" does not exist');
+        }
+        return $id;
+    }
+
     /**
      * Gets the internal context id from the context reference.
      *
index 6696111..4d7a1b5 100644 (file)
@@ -43,7 +43,7 @@ class cronlib_testcase extends basic_testcase {
         $time = 0;
 
         // Relative time stamps. Did you know data providers get executed during phpunit init?
-        $lastweekstime = -(7 * 24 * 60 * 60);
+        $lastweekstime = strtotime('-1 week') - time();
         $beforelastweekstime = $lastweekstime - 60;
         $afterlastweekstime = $lastweekstime + 60;
 
@@ -54,8 +54,8 @@ class cronlib_testcase extends basic_testcase {
         // New Directory to keep.
         $nodes[] = $this->generate_test_path('/dir1/dir1_2/', true, $time, true);
 
-        // Directory exactly 1 week old, keep.
-        $nodes[] = $this->generate_test_path('/dir2/', true, $lastweekstime, true);
+        // Directory a little less than 1 week old, keep.
+        $nodes[] = $this->generate_test_path('/dir2/', true, $afterlastweekstime, true);
 
         // Directory older than 1 week old, remove.
         $nodes[] = $this->generate_test_path('/dir3/', true, $beforelastweekstime, false);
index aa07dc5..004dc8b 100644 (file)
@@ -241,10 +241,20 @@ class core_filelib_testcase extends advanced_testcase {
         $this->assertSame(2, $curl->info['redirect_count']);
         $this->assertSame('done', $contents);
 
+        // This test was failing for people behind Squid proxies. Squid does not
+        // fully support HTTP 1.1, so converts things to HTTP 1.0, where the name
+        // of the status code is different.
+        reset($response);
+        if (key($response) === 'HTTP/1.0') {
+            $responsecode302 = '302 Moved Temporarily';
+        } else {
+            $responsecode302 = '302 Found';
+        }
+
         $curl = new curl();
         $contents = $curl->get("$testurl?redir=3", array(), array('CURLOPT_FOLLOWLOCATION'=>0));
         $response = $curl->getResponse();
-        $this->assertSame('302 Found', reset($response));
+        $this->assertSame($responsecode302, reset($response));
         $this->assertSame(0, $curl->get_errno());
         $this->assertSame(302, $curl->info['http_code']);
         $this->assertSame('', $contents);
@@ -253,7 +263,7 @@ class core_filelib_testcase extends advanced_testcase {
         $curl->emulateredirects = true;
         $contents = $curl->get("$testurl?redir=3", array(), array('CURLOPT_FOLLOWLOCATION'=>0));
         $response = $curl->getResponse();
-        $this->assertSame('302 Found', reset($response));
+        $this->assertSame($responsecode302, reset($response));
         $this->assertSame(0, $curl->get_errno());
         $this->assertSame(302, $curl->info['http_code']);
         $this->assertSame('', $contents);
index 5f43f69..5b8033d 100644 (file)
@@ -1,4 +1,19 @@
 <?php
+// 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/>.
+//
 // This file is part of BasicLTI4Moodle
 //
 // BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
 //
 // 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/>.
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
-namespace moodle\mod\lti;//Using a namespace as the basicLTI module imports classes with the same names
+namespace moodle\mod\lti; // Using a namespace as the basicLTI module imports classes with the same names.
 
 defined('MOODLE_INTERNAL') || die;
 
 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);
+function get_oauth_key_from_headers() {
+    $requestheaders = OAuthUtil::get_headers();
 
-    if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
-        $header_parameters = OAuthUtil::split_header($request_headers['Authorization']);
+    if (@substr($requestheaders['Authorization'], 0, 6) == "OAuth ") {
+        $headerparameters = OAuthUtil::split_header($requestheaders['Authorization']);
 
-        // echo("HEADER PARMS=\n");
-        // print_r($header_parameters);
-        return $header_parameters['oauth_consumer_key'];
+        return format_string($headerparameters['oauth_consumer_key']);
     }
     return false;
 }
 
-function handleOAuthBodyPOST($oauth_consumer_key, $oauth_consumer_secret, $body, $request_headers = null)
-{
-    if($request_headers == null){
-        $request_headers = OAuthUtil::get_headers();
+function handle_oauth_body_post($oauthconsumerkey, $oauthconsumersecret, $body, $requestheaders = null) {
+
+    if ($requestheaders == null) {
+        $requestheaders = OAuthUtil::get_headers();
     }
 
-    // Must reject application/x-www-form-urlencoded
-    if (isset($request_headers['Content-type'])) {
-        if ($request_headers['Content-type'] == 'application/x-www-form-urlencoded' ) {
+    // Must reject application/x-www-form-urlencoded.
+    if (isset($requestheaders['Content-type'])) {
+        if ($requestheaders['Content-type'] == 'application/x-www-form-urlencoded' ) {
             throw new OAuthException("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 (@substr($requestheaders['Authorization'], 0, 6) == "OAuth ") {
+        $headerparameters = OAuthUtil::split_header($requestheaders['Authorization']);
+        $oauthbodyhash = $headerparameters['oauth_body_hash'];
     }
 
-    if ( ! isset($oauth_body_hash)  ) {
+    if ( ! isset($oauthbodyhash)  ) {
         throw new OAuthException("OAuth request body signing requires oauth_body_hash body");
     }
 
-    // Verify the message signature
+    // Verify the message signature.
     $store = new TrivialOAuthDataStore();
-    $store->add_consumer($oauth_consumer_key, $oauth_consumer_secret);
+    $store->add_consumer($oauthconsumerkey, $oauthconsumersecret);
 
     $server = new OAuthServer($store);
 
@@ -120,46 +90,12 @@ function handleOAuthBodyPOST($oauth_consumer_key, $oauth_consumer_secret, $body,
     }
 
     $postdata = $body;
-    // echo($postdata);
 
-    $hash = base64_encode(sha1($postdata, TRUE));
+    $hash = base64_encode(sha1($postdata, true));
 
-    if ( $hash != $oauth_body_hash ) {
+    if ( $hash != $oauthbodyhash ) {
         throw new OAuthException("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 OAuthException("Problem with $endpoint, $php_errormsg");
-    }
-    $response = @stream_get_contents($fp);
-    if ($response === false) {
-        throw new OAuthException("Problem reading data from $endpoint, $php_errormsg");
-    }
-    return $response;
-}
index 73c3ad5..cc4765f 100644 (file)
@@ -1,22 +1,20 @@
 <?php
-// This file is part of BasicLTI4Moodle
+// 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.
 //
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
+// 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.
 //
-// http://www.apache.org/licenses/LICENSE-2.0
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 //
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
+// 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
 //
 // 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/>.
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains a Trivial memory-based store - no support for tokens
  * @license http://www.apache.org/licenses/LICENSE-2.0
  */
 
-namespace moodle\mod\lti;//Using a namespace as the basicLTI module imports classes with the same names
+namespace moodle\mod\lti; // Using a namespace as the basicLTI module imports classes with the same names.
 
 defined('MOODLE_INTERNAL') || die;
 
 /**
- * A Trivial memory-based store - no support for tokens
+ * A Trivial memory-based store - no support for tokens.
  */
 class TrivialOAuthDataStore extends OAuthDataStore {
+
+    /** @var array $consumers  Array of tool consumer keys and secrets */
     private $consumers = array();
 
-    function add_consumer($consumer_key, $consumer_secret) {
-        $this->consumers[$consumer_key] = $consumer_secret;
+    /**
+     * Add a consumer to the array
+     *
+     * @param string $consumerkey     Consumer key
+     * @param string $consumersecret  Consumer secret
+     */
+    public function add_consumer($consumerkey, $consumersecret) {
+        $this->consumers[$consumerkey] = $consumersecret;
     }
 
-    function lookup_consumer($consumer_key) {
-        if ( strpos($consumer_key, "http://" ) === 0 ) {
-            $consumer = new OAuthConsumer($consumer_key, "secret", null);
+    /**
+     * Get OAuth consumer given its key
+     *
+     * @param string $consumerkey     Consumer key
+     *
+     * @return moodle\mod\lti\OAuthConsumer  OAuthConsumer object
+     */
+    public function lookup_consumer($consumerkey) {
+        if (strpos($consumerkey, "http://" ) === 0) {
+            $consumer = new OAuthConsumer($consumerkey, "secret", null);
             return $consumer;
         }
-        if ( $this->consumers[$consumer_key] ) {
-            $consumer = new OAuthConsumer($consumer_key, $this->consumers[$consumer_key], null);
+        if ( $this->consumers[$consumerkey] ) {
+            $consumer = new OAuthConsumer($consumerkey, $this->consumers[$consumerkey], null);
             return $consumer;
         }
         return null;
     }
 
-    function lookup_token($consumer, $token_type, $token) {
-        return new OAuthToken($consumer, "");
+    /**
+     * Create a dummy OAuthToken object for a consumer
+     *
+     * @param moodle\mod\lti\OAuthConsumer $consumer     Consumer
+     * @param string $tokentype    Type of token
+     * @param string $token        Token ID
+     *
+     * @return moodle\mod\lti\OAuthToken OAuthToken object
+     */
+    public function lookup_token($consumer, $tokentype, $token) {
+        return new OAuthToken($consumer, '');
     }
 
-    // Return NULL if the nonce has not been used
-    // Return $nonce if the nonce was previously used
-    function lookup_nonce($consumer, $token, $nonce, $timestamp) {
+    /**
+     * Nonce values are not checked so just return a null
+     *
+     * @param moodle\mod\lti\OAuthConsumer $consumer     Consumer
+     * @param string $token        Token ID
+     * @param string $nonce        Nonce value
+     * @param string $timestamp    Timestamp
+     *
+     * @return null
+     */
+    public function lookup_nonce($consumer, $token, $nonce, $timestamp) {
         // Should add some clever logic to keep nonces from
-        // being reused - for no we are really trusting
-        // that the timestamp will save us
+        // being reused - for now we are really trusting
+        // that the timestamp will save us.
         return null;
     }
 
-    function new_request_token($consumer) {
+    /**
+     * Tokens are not used so just return a null.
+     *
+     * @param moodle\mod\lti\OAuthConsumer $consumer     Consumer
+     *
+     * @return null
+     */
+    public function new_request_token($consumer) {
         return null;
     }
 
-    function new_access_token($token, $consumer) {
+    /**
+     * Tokens are not used so just return a null.
+     *
+     * @param string $token        Token ID
+     * @param moodle\mod\lti\OAuthConsumer $consumer     Consumer
+     *
+     * @return null
+     */
+    public function new_access_token($token, $consumer) {
         return null;
     }
 }
index ab75cd3..a411633 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * AJAX service used when adding an External Tool to provide immediate feedback
+ * AJAX service used when adding an External Tool.
+ *
+ * It is used to provide immediate feedback
  * of which tool provider is to be used based on the Launch URL.
  *
- * @package    mod
+ * @package    mod_lti
  * @subpackage xml
  * @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -41,10 +43,10 @@ switch ($action) {
         $toolurl = required_param('toolurl', PARAM_RAW);
         $toolid = optional_param('toolid', 0, PARAM_INT);
 
-        if(empty($toolid) && !empty($toolurl)){
+        if (empty($toolid) && !empty($toolurl)) {
             $tool = lti_get_tool_by_url_match($toolurl, $courseid);
 
-            if(!empty($tool)){
+            if (!empty($tool)) {
                 $toolid = $tool->id;
 
                 $response->toolid = $tool->id;
@@ -56,7 +58,7 @@ switch ($action) {
         }
 
         if (!empty($toolid)) {
-            // Look up privacy settings
+            // Look up privacy settings.
             $query = '
                 SELECT name, value
                 FROM {lti_types_config}
@@ -66,7 +68,7 @@ switch ($action) {
             ';
 
             $privacyconfigs = $DB->get_records_sql($query, array('typeid' => $toolid));
-            foreach($privacyconfigs as $config){
+            foreach ($privacyconfigs as $config) {
                 $configname = $config->name;
                 $response->$configname = $config->value;
             }
index 75b638d..ce7f466 100644 (file)
@@ -34,18 +34,18 @@ class moodle1_mod_lti_handler extends moodle1_mod_handler {
     protected $moduleid = null;
 
     /**
-    * Declare the paths in moodle.xml we are able to convert
-    *
-    * The method returns list of {@link convert_path} instances.
-    * For each path returned, the corresponding conversion method must be
-    * defined.
-    *
-    * Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/LTI does not
-    * actually exist in the file. The last element with the module name was
-    * appended by the moodle1_converter class.
-    *
-    * @return array of {@link convert_path} instances
-    */
+     * Declare the paths in moodle.xml we are able to convert
+     *
+     * The method returns list of {@link convert_path} instances.
+     * For each path returned, the corresponding conversion method must be
+     * defined.
+     *
+     * Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/LTI does not
+     * actually exist in the file. The last element with the module name was
+     * appended by the moodle1_converter class.
+     *
+     * @return array of {@link convert_path} instances
+     */
     public function get_paths() {
 
         return array(
@@ -57,33 +57,33 @@ class moodle1_mod_lti_handler extends moodle1_mod_handler {
     }
 
     /**
-    * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LTI
-    * data available
-    */
+     * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LTI
+     * data available
+     */
     public function process_basiclti($data) {
         global $DB;
 
-        // get the course module id and context id
+        // Get the course module id and context id.
         $instanceid     = $data['id'];
         $cminfo         = $this->get_cminfo($instanceid);
         $this->moduleid = $cminfo['id'];
         $contextid      = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);
 
-        // get a fresh new file manager for this instance
+        // Get a fresh new file manager for this instance.
         $this->fileman = $this->converter->get_file_manager($contextid, 'mod_lti');
 
-        // convert course files embedded into the intro
+        // Convert course files embedded into the intro.
         $this->fileman->filearea = 'intro';
         $this->fileman->itemid   = 0;
         $data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);
 
-        // start writing assignment.xml
+        // Start writing assignment.xml.
         $this->open_xml_writer("activities/lti_{$this->moduleid}/lti.xml");
         $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
                 'modulename' => 'lti', 'contextid' => $contextid));
         $this->xmlwriter->begin_tag('lti', array('id' => $instanceid));
 
-        $ignore_fields = array('id', 'modtype');
+        $ignorefields = array('id', 'modtype');
         if (!$DB->record_exists('lti_types', array('id' => $data['typeid']))) {
             $ntypeid = $DB->get_field('lti_types_config',
                                       'typeid',
@@ -105,7 +105,7 @@ class moodle1_mod_lti_handler extends moodle1_mod_handler {
             $data['servicesalt'] = uniqid('', true);
         }
         foreach ($data as $field => $value) {
-            if (!in_array($field, $ignore_fields)) {
+            if (!in_array($field, $ignorefields)) {
                 $this->xmlwriter->full_tag($field, $value);
             }
         }
@@ -114,15 +114,15 @@ class moodle1_mod_lti_handler extends moodle1_mod_handler {
     }
 
     /**
-    * This is executed when we reach the closing </MOD> tag of our 'lti' path
-    */
+     * This is executed when we reach the closing </MOD> tag of our 'lti' path
+     */
     public function on_basiclti_end() {
-        // finish writing basiclti.xml
+        // Finish writing basiclti.xml.
         $this->xmlwriter->end_tag('lti');
         $this->xmlwriter->end_tag('activity');
         $this->close_xml_writer();
 
-        // write inforef.xml
+        // Write inforef.xml.
         $this->open_xml_writer("activities/lti_{$this->moduleid}/inforef.xml");
         $this->xmlwriter->begin_tag('inforef');
         $this->xmlwriter->begin_tag('fileref');
index 1c00c4e..8ca3ff1 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * Defines backup_lti_activity_task class
@@ -78,13 +78,13 @@ class backup_lti_activity_task extends backup_activity_task {
 
         $base = preg_quote($CFG->wwwroot, "/");
 
-        // Link to the list of basiclti tools
-        $search="/(".$base."\/mod\/lti\/index.php\?id\=)([0-9]+)/";
-        $content= preg_replace($search, '$@LTIINDEX*$2@$', $content);
+        // Link to the list of basiclti tools.
+        $search = "/(".$base."\/mod\/lti\/index.php\?id\=)([0-9]+)/";
+        $content = preg_replace($search, '$@LTIINDEX*$2@$', $content);
 
-        // Link to basiclti view by moduleid
-        $search="/(".$base."\/mod\/lti\/view.php\?id\=)([0-9]+)/";
-        $content= preg_replace($search, '$@LTIVIEWBYID*$2@$', $content);
+        // Link to basiclti view by moduleid.
+        $search = "/(".$base."\/mod\/lti\/view.php\?id\=)([0-9]+)/";
+        $content = preg_replace($search, '$@LTIVIEWBYID*$2@$', $content);
 
         return $content;
     }
index f74e292..055a6ef 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains all the backup steps that will be used
@@ -57,10 +57,10 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
 
         // TODO: MDL-34161 - Fix restore to support course/site tools & submissions.
 
-        // To know if we are including userinfo
+        // To know if we are including userinfo.
         $userinfo = $this->get_setting_value('userinfo');
 
-        // Define each element separated
+        // Define each element separated.
         $lti = new backup_nested_element('lti', array('id'), array(
             'name',
             'intro',
@@ -88,21 +88,22 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
         );
 
         // Build the tree
-        // (none)
+        // (none).
 
-        // Define sources
+        // Define sources.
         $lti->set_source_table('lti', array('id' => backup::VAR_ACTIVITYID));
 
         // Define id annotations
-        // (none)
+        // (none).
 
-        // Define file annotations
-        $lti->annotate_files('mod_lti', 'intro', null); // This file areas haven't itemid
+        // Define file annotations.
+        $lti->annotate_files('mod_lti', 'intro', null); // This file areas haven't itemid.
 
-        // Add support for subplugin structure.
+        // Add support for subplugin structures.
         $this->add_subplugin_structure('ltisource', $lti, true);
+        $this->add_subplugin_structure('ltiservice', $lti, true);
 
-        // Return the root element (lti), wrapped into standard activity structure
+        // Return the root element (lti), wrapped into standard activity structure.
         return $this->prepare_activity_structure($lti);
     }
 }
index a1a1e92..bc291a9 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains the lti module restore class
index c8fd855..989be59 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains all the restore steps that will be used
@@ -59,8 +59,9 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
         $lti = new restore_path_element('lti', '/activity/lti');
         $paths[] = $lti;
 
-        // Add support for subplugin structure.
+        // Add support for subplugin structures.
         $this->add_subplugin_structure('ltisource', $lti);
+        $this->add_subplugin_structure('ltiservice', $lti);
 
         // Return the paths wrapped into standard activity structure.
         return $this->prepare_activity_structure($paths);
diff --git a/mod/lti/basiclti.js b/mod/lti/basiclti.js
deleted file mode 100644 (file)
index 9fb6cec..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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/>.
-//
-// 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
-
-/**
- * This file contains a library of javasxript functions for the lti module
- *
- * @package    mod
- * @subpackage 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
- */
-
-function basicltiDebugToggle() {
-    var ele = document.getElementById('basicltiDebug');
-    if (ele.style.display == 'block') {
-        ele.style.display = 'none';
-    } else {
-        ele.style.display = 'block';
-    }
-}
diff --git a/mod/lti/classes/local/ltiservice/resource_base.php b/mod/lti/classes/local/ltiservice/resource_base.php
new file mode 100644 (file)
index 0000000..4d617fe
--- /dev/null
@@ -0,0 +1,277 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains an abstract definition of an LTI resource
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+namespace mod_lti\local\ltiservice;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/mod/lti/locallib.php');
+
+
+/**
+ * The mod_lti\local\ltiservice\resource_base class.
+ *
+ * @package    mod_lti
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class resource_base {
+
+    /** @var object Service associated with this resource. */
+    private $service;
+    /** @var string Type for this resource. */
+    protected $type;
+    /** @var string ID for this resource. */
+    protected $id;
+    /** @var string Template for this resource. */
+    protected $template;
+    /** @var array Custom parameter substitution variables associated with this resource. */
+    protected $variables;
+    /** @var array Media types supported by this resource. */
+    protected $formats;
+    /** @var array HTTP actions supported by this resource. */
+    protected $methods;
+    /** @var array Template variables parsed from the resource template. */
+    protected $params;
+
+
+    /**
+     * Class constructor.
+     *
+     * @param mod_lti\local\ltiservice\service_base $service Service instance
+     */
+    public function __construct($service) {
+
+        $this->service = $service;
+        $this->type = 'RestService';
+        $this->id = null;
+        $this->template = null;
+        $this->methods = array();
+        $this->variables = array();
+        $this->formats = array();
+        $this->methods = array();
+        $this->params = null;
+
+    }
+
+    /**
+     * Get the resource ID.
+     *
+     * @return string
+     */
+    public function get_id() {
+
+        return $this->id;
+
+    }
+
+    /**
+     * Get the resource template.
+     *
+     * @return string
+     */
+    public function get_template() {
+
+        return $this->template;
+
+    }
+
+    /**
+     * Get the resource path.
+     *
+     * @return string
+     */
+    public function get_path() {
+
+        return $this->get_template();
+
+    }
+
+    /**
+     * Get the resource type.
+     *
+     * @return string
+     */
+    public function get_type() {
+
+        return $this->type;
+
+    }
+
+    /**
+     * Get the resource's service.
+     *
+     * @return mod_lti\local\ltiservice\service_base
+     */
+    public function get_service() {
+
+        return $this->service;
+
+    }
+
+    /**
+     * Get the resource methods.
+     *
+     * @return array
+     */
+    public function get_methods() {
+
+        return $this->methods;
+
+    }
+
+    /**
+     * Get the resource media types.
+     *
+     * @return array
+     */
+    public function get_formats() {
+
+        return $this->formats;
+
+    }
+
+    /**
+     * Get the resource template variables.
+     *
+     * @return array
+     */
+    public function get_variables() {
+
+        return $this->variables;
+
+    }
+
+    /**
+     * Get the resource fully qualified endpoint.
+     *
+     * @return string
+     */
+    public function get_endpoint() {
+
+        $this->parse_template();
+        $url = $this->get_service()->get_service_path() . $this->get_template();
+        foreach ($this->params as $key => $value) {
+            $url = str_replace('{' . $key . '}', $value, $url);
+        }
+        $toolproxy = $this->get_service()->get_tool_proxy();
+        if (!empty($toolproxy)) {
+            $url = str_replace('{tool_proxy_id}', $toolproxy->guid, $url);
+        }
+
+        return $url;
+
+    }
+
+    /**
+     * Execute the request for this resource.
+     *
+     * @param mod_lti\local\ltiservice\response $response  Response object for this request.
+     */
+    public abstract function execute($response);
+
+    /**
+     * Check to make sure the request is valid.
+     *
+     * @param string $toolproxyguid Consumer key
+     * @param string $body          Body of HTTP request message
+     *
+     * @return boolean
+     */
+    public function check_tool_proxy($toolproxyguid, $body = null) {
+
+        $ok = false;
+        if ($this->get_service()->check_tool_proxy($toolproxyguid, $body)) {
+            $toolproxyjson = $this->get_service()->get_tool_proxy()->toolproxy;
+            if (empty($toolproxyjson)) {
+                $ok = true;
+            } else {
+                $toolproxy = json_decode($toolproxyjson);
+                if (!empty($toolproxy) && isset($toolproxy->security_contract->tool_service)) {
+                    $contexts = lti_get_contexts($toolproxy);
+                    $tpservices = $toolproxy->security_contract->tool_service;
+                    foreach ($tpservices as $service) {
+                        $fqid = lti_get_fqid($contexts, $service->service);
+                        $id = explode('#', $fqid, 2);
+                        if ($this->get_id() === $id[1]) {
+                            $ok = true;
+                            break;
+                        }
+                    }
+                }
+                if (!$ok) {
+                    debugging('Requested service not included in tool proxy: ' . $this->get_id());
+                }
+            }
+        }
+
+        return $ok;
+
+    }
+
+    /**
+     * Parse a value for custom parameter substitution variables.
+     *
+     * @param string $value String to be parsed
+     *
+     * @return string
+     */
+    public function parse_value($value) {
+
+        return $value;
+
+    }
+
+    /**
+     * Parse the template for variables.
+     *
+     * @return array
+     */
+    protected function parse_template() {
+
+        if (empty($this->params)) {
+            $this->params = array();
+            if (isset($_SERVER['PATH_INFO'])) {
+                $path = explode('/', $_SERVER['PATH_INFO']);
+                $parts = explode('/', $this->get_template());
+                for ($i = 0; $i < count($parts); $i++) {
+                    if ((substr($parts[$i], 0, 1) == '{') && (substr($parts[$i], -1) == '}')) {
+                        $value = '';
+                        if ($i < count($path)) {
+                            $value = $path[$i];
+                        }
+                        $this->params[substr($parts[$i], 1, -1)] = $value;
+                    }
+                }
+            }
+        }
+
+        return $this->params;
+
+    }
+
+}
diff --git a/mod/lti/classes/local/ltiservice/response.php b/mod/lti/classes/local/ltiservice/response.php
new file mode 100644 (file)
index 0000000..5029d21
--- /dev/null
@@ -0,0 +1,220 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains an abstract definition of an LTI service
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+namespace mod_lti\local\ltiservice;
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * The mod_lti\local\ltiservice\response class.
+ *
+ * @package    mod_lti
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class response {
+
+    /** @var int HTTP response code. */
+    private $code;
+    /** @var string HTTP response reason. */
+    private $reason;
+    /** @var string HTTP request method. */
+    private $requestmethod;
+    /** @var string HTTP request accept header. */
+    private $accept;
+    /** @var string HTTP response content type. */
+    private $contenttype;
+    /** @var string HTTP request body. */
+    private $data;
+    /** @var string HTTP response body. */
+    private $body;
+    /** @var array HTTP response codes. */
+    private $responsecodes;
+
+    /**
+     * Class constructor.
+     */
+    public function __construct() {
+
+        $this->code = 200;
+        $this->reason = '';
+        $this->requestmethod = $_SERVER['REQUEST_METHOD'];
+        $this->accept = '';
+        $this->contenttype = '';
+        $this->data = '';
+        $this->body = '';
+        $this->responsecodes = array(
+            200 => 'OK',
+            201 => 'Created',
+            202 => 'Accepted',
+            300 => 'Multiple Choices',
+            400 => 'Bad Request',
+            401 => 'Unauthorized',
+            402 => 'Payment Required',
+            403 => 'Forbidden',
+            404 => 'Not Found',
+            405 => 'Method Not Allowed',
+            406 => 'Not Acceptable',
+            415 => 'Unsupported Media Type',
+            500 => 'Internal Server Error',
+            501 => 'Not Implemented'
+        );
+
+    }
+
+    /**
+     * Get the response code.
+     *
+     * @return int
+     */
+    public function get_code() {
+        return $this->code;
+    }
+
+    /**
+     * Set the response code.
+     *
+     * @param int $code Response code
+     */
+    public function set_code($code) {
+        $this->code = $code;
+        $this->reason = '';
+    }
+
+    /**
+     * Get the response reason.
+     *
+     * @return string
+     */
+    public function get_reason() {
+        if (empty($this->reason)) {
+            $this->reason = $this->responsecodes[$this->code];
+        }
+        // Use generic reason for this category (based on first digit) if a specific reason is not defined.
+        if (empty($this->reason)) {
+            $this->reason = $this->responsecodes[intval($this->code / 100) * 100];
+        }
+        return $this->reason;
+    }
+
+    /**
+     * Set the response reason.
+     *
+     * @param string $reason Reason
+     */
+    public function set_reason($reason) {
+        $this->reason = $reason;
+    }
+
+    /**
+     * Get the request method.
+     *
+     * @return string
+     */
+    public function get_request_method() {
+        return $this->requestmethod;
+    }
+
+    /**
+     * Get the request accept header.
+     *
+     * @return string
+     */
+    public function get_accept() {
+        return $this->accept;
+    }
+
+    /**
+     * Set the request accept header.
+     *
+     * @param string $accept Accept header value
+     */
+    public function set_accept($accept) {
+        $this->accept = $accept;
+    }
+
+    /**
+     * Get the response content type.
+     *
+     * @return string
+     */
+    public function get_content_type() {
+        return $this->contenttype;
+    }
+
+    /**
+     * Set the response content type.
+     *
+     * @param string $contenttype Content type
+     */
+    public function set_content_type($contenttype) {
+        $this->contenttype = $contenttype;
+    }
+
+    /**
+     * Get the request body.
+     *
+     * @return string
+     */
+    public function get_request_data() {
+        return $this->data;
+    }
+
+    /**
+     * Set the response body.
+     *
+     * @param string $data Body data
+     */
+    public function set_request_data($data) {
+        $this->data = $data;
+    }
+
+    /**
+     * Set the response body.
+     *
+     * @param string $body Body data
+     */
+    public function set_body($body) {
+        $this->body = $body;
+    }
+
+    /**
+     * Send the response.
+     */
+    public function send() {
+        header("HTTP/1.0 {$this->code} {$this->get_reason()}");
+        if (($this->code >= 200) && ($this->code < 300)) {
+            if (!empty($this->contenttype)) {
+                header("Content-Type: {$this->contenttype};charset=UTF-8");
+            }
+            if (!empty($this->body)) {
+                echo $this->body;
+            }
+        }
+    }
+
+}
diff --git a/mod/lti/classes/local/ltiservice/service_base.php b/mod/lti/classes/local/ltiservice/service_base.php
new file mode 100644 (file)
index 0000000..73726bd
--- /dev/null
@@ -0,0 +1,234 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains an abstract definition of an LTI service
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+namespace mod_lti\local\ltiservice;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/mod/lti/locallib.php');
+require_once($CFG->dirroot . '/mod/lti/OAuthBody.php');
+
+// TODO: Switch to core oauthlib once implemented - MDL-30149.
+use moodle\mod\lti as lti;
+
+
+/**
+ * The mod_lti\local\ltiservice\service_base class.
+ *
+ * @package    mod_lti
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class service_base {
+
+    /** Label representing an LTI 2 message type */
+    const LTI_VERSION2P0 = 'LTI-2p0';
+
+    /** @var string ID for the service. */
+    protected $id;
+    /** @var string Human readable name for the service. */
+    protected $name;
+    /** @var boolean <code>true</code> if requests for this service do not need to be signed. */
+    protected $unsigned;
+    /** @var stdClass Tool proxy object for the current service request. */
+    private $toolproxy;
+    /** @var array Instances of the resources associated with this service. */
+    protected $resources;
+
+
+    /**
+     * Class constructor.
+     */
+    public function __construct() {
+
+        $this->id = null;
+        $this->name = null;
+        $this->unsigned = false;
+        $this->toolproxy = null;
+        $this->resources = null;
+
+    }
+
+    /**
+     * Get the service ID.
+     *
+     * @return string
+     */
+    public function get_id() {
+
+        return $this->id;
+
+    }
+
+    /**
+     * Get the service name.
+     *
+     * @return string
+     */
+    public function get_name() {
+
+        return $this->name;
+
+    }
+
+    /**
+     * Get whether the service requests need to be signed.
+     *
+     * @return boolean
+     */
+    public function is_unsigned() {
+
+        return $this->unsigned;
+
+    }
+
+    /**
+     * Get the tool proxy object.
+     *
+     * @return stdClass
+     */
+    public function get_tool_proxy() {
+
+        return $this->toolproxy;
+
+    }
+
+    /**
+     * Set the tool proxy object.
+     *
+     * @param object $toolproxy The tool proxy for this service request
+     *
+     * @var stdClass
+     */
+    public function set_tool_proxy($toolproxy) {
+
+        $this->toolproxy = $toolproxy;
+
+    }
+
+    /**
+     * Get the resources for this service.
+     *
+     * @return array
+     */
+    abstract public function get_resources();
+
+    /**
+     * Get the path for service requests.
+     *
+     * @return string
+     */
+    public static function get_service_path() {
+
+        $url = new \moodle_url('/mod/lti/services.php');
+
+        return $url->out(false);
+
+    }
+
+    /**
+     * Parse a string for custom substitution parameter variables supported by this service's resources.
+     *
+     * @param string $value  Value to be parsed
+     *
+     * @return string
+     */
+    public function parse_value($value) {
+
+        if (empty($this->resources)) {
+            $this->resources = $this->get_resources();
+        }
+        if (!empty($this->resources)) {
+            foreach ($this->resources as $resource) {
+                $value = $resource->parse_value($value);
+            }
+        }
+
+        return $value;
+
+    }
+
+    /**
+     * Check that the request has been properly signed.
+     *
+     * @param string $toolproxyguid  Tool Proxy GUID
+     * @param string $body           Request body (null if none)
+     *
+     * @return boolean
+     */
+    public function check_tool_proxy($toolproxyguid, $body = null) {
+
+        $ok = false;
+        $toolproxy = null;
+        $consumerkey = lti\get_oauth_key_from_headers();
+        if (empty($toolproxyguid)) {
+            $toolproxyguid = $consumerkey;
+        }
+
+        if (!empty($toolproxyguid)) {
+            $toolproxy = lti_get_tool_proxy_from_guid($toolproxyguid);
+            if ($toolproxy !== false) {
+                if (!$this->is_unsigned() && ($toolproxy->guid == $consumerkey)) {
+                    $ok = $this->check_signature($toolproxy->guid, $toolproxy->secret, $body);
+                } else {
+                    $ok = $this->is_unsigned();
+                }
+            }
+        }
+        if ($ok) {
+            $this->toolproxy = $toolproxy;
+        }
+
+        return $ok;
+
+    }
+
+    /**
+     * Check the request signature.
+     *
+     * @param string $consumerkey    Consumer key
+     * @param string $secret         Shared secret
+     * @param string $body           Request body
+     *
+     * @return boolean
+     */
+    private function check_signature($consumerkey, $secret, $body) {
+
+        $ok = true;
+        try {
+            // TODO: Switch to core oauthlib once implemented - MDL-30149.
+            lti\handle_oauth_body_post($consumerkey, $secret, $body);
+        } catch (\Exception $e) {
+            debugging($e->getMessage() . "\n");
+            $ok = false;
+        }
+
+        return $ok;
+
+    }
+
+}
diff --git a/mod/lti/classes/plugininfo/ltiservice.php b/mod/lti/classes/plugininfo/ltiservice.php
new file mode 100644 (file)
index 0000000..32267a5
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+// 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/>.
+
+/**
+ * LTI service plugin info.
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace mod_lti\plugininfo;
+
+use core\plugininfo\base;
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * The mod_lti\plugininfo\ltiservice class.
+ *
+ * @package    mod_lti
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class ltiservice extends base {
+
+    /**
+     * Should there be a way to uninstall the plugin via the administration UI?
+     *
+     * Uninstallation is not allowed for core subplugins.
+     *
+     * @return boolean
+     */
+    public function is_uninstall_allowed() {
+
+        if ($this->is_standard()) {
+            return false;
+        }
+
+        return true;
+
+    }
+
+}
index 13a4315..12e7941 100644 (file)
@@ -57,7 +57,7 @@ $capabilities = array(
     ),
 
     // When the user arrives at the external tool, if they have this capability
-    // in Moodle, then they given the Instructor role in the remote system,
+    // in Moodle, then they are given the Instructor role in the remote system,
     // otherwise they are given Learner. See the lti_get_ims_role function.
     'mod/lti:manage' => array(
         'riskbitmask' => RISK_PERSONAL, // A bit of a guess, but seems likely.
@@ -81,7 +81,7 @@ $capabilities = array(
         )
     ),
 
-    // The ability to request the adminstirator to configure a particular
+    // The ability to request the administrator to configure a particular
     // External tool globally.
     'mod/lti:requesttooladd' => array(
         'captype' => 'write',
index cdc0bff..1ca547f 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="mod/lti/db" VERSION="20120122" COMMENT="XMLDB file for Moodle mod/lti"
+<XMLDB PATH="mod/lti/db" VERSION="20140612" COMMENT="XMLDB file for Moodle mod/lti"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
 >
         <INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
       </INDEXES>
     </TABLE>
+    <TABLE NAME="lti_tool_proxies" COMMENT="LTI tool proxy registrations">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" DEFAULT="Tool Provider" SEQUENCE="false" COMMENT="Tool Provider name"/>
+        <FIELD NAME="regurl" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="state" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Configured = 1, Pending = 2, Accepted = 3, Rejected = 4, Cancelled = 5"/>
+        <FIELD NAME="guid" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="secret" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="vendorcode" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="capabilityoffered" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="List of capabilities offered, one per line"/>
+        <FIELD NAME="serviceoffered" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="List of services offered, one per line"/>
+        <FIELD NAME="toolproxy" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="JSON string representing tool proxy returned by tool provider"/>
+        <FIELD NAME="createdby" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of user which initiated the registration process"/>
+        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Date/time at which the record was created"/>
+        <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Date/time at which the record was last modified"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="guid" UNIQUE="true" FIELDS="guid"/>
+      </INDEXES>
+    </TABLE>
     <TABLE NAME="lti_types" COMMENT="Basic LTI pre-configured activities">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
         <FIELD NAME="state" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="2" SEQUENCE="false" COMMENT="Active = 1, Pending = 2, Rejected = 3"/>
         <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="coursevisible" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="toolproxyid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Primary key of related tool proxy (null for LTI 1 tools)"/>
+        <FIELD NAME="enabledcapability" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Enabled capabilities, one per line (null for LTI 1 tools)"/>
+        <FIELD NAME="parameter" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Launch parameters, one per line (null for LTI 1 tools)"/>
+        <FIELD NAME="icon" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="URL to icon file"/>
+        <FIELD NAME="secureicon" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Secure URL to icon file"/>
         <FIELD NAME="createdby" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
         <INDEX NAME="typeid" UNIQUE="false" FIELDS="typeid"/>
       </INDEXES>
     </TABLE>
+    <TABLE NAME="lti_tool_settings" COMMENT="LTI tool setting values">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="toolproxyid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Primary key of related tool proxy"/>
+        <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Primary key of course (null for system-wide settings)"/>
+        <FIELD NAME="coursemoduleid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Primary key of course module - tool link added to course (null for system-wide and context-wide settings)"/>
+        <FIELD NAME="settings" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Setting values as JSON"/>
+        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Date/time at which the record was created"/>
+        <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Date/time at which the record was last modified"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+        <KEY NAME="toolproxy" TYPE="foreign" FIELDS="toolproxyid" REFTABLE="lti_tool_proxies" REFFIELDS="id" COMMENT="The tool proxy to which the setting relates"/>
+        <KEY NAME="course" TYPE="foreign" FIELDS="course" REFTABLE="course" REFFIELDS="id" COMMENT="The course to which the setting relates"/>
+        <KEY NAME="coursemodule" TYPE="foreign" FIELDS="coursemoduleid" REFTABLE="lti" REFFIELDS="id" COMMENT="The module instance to which the setting relates"/>
+      </KEYS>
+    </TABLE>
     <TABLE NAME="lti_submission" COMMENT="Keeps track of individual submissions for LTI activities.">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
index f00306e..fd3295f 100644 (file)
@@ -27,7 +27,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $logs = array(
-    array('module'=>'lti', 'action'=>'view', 'mtable'=>'lti', 'field'=>'name'),
-    array('module'=>'lti', 'action'=>'launch', 'mtable'=>'lti', 'field'=>'name'),
-    array('module'=>'lti', 'action'=>'view all', 'mtable'=>'lti', 'field'=>'name')
+    array('module' => 'lti', 'action' => 'view', 'mtable' => 'lti', 'field' => 'name'),
+    array('module' => 'lti', 'action' => 'launch', 'mtable' => 'lti', 'field' => 'name'),
+    array('module' => 'lti', 'action' => 'view all', 'mtable' => 'lti', 'field' => 'name')
 );
\ No newline at end of file
index ed665b5..d5244d2 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -27,4 +26,5 @@ defined('MOODLE_INTERNAL') || die();
 
 $subplugins = array(
     'ltisource' => 'mod/lti/source',
+    'ltiservice' => 'mod/lti/service'
 );
index 7ecc04e..f16ba8c 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file keeps track of upgrades to the lti module
 function xmldb_lti_upgrade($oldversion) {
     global $CFG, $DB;
 
-    $dbman = $DB->get_manager();
+    require_once(__DIR__ . '/upgradelib.php');
 
+    $dbman = $DB->get_manager();
 
     // Moodle v2.2.0 release upgrade line
-    // Put any upgrade step following this
+    // Put any upgrade step following this.
 
     // Moodle v2.3.0 release upgrade line
-    // Put any upgrade step following this
-
+    // Put any upgrade step following this.
 
     // Moodle v2.4.0 release upgrade line
-    // Put any upgrade step following this
-
+    // Put any upgrade step following this.
 
     // Moodle v2.5.0 release upgrade line.
     // Put any upgrade step following this.
 
-
     // Moodle v2.6.0 release upgrade line.
     // Put any upgrade step following this.
 
@@ -99,6 +97,97 @@ function xmldb_lti_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2014060201, 'lti');
     }
 
+    if ($oldversion < 2014061200) {
+
+        // Define table lti_tool_proxies to be created.
+        $table = new xmldb_table('lti_tool_proxies');
+
+        // Adding fields to table lti_tool_proxies.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'Tool Provider');
+        $table->add_field('regurl', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        $table->add_field('state', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
+        $table->add_field('guid', XMLDB_TYPE_CHAR, '255', null, null, null, null);
+        $table->add_field('secret', XMLDB_TYPE_CHAR, '255', null, null, null, null);
+        $table->add_field('vendorcode', XMLDB_TYPE_CHAR, '255', null, null, null, null);
+        $table->add_field('capabilityoffered', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
+        $table->add_field('serviceoffered', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
+        $table->add_field('toolproxy', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        $table->add_field('createdby', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table lti_tool_proxies.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+        // Adding indexes to table lti_tool_proxies.
+        $table->add_index('guid', XMLDB_INDEX_UNIQUE, array('guid'));
+
+        // Conditionally launch create table for lti_tool_proxies.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table lti_tool_settings to be created.
+        $table = new xmldb_table('lti_tool_settings');
+
+        // Adding fields to table lti_tool_settings.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('toolproxyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
+        $table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
+        $table->add_field('settings', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table lti_tool_settings.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('toolproxy', XMLDB_KEY_FOREIGN, array('toolproxyid'), 'lti_tool_proxies', array('id'));
+        $table->add_key('course', XMLDB_KEY_FOREIGN, array('course'), 'course', array('id'));
+        $table->add_key('coursemodule', XMLDB_KEY_FOREIGN, array('coursemoduleid'), 'lti', array('id'));
+
+        // Conditionally launch create table for lti_tool_settings.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table lti_types to be updated.
+        $table = new xmldb_table('lti_types');
+
+        // Adding fields to table lti_types.
+        $field = new xmldb_field('toolproxyid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        $field = new xmldb_field('enabledcapability', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        $field = new xmldb_field('parameter', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        $field = new xmldb_field('icon', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        $field = new xmldb_field('secureicon', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Lti savepoint reached.
+        upgrade_mod_savepoint(true, 2014061200, 'lti');
+    }
+
+    if ($oldversion < 2014100300) {
+
+        mod_lti_upgrade_custom_separator();
+
+        // Lti savepoint reached.
+        upgrade_mod_savepoint(true, 2014100300, 'lti');
+    }
+
     return true;
 }
 
diff --git a/mod/lti/db/upgradelib.php b/mod/lti/db/upgradelib.php
new file mode 100644 (file)
index 0000000..232d410
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// 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/>.
+
+/**
+ * LTI upgrade script.
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Update any custom parameter settings separated by semicolons.
+ */
+function mod_lti_upgrade_custom_separator() {
+    global $DB;
+
+    if ($DB->replace_all_text_supported()) {
+
+        // Initialise parameter array.
+        $params = array('semicolon' => ';', 'likecr' => "%\r%", 'likelf' => "%\n%", 'lf' => "\n");
+
+        // Initialise NOT LIKE clauses to check for CR and LF characters.
+        $notlikecr = $DB->sql_like('value', ':likecr', true, true, true);
+        $notlikelf = $DB->sql_like('value', ':likelf', true, true, true);
+
+        // Update any instances in the lti_types_config table.
+        $sql = 'UPDATE {lti_types_config} ' .
+               'SET value = REPLACE(value, :semicolon, :lf) ' .
+               'WHERE (name = \'customparameters\') AND (' . $notlikecr . ') AND (' . $notlikelf . ')';
+        $DB->execute($sql, $params);
+
+        // Initialise NOT LIKE clauses to check for CR and LF characters.
+        $notlikecr = $DB->sql_like('instructorcustomparameters', ':likecr', true, true, true);
+        $notlikelf = $DB->sql_like('instructorcustomparameters', ':likelf', true, true, true);
+
+        // Update any instances in the lti table.
+        $sql = 'UPDATE {lti} ' .
+               'SET instructorcustomparameters = REPLACE(instructorcustomparameters, :semicolon, :lf) ' .
+               'WHERE (instructorcustomparameters IS NOT NULL) AND (' . $notlikecr . ') AND (' . $notlikelf . ')';
+        $DB->execute($sql, $params);
+
+    }
+
+}
index 2b13b9e..d57a0dc 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file defines de main basiclti configuration form
@@ -58,8 +58,9 @@ class mod_lti_edit_types_form extends moodleform{
 
         $mform    =& $this->_form;
 
-        //-------------------------------------------------------------------------------
-        // Add basiclti elements
+        $istool = $this->_customdata->istool;
+
+        // Add basiclti elements.
         $mform->addElement('header', 'setup', get_string('tool_settings', 'lti'));
 
         $mform->addElement('text', 'lti_typename', get_string('typename', 'lti'));
@@ -67,24 +68,37 @@ class mod_lti_edit_types_form extends moodleform{
         $mform->addHelpButton('lti_typename', 'typename', 'lti');
         $mform->addRule('lti_typename', null, 'required', null, 'client');
 
-        $mform->addElement('text', 'lti_toolurl', get_string('toolurl', 'lti'), array('size'=>'64'));
+        $mform->addElement('text', 'lti_toolurl', get_string('toolurl', 'lti'), array('size' => '64'));
         $mform->setType('lti_toolurl', PARAM_TEXT);
         $mform->addHelpButton('lti_toolurl', 'toolurl', 'lti');
-        $mform->addRule('lti_toolurl', null, 'required', null, 'client');
+        if (!$istool) {
+            $mform->addRule('lti_toolurl', null, 'required', null, 'client');
+        } else {
+            $mform->disabledIf('lti_toolurl', null);
+        }
 
-        $mform->addElement('text', 'lti_resourcekey', get_string('resourcekey_admin', 'lti'));
-        $mform->setType('lti_resourcekey', PARAM_TEXT);
-        $mform->addHelpButton('lti_resourcekey', 'resourcekey_admin', 'lti');
+        if (!$istool) {
+            $mform->addElement('text', 'lti_resourcekey', get_string('resourcekey_admin', 'lti'));
+            $mform->setType('lti_resourcekey', PARAM_TEXT);
+            $mform->addHelpButton('lti_resourcekey', 'resourcekey_admin', 'lti');
 
-        $mform->addElement('passwordunmask', 'lti_password', get_string('password_admin', 'lti'));
-        $mform->setType('lti_password', PARAM_TEXT);
-        $mform->addHelpButton('lti_password', 'password_admin', 'lti');
+            $mform->addElement('passwordunmask', 'lti_password', get_string('password_admin', 'lti'));
+            $mform->setType('lti_password', PARAM_TEXT);
+            $mform->addHelpButton('lti_password', 'password_admin', 'lti');
+        }
 
-        $mform->addElement('textarea', 'lti_customparameters', get_string('custom', 'lti'), array('rows'=>4, 'cols'=>60));
+        if ($istool) {
+            $mform->addElement('textarea', 'lti_parameters', get_string('parameter', 'lti'), array('rows' => 4, 'cols' => 60));
+            $mform->setType('lti_parameters', PARAM_TEXT);
+            $mform->addHelpButton('lti_parameters', 'parameter', 'lti');
+            $mform->disabledIf('lti_parameters', null);
+        }
+
+        $mform->addElement('textarea', 'lti_customparameters', get_string('custom', 'lti'), array('rows' => 4, 'cols' => 60));
         $mform->setType('lti_customparameters', PARAM_TEXT);
         $mform->addHelpButton('lti_customparameters', 'custom', 'lti');
 
-        if (!empty($this->_customdata->isadmin)) {
+        if (!$istool && !empty($this->_customdata->isadmin)) {
             $mform->addElement('checkbox', 'lti_coursevisible', '&nbsp;', ' ' . get_string('show_in_course', 'lti'));
             $mform->addHelpButton('lti_coursevisible', 'show_in_course', 'lti');
         } else {
@@ -95,7 +109,7 @@ class mod_lti_edit_types_form extends moodleform{
         $mform->addElement('hidden', 'typeid');
         $mform->setType('typeid', PARAM_INT);
 
-        $launchoptions=array();
+        $launchoptions = array();
         $launchoptions[LTI_LAUNCH_CONTAINER_EMBED] = get_string('embed', 'lti');
         $launchoptions[LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS] = get_string('embed_no_blocks', 'lti');
         $launchoptions[LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW] = get_string('existing_window', 'lti');
@@ -106,76 +120,72 @@ class mod_lti_edit_types_form extends moodleform{
         $mform->addHelpButton('lti_launchcontainer', 'default_launch_container', 'lti');
         $mform->setType('lti_launchcontainer', PARAM_INT);
 
-        // Add privacy preferences fieldset where users choose whether to send their data
-        $mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
-
-        $options=array();
-        $options[0] = get_string('never', 'lti');
-        $options[1] = get_string('always', 'lti');
-        $options[2] = get_string('delegate', 'lti');
-
-        $mform->addElement('select', 'lti_sendname', get_string('share_name_admin', 'lti'), $options);
-        $mform->setType('lti_sendname', PARAM_INT);
-        $mform->setDefault('lti_sendname', '2');
-        $mform->addHelpButton('lti_sendname', 'share_name_admin', 'lti');
-
-        $mform->addElement('select', 'lti_sendemailaddr', get_string('share_email_admin', 'lti'), $options);
-        $mform->setType('lti_sendemailaddr', PARAM_INT);
-        $mform->setDefault('lti_sendemailaddr', '2');
-        $mform->addHelpButton('lti_sendemailaddr', 'share_email_admin', 'lti');
-
-        //-------------------------------------------------------------------------------
-        // LTI Extensions
-
-        // Add grading preferences fieldset where the tool is allowed to return grades
-        $mform->addElement('select', 'lti_acceptgrades', get_string('accept_grades_admin', 'lti'), $options);
-        $mform->setType('lti_acceptgrades', PARAM_INT);
-        $mform->setDefault('lti_acceptgrades', '2');
-        $mform->addHelpButton('lti_acceptgrades', 'accept_grades_admin', 'lti');
-
-        // Add grading preferences fieldset where the tool is allowed to retrieve rosters
-        //$mform->addElement('select', 'lti_allowroster', get_string('share_roster_admin', 'lti'), $options);
-        //$mform->setDefault('lti_allowroster', '2');
-        //$mform->addHelpButton('lti_allowroster', 'share_roster_admin', 'lti');
-
-        $mform->addElement('checkbox', 'lti_forcessl', '&nbsp;', ' ' . get_string('force_ssl', 'lti'), $options);
-        $mform->setType('lti_forcessl', PARAM_BOOL);
-        if (!empty($CFG->mod_lti_forcessl)) {
-            $mform->setDefault('lti_forcessl', '1');
-            $mform->freeze('lti_forcessl');
-        } else {
-            $mform->setDefault('lti_forcessl', '0');
-        }
-        $mform->addHelpButton('lti_forcessl', 'force_ssl', 'lti');
-
-        if (!empty($this->_customdata->isadmin)) {
-            //-------------------------------------------------------------------------------
-            // Add setup parameters fieldset
-            $mform->addElement('header', 'setupoptions', get_string('miscellaneous', 'lti'));
-
-            // Adding option to change id that is placed in context_id
-            $idoptions = array();
-            $idoptions[0] = get_string('id', 'lti');
-            $idoptions[1] = get_string('courseid', 'lti');
-
-            $mform->addElement('text', 'lti_organizationid', get_string('organizationid', 'lti'));
-            $mform->setType('lti_organizationid', PARAM_TEXT);
-            $mform->addHelpButton('lti_organizationid', 'organizationid', 'lti');
-
-            $mform->addElement('text', 'lti_organizationurl', get_string('organizationurl', 'lti'));
-            $mform->setType('lti_organizationurl', PARAM_TEXT);
-            $mform->addHelpButton('lti_organizationurl', 'organizationurl', 'lti');
+        if (!$istool) {
+            // Add privacy preferences fieldset where users choose whether to send their data.
+            $mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
+
+            $options = array();
+            $options[0] = get_string('never', 'lti');
+            $options[1] = get_string('always', 'lti');
+            $options[2] = get_string('delegate', 'lti');
+
+            $mform->addElement('select', 'lti_sendname', get_string('share_name_admin', 'lti'), $options);
+            $mform->setType('lti_sendname', PARAM_INT);
+            $mform->setDefault('lti_sendname', '2');
+            $mform->addHelpButton('lti_sendname', 'share_name_admin', 'lti');
+
+            $mform->addElement('select', 'lti_sendemailaddr', get_string('share_email_admin', 'lti'), $options);
+            $mform->setType('lti_sendemailaddr', PARAM_INT);
+            $mform->setDefault('lti_sendemailaddr', '2');
+            $mform->addHelpButton('lti_sendemailaddr', 'share_email_admin', 'lti');
+
+            // LTI Extensions.
+
+            // Add grading preferences fieldset where the tool is allowed to return grades.
+            $mform->addElement('select', 'lti_acceptgrades', get_string('accept_grades_admin', 'lti'), $options);
+            $mform->setType('lti_acceptgrades', PARAM_INT);
+            $mform->setDefault('lti_acceptgrades', '2');
+            $mform->addHelpButton('lti_acceptgrades', 'accept_grades_admin', 'lti');
+
+            $mform->addElement('checkbox', 'lti_forcessl', '&nbsp;', ' ' . get_string('force_ssl', 'lti'), $options);
+            $mform->setType('lti_forcessl', PARAM_BOOL);
+            if (!empty($CFG->mod_lti_forcessl)) {
+                $mform->setDefault('lti_forcessl', '1');
+                $mform->freeze('lti_forcessl');
+            } else {
+                $mform->setDefault('lti_forcessl', '0');
+            }
+            $mform->addHelpButton('lti_forcessl', 'force_ssl', 'lti');
+
+            if (!empty($this->_customdata->isadmin)) {
+                // Add setup parameters fieldset.
+                $mform->addElement('header', 'setupoptions', get_string('miscellaneous', 'lti'));
+
+                // Adding option to change id that is placed in context_id.
+                $idoptions = array();
+                $idoptions[0] = get_string('id', 'lti');
+                $idoptions[1] = get_string('courseid', 'lti');
+
+                $mform->addElement('text', 'lti_organizationid', get_string('organizationid', 'lti'));
+                $mform->setType('lti_organizationid', PARAM_TEXT);
+                $mform->addHelpButton('lti_organizationid', 'organizationid', 'lti');
+
+                $mform->addElement('text', 'lti_organizationurl', get_string('organizationurl', 'lti'));
+                $mform->setType('lti_organizationurl', PARAM_TEXT);
+                $mform->addHelpButton('lti_organizationurl', 'organizationurl', 'lti');
+            }
         }
 
         /* Suppress this for now - Chuck
-        $mform->addElement('text', 'lti_organizationdescr', get_string('organizationdescr', 'lti'));
-        $mform->setType('lti_organizationdescr', PARAM_TEXT);
-        $mform->addHelpButton('lti_organizationdescr', 'organizationdescr', 'lti');
-        */
+         * mform->addElement('text', 'lti_organizationdescr', get_string('organizationdescr', 'lti'))
+         * mform->setType('lti_organizationdescr', PARAM_TEXT)
+         * mform->addHelpButton('lti_organizationdescr', 'organizationdescr', 'lti')
+         */
 
-        //-------------------------------------------------------------------------------
+        /*
         // Add a hidden element to signal a tool fixing operation after a problematic backup - restore process
         //$mform->addElement('hidden', 'lti_fix');
+        */
 
         $tab = optional_param('tab', '', PARAM_ALPHAEXT);
         $mform->addElement('hidden', 'tab', $tab);
@@ -185,8 +195,7 @@ class mod_lti_edit_types_form extends moodleform{
         $mform->addElement('hidden', 'course', $courseid);
         $mform->setType('course', PARAM_INT);
 
-        //-------------------------------------------------------------------------------
-        // Add standard buttons, common to all modules
+        // Add standard buttons, common to all modules.
         $this->add_action_buttons();
 
     }
index 3dd7931..6eec41f 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains submissions-specific code for the lti module
index eab0280..1a0e97b 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This page lists all the instances of lti in a particular course
@@ -48,9 +48,9 @@
 require_once("../../config.php");
 require_once($CFG->dirroot.'/mod/lti/lib.php');
 
-$id = required_param('id', PARAM_INT);   // course id
+$id = required_param('id', PARAM_INT);   // Course id.
 
-$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
+$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
 
 require_login($course);
 $PAGE->set_pagelayout('incourse');
@@ -69,16 +69,16 @@ $PAGE->set_heading($course->fullname);
 
 echo $OUTPUT->header();
 
-// Print the main part of the page
+// Print the main part of the page.
 echo $OUTPUT->heading(get_string("modulenamepluralformatted", "lti"));
 
-// Get all the appropriate data
+// Get all the appropriate data.
 if (! $basicltis = get_all_instances_in_course("lti", $course)) {
     notice(get_string('noltis', 'lti'), "../../course/view.php?id=$course->id");
     die;
 }
 
-// Print the list of instances (your module will probably extend this)
+// Print the list of instances (your module will probably extend this).
 $timenow = time();
 $strname = get_string("name");
 $usesections = course_format_uses_sections($course->format);
@@ -96,10 +96,10 @@ if ($usesections) {
 
 foreach ($basicltis as $basiclti) {
     if (!$basiclti->visible) {
-        //Show dimmed if the mod is hidden
+        // Show dimmed if the mod is hidden.
         $link = "<a class=\"dimmed\" href=\"view.php?id=$basiclti->coursemodule\">$basiclti->name</a>";
     } else {
-        //Show normal if the mod is visible
+        // Show normal if the mod is visible.
         $link = "<a href=\"view.php?id=$basiclti->coursemodule\">$basiclti->name</a>";
     }
 
@@ -114,5 +114,5 @@ echo "<br />";
 
 echo html_writer::table($table);
 
-// Finish the page
+// Finish the page.
 echo $OUTPUT->footer();
index 2a2cefb..7e28380 100644 (file)
@@ -59,7 +59,7 @@ if ($data = $form->get_data()) {
         $fromdb = lti_get_type($typeid);
         $json = json_encode($fromdb);
 
-        //Output script to update the calling window.
+        // Output script to update the calling window.
         $script = "
             <html>
                 <script type=\"text/javascript\">
@@ -80,7 +80,7 @@ if ($data = $form->get_data()) {
         $fromdb = lti_get_type($id);
         $json = json_encode($fromdb);
 
-        //Output script to update the calling window.
+        // Output script to update the calling window.
         $script = "
             <html>
                 <script type=\"text/javascript\">
@@ -107,7 +107,7 @@ if ($data = $form->get_data()) {
     die;
 }
 
-//Delete action is called via ajax
+// Delete action is called via ajax.
 if ($action == 'delete') {
     lti_delete_type($typeid);
     die;
index 4c40700..4102e39 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains en_utf8 translation of the Basic LTI module
@@ -49,6 +49,7 @@
 defined('MOODLE_INTERNAL') || die;
 
 $string['accept'] = 'Accept';
+$string['accepted'] = 'Accepted';
 $string['accept_grades'] = 'Accept grades from the tool';
 $string['accept_grades_admin'] = 'Accept grades from the tool';
 $string['accept_grades_admin_help'] = 'Specify whether the tool provider can add, update, read, and delete grades associated with instances of this tool type.
@@ -72,7 +73,7 @@ $string['allowinstructorcustom'] = 'Allow teachers to add custom parameters';
 $string['allowsetting'] = 'Allow tool to store 8K of settings in Moodle';
 $string['always'] = 'Always';
 $string['automatic'] = 'Automatic, based on Launch URL';
-$string['baseurl'] = 'Base URL';
+$string['baseurl'] = 'Base URL/Tool Registration Name';
 $string['basiclti'] = 'LTI';
 $string['basiclti_base_string'] = 'LTI OAuth Base String';
 $string['basiclti_endpoint'] = 'LTI Launch Endpoint';
@@ -83,8 +84,13 @@ $string['basicltifieldset'] = 'Custom example fieldset';
 $string['basicltiintro'] = 'Activity Description';
 $string['basicltiname'] = 'Activity Name';
 $string['basicltisettings'] = 'Basic Learning Tool Interoperability Settings';
+$string['cancel'] = 'Cancel';
+$string['cancelled'] = 'Cancelled';
 $string['cannot_delete'] = 'You may not delete this tool configuration.';
 $string['cannot_edit'] = 'You may not edit this tool configuration.';
+$string['capabilities'] = 'Capabilities';
+$string['capabilities_help'] = 'Select those capabilities which you wish to offer to the tool provider.  More than one capability can be selected.';
+$string['click_to_continue'] = '<a href="{$a->link}" target="_top">Click to continue</a>';
 $string['comment'] = 'Comment';
 $string['configpassword'] = 'Default Remote Tool Password';
 $string['configpreferheight'] = 'Default preferred height';
@@ -93,6 +99,7 @@ $string['configpreferwidth'] = 'Default preferred width';
 $string['configresourceurl'] = 'Default Resource URL';
 $string['configtoolurl'] = 'Default Remote Tool URL';
 $string['configtypes'] = 'Enable LTI Applications';
+$string['configured'] = 'Configured';
 $string['course_tool_types'] = 'Course tool types';
 $string['courseid'] = 'Course id number';
 $string['coursemisconf'] = 'Course is misconfigured';
@@ -101,7 +108,7 @@ $string['curllibrarymissing'] = 'PHP Curl library must be installed to use LTI';
 $string['custom'] = 'Custom parameters';
 $string['custom_config'] = 'Using custom tool configuration.';
 $string['custom_help'] = 'Custom parameters are settings used by the tool provider. For example, a custom parameter may be used to display
-a specific resource from the provider.
+a specific resource from the provider.  Each parameter should be entered on a separate line using a format of "name=value"; for example, "chapter=3".
 
 It is safe to leave this field unchanged unless directed by the tool provider.';
 $string['custominstr'] = 'Custom parameters';
@@ -141,6 +148,7 @@ $string['domain_mismatch'] = 'Launch URL\'s domain does not match tool configura
 $string['donot'] = 'Do not send';
 $string['donotaccept'] = 'Do not accept';
 $string['donotallow'] = 'Do not allow';
+$string['duplicateregurl'] = 'This registration URL is already in use';
 $string['edittype'] = 'Edit external tool configuration';
 $string['embed'] = 'Embed';
 $string['embed_no_blocks'] = 'Embed, without blocks';
@@ -250,6 +258,8 @@ Tool types listed on this page are separated into three categories:
         Teachers may still use tools from these providers if they have a consumer key and shared secret, or if none is required.
 * **Rejected** - These tools providers are flagged as ones which an administrator has no intention of making available to the entire
         Moodle instance. Teachers may still use tools from these providers if they have a consumer key and shared secret, or if none is required.';
+$string['manage_tools'] = 'Manage External Tool Types';
+$string['manage_tool_proxies'] = 'Manage External Tool Registrations';
 $string['miscellaneous'] = 'Miscellaneous';
 $string['misconfiguredtools'] = 'Misconfigured tool instances were detected';
 $string['missingparameterserror'] = 'The page is misconfigured: "{$a}"';
@@ -267,28 +277,37 @@ External tool activities differ from URL resources in a few ways:
 $string['modulename_link'] = 'mod/lti/view';
 $string['modulenameplural'] = 'External Tools';
 $string['modulenamepluralformatted'] = 'LTI Instances';
+$string['name'] = 'Name';
 $string['never'] = 'Never';
 $string['new_window'] = 'New window';
 $string['no_lti_configured'] = 'There are no active External Tools configured.';
 $string['no_lti_pending'] = 'There are no pending External Tools.';
 $string['no_lti_rejected'] = 'There are no rejected External Tools.';
+$string['no_tp_accepted'] = 'There are no accepted External Tool Registrations.';
+$string['no_tp_cancelled'] = 'There are no cancelled External Tool Registrations .';
+$string['no_tp_configured'] = 'There are no unregistered External Tool Registrations configured.';
+$string['no_tp_pending'] = 'There are no pending External Tool Registrations .';
+$string['no_tp_rejected'] = 'There are no rejected External Tool Registrations .';
 $string['noattempts'] = 'No attempts have been made on this tool instance';
 $string['noltis'] = 'There are no lti instances';
+$string['noprofileservice'] = 'Profile service not found';
 $string['noservers'] = 'No servers found';
 $string['notypes'] = 'There are currently no LTI tools setup in Moodle. Click the Install link above to add some.';
 $string['noviewusers'] = 'No users were found with permissions to use this tool';
 $string['optionalsettings'] = 'Optional settings';
-$string['organization'] ='Organization details';
-$string['organizationdescr'] ='Organization Description';
-$string['organizationid'] ='Organization ID';
+$string['organization'] = 'Organization details';
+$string['organizationdescr'] = 'Organization Description';
+$string['organizationid'] = 'Organization ID';
 $string['organizationid_help'] = 'A unique identifier for this Moodle instance. Typically, the DNS name of the organization is used.
 
 If this field is left blank, the host name of this Moodle site will be used as the default value.';
-$string['organizationurl'] ='Organization URL';
+$string['organizationurl'] = 'Organization URL';
 $string['organizationurl_help'] = 'The base URL of this Moodle instance.
 
 If this field is left blank, a default value will be used based on the site configuration.';
 $string['pagesize'] = 'Submissions shown per page';
+$string['parameter'] = 'Tool parameters';
+$string['parameter_help'] = 'Tool parameters are settings requested to be passed by the tool provider in the accepted tool proxy.';
 $string['password'] = 'Shared Secret';
 $string['password_admin'] = 'Shared Secret';
 $string['password_admin_help'] = 'The shared secret can be thought of as a password used to authenticate access to the tool. It should be provided
@@ -318,6 +337,14 @@ $string['privacy'] = 'Privacy';
 $string['quickgrade'] = 'Allow quick grading';
 $string['quickgrade_help'] = 'If enabled, multiple tools can be graded on one page. Add grades and comments then click the "Save all my feedback" button to save all changes for that page.';
 $string['redirect'] = 'You will be redirected in few seconds. If you are not, press the button.';
+$string['register'] = 'Register';
+$string['register_warning'] = 'The registration page seems to be taking a while to open.  If it does not appear, check that you entered the correct URL in the configuration settings.';
+$string['registertype'] = 'Configure a new External Tool Registration';
+$string['registration_options'] = 'Registration Options';
+$string['registrationname'] = 'Tool Provider name';
+$string['registrationname_help'] = 'Enter the name of the tool provider being registered.';
+$string['registrationurl'] = 'Registration URL';
+$string['registrationurl_help'] = 'The registration URL should be available from the tool provider as the location to which registration requests should be sent.';
 $string['reject'] = 'Reject';
 $string['rejected'] = 'Rejected';
 $string['resource'] = 'Resource';
@@ -358,6 +385,8 @@ is set to always launch through SSL.
 
 The Launch URL may also be set to an https address to force launching through SSL, and this field may be left blank.';
 $string['send'] = 'Send';
+$string['services'] = 'Services';
+$string['services_help'] = 'Select those services which you wish to offer to the tool provider.  More than one service can be selected.';
 $string['setupoptions'] = 'Setup Options';
 $string['share_email'] = 'Share launcher\'s email with the tool';
 $string['share_email_admin'] = 'Share launcher\'s email with tool';
@@ -396,11 +425,31 @@ $string['size'] = 'Size parameters';
 $string['submission'] = 'Submission';
 $string['submissions'] = 'Submissions';
 $string['submissionsfor'] = 'Submissions for {$a}';
+$string['subplugintype_ltiresource'] = 'LTI service resource';
+$string['subplugintype_ltiresource_plural'] = 'LTI service resources';
+$string['subplugintype_ltiservice'] = 'LTI service';
+$string['subplugintype_ltiservice_plural'] = 'LTI services';
 $string['subplugintype_ltisource'] = 'LTI source';
 $string['subplugintype_ltisource_plural'] = 'LTI sources';
 $string['toggle_debug_data'] = 'Toggle Debug Data';
 $string['tool_config_not_found'] = 'Tool configuration not found for this URL.';
 $string['tool_settings'] = 'Tool Settings';
+$string['toolproxy'] = 'External Tool Registrations';
+$string['toolproxy_help'] = 'External tool registrations allow Moodle site administrators to configure external tools from a tool proxy obtained from
+a tool provider supporting LTI 2.0.  A registration URL provided by the tool provider is all that is required to initiate the process.  The capabilities
+and services offered to the tool provider are selected when configuring a new registration.
+
+Tool registrations listed on this page are separated into four categories:
+
+* **Configured** - These tool registrations have been set up but the registration process has not yet been started.
+* **Pending** - The regisitration process for these tool registrations has been started but has not completed.  Open and save the settings to move it
+        back to the \'Configured\' category.
+* **Accepted** - These tool registrations have been approved; the resources specified in the tool proxy will appear on the external tool types page
+        with an initial status of \'Pending\'.
+* **Rejected** - These tool registrations are ones which were rejected during the registration process.  Open and save the settings to move it
+        back to the \'Configured\' category so the registration process cna be restarted.';
+$string['toolproxyregistration'] = 'External Tool Registration';
+$string['toolregistration'] = 'External Tool Registration';
 $string['toolsetup'] = 'External Tool Configuration';
 $string['toolurl'] = 'Tool Base URL';
 $string['toolurl_help'] = 'The tool base URL is used to match tool launch URLs to the correct tool configuration. Prefixing the URL with http(s) is optional.
index 67e88ab..580d88b 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains all necessary code to view a lti activity instance
@@ -50,7 +50,7 @@ require_once("../../config.php");
 require_once($CFG->dirroot.'/mod/lti/lib.php');
 require_once($CFG->dirroot.'/mod/lti/locallib.php');
 
-$id = required_param('id', PARAM_INT); // Course Module ID
+$id = required_param('id', PARAM_INT); // Course Module ID.
 
 $cm = get_coursemodule_from_id('lti', $id, 0, false, MUST_EXIST);
 $lti = $DB->get_record('lti', array('id' => $cm->instance), '*', MUST_EXIST);
index fd47118..a41d980 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains a library of functions and constants for the lti module
@@ -63,17 +63,20 @@ function lti_get_extra_capabilities() {
  * @return mixed True if module supports feature, false if not, null if doesn't know
  */
 function lti_supports($feature) {
-    switch($feature) {
-        case FEATURE_GROUPS:                  return false;
-        case FEATURE_GROUPINGS:               return false;
-        case FEATURE_MOD_INTRO:               return true;
-        case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
-        case FEATURE_GRADE_HAS_GRADE:         return true;
-        case FEATURE_GRADE_OUTCOMES:          return true;
-        case FEATURE_BACKUP_MOODLE2:          return true;
-        case FEATURE_SHOW_DESCRIPTION:        return true;
-
-        default: return null;
+    switch ($feature) {
+        case FEATURE_GROUPS:
+        case FEATURE_GROUPINGS:
+            return false;
+        case FEATURE_MOD_INTRO:
+        case FEATURE_COMPLETION_TRACKS_VIEWS:
+        case FEATURE_GRADE_HAS_GRADE:
+        case FEATURE_GRADE_OUTCOMES:
+        case FEATURE_BACKUP_MOODLE2:
+        case FEATURE_SHOW_DESCRIPTION:
+            return true;
+
+        default:
+            return null;
     }
 }
 
@@ -90,6 +93,10 @@ function lti_add_instance($lti, $mform) {
     global $DB, $CFG;
     require_once($CFG->dirroot.'/mod/lti/locallib.php');
 
+    if (!isset($lti->toolurl)) {
+        $lti->toolurl = '';
+    }
+
     $lti->timecreated = time();
     $lti->timemodified = $lti->timecreated;
     $lti->servicesalt = uniqid('', true);
@@ -177,9 +184,13 @@ function lti_delete_instance($id) {
 
     $result = true;
 
-    # Delete any dependent records here #
+    // Delete any dependent records here.
     lti_grade_item_delete($basiclti);
 
+    $ltitype = $DB->get_record('lti_types', array('id' => $basiclti->typeid));
+    $DB->delete_records('lti_tool_settings',
+        array('toolproxyid' => $ltitype->toolproxyid, 'course' => $basiclti->course, 'coursemoduleid' => $id));
+
     return $DB->delete_records("lti", array("id" => $basiclti->id));
 }
 
@@ -313,7 +324,7 @@ function lti_user_complete($course, $user, $mod, $basiclti) {
  * @TODO: implement this moodle function
  **/
 function lti_print_recent_activity($course, $isteacher, $timestart) {
-    return false;  //  True if anything was printed, otherwise false
+    return false;  //  True if anything was printed, otherwise false.
 }
 
 /**
@@ -361,11 +372,11 @@ function lti_grades($basicltiid) {
 function lti_scale_used ($basicltiid, $scaleid) {
     $return = false;
 
-    //$rec = get_record("basiclti","id","$basicltiid","scale","-$scaleid");
+    // $rec = get_record("basiclti","id","$basicltiid","scale","-$scaleid");
     //
-    //if (!empty($rec)  && !empty($scaleid)) {
-    //    $return = true;
-    //}
+    // if (!empty($rec)  && !empty($scaleid)) {
+    //     $return = true;
+    // }
 
     return $return;
 }
@@ -428,11 +439,11 @@ function lti_get_lti_types() {
  * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook
  * @return int 0 if ok, error code otherwise
  */
-function lti_grade_item_update($basiclti, $grades=null) {
+function lti_grade_item_update($basiclti, $grades = null) {
     global $CFG;
     require_once($CFG->libdir.'/gradelib.php');
 
-    $params = array('itemname'=>$basiclti->name, 'idnumber'=>$basiclti->cmidnumber);
+    $params = array('itemname' => $basiclti->name, 'idnumber' => $basiclti->cmidnumber);
 
     if ($basiclti->grade > 0) {
         $params['gradetype'] = GRADE_TYPE_VALUE;
@@ -444,10 +455,10 @@ function lti_grade_item_update($basiclti, $grades=null) {
         $params['scaleid']   = -$basiclti->grade;
 
     } else {
-        $params['gradetype'] = GRADE_TYPE_TEXT; // allow text comments only
+        $params['gradetype'] = GRADE_TYPE_TEXT; // Allow text comments only.
     }
 
-    if ($grades  === 'reset') {
+    if ($grades === 'reset') {
         $params['reset'] = true;
         $grades = null;
     }
@@ -466,7 +477,7 @@ function lti_grade_item_delete($basiclti) {
     global $CFG;
     require_once($CFG->libdir.'/gradelib.php');
 
-    return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, null, array('deleted'=>1));
+    return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, null, array('deleted' => 1));
 }
 
 function lti_extend_settings_navigation($settings, $parentnode) {
@@ -476,7 +487,7 @@ function lti_extend_settings_navigation($settings, $parentnode) {
         $keys = $parentnode->get_children_key_list();
 
         $node = navigation_node::create('Submissions',
-            new moodle_url('/mod/lti/grade.php', array('id'=>$PAGE->cm->id)),
+            new moodle_url('/mod/lti/grade.php', array('id' => $PAGE->cm->id)),
             navigation_node::TYPE_SETTING, null, 'mod_lti_submissions');
 
         $parentnode->add_node($node, $keys[1]);
diff --git a/mod/lti/localadminlib.php b/mod/lti/localadminlib.php
deleted file mode 100644 (file)
index 1ccb424..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-// 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/>.
-//
-// 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
-
-/**
- * This file contains some functions and classes used by the lti
- * module administration
- *
- * @package mod_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     Chris Scribner
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die;
-
-require_once($CFG->libdir.'/adminlib.php');
-
-/**
- *
- * @TODO: finish doc this class and it's functions
- */
-class admin_setting_ltimodule_configlink extends admin_setting {
-
-    /**
-     * Constructor
-     * @param string $name of setting
-     * @param string $visiblename localised
-     * @param string $description long localised info
-     */
-    public function __construct($name, $visiblename, $description) {
-        parent::__construct($name, $visiblename, $description, '');
-    }
-
-    public function get_setting() {
-        return true;
-    }
-
-    public function write_setting($data) {
-        return "";
-    }
-
-    public function output_html($data, $query='') {
-        global $CFG;
-        return format_admin_setting($this, "",
-                '<div class="defaultsnext" >'.
-                '<a href="'.$CFG->wwwroot.'/mod/lti/typessettings.php">'.get_string('filterconfig', 'lti').'</a>'.
-                '</div>',
-                $this->description, true, '', null, $query);
-    }
-}
index 4eeaf9d..08d3ca0 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file contains the library of functions and constants for the lti module
@@ -48,7 +48,7 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-// TODO: Switch to core oauthlib once implemented - MDL-30149
+// TODO: Switch to core oauthlib once implemented - MDL-30149.
 use moodle\mod\lti as lti;
 
 require_once($CFG->dirroot.'/mod/lti/OAuth.php');
@@ -65,6 +65,12 @@ 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_TOOL_PROXY_TAB', 4);
+
+define('LTI_TOOL_PROXY_STATE_CONFIGURED', 1);
+define('LTI_TOOL_PROXY_STATE_PENDING', 2);
+define('LTI_TOOL_PROXY_STATE_ACCEPTED', 3);
+define('LTI_TOOL_PROXY_STATE_REJECTED', 4);
 
 define('LTI_SETTING_NEVER', 0);
 define('LTI_SETTING_ALWAYS', 1);
@@ -87,12 +93,13 @@ function lti_view($instance) {
         }
     } else {
         $typeid = $instance->typeid;
+        $tool = lti_get_type($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.
+        // 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;
@@ -103,39 +110,45 @@ function lti_view($instance) {
         $typeconfig['forcessl'] = '0';
     }
 
-    //Default the organizationid if not specified
+    // Default the organizationid if not specified.
     if (empty($typeconfig['organizationid'])) {
         $urlparts = parse_url($CFG->wwwroot);
 
         $typeconfig['organizationid'] = $urlparts['host'];
     }
 
-    if (!empty($instance->resourcekey)) {
-        $key = $instance->resourcekey;
-    } else if (!empty($typeconfig['resourcekey'])) {
-        $key = $typeconfig['resourcekey'];
-    } else {
-        $key = '';
-    }
-
-    if (!empty($instance->password)) {
-        $secret = $instance->password;
-    } else if (!empty($typeconfig['password'])) {
-        $secret = $typeconfig['password'];
+    if (isset($tool->toolproxyid)) {
+        $toolproxy = lti_get_tool_proxy($tool->toolproxyid);
+        $key = $toolproxy->guid;
+        $secret = $toolproxy->secret;
     } else {
-        $secret = '';
+        $toolproxy = null;
+        if (!empty($instance->resourcekey)) {
+            $key = $instance->resourcekey;
+        } else if (!empty($typeconfig['resourcekey'])) {
+            $key = $typeconfig['resourcekey'];
+        } else {
+            $key = '';
+        }
+        if (!empty($instance->password)) {
+            $secret = $instance->password;
+        } else if (!empty($typeconfig['password'])) {
+            $secret = $typeconfig['password'];
+        } else {
+            $secret = '';
+        }
     }
 
     $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];
     $endpoint = trim($endpoint);
 
-    //If the current request is using SSL and a secure tool URL is specified, use it
+    // If the current request is using SSL and a secure tool URL is specified, use it.
     if (lti_request_is_using_ssl() && !empty($instance->securetoolurl)) {
         $endpoint = trim($instance->securetoolurl);
     }
 
-    //If SSL is forced, use the secure tool url if specified. Otherwise, make sure https is on the normal launch URL.
-    if ($typeconfig['forcessl'] == '1') {
+    // If SSL is forced, use the secure tool url if specified. Otherwise, make sure https is on the normal launch URL.
+    if (isset($typeconfig['forcessl']) && ($typeconfig['forcessl'] == '1')) {
         if (!empty($instance->securetoolurl)) {
             $endpoint = trim($instance->securetoolurl);
         }
@@ -150,32 +163,33 @@ function lti_view($instance) {
     $orgid = $typeconfig['organizationid'];
 
     $course = $PAGE->course;
-    $requestparams = lti_build_request($instance, $typeconfig, $course, $typeid);
-
-    $launchcontainer = lti_get_launch_container($instance, $typeconfig);
-    $returnurlparams = array('course' => $course->id, 'launch_container' => $launchcontainer, 'instanceid' => $instance->id);
-
-    if ( $orgid ) {
-        $requestparams["tool_consumer_instance_guid"] = $orgid;
-    }
-    if (!empty($CFG->mod_lti_institution_name)) {
-        $requestparams['tool_consumer_instance_name'] = $CFG->mod_lti_institution_name;
+    $islti2 = isset($tool->toolproxyid);
+    $allparams = lti_build_request($instance, $typeconfig, $course, $typeid, $islti2);
+    if ($islti2) {
+        $requestparams = lti_build_request_lti2($tool, $allparams);
     } else {
-        $requestparams['tool_consumer_instance_name'] = get_site()->fullname;
+        $requestparams = $allparams;
     }
-    if (empty($key) || empty($secret)) {
-        $returnurlparams['unsigned'] = '1';
+    $requestparams = array_merge($requestparams, lti_build_standard_request($instance, $orgid, $islti2));
+    $customstr = '';
+    if (isset($typeconfig['customparameters'])) {
+        $customstr = $typeconfig['customparameters'];
     }
+    $requestparams = array_merge($requestparams, lti_build_custom_parameters($toolproxy, $tool, $instance, $allparams, $customstr,
+        $instance->instructorcustomparameters, $islti2));
+
+    $launchcontainer = lti_get_launch_container($instance, $typeconfig);
+    $returnurlparams = array('course' => $course->id, 'launch_container' => $launchcontainer, 'instanceid' => $instance->id);
 
     // Add the return URL. We send the launch container along to help us avoid frames-within-frames when the user returns.
-    $url = new moodle_url('/mod/lti/return.php', $returnurlparams);
+    $url = new \moodle_url('/mod/lti/return.php', $returnurlparams);
     $returnurl = $url->out(false);
 
-    if ($typeconfig['forcessl'] == '1') {
+    if (isset($typeconfig['forcessl']) && ($typeconfig['forcessl'] == '1')) {
         $returnurl = lti_ensure_url_is_https($returnurl);
     }
 
-    $target = null;
+    $target = '';
     switch($launchcontainer) {
         case LTI_LAUNCH_CONTAINER_EMBED:
         case LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS:
@@ -188,7 +202,7 @@ function lti_view($instance) {
             $target = 'window';
             break;
     }
-    if (!is_null($target)) {
+    if (!empty($target)) {
         $requestparams['launch_presentation_document_target'] = $target;
     }
 
@@ -208,7 +222,7 @@ function lti_view($instance) {
     if (!empty($key) && !empty($secret)) {
         $parms = lti_sign_parameters($requestparams, $endpoint, "POST", $key, $secret);
 
-        $endpointurl = new moodle_url($endpoint);
+        $endpointurl = new \moodle_url($endpoint);
         $endpointparams = $endpointurl->params();
 
         // Strip querystring params in endpoint url from $parms to avoid duplication.
@@ -221,7 +235,8 @@ function lti_view($instance) {
         }
 
     } else {
-        //If no key and secret, do the launch unsigned.
+        // If no key and secret, do the launch unsigned.
+        $returnurlparams['unsigned'] = '1';
         $parms = $requestparams;
     }
 
@@ -232,6 +247,44 @@ function lti_view($instance) {
     echo $content;
 }
 
+/**
+ * Prepares an LTI registration request message
+ *
+ * $param object $instance       Tool Proxy instance object
+ */
+function lti_register($toolproxy) {
+    global $PAGE, $CFG;
+
+    $key = $toolproxy->guid;
+    $secret = $toolproxy->secret;
+    $endpoint = $toolproxy->regurl;
+
+    $requestparams = array();
+    $requestparams['lti_message_type'] = 'ToolProxyRegistrationRequest';
+    $requestparams['lti_version'] = 'LTI-2p0';
+    $requestparams['reg_key'] = $key;
+    $requestparams['reg_password'] = $secret;
+
+    // Change the status to pending.
+    $toolproxy->state = LTI_TOOL_PROXY_STATE_PENDING;
+    lti_update_tool_proxy($toolproxy);
+
+    // Add the profile URL.
+    $profileservice = lti_get_service_by_name('profile');
+    $profileservice->set_tool_proxy($toolproxy);
+    $requestparams['tc_profile_url'] = $profileservice->parse_value('$ToolConsumerProfile.url');
+
+    // Add the return URL.
+    $returnurlparams = array('id' => $toolproxy->id);
+    $url = new \moodle_url('/mod/lti/registrationreturn.php', $returnurlparams);
+    $returnurl = $url->out(false);
+
+    $requestparams['launch_presentation_return_url'] = $returnurl;
+    $content = lti_post_launch_html($requestparams, $endpoint, false);
+
+    echo $content;
+}
+
 /**
  * Build source ID
  *
@@ -243,7 +296,7 @@ function lti_view($instance) {
  * @return stdClass
  */
 function lti_build_sourcedid($instanceid, $userid, $servicesalt, $typeid = null, $launchid = null) {
-    $data = new stdClass();
+    $data = new \stdClass();
 
     $data->instanceid = $instanceid;
     $data->userid = $userid;
@@ -258,7 +311,7 @@ function lti_build_sourcedid($instanceid, $userid, $servicesalt, $typeid = null,
 
     $hash = hash('sha256', $json . $servicesalt, false);
 
-    $container = new stdClass();
+    $container = new \stdClass();
     $container->data = $data;
     $container->hash = $hash;
 
@@ -272,17 +325,18 @@ function lti_build_sourcedid($instanceid, $userid, $servicesalt, $typeid = null,
  * @param array     $typeconfig     Basic LTI tool configuration
  * @param object    $course         Course object
  * @param int|null  $typeid         Basic LTI tool ID
+ * @param boolean   $islti2         True if an LTI 2 tool is being launched
  *
- * @return array    $request        Request details
+ * @return array                    Request details
  */
-function lti_build_request($instance, $typeconfig, $course, $typeid = null) {
+function lti_build_request($instance, $typeconfig, $course, $typeid = null, $islti2 = false) {
     global $USER, $CFG;
 
     if (empty($instance->cmid)) {
         $instance->cmid = 0;
     }
 
-    $role = lti_get_ims_role($USER, $instance->cmid, $instance->course);
+    $role = lti_get_ims_role($USER, $instance->cmid, $instance->course, $islti2);
 
     $intro = '';
     if (!empty($instance->cmid)) {
@@ -294,19 +348,20 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null) {
         $intro = str_replace("\n", "\r\n", $intro);
     }
     $requestparams = array(
-        'resource_link_id' => $instance->id,
         'resource_link_title' => $instance->name,
         'resource_link_description' => $intro,
         'user_id' => $USER->id,
+        'lis_person_sourcedid' => $USER->idnumber,
         'roles' => $role,
         'context_id' => $course->id,
         'context_label' => $course->shortname,
         'context_title' => $course->fullname,
-        'launch_presentation_locale' => current_language()
     );
-
-    if (property_exists($instance, 'resource_link_id') and !empty($instance->resource_link_id)) {
-        $requestparams['resource_link_id'] = $instance->resource_link_id;
+    if ($course->format == 'site') {
+        $requestparams['context_type'] = 'Group';
+    } else {
+        $requestparams['context_type'] = 'CourseSection';
+        $requestparams['lis_course_section_sourcedid'] = $course->idnumber;
     }
     $placementsecret = $instance->servicesalt;
 
@@ -315,12 +370,12 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null) {
         $requestparams['lis_result_sourcedid'] = $sourcedid;
     }
 
-    if ( isset($placementsecret) &&
-         $typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
-         ( $typeconfig['acceptgrades'] == LTI_SETTING_DELEGATE && $instance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS ) ) ) {
+    if ( isset($placementsecret) && ($islti2 ||
+         $typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
+         ($typeconfig['acceptgrades'] == LTI_SETTING_DELEGATE && $instance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS))) {
 
-        //Add outcome service URL
-        $serviceurl = new moodle_url('/mod/lti/service.php');
+        // Add outcome service URL.
+        $serviceurl = new \moodle_url('/mod/lti/service.php');
         $serviceurl = $serviceurl->out();
 
         $forcessl = false;
@@ -328,71 +383,147 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null) {
             $forcessl = true;
         }
 
-        if ($typeconfig['forcessl'] == '1' or $forcessl) {
+        if ((isset($typeconfig['forcessl']) && ($typeconfig['forcessl'] == '1')) or $forcessl) {
             $serviceurl = lti_ensure_url_is_https($serviceurl);
         }
 
         $requestparams['lis_outcome_service_url'] = $serviceurl;
     }
 
-    // Send user's name and email data if appropriate
-    if ( $typeconfig['sendname'] == LTI_SETTING_ALWAYS ||
+    // Send user's name and email data if appropriate.
+    if ($islti2 || $typeconfig['sendname'] == LTI_SETTING_ALWAYS ||
          ( $typeconfig['sendname'] == LTI_SETTING_DELEGATE && $instance->instructorchoicesendname == LTI_SETTING_ALWAYS ) ) {
-        $requestparams['lis_person_name_given'] =  $USER->firstname;
-        $requestparams['lis_person_name_family'] =  $USER->lastname;
-        $requestparams['lis_person_name_full'] =  $USER->firstname." ".$USER->lastname;
+        $requestparams['lis_person_name_given'] = $USER->firstname;
+        $requestparams['lis_person_name_family'] = $USER->lastname;
+        $requestparams['lis_person_name_full'] = $USER->firstname . ' ' . $USER->lastname;
         $requestparams['ext_user_username'] = $USER->username;
     }
 
-    if ( $typeconfig['sendemailaddr'] == LTI_SETTING_ALWAYS ||
-         ( $typeconfig['sendemailaddr'] == LTI_SETTING_DELEGATE && $instance->instructorchoicesendemailaddr == LTI_SETTING_ALWAYS ) ) {
+    if ($islti2 || $typeconfig['sendemailaddr'] == LTI_SETTING_ALWAYS ||
+         ($typeconfig['sendemailaddr'] == LTI_SETTING_DELEGATE && $instance->instructorchoicesendemailaddr == LTI_SETTING_ALWAYS)) {
         $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 = lti_split_custom_parameters($customstr);
-    }
-    if (isset($typeconfig['allowinstructorcustom']) && $typeconfig['allowinstructorcustom'] == LTI_SETTING_NEVER) {
-        $requestparams = array_merge($custom, $requestparams);
-    } else {
-        if ($instructorcustomstr) {
-            $instructorcustom = lti_split_custom_parameters($instructorcustomstr);
-        }
-        foreach ($instructorcustom as $key => $val) {
-            // Ignore the instructor's parameter
-            if (!array_key_exists($key, $custom)) {
-                $custom[$key] = $val;
+    return $requestparams;
+}
+
+/**
+ * This function builds the request that must be sent to an LTI 2 tool provider
+ *
+ * @param object    $tool           Basic LTI tool object
+ * @param array     $params         Custom launch parameters
+ *
+ * @return array                    Request details
+ */
+function lti_build_request_lti2($tool, $params) {
+
+    $requestparams = array();
+
+    $capabilities = lti_get_capabilities();
+    $enabledcapabilities = explode("\n", $tool->enabledcapability);
+    foreach ($enabledcapabilities as $capability) {
+        if (array_key_exists($capability, $capabilities)) {
+            $val = $capabilities[$capability];
+            if ($val && (substr($val, 0, 1) != '$')) {
+                if (isset($params[$val])) {
+                    $requestparams[$capabilities[$capability]] = $params[$capabilities[$capability]];
+                }
             }
         }
-        $requestparams = array_merge($custom, $requestparams);
     }
 
-    // Make sure we let the tool know what LMS they are being called from
-    $requestparams["ext_lms"] = "moodle-2";
+    return $requestparams;
+
+}
+
+/**
+ * This function builds the standard parameters for an LTI 1 or 2 request that must be sent to the tool producer
+ *
+ * @param object    $instance       Basic LTI instance object
+ * @param string    $orgid          Organisation ID
+ * @param boolean   $islti2         True if an LTI 2 tool is being launched
+ *
+ * @return array                    Request details
+ */
+function lti_build_standard_request($instance, $orgid, $islti2) {
+    global $CFG;
+
+    $requestparams = array();
+
+    $requestparams['resource_link_id'] = $instance->id;
+    if (property_exists($instance, 'resource_link_id') and !empty($instance->resource_link_id)) {
+        $requestparams['resource_link_id'] = $instance->resource_link_id;
+    }
+
+    $requestparams['launch_presentation_locale'] = current_language();
+
+    // Make sure we let the tool know what LMS they are being called from.
+    $requestparams['ext_lms'] = 'moodle-2';
     $requestparams['tool_consumer_info_product_family_code'] = 'moodle';
     $requestparams['tool_consumer_info_version'] = strval($CFG->version);
 
-    // Add oauth_callback to be compliant with the 1.0A spec
+    // Add oauth_callback to be compliant with the 1.0A spec.
     $requestparams['oauth_callback'] = 'about:blank';
 
-    //The submit button needs to be part of the signature as it gets posted with the form.
-    //This needs to be here to support launching without javascript.
-    $submittext = get_string('press_to_submit', 'lti');
-    $requestparams['ext_submit'] = $submittext;
-
-    $requestparams['lti_version'] = 'LTI-1p0';
+    if (!$islti2) {
+        $requestparams['lti_version'] = 'LTI-1p0';
+    } else {
+        $requestparams['lti_version'] = 'LTI-2p0';
+    }
     $requestparams['lti_message_type'] = 'basic-lti-launch-request';
 
+    if ($orgid) {
+        $requestparams["tool_consumer_instance_guid"] = $orgid;
+    }
+    if (!empty($CFG->mod_lti_institution_name)) {
+        $requestparams['tool_consumer_instance_name'] = $CFG->mod_lti_institution_name;
+    } else {
+        $requestparams['tool_consumer_instance_name'] = get_site()->fullname;
+    }
+
     return $requestparams;
 }
 
+/**
+ * This function builds the custom parameters
+ *
+ * @param object    $toolproxy      Tool proxy instance object
+ * @param object    $tool           Tool instance object
+ * @param object    $instance       Tool placement instance object
+ * @param array     $params         LTI launch parameters
+ * @param string    $customstr      Custom parameters defined for tool
+ * @param string    $instructorcustomstr      Custom parameters defined for this placement
+ * @param boolean   $islti2         True if an LTI 2 tool is being launched
+ *
+ * @return array                    Custom parameters
+ */
+function lti_build_custom_parameters($toolproxy, $tool, $instance, $params, $customstr, $instructorcustomstr, $islti2) {
+
+    // Concatenate the custom parameters from the administrator and the instructor
+    // Instructor parameters are only taken into consideration if the administrator
+    // has given permission.
+    $custom = array();
+    if ($customstr) {
+        $custom = lti_split_custom_parameters($toolproxy, $tool, $params, $customstr, $islti2);
+    }
+    if (!isset($typeconfig['allowinstructorcustom']) || $typeconfig['allowinstructorcustom'] != LTI_SETTING_NEVER) {
+        if ($instructorcustomstr) {
+            $custom = array_merge(lti_split_custom_parameters($toolproxy, $tool, $params, $instructorcustomstr, $islti2), $custom);
+        }
+    }
+    if ($islti2) {
+        $custom = array_merge(lti_split_custom_parameters($toolproxy, $tool, $params, $tool->parameter, true), $custom);
+        $settings = lti_get_tool_settings($tool->toolproxyid);
+        $custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
+        $settings = lti_get_tool_settings($tool->toolproxyid, $instance->course);
+        $custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
+        $settings = lti_get_tool_settings($tool->toolproxyid, $instance->course, $instance->id);
+        $custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
+    }
+
+    return $custom;
+}
+
 function lti_get_tool_table($tools, $id) {
     global $CFG, $OUTPUT, $USER;
     $html = '';
@@ -402,13 +533,9 @@ function lti_get_tool_table($tools, $id) {
     $action = get_string('action', 'lti');
     $createdon = get_string('createdon', 'lti');
 
-    if ($id == 'lti_configured') {
-        $html .= '<div><a style="margin-top:.25em" href="'.$CFG->wwwroot.'/mod/lti/typessettings.php?action=add&amp;sesskey='.$USER->sesskey.'">'.get_string('addtype', 'lti').'</a></div>';
-    }
-
     if (!empty($tools)) {
         $html .= "
-        <div id=\"{$id}_container\" style=\"margin-top:.5em;margin-bottom:.5em\">
+        <div id=\"{$id}_tools_container\" style=\"margin-top:.5em;margin-bottom:.5em\">
             <table id=\"{$id}_tools\">
                 <thead>
                     <tr>
@@ -426,15 +553,26 @@ function lti_get_tool_table($tools, $id) {
             $update = get_string('update', 'lti');
             $delete = get_string('delete', 'lti');
 
-            $baseurl = new moodle_url('/mod/lti/typessettings.php', array(
-                    'action' => 'accept',
-                    'id' => $type->id,
-                    'sesskey' => sesskey(),
-                    'tab' => $id
-                ));
+            if (empty($type->toolproxyid)) {
+                $baseurl = new \moodle_url('/mod/lti/typessettings.php', array(
+                        'action' => 'accept',
+                        'id' => $type->id,
+                        'sesskey' => sesskey(),
+                        'tab' => $id
+                    ));
+                $ref = $type->baseurl;
+            } else {
+                $baseurl = new \moodle_url('/mod/lti/toolssettings.php', array(
+                        'action' => 'accept',
+                        'id' => $type->id,
+                        'sesskey' => sesskey(),
+                        'tab' => $id
+                    ));
+                $ref = $type->tpname;
+            }
 
             $accepthtml = $OUTPUT->action_icon($baseurl,
-                    new pix_icon('t/check', $accept, '', array('class' => 'iconsmall')), null,
+                    new \pix_icon('t/check', $accept, '', array('class' => 'iconsmall')), null,
                     array('title' => $accept, 'class' => 'editing_accept'));
 
             $deleteaction = 'delete';
@@ -451,21 +589,25 @@ function lti_get_tool_table($tools, $id) {
             $updateurl = clone($baseurl);
             $updateurl->param('action', 'update');
             $updatehtml = $OUTPUT->action_icon($updateurl,
-                    new pix_icon('t/edit', $update, '', array('class' => 'iconsmall')), null,
+                    new \pix_icon('t/edit', $update, '', array('class' => 'iconsmall')), null,
                     array('title' => $update, 'class' => 'editing_update'));
 
-            $deleteurl = clone($baseurl);
-            $deleteurl->param('action', $deleteaction);
-            $deletehtml = $OUTPUT->action_icon($deleteurl,
-                    new pix_icon('t/delete', $delete, '', array('class' => 'iconsmall')), null,
-                    array('title' => $delete, 'class' => 'editing_delete'));
+            if (($type->state != LTI_TOOL_STATE_REJECTED) || empty($type->toolproxyid)) {
+                $deleteurl = clone($baseurl);
+                $deleteurl->param('action', $deleteaction);
+                $deletehtml = $OUTPUT->action_icon($deleteurl,
+                        new \pix_icon('t/delete', $delete, '', array('class' => 'iconsmall')), null,
+                        array('title' => $delete, 'class' => 'editing_delete'));
+            } else {
+                $deletehtml = '';
+            }
             $html .= "
             <tr>
                 <td>
                     {$type->name}
                 </td>
                 <td>
-                    {$type->baseurl}
+                    {$ref}
                 </td>
                 <td>
                     {$date}
@@ -484,15 +626,120 @@ function lti_get_tool_table($tools, $id) {
     return $html;
 }
 
+/**
+ * This function builds the tab for a category of tool proxies
+ *
+ * @param object    $toolproxies    Tool proxy instance objects
+ * @param string    $id             Category ID
+ *
+ * @return string                   HTML for tab
+ */
+function lti_get_tool_proxy_table($toolproxies, $id) {
+    global $OUTPUT;
+
+    if (!empty($toolproxies)) {
+        $typename = get_string('typename', 'lti');
+        $url = get_string('registrationurl', 'lti');
+        $action = get_string('action', 'lti');
+        $createdon = get_string('createdon', 'lti');
+
+        $html = <<< EOD
+        <div id="{$id}_tool_proxies_container" style="margin-top: 0.5em; margin-bottom: 0.5em">
+            <table id="{$id}_tool_proxies">
+                <thead>
+                    <tr>
+                        <th>{$typename}</th>
+                        <th>{$url}</th>
+                        <th>{$createdon}</th>
+                        <th>{$action}</th>
+                    </tr>
+                </thead>
+EOD;
+        foreach ($toolproxies as $toolproxy) {
+            $date = userdate($toolproxy->timecreated, get_string('strftimedatefullshort', 'core_langconfig'));
+            $accept = get_string('register', 'lti');
+            $update = get_string('update', 'lti');
+            $delete = get_string('delete', 'lti');
+
+            $baseurl = new \moodle_url('/mod/lti/registersettings.php', array(
+                    'action' => 'accept',
+                    'id' => $toolproxy->id,
+                    'sesskey' => sesskey(),
+                    'tab' => $id
+                ));
+
+            $registerurl = new \moodle_url('/mod/lti/register.php', array(
+                    'id' => $toolproxy->id,
+                    'sesskey' => sesskey(),
+                    'tab' => 'tool_proxy'
+                ));
+
+            $accepthtml = $OUTPUT->action_icon($registerurl,
+                    new \pix_icon('t/check', $accept, '', array('class' => 'iconsmall')), null,
+                    array('title' => $accept, 'class' => 'editing_accept'));
+
+            $deleteaction = 'delete';
+
+            if ($toolproxy->state != LTI_TOOL_PROXY_STATE_CONFIGURED) {
+                $accepthtml = '';
+            }
+
+            if (($toolproxy->state == LTI_TOOL_PROXY_STATE_CONFIGURED) || ($toolproxy->state == LTI_TOOL_PROXY_STATE_PENDING)) {
+                $delete = get_string('cancel', 'lti');
+            }
+
+            $updateurl = clone($baseurl);
+            $updateurl->param('action', 'update');
+            $updatehtml = $OUTPUT->action_icon($updateurl,
+                    new \pix_icon('t/edit', $update, '', array('class' => 'iconsmall')), null,
+                    array('title' => $update, 'class' => 'editing_update'));
+
+            $deleteurl = clone($baseurl);
+            $deleteurl->param('action', $deleteaction);
+            $deletehtml = $OUTPUT->action_icon($deleteurl,
+                    new \pix_icon('t/delete', $delete, '', array('class' => 'iconsmall')), null,
+                    array('title' => $delete, 'class' => 'editing_delete'));
+            $html .= <<< EOD
+            <tr>
+                <td>
+                    {$toolproxy->name}
+                </td>
+                <td>
+                    {$toolproxy->regurl}
+                </td>
+                <td>
+                    {$date}
+                </td>
+                <td align="center">
+                    {$accepthtml}{$updatehtml}{$deletehtml}
+                </td>
+            </tr>
+EOD;
+        }
+        $html .= '</table></div>';
+    } else {
+        $html = get_string('no_' . $id, 'lti');
+    }
+
+    return $html;
+}
+
 /**
  * Splits the custom parameters field to the various parameters
  *
- * @param string $customstr     String containing the parameters
+ * @param object    $toolproxy      Tool proxy instance object
+ * @param object    $tool           Tool instance object
+ * @param array     $params         LTI launch parameters
+ * @param string    $customstr      String containing the parameters
+ * @param boolean   $islti2         True if an LTI 2 tool is being launched
  *
  * @return Array of custom parameters
  */
-function lti_split_custom_parameters($customstr) {
-    $lines = preg_split("/[\n;]/", $customstr);
+function lti_split_custom_parameters($toolproxy, $tool, $params, $customstr, $islti2 = false) {
+    $customstr = str_replace("\r\n", "\n", $customstr);
+    $customstr = str_replace("\n\r", "\n", $customstr);
+    $customstr = str_replace("\r", "\n", $customstr);
+    $lines = explode("\n", $customstr);  // Or should this split on "/[\n;]/"?
     $retval = array();
     foreach ($lines as $line) {
         $pos = strpos($line, "=");
@@ -500,13 +747,92 @@ function lti_split_custom_parameters($customstr) {
             continue;
         }
         $key = trim(core_text::substr($line, 0, $pos));
-        $val = trim(core_text::substr($line, $pos+1, strlen($line)));
-        $key = lti_map_keyname($key);
-        $retval['custom_'.$key] = $val;
+        $val = trim(core_text::substr($line, $pos + 1, strlen($line)));
+        $val = lti_parse_custom_parameter($toolproxy, $tool, $params, $val, $islti2);
+        $key2 = lti_map_keyname($key);
+        $retval['custom_'.$key2] = $val;
+        if ($islti2 && ($key != $key2)) {
+            $retval['custom_'.$key] = $val;
+        }
+    }
+    return $retval;
+}
+
+/**
+ * Adds the custom parameters to an array
+ *
+ * @param object    $toolproxy      Tool proxy instance object
+ * @param object    $tool           Tool instance object
+ * @param array     $params         LTI launch parameters
+ * @param array     $parameters     Array containing the parameters
+ *
+ * @return array    Array of custom parameters
+ */
+function lti_get_custom_parameters($toolproxy, $tool, $params, $parameters) {
+    $retval = array();
+    foreach ($parameters as $key => $val) {
+        $key2 = lti_map_keyname($key);
+        $val = lti_parse_custom_parameter($toolproxy, $tool, $params, $val, true);
+        $retval['custom_'.$key2] = $val;
+        if ($key != $key2) {
+            $retval['custom_'.$key] = $val;
+        }
     }
     return $retval;
 }
 
+/**
+ * Parse a custom parameter to replace any substitution variables
+ *
+ * @param object    $toolproxy      Tool proxy instance object
+ * @param object    $tool           Tool instance object
+ * @param array     $params         LTI launch parameters
+ * @param string    $value          Custom parameter value
+ * @param boolean   $islti2         True if an LTI 2 tool is being launched
+ *
+ * @return Parsed value of custom parameter
+ */
+function lti_parse_custom_parameter($toolproxy, $tool, $params, $value, $islti2) {
+    global $USER, $COURSE;
+
+    if ($value) {
+        if (substr($value, 0, 1) == '\\') {
+            $value = substr($value, 1);
+        } else if (substr($value, 0, 1) == '$') {
+            $value1 = substr($value, 1);
+            $enabledcapabilities = explode("\n", $tool->enabledcapability);
+            if (!$islti2 || in_array($value1, $enabledcapabilities)) {
+                $capabilities = lti_get_capabilities();
+                if (array_key_exists($value1, $capabilities)) {
+                    $val = $capabilities[$value1];
+                    if ($val) {
+                        if (substr($val, 0, 1) != '$') {
+                            $value = $params[$val];
+                        } else {
+                            $valarr = explode('->', substr($val, 1), 2);
+                            $value = "{${$valarr[0]}->$valarr[1]}";
+                            $value = str_replace('<br />' , ' ', $value);
+                            $value = str_replace('<br>' , ' ', $value);
+                            $value = format_string($value);
+                        }
+                    }
+                } else if ($islti2) {
+                    $val = $value;
+                    $services = lti_get_services();
+                    foreach ($services as $service) {
+                        $service->set_tool_proxy($toolproxy);
+                        $value = $service->parse_value($val);
+                        if ($val != $value) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return $value;
+}
+
 /**
  * Used for building the names of the different custom parameters
  *
@@ -530,17 +856,20 @@ function lti_map_keyname($key) {
 /**
  * Gets the IMS role string for the specified user and LTI course module.
  *
- * @param mixed $user User object or user id
- * @param int $cmid The course module id of the LTI activity
+ * @param mixed    $user      User object or user id
+ * @param int      $cmid      The course module id of the LTI activity
+ * @param int      $courseid  The course id of the LTI activity
+ * @param boolean  $islti2    True if an LTI 2 tool is being launched
+ *
  * @return string A role string suitable for passing with an LTI launch
  */
-function lti_get_ims_role($user, $cmid, $courseid) {
+function lti_get_ims_role($user, $cmid, $courseid, $islti2) {
     $roles = array();
 
     if (empty($cmid)) {
-        //If no cmid is passed, check if the user is a teacher in the course
-        //This allows other modules to programmatically "fake" a launch without
-        //a real LTI instance
+        // If no cmid is passed, check if the user is a teacher in the course
+        // This allows other modules to programmatically "fake" a launch without
+        // a real LTI instance.
         $coursecontext = context_course::instance($courseid);
 
         if (has_capability('moodle/course:manageactivities', $coursecontext)) {
@@ -559,7 +888,11 @@ function lti_get_ims_role($user, $cmid, $courseid) {
     }
 
     if (is_siteadmin($user)) {
-        array_push($roles, 'urn:lti:sysrole:ims/lis/Administrator', 'urn:lti:instrole:ims/lis/Administrator');
+        if (!$islti2) {
+            array_push($roles, 'urn:lti:sysrole:ims/lis/Administrator', 'urn:lti:instrole:ims/lis/Administrator');
+        } else {
+            array_push($roles, 'http://purl.imsglobal.org/vocab/lis/v2/person#Administrator');
+        }
     }
 
     return join(',', $roles);
@@ -639,12 +972,16 @@ function lti_filter_get_types($course) {
     global $DB;
 
     if (!empty($course)) {
-        $filter = array('course' => $course);
+        $where = "WHERE t.course = :course";
+        $params = array('course' => $course);
     } else {
-        $filter = array();
+        $where = '';
+        $params = array();
     }
-
-    return $DB->get_records('lti_types', $filter);
+    $query = "SELECT t.id, t.name, t.baseurl, t.state, t.toolproxyid, t.timecreated, tp.name tpname
+                FROM {lti_types} t LEFT OUTER JOIN {lti_tool_proxies} tp ON t.toolproxyid = tp.id
+                {$where}";
+    return $DB->get_records_sql($query, $params);
 }
 
 /**
@@ -673,10 +1010,11 @@ function lti_get_types_for_add_instance() {
                  AND (course = :siteid OR course = :courseid)
                  AND state = :active";
 
-    $admintypes = $DB->get_records_sql($query, array('siteid' => $SITE->id, 'courseid' => $COURSE->id, 'active' => LTI_TOOL_STATE_CONFIGURED));
+    $admintypes = $DB->get_records_sql($query,
+        array('siteid' => $SITE->id, 'courseid' => $COURSE->id, 'active' => LTI_TOOL_STATE_CONFIGURED));
 
     $types = array();
-    $types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => 0);
+    $types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => 0, 'toolproxyid' => null);
 
     foreach ($admintypes as $type) {
         $types[$type->id] = $type;
@@ -733,16 +1071,16 @@ function lti_get_best_tool_by_url($url, $tools, $courseid = null) {
         $toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);
 
         if ($urllower === $toolbaseurllower) {
-            //100 points for exact thumbprint match
+            // 100 points for exact thumbprint match.
             $tool->_matchscore += 100;
         } else if (substr($urllower, 0, strlen($toolbaseurllower)) === $toolbaseurllower) {
-            //50 points if tool thumbprint starts with the base URL thumbprint
+            // 50 points if tool thumbprint starts with the base URL thumbprint.
             $tool->_matchscore += 50;
         }
 
-        //Prefer course tools over site tools
+        // Prefer course tools over site tools.
         if (!empty($courseid)) {
-            //Minus 10 points for not matching the course id (global tools)
+            // Minus 10 points for not matching the course id (global tools).
             if ($tool->course != $courseid) {
                 $tool->_matchscore -= 10;
             }
@@ -758,7 +1096,7 @@ function lti_get_best_tool_by_url($url, $tools, $courseid = null) {
 
     }, (object)array('_matchscore' => -1));
 
-    //None of the tools are suitable for this URL
+    // None of the tools are suitable for this URL.
     if ($bestmatch->_matchscore <= 0) {
         return null;
     }
@@ -769,8 +1107,8 @@ function lti_get_best_tool_by_url($url, $tools, $courseid = null) {
 function lti_get_shared_secrets_by_key($key) {
     global $DB;
 
-    //Look up the shared secret for the specified key in both the types_config table (for configured tools)
-    //And in the lti resource table for ad-hoc tools
+    // Look up the shared secret for the specified key in both the types_config table (for configured tools)
+    // And in the lti resource table for ad-hoc tools.
     $query = "SELECT t2.value
                 FROM {lti_types_config} t1
                 JOIN {lti_types_config} t2 ON t1.typeid = t2.typeid
@@ -778,20 +1116,27 @@ function lti_get_shared_secrets_by_key($key) {
               WHERE t1.name = 'resourcekey'
                 AND t1.value = :key1
                 AND t2.name = 'password'
-                AND type.state = :configured
+                AND type.state = :configured1
+               UNION
+              SELECT tp.secret AS value
+                FROM {lti_tool_proxies} tp
+                JOIN {lti_types} t ON tp.id = t.toolproxyid
+              WHERE tp.guid = :key2
+                AND t.state = :configured2
               UNION
              SELECT password AS value
                FROM {lti}
-              WHERE resourcekey = :key2";
+              WHERE resourcekey = :key3";
 
-    $sharedsecrets = $DB->get_records_sql($query, array('configured' => LTI_TOOL_STATE_CONFIGURED, 'key1' => $key, 'key2' => $key));
+    $sharedsecrets = $DB->get_records_sql($query, array('configured1' => LTI_TOOL_STATE_CONFIGURED,
+        'configured2' => LTI_TOOL_STATE_CONFIGURED, 'key1' => $key, 'key2' => $key, 'key3' => $key));
 
     $values = array_map(function($item) {
         return $item->value;
     }, $sharedsecrets);
 
-    //There should really only be one shared secret per key. But, we can't prevent
-    //more than one getting entered. For instance, if the same key is used for two tool providers.
+    // There should really only be one shared secret per key. But, we can't prevent
+    // more than one getting entered. For instance, if the same key is used for two tool providers.
     return $values;
 }
 
@@ -803,7 +1148,7 @@ function lti_get_shared_secrets_by_key($key) {
 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
+    // 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) {
@@ -851,7 +1196,7 @@ function lti_get_type_config_from_instance($id) {
     $instance = $DB->get_record('lti', array('id' => $id));
     $config = lti_get_config($instance);
 
-    $type = new stdClass();
+    $type = new \stdClass();
     $type->lti_fix = $id;
     if (isset($config['toolurl'])) {
         $type->lti_toolurl = $config['toolurl'];
@@ -888,14 +1233,18 @@ function lti_get_type_type_config($id) {
     $basicltitype = $DB->get_record('lti_types', array('id' => $id));
     $config = lti_get_type_config($id);
 
-    $type = new stdClass();
+    $type = new \stdClass();
 
     $type->lti_typename = $basicltitype->name;
 
     $type->typeid = $basicltitype->id;
 
+    $type->toolproxyid = $basicltitype->toolproxyid;
+
     $type->lti_toolurl = $basicltitype->baseurl;
 
+    $type->lti_parameters = $basicltitype->parameter;
+
     if (isset($config['resourcekey'])) {
         $type->lti_resourcekey = $config['resourcekey'];
     }
@@ -965,15 +1314,20 @@ function lti_get_type_type_config($id) {
 }
 
 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;
-
+    if (isset($config->lti_toolurl)) {
+        $type->baseurl = $config->lti_toolurl;
+        $type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
+    }
+    if (isset($config->lti_typename)) {
+        $type->name = $config->lti_typename;
+    }
     $type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;
     $config->lti_coursevisible = $type->coursevisible;
 
-    $type->forcessl = !empty($config->lti_forcessl) ? $config->lti_forcessl : 0;
-    $config->lti_forcessl = $type->forcessl;
+    if (isset($config->lti_forcessl)) {
+        $type->forcessl = !empty($config->lti_forcessl) ? $config->lti_forcessl : 0;
+        $config->lti_forcessl = $type->forcessl;
+    }
 
     $type->timemodified = time();
 
@@ -988,12 +1342,11 @@ function lti_update_type($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();
+            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);
             }
         }
@@ -1021,17 +1374,17 @@ function lti_add_type($type, $config) {
         $type->course = $SITE->id;
     }
 
-    //Create a salt value to be used for signing passed data to extension services
-    //The outcome service uses the service salt on the instance. This can be used
-    //for communication with services not related to a specific LTI instance.
+    // Create a salt value to be used for signing passed data to extension services
+    // The outcome service uses the service salt on the instance. This can be used
+    // for communication with services not related to a specific LTI instance.
     $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();
+            if (substr($key, 0, 4) == 'lti_' && !is_null($value)) {
+                $record = new \StdClass();
                 $record->typeid = $id;
                 $record->name = substr($key, 4);
                 $record->value = $value;
@@ -1044,10 +1397,155 @@ function lti_add_type($type, $config) {
     return $id;
 }
 
+/**
+ * Given an array of tool proxies, filter them based on their state
+ *
+ * @param array $toolproxies An array of lti_tool_proxies records
+ * @param int $state One of the LTI_TOOL_PROXY_STATE_* constants
+ *
+ * @return array
+ */
+function lti_filter_tool_proxy_types(array $toolproxies, $state) {
+    $return = array();
+    foreach ($toolproxies as $key => $toolproxy) {
+        if ($toolproxy->state == $state) {
+            $return[$key] = $toolproxy;
+        }
+    }
+    return $return;
+}
+
+/**
+ * Get the tool proxy instance given its GUID
+ *
+ * @param string  $toolproxyguid   Tool proxy GUID value
+ *
+ * @return object
+ */
+function lti_get_tool_proxy_from_guid($toolproxyguid) {
+    global $DB;
+
+    $toolproxy = $DB->get_record('lti_tool_proxies', array('guid' => $toolproxyguid));
+
+    return $toolproxy;
+}
+
+/**
+ * Generates some of the tool proxy configuration based on the admin configuration details
+ *
+ * @param int $id
+ *
+ * @return Tool Proxy details
+ */
+function lti_get_tool_proxy($id) {
+    global $DB;
+
+    $toolproxy = $DB->get_record('lti_tool_proxies', array('id' => $id));
+    return $toolproxy;
+}
+
+/**
+ * Generates some of the tool proxy configuration based on the admin configuration details
+ *
+ * @param int $id
+ *
+ * @return Tool Proxy details
+ */
+function lti_get_tool_proxy_config($id) {
+    $toolproxy = lti_get_tool_proxy($id);
+
+    $tp = new \stdClass();
+    $tp->lti_registrationname = $toolproxy->name;
+    $tp->toolproxyid = $toolproxy->id;
+    $tp->state = $toolproxy->state;
+    $tp->lti_registrationurl = $toolproxy->regurl;
+    $tp->lti_capabilities = explode("\n", $toolproxy->capabilityoffered);
+    $tp->lti_services = explode("\n", $toolproxy->serviceoffered);
+
+    return $tp;
+}
+
+/**
+ * Update the database with a tool proxy instance
+ *
+ * @param object   $config    Tool proxy definition
+ *
+ * @return int  Record id number
+ */
+function lti_add_tool_proxy($config) {
+    global $USER, $DB;
+
+    $toolproxy = new \stdClass();
+    if (isset($config->lti_registrationname)) {
+        $toolproxy->name = trim($config->lti_registrationname);
+    }
+    if (isset($config->lti_registrationurl)) {
+        $toolproxy->regurl = trim($config->lti_registrationurl);
+    }
+    if (isset($config->lti_capabilities)) {
+        $toolproxy->capabilityoffered = implode("\n", $config->lti_capabilities);
+    }
+    if (isset($config->lti_services)) {
+        $toolproxy->serviceoffered = implode("\n", $config->lti_services);
+    }
+    if (isset($config->toolproxyid) && !empty($config->toolproxyid)) {
+        $toolproxy->id = $config->toolproxyid;
+        if (!isset($toolproxy->state) || ($toolproxy->state != LTI_TOOL_PROXY_STATE_ACCEPTED)) {
+            $toolproxy->state = LTI_TOOL_PROXY_STATE_CONFIGURED;
+            $toolproxy->guid = random_string();
+            $toolproxy->secret = random_string();
+        }
+        $id = lti_update_tool_proxy($toolproxy);
+    } else {
+        $toolproxy->state = LTI_TOOL_PROXY_STATE_CONFIGURED;
+        $toolproxy->timemodified = time();
+        $toolproxy->timecreated = $toolproxy->timemodified;
+        if (!isset($toolproxy->createdby)) {
+            $toolproxy->createdby = $USER->id;
+        }
+        $toolproxy->guid = random_string();
+        $toolproxy->secret = random_string();
+        $id = $DB->insert_record('lti_tool_proxies', $toolproxy);
+    }
+
+    return $id;
+}
+
+/**
+ * Updates a tool proxy in the database
+ *
+ * @param object  $toolproxy   Tool proxy
+ *
+ * @return int    Record id number
+ */
+function lti_update_tool_proxy($toolproxy) {
+    global $DB;
+
+    $toolproxy->timemodified = time();
+    $id = $DB->update_record('lti_tool_proxies', $toolproxy);
+
+    return $id;
+}
+
+/**
+ * Delete a Tool Proxy
+ *
+ * @param int $id   Tool Proxy id
+ */
+function lti_delete_tool_proxy($id) {
+    global $DB;
+    $DB->delete_records('lti_tool_settings', array('toolproxyid' => $id));
+    $tools = $DB->get_records('lti_types', array('toolproxyid' => $id));
+    foreach ($tools as $tool) {
+        lti_delete_type($tool->id);
+    }
+    $DB->delete_records('lti_tool_proxies', array('id' => $id));
+}
+
 /**
  * Add a tool configuration in the database
  *
- * @param $config   Tool configuration
+ * @param object $config   Tool configuration
  *
  * @return int Record id number
  */
@@ -1060,7 +1558,7 @@ function lti_add_config($config) {
 /**
  * Updates a tool configuration in the database
  *
- * @param $config   Tool configuration
+ * @param object  $config   Tool configuration
  *
  * @return Record id number
  */
@@ -1079,6 +1577,55 @@ function lti_update_config($config) {
     return $return;
 }
 
+/**
+ * Gets the tool settings
+ *
+ * @param int  $toolproxyid   Id of tool proxy record
+ * @param int  $courseid      Id of course (null if system settings)
+ * @param int  $instanceid    Id of course module (null if system or context settings)
+ *
+ * @return array  Array settings
+ */
+function lti_get_tool_settings($toolproxyid, $courseid = null, $instanceid = null) {
+    global $DB;
+
+    $settings = array();
+    $settingsstr = $DB->get_field('lti_tool_settings', 'settings', array('toolproxyid' => $toolproxyid,
+        'course' => $courseid, 'coursemoduleid' => $instanceid));
+    if ($settingsstr !== false) {
+        $settings = json_decode($settingsstr, true);
+    }
+    return $settings;
+}
+
+/**
+ * Sets the tool settings (
+ *
+ * @param array  $settings      Array of settings
+ * @param int    $toolproxyid   Id of tool proxy record
+ * @param int    $courseid      Id of course (null if system settings)
+ * @param int    $instanceid    Id of course module (null if system or context settings)
+ */
+function lti_set_tool_settings($settings, $toolproxyid, $courseid = null, $instanceid = null) {
+    global $DB;
+
+    $json = json_encode($settings);
+    $record = $DB->get_record('lti_tool_settings', array('toolproxyid' => $toolproxyid,
+        'course' => $courseid, 'coursemoduleid' => $instanceid));
+    if ($record !== false) {
+        $DB->update_record('lti_tool_settings', array('id' => $record->id, 'settings' => $json, 'timemodified' => time()));
+    } else {
+        $record = new \stdClass();
+        $record->toolproxyid = $toolproxyid;
+        $record->course = $courseid;
+        $record->coursemoduleid = $instanceid;
+        $record->settings = $json;
+        $record->timecreated = time();
+        $record->timemodified = $record->timecreated;
+        $DB->insert_record('lti_tool_settings', $record);
+    }
+}
+
 /**
  * Signs the petition to launch the external tool using OAuth
  *
@@ -1087,25 +1634,19 @@ function lti_update_config($config) {
  * @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 lti_sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $oauthconsumersecret) {
-    //global $lastbasestring;
+
     $parms = $oldparms;
 
     $testtoken = '';
 
-    // TODO: Switch to core oauthlib once implemented - MDL-30149
+    // TODO: Switch to core oauthlib once implemented - MDL-30149.
     $hmacmethod = new lti\OAuthSignatureMethod_HMAC_SHA1();
     $testconsumer = new lti\OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);
     $accreq = lti\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;
@@ -1119,21 +1660,19 @@ function lti_sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $
  * @param $debug        Debug (true/false)
  */
 function lti_post_launch_html($newparms, $endpoint, $debug=false) {
-    $r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";
+    $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
+    // 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=\"";
+            $r .= "<input type=\"submit\"";
         } else {
-            $r .= "<input type=\"hidden\" name=\"";
+            $r .= "<input type=\"hidden\" name=\"{$key}\"";
         }
-        $r .= $key;
-        $r .= "\" value=\"";
+        $r .= " value=\"";
         $r .= $value;
         $r .= "\"/>\n";
     }
@@ -1155,31 +1694,22 @@ function lti_post_launch_html($newparms, $endpoint, $debug=false) {
         $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 .= "<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";
+        $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";
@@ -1212,9 +1742,9 @@ function lti_get_launch_container($lti, $toolconfig) {
 
     $devicetype = core_useragent::get_device_type();
 
-    //Scrolling within the object element doesn't work on iOS or Android
-    //Opening the popup window also had some issues in testing
-    //For mobile devices, always take up the entire screen to ensure the best experience
+    // Scrolling within the object element doesn't work on iOS or Android
+    // Opening the popup window also had some issues in testing
+    // For mobile devices, always take up the entire screen to ensure the best experience.
     if ($devicetype === core_useragent::DEVICETYPE_MOBILE || $devicetype === core_useragent::DEVICETYPE_TABLET ) {
         $launchcontainer = LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW;
     }
@@ -1231,7 +1761,7 @@ function lti_ensure_url_is_https($url) {
     if (!strstr($url, '://')) {
         $url = 'https://' . $url;
     } else {
-        //If the URL starts with http, replace with https
+        // If the URL starts with http, replace with https.
         if (stripos($url, 'http://') === 0) {
             $url = 'https://' . substr($url, 7);
         }
@@ -1259,7 +1789,7 @@ function lti_should_log_request($rawbody) {
     }
 
     try {
-        $xml = new SimpleXMLElement($rawbody);
+        $xml = new \SimpleXMLElement($rawbody);
         $ns  = $xml->getNamespaces();
         $ns  = array_shift($ns);
         $xml->registerXPathNamespace('lti', $ns);
@@ -1339,3 +1869,147 @@ function lti_force_type_config_settings($instance, array $typeconfig) {
     }
 }
 
+/**
+ * Initializes an array with the capabilities supported by the LTI module
+ *
+ * @return array List of capability names (without a dollar sign prefix)
+ */
+function lti_get_capabilities() {
+
+    $capabilities = array(
+       'basic-lti-launch-request' => '',
+       'Context.id' => 'context_id',
+       'CourseSection.title' => 'context_title',
+       'CourseSection.label' => 'context_label',
+       'CourseSection.sourcedId' => 'lis_course_section_sourcedid',
+       'CourseSection.longDescription' => '$COURSE->summary',
+       'CourseSection.timeFrame.begin' => '$COURSE->startdate',
+       'ResourceLink.id' => 'resource_link_id',
+       'ResourceLink.title' => 'resource_link_title',
+       'ResourceLink.description' => 'resource_link_description',
+       'User.id' => 'user_id',
+       'User.username' => '$USER->username',
+       'Person.name.full' => 'lis_person_name_full',
+       'Person.name.given' => 'lis_person_name_given',
+       'Person.name.family' => 'lis_person_name_family',
+       'Person.email.primary' => 'lis_person_contact_email_primary',
+       'Person.sourcedId' => 'lis_person_sourcedid',
+       'Person.name.middle' => '$USER->middlename',
+       'Person.address.street1' => '$USER->address',
+       'Person.address.locality' => '$USER->city',
+       'Person.address.country' => '$USER->country',
+       'Person.address.timezone' => '$USER->timezone',
+       'Person.phone.primary' => '$USER->phone1',
+       'Person.phone.mobile' => '$USER->phone2',
+       'Person.webaddress' => '$USER->url',
+       'Membership.role' => 'roles',
+       'Result.sourcedId' => 'lis_result_sourcedid',
+       'Result.autocreate' => 'lis_outcome_service_url');
+
+    return $capabilities;
+
+}
+
+/**
+ * Initializes an array with the services supported by the LTI module
+ *
+ * @return array List of services
+ */
+function lti_get_services() {
+
+    $services = array();
+    $definedservices = core_component::get_plugin_list('ltiservice');
+    foreach ($definedservices as $name => $location) {
+        $classname = "\\ltiservice_{$name}\\local\\service\\{$name}";
+        $services[] = new $classname();
+    }
+
+    return $services;
+
+}
+
+/**
+ * Initializes an instance of the named service
+ *
+ * @param string $servicename Name of service
+ *
+ * @return mod_lti\local\ltiservice\service_base Service
+ */
+function lti_get_service_by_name($servicename) {
+
+    $service = false;
+    $classname = "\\ltiservice_{$servicename}\\local\\service\\{$servicename}";
+    if (class_exists($classname)) {
+        $service = new $classname();
+    }
+
+    return $service;
+
+}
+
+/**
+ * Finds a service by id
+ *
+ * @param array  $services    Array of services
+ * @param string $resourceid  ID of resource
+ *
+ * @return mod_lti\local\ltiservice\service_base Service
+ */
+function lti_get_service_by_resource_id($services, $resourceid) {
+
+    $service = false;
+    foreach ($services as $aservice) {
+        foreach ($aservice->get_resources() as $resource) {
+            if ($resource->get_id() === $resourceid) {
+                $service = $aservice;
+                break 2;
+            }
+        }
+    }
+
+    return $service;
+
+}
+
+/**
+ * Extracts the named contexts from a tool proxy
+ *
+ * @param object $json
+ *
+ * @return array Contexts
+ */
+function lti_get_contexts($json) {
+
+    $contexts = array();
+    if (isset($json->{'@context'})) {
+        foreach ($json->{'@context'} as $context) {
+            if (is_object($context)) {
+                $contexts = array_merge(get_object_vars($context), $contexts);
+            }
+        }
+    }
+
+    return $contexts;
+
+}
+
+/**
+ * Converts an ID to a fully-qualified ID
+ *
+ * @param array $contexts
+ * @param string $id
+ *
+ * @return string Fully-qualified ID
+ */
+function lti_get_fqid($contexts, $id) {
+
+    $parts = explode(':', $id, 2);
+    if (count($parts) > 1) {
+        if (array_key_exists($parts[0], $contexts)) {
+            $id = $contexts[$parts[0]] . $parts[1];
+        }
+    }
+
+    return $id;
+
+}
index e11f8c3..306b90f 100644 (file)
                 updateToolMatches();
 
                 self.toggleEditButtons();
+
+                if (self.getSelectedToolTypeOption().getAttribute('toolproxy')){
+                    var allowname = Y.one('#id_instructorchoicesendname');
+                    allowname.set('checked', !self.getSelectedToolTypeOption().getAttribute('noname'));
+
+                    var allowemail = Y.one('#id_instructorchoicesendemailaddr');
+                    allowemail.set('checked', !self.getSelectedToolTypeOption().getAttribute('noemail'));
+
+                    var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
+                    allowgrades.set('checked', !self.getSelectedToolTypeOption().getAttribute('nogrades'));
+                    self.toggleGradeSection();
+                }
+
             });
 
             this.createTypeEditorButtons();
index e34eb23..1cbeee2 100644 (file)
@@ -30,7 +30,7 @@
 //
 // 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
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
 
 /**
  * This file defines the main lti configuration form
@@ -63,21 +63,20 @@ class mod_lti_mod_form extends moodleform_mod {
         $this->typeid = 0;
 
         $mform =& $this->_form;
-        //-------------------------------------------------------------------------------
-        // Adding the "general" fieldset, where all the common settings are shown
+        // Adding the "general" fieldset, where all the common settings are shown.
         $mform->addElement('header', 'general', get_string('general', 'form'));
-        // Adding the standard "name" field
-        $mform->addElement('text', 'name', get_string('basicltiname', 'lti'), array('size'=>'64'));
+        // Adding the standard "name" field.
+        $mform->addElement('text', 'name', get_string('basicltiname', 'lti'), array('size' => '64'));
         $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', null, 'required', null, 'client');
         $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
-        // Adding the optional "intro" and "introformat" pair of fields
+        // Adding the optional "intro" and "introformat" pair of fields.
         $this->add_intro_editor(false, get_string('basicltiintro', 'lti'));
         $mform->setAdvanced('introeditor');
 
-        // Display the label to the right of the checkbox so it looks better & matches rest of the form
+        // Display the label to the right of the checkbox so it looks better & matches rest of the form.
         $coursedesc = $mform->getElement('showdescription');
-        if(!empty($coursedesc)){
+        if (!empty($coursedesc)) {
             $coursedesc->setText(' ' . $coursedesc->getLabel());
             $coursedesc->setLabel('&nbsp');
         }
@@ -93,12 +92,27 @@ class mod_lti_mod_form extends moodleform_mod {
         $mform->setAdvanced('showdescriptionlaunch');
         $mform->addHelpButton('showdescriptionlaunch', 'display_description', 'lti');
 
-        // Tool settings
+        // Tool settings.
         $tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'), array());
         $mform->addHelpButton('typeid', 'external_tool_type', 'lti');
+        $toolproxy = array();
 
         foreach (lti_get_types_for_add_instance() as $id => $type) {
-            if ($type->course == $COURSE->id) {
+            if (!empty($type->toolproxyid)) {
+                $toolproxy[] = $type->id;
+                $attributes = array( 'globalTool' => 1, 'toolproxy' => 1);
+                $enabledcapabilities = explode("\n", $type->enabledcapability);
+                if (!in_array('Result.autocreate', $enabledcapabilities)) {
+                    $attributes['nogrades'] = 1;
+                }
+                if (!in_array('Person.name.full', $enabledcapabilities) && !in_array('Person.name.family', $enabledcapabilities) &&
+                    !in_array('Person.name.given', $enabledcapabilities)) {
+                    $attributes['noname'] = 1;
+                }
+                if (!in_array('Person.email.primary', $enabledcapabilities)) {
+                    $attributes['noemail'] = 1;
+                }
+            } else if ($type->course == $COURSE->id) {
                 $attributes = array( 'editable' => 1, 'courseTool' => 1, 'domain' => $type->tooldomain );
             } else if ($id != 0) {
                 $attributes = array( 'globalTool' => 1, 'domain' => $type->tooldomain);
@@ -109,19 +123,21 @@ class mod_lti_mod_form extends moodleform_mod {
             $tooltypes->addOption($type->name, $id, $attributes);
         }
 
-        $mform->addElement('text', 'toolurl', get_string('launch_url', 'lti'), array('size'=>'64'));
+        $mform->addElement('text', 'toolurl', get_string('launch_url', 'lti'), array('size' => '64'));
         $mform->setType('toolurl', PARAM_TEXT);
         $mform->addHelpButton('toolurl', 'launch_url', 'lti');
+        $mform->disabledIf('toolurl', 'typeid', 'neq', '0');
 
-        $mform->addElement('text', 'securetoolurl', get_string('secure_launch_url', 'lti'), array('size'=>'64'));
+        $mform->addElement('text', 'securetoolurl', get_string('secure_launch_url', 'lti'), array('size' => '64'));
         $mform->setType('securetoolurl', PARAM_TEXT);
         $mform->setAdvanced('securetoolurl');
         $mform->addHelpButton('securetoolurl', 'secure_launch_url', 'lti');
+        $mform->disabledIf('securetoolurl', 'typeid', 'neq', '0');
 
         $mform->addElement('hidden', 'urlmatchedtypeid', '', array( 'id' => 'id_urlmatchedtypeid' ));
         $mform->setType('urlmatchedtypeid', PARAM_INT);
 
-        $launchoptions=array();
+        $launchoptions = array();
         $launchoptions[LTI_LAUNCH_CONTAINER_DEFAULT] = get_string('default', 'lti');
         $launchoptions[LTI_LAUNCH_CONTAINER_EMBED] = get_string('embed', 'lti');
         $launchoptions[LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS] = get_string('embed_no_blocks', 'lti');
@@ -136,74 +152,57 @@ class mod_lti_mod_form extends moodleform_mod {
         $mform->setType('resourcekey', PARAM_TEXT);
         $mform->setAdvanced('resourcekey');
         $mform->addHelpButton('resourcekey', 'resourcekey', 'lti');
+        $mform->disabledIf('resourcekey', 'typeid', 'neq', '0');
 
         $mform->addElement('passwordunmask', 'password', get_string('password', 'lti'));
         $mform->setType('password', PARAM_TEXT);
         $mform->setAdvanced('password');
         $mform->addHelpButton('password', 'password', 'lti');
+        $mform->disabledIf('password', 'typeid', 'neq', '0');
 
-        $mform->addElement('textarea', 'instructorcustomparameters', get_string('custom', 'lti'), array('rows'=>4, 'cols'=>60));
+        $mform->addElement('textarea', 'instructorcustomparameters', get_string('custom', 'lti'), array('rows' => 4, 'cols' => 60));
         $mform->setType('instructorcustomparameters', PARAM_TEXT);
         $mform->setAdvanced('instructorcustomparameters');
         $mform->addHelpButton('instructorcustomparameters', 'custom', 'lti');
 
-        $mform->addElement('text', 'icon', get_string('icon_url', 'lti'), array('size'=>'64'));
+        $mform->addElement('text', 'icon', get_string('icon_url', 'lti'), array('size' => '64'));
         $mform->setType('icon', PARAM_TEXT);
         $mform->setAdvanced('icon');
         $mform->addHelpButton('icon', 'icon_url', 'lti');
+        $mform->disabledIf('icon', 'typeid', 'neq', '0');
 
-        $mform->addElement('text', 'secureicon', get_string('secure_icon_url', 'lti'), array('size'=>'64'));
+        $mform->addElement('text', 'secureicon', get_string('secure_icon_url', 'lti'), array('size' => '64'));
         $mform->setType('secureicon', PARAM_TEXT);
         $mform->setAdvanced('secureicon');
         $mform->addHelpButton('secureicon', 'secure_icon_url', 'lti');
+        $mform->disabledIf('secureicon', 'typeid', 'neq', '0');
 
-        //-------------------------------------------------------------------------------
-        // Add privacy preferences fieldset where users choose whether to send their data
+        // Add privacy preferences fieldset where users choose whether to send their data.
         $mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
 
         $mform->addElement('advcheckbox', 'instructorchoicesendname', '&nbsp;', ' ' . get_string('share_name', 'lti'));
         $mform->setDefault('instructorchoicesendname', '1');
         $mform->addHelpButton('instructorchoicesendname', 'share_name', 'lti');
+        $mform->disabledIf('instructorchoicesendname', 'typeid', 'in', $toolproxy);
 
         $mform->addElement('advcheckbox', 'instructorchoicesendemailaddr', '&nbsp;', ' ' . get_string('share_email', 'lti'));
         $mform->setDefault('instructorchoicesendemailaddr', '1');
         $mform->addHelpButton('instructorchoicesendemailaddr', 'share_email', 'lti');
+        $mform->disabledIf('instructorchoicesendemailaddr', 'typeid', 'in', $toolproxy);
 
         $mform->addElement('advcheckbox', 'instructorchoiceacceptgrades', '&nbsp;', ' ' . get_string('accept_grades', 'lti'));
         $mform->setDefault('instructorchoiceacceptgrades', '1');
         $mform->addHelpButton('instructorchoiceacceptgrades', 'accept_grades', 'lti');
-
-        //$mform->addElement('checkbox', 'instructorchoiceallowroster', '&nbsp;', ' ' . get_string('share_roster', 'lti'));
-        //$mform->setDefault('instructorchoiceallowroster', '1');
-        //$mform->addHelpButton('instructorchoiceallowroster', 'share_roster', 'lti');
-
-        //-------------------------------------------------------------------------------
-
-        /**
-        $debugoptions=array();
-        $debugoptions[0] = get_string('debuglaunchoff', 'lti');
-        $debugoptions[1] = get_string('debuglaunchon', 'lti');
-
-        $mform->addElement('select', 'debuglaunch', get_string('debuglaunch', 'lti'), $debugoptions);
-
-        if (isset($this->typeconfig['debuglaunch'])) {
-            if ($this->typeconfig['debuglaunch'] == 0) {
-                $mform->setDefault('debuglaunch', '0');
-            } else if ($this->typeconfig['debuglaunch'] == 1) {
-                $mform->setDefault('debuglaunch', '1');
-            }
-        }
-        */
+        $mform->disabledIf('instructorchoiceacceptgrades', 'typeid', 'in', $toolproxy);
 
         // Add standard course module grading elements.
         $this->standard_grading_coursemodule_elements();
 
-        //-------------------------------------------------------------------------------
-        // add standard elements, common to all modules
+        // Add standard elements, common to all modules.
         $this->standard_coursemodule_elements();
         $mform->setAdvanced('cmidnumber');
-        //-------------------------------------------------------------------------------
-        // add standard buttons, common to all modules
+
+        // Add standard buttons, common to all modules.
         $this->add_action_buttons();
 
         $editurl = new moodle_url('/mod/lti/instructor_edit_tool_type.php',
@@ -222,10 +221,10 @@ class mod_lti_mod_form extends moodleform_mod {
                   );
 
         $module = array(
-            'name'      => 'mod_lti_edit',
-            'fullpath'  => '/mod/lti/mod_form.js',
-            'requires'  => array('base', 'io', 'querystring-stringify-simple', 'node', 'event', 'json-parse'),
-            'strings'   => array(
+            'name' => 'mod_lti_edit',
+            'fullpath' => '/mod/lti/mod_form.js',
+            'requires' => array('base', 'io', 'querystring-stringify-simple', 'node', 'event', 'json-parse'),
+            'strings' => array(
                 array('addtype', 'lti'),
                 array('edittype', 'lti'),
                 array('deletetype', 'lti'),
@@ -245,24 +244,5 @@ class mod_lti_mod_form extends moodleform_mod {
         $PAGE->requires->js_init_call('M.mod_lti.editor.init', array(json_encode($jsinfo)), true, $module);
     }
 
-    /**
-     * Make fields editable or non-editable depending on the administrator choices
-     * @see moodleform_mod::definition_after_data()
-     */
-    public function definition_after_data() {
-        parent::definition_after_data();
-
-        //$mform =& $this->_form;
-    }
-
-    /**
-     * Function overwritten to change default values using
-     * global configuration
-     *
-     * @param array $default_values passed by reference
-     */
-    public function data_preprocessing(&$default_values) {
-
-    }
 }
 
diff --git a/mod/lti/register.php b/mod/lti/register.php
new file mode 100644 (file)
index 0000000..20a460f
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains all necessary code to launch a Tool Proxy registration
+ *
+ * @package mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once('../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->dirroot.'/mod/lti/locallib.php');
+
+$id = required_param('id', PARAM_INT);
+$tab = optional_param('tab', '', PARAM_ALPHAEXT);
+
+require_login(0, false);
+
+$redirect = new moodle_url('/mod/lti/toolproxies.php', array('tab' => $tab));
+$redirect = $redirect->out();
+
+require_sesskey();
+
+$toolproxies = $DB->get_records('lti_tool_proxies');
+
+$duplicate = false;
+foreach ($toolproxies as $key => $toolproxy) {
+    if (($toolproxy->state == LTI_TOOL_PROXY_STATE_PENDING) || ($toolproxy->state == LTI_TOOL_PROXY_STATE_ACCEPTED)) {
+        if ($toolproxy->regurl == $toolproxies[$id]->regurl) {
+            $duplicate = true;
+            break;
+        }
+    }
+}
+
+$redirect = new moodle_url('/mod/lti/toolproxies.php');
+if ($duplicate) {
+    redirect($redirect,  get_string('duplicateregurl', 'lti'));
+}
+
+
+$profileservice = lti_get_service_by_name('profile');
+if (empty($profileservice)) {
+    redirect($redirect,  get_string('noprofileservice', 'lti'));
+}
+
+$url = new moodle_url('/mod/lti/register.php', array('id' => $id));
+$PAGE->set_url($url);
+
+admin_externalpage_setup('ltitoolproxies');
+
+
+$PAGE->set_heading(get_string('toolproxyregistration', 'lti'));
+$PAGE->set_title("{$SITE->shortname}: " . get_string('toolproxyregistration', 'lti'));
+
+// Print the page header.
+echo $OUTPUT->header();
+
+echo $OUTPUT->heading(get_string('toolproxyregistration', 'lti'));
+
+echo $OUTPUT->box_start('generalbox');
+
+// Request the registration request content with an object tag.
+$registration = new moodle_url('/mod/lti/registration.php',
+    array('id' => $id, 'sesskey' => sesskey()));
+
+echo "<p id=\"id_warning\" style=\"display: none; color: red; font-weight: bold; margin-top: 1em; padding-top: 1em;\">\n";
+echo get_string('register_warning', 'lti');
+echo "\n</p>\n";
+
+echo '<iframe id="contentframe" height="600px" width="100%" src="' . $registration->out() . '" onload="doOnload()"></iframe>';
+
+// Output script to make the object tag be as large as possible.
+$resize = '
+        <script type="text/javascript">
+        //<![CDATA[
+            function doReveal() {
+              var el = document.getElementById(\'id_warning\');
+              el.style.display = \'block\';
+            }
+            function doOnload() {
+                window.clearTimeout(mod_lti_timer);
+            }
+            var mod_lti_timer = window.setTimeout(doReveal, 20000);
+            YUI().use("node", "event", function(Y) {
+                //Take scrollbars off the outer document to prevent double scroll bar effect
+                var doc = Y.one("body");
+                doc.setStyle("overflow", "hidden");
+
+                var frame = Y.one("#contentframe");
+                var padding = 15; //The bottom of the iframe wasn\'t visible on some themes. Probably because of border widths, etc.
+                var lastHeight;
+                var resize = function(e) {
+                    var viewportHeight = doc.get("winHeight");
+                    if(lastHeight !== Math.min(doc.get("docHeight"), viewportHeight)){
+                        frame.setStyle("height", viewportHeight - frame.getY() - padding + "px");
+                        lastHeight = Math.min(doc.get("docHeight"), doc.get("winHeight"));
+                    }
+                };
+
+                resize();
+
+                Y.on("windowresize", resize);
+            });
+        //]]
+        </script>
+';
+
+echo $resize;
+
+// Finish the page.
+echo $OUTPUT->box_end();
+echo $OUTPUT->footer();
diff --git a/mod/lti/register_form.php b/mod/lti/register_form.php
new file mode 100644 (file)
index 0000000..42473a2
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+// 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/>.
+
+/**
+ * This file defines the main tool registration configuration form
+ *
+ * @package mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->libdir.'/formslib.php');
+require_once($CFG->dirroot.'/mod/lti/locallib.php');
+
+/**
+ * The mod_lti_register_types_form class.
+ *
+ * @package    mod_lti
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mod_lti_register_types_form extends moodleform {
+
+    /**
+     * Set up the form definition.
+     */
+    public function definition() {
+        global $CFG;
+
+        $mform    =& $this->_form;
+
+        $mform->addElement('header', 'setup', get_string('registration_options', 'lti'));
+
+        // Tool Provider name.
+
+        $mform->addElement('text', 'lti_registrationname', get_string('registrationname', 'lti'));
+        $mform->setType('lti_registrationname', PARAM_TEXT);
+        $mform->addHelpButton('lti_registrationname', 'registrationname', 'lti');
+        $mform->addRule('lti_registrationname', null, 'required', null, 'client');
+
+        // Registration URL.
+
+        $mform->addElement('text', 'lti_registrationurl', get_string('registrationurl', 'lti'), array('size' => '64'));
+        $mform->setType('lti_registrationurl', PARAM_TEXT);
+        $mform->addHelpButton('lti_registrationurl', 'registrationurl', 'lti');
+
+        // LTI Capabilities.
+
+        $options = array_keys(lti_get_capabilities());
+        natcasesort($options);
+        $attributes = array( 'multiple' => 1, 'size' => min(count($options), 10) );
+        $mform->addElement('select', 'lti_capabilities', get_string('capabilities', 'lti'),
+            array_combine($options, $options), $attributes);
+        $mform->setType('lti_capabilities', PARAM_TEXT);
+        $mform->addHelpButton('lti_capabilities', 'capabilities', 'lti');
+
+        // LTI Services.
+
+        $services = lti_get_services();
+        $options = array();
+        foreach ($services as $service) {
+            $options[$service->get_id()] = $service->get_name();
+        }
+        $attributes = array( 'multiple' => 1, 'size' => min(count($options), 10) );
+        $mform->addElement('select', 'lti_services', get_string('services', 'lti'), $options, $attributes);
+        $mform->setType('lti_services', PARAM_TEXT);
+        $mform->addHelpButton('lti_services', 'services', 'lti');
+
+        $mform->addElement('hidden', 'toolproxyid');
+        $mform->setType('toolproxyid', PARAM_INT);
+
+        $tab = optional_param('tab', '', PARAM_ALPHAEXT);
+        $mform->addElement('hidden', 'tab', $tab);
+        $mform->setType('tab', PARAM_ALPHAEXT);
+
+        $courseid = optional_param('course', 1, PARAM_INT);
+        $mform->addElement('hidden', 'course', $courseid);
+        $mform->setType('course', PARAM_INT);
+
+        // Add standard buttons, common to all modules.
+
+        $this->add_action_buttons();
+
+    }
+
+    /**
+     * Set up rules for disabling fields.
+     */
+    public function disable_fields() {
+
+        $mform    =& $this->_form;
+
+        $mform->disabledIf('lti_registrationurl', null);
+        $mform->disabledIf('lti_capabilities', null);
+        $mform->disabledIf('lti_services', null);
+
+    }
+
+    /**
+     * Set up rules for required fields.
+     */
+    public function required_fields() {
+
+        $mform    =& $this->_form;
+
+        $mform->addRule('lti_registrationurl', null, 'required', null, 'client');
+
+    }
+
+}
diff --git a/mod/lti/registersettings.php b/mod/lti/registersettings.php
new file mode 100644 (file)
index 0000000..a96a6f1
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains the script used to register a new external tool.
+ *
+ * It is used to create a new form used to configure the capabilities
+ * and services to be offered to the tool provider.
+ *
+ * @package mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once('../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->dirroot.'/mod/lti/register_form.php');
+require_once($CFG->dirroot.'/mod/lti/locallib.php');
+
+$action       = optional_param('action', null, PARAM_ALPHANUMEXT);
+$id           = optional_param('id', null, PARAM_INT);
+$tab          = optional_param('tab', '', PARAM_ALPHAEXT);
+
+// No guest autologin.
+require_login(0, false);
+
+$isupdate = !empty($id);
+$pageurl = new moodle_url('/mod/lti/registersettings.php');
+if ($isupdate) {
+    $pageurl->param('id', $id);
+}
+$PAGE->set_url($pageurl);
+
+admin_externalpage_setup('ltitoolproxies');
+
+$redirect = new moodle_url('/mod/lti/toolproxies.php', array('tab' => $tab));
+$redirect = $redirect->out();
+
+require_sesskey();
+
+if ($action == 'delete') {
+    lti_delete_tool_proxy($id);
+    redirect($redirect);
+}
+
+$data = array();
+if ($isupdate) {
+    $data['isupdate'] = true;
+}
+
+$form = new mod_lti_register_types_form($pageurl, (object)$data);
+
+if ($form->is_cancelled()) {
+    redirect($redirect);
+} else if ($data = $form->get_data()) {
+    $id = lti_add_tool_proxy($data);
+    redirect($redirect);
+} else {
+    $PAGE->set_title("{$SITE->shortname}: " . get_string('toolregistration', 'lti'));
+    $PAGE->navbar->add(get_string('lti_administration', 'lti'), $redirect);
+
+    echo $OUTPUT->header();
+    echo $OUTPUT->heading(get_string('toolregistration', 'lti'));
+    echo $OUTPUT->box_start('generalbox');
+    if ($action == 'update') {
+        $toolproxy = lti_get_tool_proxy_config($id);
+        $form->set_data($toolproxy);
+        if ($toolproxy->state == LTI_TOOL_PROXY_STATE_ACCEPTED) {
+            $form->disable_fields();
+        } else {
+            $form->required_fields();
+        }
+    } else {
+        $form->required_fields();
+    }
+    $form->display();
+
+    echo $OUTPUT->box_end();
+    echo $OUTPUT->footer();
+}
diff --git a/mod/lti/registration.php b/mod/lti/registration.php
new file mode 100644 (file)
index 0000000..d1b5c7a
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains all necessary code to initiate a tool registration process
+ *
+ * @package    mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @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');
+
+$id = required_param('id', PARAM_INT); // Tool Proxy ID.
+
+$toolproxy = $DB->get_record('lti_tool_proxies', array('id' => $id), '*', MUST_EXIST);
+
+require_login(0, false);
+
+$systemcontext = context_system::instance();
+require_capability('moodle/site:config', $systemcontext);
+
+lti_register($toolproxy);
diff --git a/mod/lti/registrationreturn.php b/mod/lti/registrationreturn.php
new file mode 100644 (file)
index 0000000..3209a1c
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+// 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/>.
+
+/**
+ * Handle the return from the Tool Provider after registering a tool proxy.
+ *
+ * @package mod_lti
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once('../../config.php');
+require_once($CFG->dirroot.'/mod/lti/locallib.php');
+
+$top = optional_param('top', 0, PARAM_INT);
+$msg = optional_param('lti_msg', '', PARAM_RAW);
+$err = optional_param('lti_errormsg', '', PARAM_RAW);
+$id = optional_param('id', 0, PARAM_INT);
+
+// No guest autologin.
+require_login(0, false);
+
+$systemcontext = context_system::instance();
+require_capability('moodle/site:config', $systemcontext);
+
+if (empty($top)) {
+
+    $params = array();
+    $params['top'] = '1';
+    if (!empty($msg)) {
+        $params['lti_msg'] = $msg;
+    }
+    if (!empty($err)) {
+        $params['lti_errormsg'] = $err;
+    }
+    if (!empty($id)) {
+        $params['id'] = $id;
+    }
+    $redirect = new moodle_url('/mod/lti/registrationreturn.php', $params);
+    $redirect = $redirect->out(false);
+
+    $clickhere = get_string('click_to_continue', 'lti', (object)array('link' => $redirect));
+    $html = <<< EOD
+<html>
+<head>
+<script type="text/javascript">
+//<![CDATA[
+top.location.href = '{$redirect}';
+//]]
+</script>
+</head>
+<body>
+<noscript>
+{$clickhere}
+</noscript>
+</body>
+</html>
+EOD;
+    echo $html;
+
+} else if (!empty($msg) && !empty($err)) {
+
+    $params = array();
+    $params['top'] = '1';
+    if (!empty($err)) {
+        $params['lti_errormsg'] = $err;
+    }
+    if (!empty($id)) {
+        $params['id'] = $id;
+    }
+    $redirect = new moodle_url('/mod/lti/registrationreturn.php', $params);
+    $redirect = $redirect->out(false);
+    redirect($redirect, $err);
+
+} else {
+
+    $redirect = new moodle_url('/mod/lti/toolproxies.php');
+    if (!empty($id)) {
+        $toolproxy = $DB->get_record('lti_tool_proxies', array('id' => $id));
+        switch($toolproxy->state) {
+            case LTI_TOOL_PROXY_STATE_ACCEPTED:
+                $redirect->param('tab', 'tp_accepted');
+                break;
+            case LTI_TOOL_PROXY_STATE_REJECTED:
+                $redirect->param('tab', 'tp_rejected');
+                break;
+            case LTI_TOOL_PROXY_STATE_PENDING:
+                // Change the status to configured.
+                $toolproxy->state = LTI_TOOL_PROXY_STATE_CONFIGURED;
+                lti_update_tool_proxy($toolproxy);
+        }
+    }
+
+    $redirect = $redirect->out();
+
+    if (empty($msg)) {
+        $msg = $err;
+    }
+    redirect($redirect, $msg);
+
+}
index d929e73..b044bf6 100644 (file)
@@ -52,9 +52,9 @@ $PAGE->set_pagelayout('incourse');
 echo $OUTPUT->header();
 echo $OUTPUT->heading(format_string($lti->name, true, array('context' => $context)));
 
-//Add a tool type if one does not exist already
+// Add a tool type if one does not exist already.
 if (!lti_get_tool_by_url_match($lti->toolurl, $lti->course, LTI_TOOL_STATE_ANY)) {
-    //There are no tools (active, pending, or rejected) for the launch URL. Create a new pending tool
+    // There are no tools (active, pending, or rejected) for the launch URL. Create a new pending tool.
     $tooltype = new stdClass();
     $toolconfig = new stdClass();
 
index 0446d40..66e14ce 100644 (file)
@@ -56,7 +56,7 @@ if (!empty($errormsg) || !empty($msg)) {
     $PAGE->set_title($pagetitle);
     $PAGE->set_heading($course->fullname);
 
-    //Avoid frame-in-frame action
+    // Avoid frame-in-frame action.
     if ($launchcontainer == LTI_LAUNCH_CONTAINER_EMBED || $launchcontainer == LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS) {
         $PAGE->set_pagelayout('embedded');
     } else {
@@ -80,7 +80,8 @@ if (!empty($errormsg)) {
         echo '<br /><br />';
 
         $links = new stdClass();
-        $coursetooleditor = new moodle_url('/mod/lti/instructor_edit_tool_type.php', array('course' => $courseid, 'action' => 'add'));
+        $coursetooleditor = new moodle_url('/mod/lti/instructor_edit_tool_type.php',
+            array('course' => $courseid, 'action' => 'add'));
         $links->course_tool_editor = $coursetooleditor->out(false);
 
         echo get_string('lti_launch_error_unsigned_help', 'lti', $links);
@@ -103,9 +104,9 @@ if (!empty($errormsg)) {
     $courseurl = new moodle_url('/course/view.php', array('id' => $courseid));
     $url = $courseurl->out();
 
-    //Avoid frame-in-frame action
+    // Avoid frame-in-frame action.
     if ($launchcontainer == LTI_LAUNCH_CONTAINER_EMBED || $launchcontainer == LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS) {
-        //Output a page containing some script to break out of frames and redirect them
+        // Output a page containing some script to break out of frames and redirect them.
 
         echo '<html><body>';
 
@@ -132,7 +133,7 @@ if (!empty($errormsg)) {
 
         echo '</body></html>';
     } else {
-        //If no error, take them back to the course
+        // If no error, take them back to the course.
         redirect($url);
     }
 }
index f117087..0075f8e 100644 (file)
  */
 
 define('NO_DEBUG_DISPLAY', true);
+define('NO_MOODLE_COOKIES', true);
 
 require_once(dirname(__FILE__) . "/../../config.php");
 require_once($CFG->dirroot.'/mod/lti/locallib.php');
 require_once($CFG->dirroot.'/mod/lti/servicelib.php');
 
-// TODO: Switch to core oauthlib once implemented - MDL-30149
+// TODO: Switch to core oauthlib once implemented - MDL-30149.
 use moodle\mod\lti as lti;
 
 $rawbody = file_get_contents("php://input");
@@ -40,7 +41,7 @@ if (lti_should_log_request($rawbody)) {
 
 foreach (lti\OAuthUtil::get_headers() as $name => $value) {
     if ($name === 'Authorization') {
-        // TODO: Switch to core oauthlib once implemented - MDL-30149
+        // TODO: Switch to core oauthlib once implemented - MDL-30149.
         $oauthparams = lti\OAuthUtil::split_header($value);
 
         $consumerkey = $oauthparams['oauth_consumer_key'];
@@ -118,7 +119,7 @@ switch ($messagetype) {
             throw new Exception('Tool does not accept grades');
         }
 
-        //Getting the grade requires the context is set
+        // Getting the grade requires the context is set.
         $context = context_course::instance($ltiinstance->course);
         $PAGE->set_context($context);
 
@@ -127,7 +128,7 @@ switch ($messagetype) {
         $grade = lti_read_grade($ltiinstance, $parsed->userid);
 
         $responsexml = lti_get_response_xml(
-                'success',  // Empty grade is also 'success'
+                'success',  // Empty grade is also 'success'.
                 'Result read',
                 $parsed->messageid,
                 'readResultResponse'
@@ -168,9 +169,9 @@ switch ($messagetype) {
         break;
 
     default:
-        //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.
+        // 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.
         $data = new stdClass();
         $data->body = $rawbody;
         $data->xml = $xml;
@@ -189,20 +190,20 @@ switch ($messagetype) {
             break;
         }
 
-        //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 $lti_web_service_handled;
-        $lti_web_service_handled = false;
+        // 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;
 
         try {
             $event = \mod_lti\event\unknown_service_api_called::create($eventdata);
             $event->set_message_data($data);
             $event->trigger();
         } catch (Exception $e) {
-            $lti_web_service_handled = false;
+            $ltiwebservicehandled = false;
         }
 
-        if (!$lti_web_service_handled) {
+        if (!$ltiwebservicehandled) {
             $responsexml = lti_get_response_xml(
                 'unsupported',
                 'unsupported',
@@ -215,10 +216,3 @@ switch ($messagetype) {
 
         break;
 }
-
-
-//echo print_r(apache_request_headers(), true);
-
-//echo '<br />';
-
-//echo file_get_contents("php://input");
diff --git a/mod/lti/service/profile/classes/local/resource/profile.php b/mod/lti/service/profile/classes/local/resource/profile.php
new file mode 100644 (file)
index 0000000..529a951
--- /dev/null
@@ -0,0 +1,228 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains a class definition for the Tool Consumer Profile resource
+ *
+ * @package    ltiservice_profile
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+namespace ltiservice_profile\local\resource;
+
+use \mod_lti\local\ltiservice\service_base;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * A resource implementing the Tool Consumer Profile.
+ *
+ * @package    ltiservice_profile
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class profile extends \mod_lti\local\ltiservice\resource_base {
+
+    /**
+     * Class constructor.
+     *
+     * @param ltiservice_profile\local\resource\profile $service Service instance
+     */
+    public function __construct($service) {
+
+        parent::__construct($service);
+        $this->id = 'ToolConsumerProfile';
+        $this->template = '/profile/{tool_proxy_id}';
+        $this->variables[] = 'ToolConsumerProfile.url';
+        $this->formats[] = 'application/vnd.ims.lti.v2.toolconsumerprofile+json';
+        $this->methods[] = 'GET';
+
+    }
+
+    /**
+     * Get the path for this resource.
+     *
+     * @return string
+     */
+    public function get_path() {
+
+        $path = $this->template;
+        $toolproxy = $this->get_service()->get_tool_proxy();
+        if (!empty($toolproxy)) {
+            $path = str_replace('{tool_proxy_id}', $toolproxy->guid, $path);
+        }
+
+        return $path;
+
+    }
+
+    /**
+     * Execute the request for this resource.
+     *
+     * @param mod_lti\local\ltiservice\response $response  Response object for this request.
+     */
+    public function execute($response) {
+
+        global $CFG;
+
+        $version = service_base::LTI_VERSION2P0;
+        $params = $this->parse_template();
+        $ok = $this->get_service()->check_tool_proxy($params['tool_proxy_id']);
+        if (!$ok) {
+            $response->set_code(404);
+        } else if (optional_param('lti_version', '', PARAM_ALPHANUMEXT) != $version) {
+            $response->set_code(400);
+        } else {
+            $toolproxy = $this->get_service()->get_tool_proxy();
+            $response->set_content_type($this->formats[0]);
+
+            $servicepath = $this->get_service()->get_service_path();
+            $id = $servicepath . $this->get_path();
+            $now = date('Y-m-d\TH:iO');
+            $capabilityofferedarr = explode("\n", $toolproxy->capabilityoffered);
+            $serviceofferedarr = explode("\n", $toolproxy->serviceoffered);
+            $serviceoffered = '';
+            $sep = '';
+            $services = \core_component::get_plugin_list('ltiservice');
+            foreach ($services as $name => $location) {
+                if (in_array($name, $serviceofferedarr)) {
+                    $classname = "\\ltiservice_{$name}\\local\\service\\{$name}";
+                    $service = new $classname();
+                    $service->set_tool_proxy($toolproxy);
+                    $resources = $service->get_resources();
+                    foreach ($resources as $resource) {
+                        $formats = implode("\", \"", $resource->get_formats());
+                        $methods = implode("\", \"", $resource->get_methods());
+                        $capabilityofferedarr = array_merge($capabilityofferedarr, $resource->get_variables());
+                        $path = $servicepath . preg_replace('/\{?.*\}$/', '', $resource->get_path());
+                        $serviceoffered .= <<< EOD
+{$sep}
+    {
+      "@type":"{$resource->get_type()}",
+      "@id":"tcp:{$resource->get_id()}",
+      "endpoint":"{$path}",
+      "format":["{$formats}"],
+      "action":["{$methods}"]
+    }
+EOD;
+                        $sep = ',';
+                    }
+                }
+            }
+            $capabilityoffered = implode("\",\n    \"", $capabilityofferedarr);
+            if (strlen($capabilityoffered) > 0) {
+                $capabilityoffered = "\n    \"{$capabilityoffered}\"";
+            }
+            $urlparts = parse_url($CFG->wwwroot);
+            $orgid = $urlparts['host'];
+            $name = 'Moodle';
+            $code = 'moodle';
+            $vendorname = 'Moodle.org';
+            $vendorcode = 'mdl';
+            $prodversion = strval($CFG->version);
+            if (!empty($CFG->mod_lti_institution_name)) {
+                $consumername = $CFG->mod_lti_institution_name;
+                $consumerdesc = '';
+            } else {
+                $consumername = get_site()->fullname;
+                $consumerdesc = strip_tags(get_site()->summary);
+            }
+            $profile = <<< EOD
+{
+  "@context":[
+    "http://purl.imsglobal.org/ctx/lti/v2/ToolConsumerProfile",
+    {
+      "tcp":"{$id}#"
+    }
+  ],
+  "@type":"ToolConsumerProfile",
+  "@id":"{$id}",
+  "lti_version":"{$version}",
+  "guid":"{$toolproxy->guid}",
+  "product_instance":{
+    "guid":"{$orgid}",
+    "product_info":{
+      "product_name":{
+        "default_value":"{$name}",
+        "key":"product.name"
+      },
+      "product_version":"{$prodversion}",
+      "product_family":{
+        "code":"{$code}",
+        "vendor":{
+          "code":"{$vendorcode}",
+          "vendor_name":{
+            "default_value":"{$vendorname}",
+            "key":"product.vendor.name"
+          },
+          "timestamp":"{$now}"
+        }
+      }
+    },
+    "service_owner":{
+      "@id":"ServiceOwner",
+      "service_owner_name":{
+        "default_value":"{$consumername}",
+        "key":"service_owner.name"
+      },
+      "description":{
+        "default_value":"{$consumerdesc}",
+        "key":"service_owner.description"
+      }
+    }
+  },
+  "capability_offered":[{$capabilityoffered}
+  ],
+  "service_offered":[{$serviceoffered}
+  ]
+}
+EOD;
+            $response->set_body($profile);
+
+        }
+    }
+
+    /**
+     * Get the resource fully qualified endpoint.
+     *
+     * @return string
+     */
+    public function get_endpoint() {
+
+        return parent::get_endpoint() . '?lti_version=' . service_base::LTI_VERSION2P0;
+
+    }
+
+    /**
+     * Parse a value for custom parameter substitution variables.
+     *
+     * @param string $value String to be parsed
+     *
+     * @return string
+     */
+    public function parse_value($value) {
+
+        $value = str_replace('$ToolConsumerProfile.url', $this->get_endpoint(), $value);
+
+        return $value;
+
+    }
+
+}
diff --git a/mod/lti/service/profile/classes/local/service/profile.php b/mod/lti/service/profile/classes/local/service/profile.php
new file mode 100644 (file)
index 0000000..dcea867
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains a class definition for the Tool Consumer Profile service
+ *
+ * @package    ltiservice_profile
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @author     Stephen Vickers
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+namespace ltiservice_profile\local\service;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * A service implementing the Tool Consumer Profile.
+ *
+ * @package    ltiservice_profile
+ * @since      Moodle 2.8
+ * @copyright  2014 Vital Source Technologies http://vitalsource.com
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later