MDL-65306 mod_lti: fix deeplinking support for tag and resourceid
This commit is contained in:
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("mod_lti/contentitem",["jquery","core/notification","core/str","core/templates","mod_lti/form-field","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){var h,i,j=[new e("name",e.TYPES.TEXT,!1,""),new e("introeditor",e.TYPES.EDITOR,!1,""),new e("toolurl",e.TYPES.TEXT,!0,""),new e("securetoolurl",e.TYPES.TEXT,!0,""),new e("instructorchoiceacceptgrades",e.TYPES.CHECKBOX,!0,!0),new e("instructorchoicesendname",e.TYPES.CHECKBOX,!0,!0),new e("instructorchoicesendemailaddr",e.TYPES.CHECKBOX,!0,!0),new e("instructorcustomparameters",e.TYPES.TEXT,!0,""),new e("icon",e.TYPES.TEXT,!0,""),new e("secureicon",e.TYPES.TEXT,!0,""),new e("launchcontainer",e.TYPES.SELECT,!0,0),new e("grade_modgrade_point",e.TYPES.TEXT,!1,""),new e("cmidnumber",e.TYPES.TEXT,!0,"")];window.processContentItemReturnData=function(a){if(h){h.hide()}for(var b in j){var c=j[b],d=null;if("undefined"!=typeof a[c.name]){d=a[c.name]}c.setFieldValue(d)}if(i){i()}};return{init:function init(a,e,j){i=j;var k=d.render("mod_lti/contentitem",{url:a,postData:e});if(h){h.setBody(k);h.show();return}c.get_string("selectcontent","lti").then(function(a){return f.create({title:a,body:k,large:!0})}).then(function(a){h=a;a.getRoot().on(g.hidden,function(){a.setBody("");b.fetchNotifications()});a.show()}).catch(b.exception)}}});
|
||||
define ("mod_lti/contentitem",["jquery","core/notification","core/str","core/templates","mod_lti/form-field","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){var h,i,j=[new e("name",e.TYPES.TEXT,!1,""),new e("introeditor",e.TYPES.EDITOR,!1,""),new e("toolurl",e.TYPES.TEXT,!0,""),new e("securetoolurl",e.TYPES.TEXT,!0,""),new e("instructorchoiceacceptgrades",e.TYPES.CHECKBOX,!0,!0),new e("instructorchoicesendname",e.TYPES.CHECKBOX,!0,!0),new e("instructorchoicesendemailaddr",e.TYPES.CHECKBOX,!0,!0),new e("instructorcustomparameters",e.TYPES.TEXT,!0,""),new e("icon",e.TYPES.TEXT,!0,""),new e("secureicon",e.TYPES.TEXT,!0,""),new e("launchcontainer",e.TYPES.SELECT,!0,0),new e("grade_modgrade_point",e.TYPES.TEXT,!1,""),new e("lineitemresourceid",e.TYPES.TEXT,!0,""),new e("lineitemtag",e.TYPES.TEXT,!0,"")];window.processContentItemReturnData=function(a){if(h){h.hide()}for(var b in j){var c=j[b],d=null;if("undefined"!=typeof a[c.name]){d=a[c.name]}c.setFieldValue(d)}if(i){i()}};return{init:function init(a,e,j){i=j;var k=d.render("mod_lti/contentitem",{url:a,postData:e});if(h){h.setBody(k);h.show();return}c.get_string("selectcontent","lti").then(function(a){return f.create({title:a,body:k,large:!0})}).then(function(a){h=a;a.getRoot().on(g.hidden,function(){a.setBody("");b.fetchNotifications()});a.show()}).catch(b.exception)}}});
|
||||
//# sourceMappingURL=contentitem.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -105,7 +105,8 @@ define(
|
||||
new FormField('secureicon', FormField.TYPES.TEXT, true, ''),
|
||||
new FormField('launchcontainer', FormField.TYPES.SELECT, true, 0),
|
||||
new FormField('grade_modgrade_point', FormField.TYPES.TEXT, false, ''),
|
||||
new FormField('cmidnumber', FormField.TYPES.TEXT, true, '')
|
||||
new FormField('lineitemresourceid', FormField.TYPES.TEXT, true, ''),
|
||||
new FormField('lineitemtag', FormField.TYPES.TEXT, true, '')
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
use ltiservice_gradebookservices\local\service\gradebookservices;
|
||||
|
||||
/**
|
||||
* List of features supported in URL module
|
||||
@@ -118,6 +119,8 @@ function lti_add_instance($lti, $mform) {
|
||||
lti_grade_item_update($lti);
|
||||
}
|
||||
|
||||
gradebookservices::update_coupled_gradebookservices($lti, $lti->lineitemresourceid ?? '', $lti->lineitemtag ?? '');
|
||||
|
||||
$completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null;
|
||||
\core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected);
|
||||
|
||||
@@ -165,6 +168,8 @@ function lti_update_instance($lti, $mform) {
|
||||
$lti->typeid = $lti->urlmatchedtypeid;
|
||||
}
|
||||
|
||||
gradebookservices::update_coupled_gradebookservices($lti, $lti->lineitemresourceid, $lti->lineitemtag);
|
||||
|
||||
$completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null;
|
||||
\core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected);
|
||||
|
||||
|
||||
@@ -1515,8 +1515,13 @@ function lti_tool_configuration_from_content_item($typeid, $messagetype, $ltiver
|
||||
}
|
||||
}
|
||||
$config->grade_modgrade_point = $maxscore;
|
||||
$config->lineitemresourceid = '';
|
||||
$config->lineitemtag = '';
|
||||
if (isset($lineitem->assignedActivity) && isset($lineitem->assignedActivity->activityId)) {
|
||||
$config->cmidnumber = $lineitem->assignedActivity->activityId;
|
||||
$config->lineitemresourceid = $lineitem->assignedActivity->activityId ? : '';
|
||||
}
|
||||
if (isset($lineitem->tag)) {
|
||||
$config->lineitemtag = $lineitem->tag ? : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1613,6 +1618,9 @@ function lti_convert_content_items($param) {
|
||||
$newitem->lineItem->assignedActivity = new stdClass();
|
||||
$newitem->lineItem->assignedActivity->activityId = $item->lineItem->resourceId;
|
||||
}
|
||||
if (isset($item->lineItem->tag)) {
|
||||
$newitem->lineItem->tag = $item->lineItem->tag;
|
||||
}
|
||||
if (isset($item->lineItem->scoreMaximum)) {
|
||||
$newitem->lineItem->scoreConstraints = new stdClass();
|
||||
$newitem->lineItem->scoreConstraints->{'@type'} = 'NumericLimits';
|
||||
|
||||
@@ -50,6 +50,7 @@ defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->dirroot.'/course/moodleform_mod.php');
|
||||
require_once($CFG->dirroot.'/mod/lti/locallib.php');
|
||||
use ltiservice_gradebookservices\local\service\gradebookservices;
|
||||
|
||||
class mod_lti_mod_form extends moodleform_mod {
|
||||
|
||||
@@ -207,6 +208,12 @@ class mod_lti_mod_form extends moodleform_mod {
|
||||
$mform->addElement('hidden', 'urlmatchedtypeid', '', array( 'id' => 'id_urlmatchedtypeid' ));
|
||||
$mform->setType('urlmatchedtypeid', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'lineitemresourceid', '', array( 'id' => 'id_lineitemresourceid' ));
|
||||
$mform->setType('lineitemresourceid', PARAM_TEXT);
|
||||
|
||||
$mform->addElement('hidden', 'lineitemtag', '', array( 'id' => 'id_lineitemtag'));
|
||||
$mform->setType('lineitemtag', PARAM_TEXT);
|
||||
|
||||
$launchoptions = array();
|
||||
$launchoptions[LTI_LAUNCH_CONTAINER_DEFAULT] = get_string('default', 'lti');
|
||||
$launchoptions[LTI_LAUNCH_CONTAINER_EMBED] = get_string('embed', 'lti');
|
||||
@@ -331,4 +338,22 @@ class mod_lti_mod_form extends moodleform_mod {
|
||||
$PAGE->requires->js_init_call('M.mod_lti.editor.init', array(json_encode($jsinfo)), true, $module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current values for resource and tag in case of update.
|
||||
*
|
||||
* @param object $defaultvalues default values to populate the form with.
|
||||
*/
|
||||
public function set_data($defaultvalues) {
|
||||
$defaultvalues->lineitemresourceid = '';
|
||||
$defaultvalues->lineitemtag = '';
|
||||
if (is_object($defaultvalues) && $defaultvalues->instance) {
|
||||
$gbs = gradebookservices::find_ltiservice_gradebookservice_for_lti($defaultvalues->instance);
|
||||
if ($gbs) {
|
||||
$defaultvalues->lineitemresourceid = $gbs->resourceid;
|
||||
$defaultvalues->lineitemtag = $gbs->tag;
|
||||
}
|
||||
}
|
||||
|
||||
parent::set_data($defaultvalues);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -61,6 +61,7 @@ class backup_ltiservice_gradebookservices_subplugin extends backup_subplugin {
|
||||
'typeid',
|
||||
'baseurl',
|
||||
'ltilinkid',
|
||||
'resourceid',
|
||||
'tag',
|
||||
'vendorcode',
|
||||
'guid'
|
||||
|
||||
+5
@@ -97,6 +97,10 @@ class restore_ltiservice_gradebookservices_subplugin extends restore_subplugin {
|
||||
} else {
|
||||
$ltilinkid = null;
|
||||
}
|
||||
$resourceid = null;
|
||||
if (property_exists( $data, 'resourceid' )) {
|
||||
$resourceid = $data->resourceid;
|
||||
}
|
||||
// If this has not been restored before.
|
||||
if ($this->get_mappingid('gbsgradeitemrestored', $data->id, 0) == 0) {
|
||||
$newgbsid = $DB->insert_record('ltiservice_gradebookservices', (object) array(
|
||||
@@ -106,6 +110,7 @@ class restore_ltiservice_gradebookservices_subplugin extends restore_subplugin {
|
||||
'ltilinkid' => $ltilinkid,
|
||||
'typeid' => $newtypeid,
|
||||
'baseurl' => $data->baseurl,
|
||||
'resourceid' => $resourceid,
|
||||
'tag' => $data->tag
|
||||
));
|
||||
$this->set_mapping('gbsgradeitemoldid', $newgbsid, $data->gradeitemid);
|
||||
|
||||
@@ -170,17 +170,14 @@ class lineitem extends resource_base {
|
||||
}
|
||||
$item->grademax = grade_floatval($json->scoreMaximum);
|
||||
}
|
||||
$resourceid = (isset($json->resourceId)) ? $json->resourceId : '';
|
||||
if ($item->idnumber !== $resourceid) {
|
||||
$updategradeitem = true;
|
||||
}
|
||||
$item->idnumber = $resourceid;
|
||||
if ($gbs) {
|
||||
$tag = (isset($json->tag)) ? $json->tag : null;
|
||||
if ($gbs->tag !== $tag) {
|
||||
$resourceid = (isset($json->resourceId)) ? $json->resourceId : '';
|
||||
$tag = (isset($json->tag)) ? $json->tag : '';
|
||||
if ($gbs->tag !== $tag || $gbs->resourceid !== $resourceid) {
|
||||
$upgradegradebookservices = true;
|
||||
}
|
||||
$gbs->tag = $tag;
|
||||
$gbs->resourceid = $resourceid;
|
||||
}
|
||||
$ltilinkid = null;
|
||||
if (isset($json->resourceLinkId)) {
|
||||
@@ -259,6 +256,7 @@ class lineitem extends resource_base {
|
||||
'typeid' => $typeid,
|
||||
'baseurl' => $baseurl,
|
||||
'ltilinkid' => $ltilinkid,
|
||||
'resourceid' => $resourceid,
|
||||
'tag' => $gbs->tag
|
||||
));
|
||||
}
|
||||
|
||||
@@ -266,33 +266,23 @@ class lineitems extends resource_base {
|
||||
$toolproxyid = null;
|
||||
$baseurl = lti_get_type_type_config($typeid)->lti_toolurl;
|
||||
}
|
||||
$params = array();
|
||||
$params['itemname'] = $json->label;
|
||||
$params['gradetype'] = GRADE_TYPE_VALUE;
|
||||
$params['grademax'] = $max;
|
||||
$params['grademin'] = 0;
|
||||
$item = new \grade_item(array('id' => 0, 'courseid' => $contextid));
|
||||
\grade_item::set_properties($item, $params);
|
||||
$item->itemtype = 'manual';
|
||||
$item->idnumber = $resourceid;
|
||||
$item->grademax = $max;
|
||||
$id = $item->insert('mod/ltiservice_gradebookservices');
|
||||
$DB->insert_record('ltiservice_gradebookservices', (object)array(
|
||||
'gradeitemid' => $id,
|
||||
'courseid' => $contextid,
|
||||
'toolproxyid' => $toolproxyid,
|
||||
'typeid' => $typeid,
|
||||
'baseurl' => $baseurl,
|
||||
'ltilinkid' => $ltilinkid,
|
||||
'tag' => $tag
|
||||
));
|
||||
$gradebookservices = new gradebookservices();
|
||||
$id = $gradebookservices->add_standalone_lineitem($contextid,
|
||||
$json->label,
|
||||
$max,
|
||||
$baseurl,
|
||||
$ltilinkid,
|
||||
$resourceid,
|
||||
$tag,
|
||||
$typeid,
|
||||
$toolproxyid);
|
||||
|
||||
if (is_null($typeid)) {
|
||||
$json->id = parent::get_endpoint() . "/{$id}/lineitem";
|
||||
} else {
|
||||
$json->id = parent::get_endpoint() . "/{$id}/lineitem?type_id={$typeid}";
|
||||
}
|
||||
return json_encode($json, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,25 +158,25 @@ class gradebookservices extends service_base {
|
||||
$this->get_typeconfig()['ltiservice_gradesynchronization'] == self::GRADEBOOKSERVICES_FULL) {
|
||||
// Check for used in context is only needed because there is no explicit site tool - course relation.
|
||||
if ($this->is_allowed_in_context($typeid, $courseid)) {
|
||||
if (is_null($modlti)) {
|
||||
$id = null;
|
||||
} else {
|
||||
$id = null;
|
||||
if (!is_null($modlti)) {
|
||||
$conditions = array('courseid' => $courseid, 'itemtype' => 'mod',
|
||||
'itemmodule' => 'lti', 'iteminstance' => $modlti);
|
||||
|
||||
$lineitems = $DB->get_records('grade_items', $conditions);
|
||||
$coupledlineitems = $DB->get_records('grade_items', $conditions);
|
||||
$conditionsgbs = array('courseid' => $courseid, 'ltilinkid' => $modlti);
|
||||
$lineitemsgbs = $DB->get_records('ltiservice_gradebookservices', $conditionsgbs);
|
||||
if (count($lineitems) + count($lineitemsgbs) == 1) {
|
||||
if ($lineitems) {
|
||||
$lineitem = reset($lineitems);
|
||||
$id = $lineitem->id;
|
||||
// If a link has more that one attached grade items, per spec we do not populate line item url.
|
||||
if (count($lineitemsgbs) == 1) {
|
||||
$id = reset($lineitemsgbs)->gradeitemid;
|
||||
}
|
||||
if (count($lineitemsgbs) < 2 && count($coupledlineitems) == 1) {
|
||||
$coupledid = reset($coupledlineitems)->id;
|
||||
if (!is_null($id) && $id != $coupledid) {
|
||||
$id = null;
|
||||
} else {
|
||||
$lineitemsgb = reset($lineitemsgbs);
|
||||
$id = $lineitemsgb->gradeitemid;
|
||||
$id = $coupledid;
|
||||
}
|
||||
} else {
|
||||
$id = null;
|
||||
}
|
||||
}
|
||||
$launchparameters['gradebookservices_scope'] = implode(',', $this->get_permitted_scopes());
|
||||
@@ -210,15 +210,9 @@ class gradebookservices extends service_base {
|
||||
// Select all lti potential linetiems in site.
|
||||
$params = array('courseid' => $courseid);
|
||||
|
||||
$optionalfilters = "";
|
||||
if (isset($resourceid)) {
|
||||
$optionalfilters .= " AND (i.idnumber = :resourceid)";
|
||||
$params['resourceid'] = $resourceid;
|
||||
}
|
||||
$sql = "SELECT i.*
|
||||
FROM {grade_items} i
|
||||
WHERE (i.courseid = :courseid)
|
||||
{$optionalfilters}
|
||||
ORDER BY i.id";
|
||||
$lineitems = $DB->get_records_sql($sql, $params);
|
||||
|
||||
@@ -230,7 +224,8 @@ class gradebookservices extends service_base {
|
||||
foreach ($lineitems as $lineitem) {
|
||||
$gbs = $this->find_ltiservice_gradebookservice_for_lineitem($lineitem->id);
|
||||
if ($gbs && (!isset($tag) || (isset($tag) && $gbs->tag == $tag))
|
||||
&& (!isset($ltilinkid) || (isset($ltilinkid) && $gbs->ltilinkid == $ltilinkid))) {
|
||||
&& (!isset($ltilinkid) || (isset($ltilinkid) && $gbs->ltilinkid == $ltilinkid))
|
||||
&& (!isset($resourceid) || (isset($resourceid) && $gbs->resourceid == $resourceid))) {
|
||||
if (is_null($typeid)) {
|
||||
if ($this->get_tool_proxy()->id == $gbs->toolproxyid) {
|
||||
array_push($lineitemstoreturn, $lineitem);
|
||||
@@ -240,8 +235,12 @@ class gradebookservices extends service_base {
|
||||
array_push($lineitemstoreturn, $lineitem);
|
||||
}
|
||||
}
|
||||
} else if (($lineitem->itemtype == 'mod') && ($lineitem->itemmodule == 'lti') && (!isset($tag) &&
|
||||
(!isset($ltilinkid) || (isset($ltilinkid) && $lineitem->iteminstance == $ltilinkid)))) {
|
||||
} else if (($lineitem->itemtype == 'mod'
|
||||
&& $lineitem->itemmodule == 'lti'
|
||||
&& !isset($resourceid)
|
||||
&& !isset($tag)
|
||||
&& (!isset($ltilinkid) || (isset($ltilinkid)
|
||||
&& $lineitem->iteminstance == $ltilinkid)))) {
|
||||
// We will need to check if the activity related belongs to our tool proxy.
|
||||
$ltiactivity = $DB->get_record('lti', array('id' => $lineitem->iteminstance));
|
||||
if (($ltiactivity) && (isset($ltiactivity->typeid))) {
|
||||
@@ -323,6 +322,59 @@ class gradebookservices extends service_base {
|
||||
return $lineitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a decoupled (standalone) line item.
|
||||
* Decoupled line items are not directly attached to
|
||||
* an lti instance activity. They are recorded in
|
||||
* the gradebook as manual activities and the
|
||||
* gradebookservices is used to associate that manual column
|
||||
* with the tool in addition to storing the LTI related
|
||||
* metadata (resource id, tag).
|
||||
*
|
||||
* @param string $courseid ID of course
|
||||
* @param string $label label of lineitem
|
||||
* @param float $maximumscore maximum score of lineitem
|
||||
* @param string $baseurl
|
||||
* @param int|null $ltilinkid id of lti instance this line item is associated with
|
||||
* @param string|null $resourceid resource id of lineitem
|
||||
* @param string|null $tag tag of lineitem
|
||||
* @param int $typeid lti type to which this line item is associated with
|
||||
* @param int|null $toolproxyid lti2 tool proxy to which this lineitem is associated to
|
||||
*
|
||||
* @return int id of the created gradeitem
|
||||
*/
|
||||
public function add_standalone_lineitem(string $courseid,
|
||||
string $label,
|
||||
float $maximumscore,
|
||||
string $baseurl,
|
||||
?int $ltilinkid,
|
||||
?string $resourceid,
|
||||
?string $tag,
|
||||
int $typeid,
|
||||
int $toolproxyid = null) : int {
|
||||
global $DB;
|
||||
$params = array();
|
||||
$params['itemname'] = $label;
|
||||
$params['gradetype'] = GRADE_TYPE_VALUE;
|
||||
$params['grademax'] = $maximumscore;
|
||||
$params['grademin'] = 0;
|
||||
$item = new \grade_item(array('id' => 0, 'courseid' => $courseid));
|
||||
\grade_item::set_properties($item, $params);
|
||||
$item->itemtype = 'manual';
|
||||
$item->grademax = $maximumscore;
|
||||
$id = $item->insert('mod/ltiservice_gradebookservices');
|
||||
$DB->insert_record('ltiservice_gradebookservices', (object)array(
|
||||
'gradeitemid' => $id,
|
||||
'courseid' => $courseid,
|
||||
'toolproxyid' => $toolproxyid,
|
||||
'typeid' => $typeid,
|
||||
'baseurl' => $baseurl,
|
||||
'ltilinkid' => $ltilinkid,
|
||||
'resourceid' => $resourceid,
|
||||
'tag' => $tag
|
||||
));
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a grade item.
|
||||
@@ -341,7 +393,7 @@ class gradebookservices extends service_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a grade item.
|
||||
* Saves a score received from the LTI tool.
|
||||
*
|
||||
* @param object $gradeitem Grade Item record
|
||||
* @param object $score Result object
|
||||
@@ -428,9 +480,9 @@ class gradebookservices extends service_base {
|
||||
$lineitem->id = "{$endpoint}/{$item->id}/lineitem" . $typeidstring;
|
||||
$lineitem->label = $item->itemname;
|
||||
$lineitem->scoreMaximum = floatval($item->grademax);
|
||||
$lineitem->resourceId = (!empty($item->idnumber)) ? $item->idnumber : '';
|
||||
$gbs = self::find_ltiservice_gradebookservice_for_lineitem($item->id);
|
||||
if ($gbs) {
|
||||
$lineitem->resourceId = (!empty($gbs->resourceid)) ? $gbs->resourceid : '';
|
||||
$lineitem->tag = (!empty($gbs->tag)) ? $gbs->tag : '';
|
||||
if (isset($gbs->ltilinkid)) {
|
||||
$lineitem->resourceLinkId = strval($gbs->ltilinkid);
|
||||
@@ -561,6 +613,42 @@ class gradebookservices extends service_base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tag and resourceid values for a grade item coupled to an lti link instance.
|
||||
*
|
||||
* @param object $ltiinstance The lti instance to which the grade item is coupled to
|
||||
* @param string|null $resourceid The resourceid to apply to the lineitem. Might be an empty string.
|
||||
* @param string|null $tag The tag to apply to the lineitem. Might be an empty string.
|
||||
*
|
||||
*/
|
||||
public static function update_coupled_gradebookservices(object $ltiinstance,
|
||||
?string $resourceid,
|
||||
?string $tag) : void {
|
||||
global $DB;
|
||||
if ($ltiinstance && $ltiinstance->typeid) {
|
||||
$gradeitem = $DB->get_record('grade_items', array('itemmodule' => 'lti', 'iteminstance' => $ltiinstance->id));
|
||||
if ($gradeitem) {
|
||||
$gbs = self::find_ltiservice_gradebookservice_for_lineitem($gradeitem->id);
|
||||
if ($gbs) {
|
||||
$gbs->resourceid = $resourceid;
|
||||
$gbs->tag = $tag;
|
||||
$DB->update_record('ltiservice_gradebookservices', $gbs);
|
||||
} else {
|
||||
$baseurl = lti_get_type_type_config($ltiinstance->typeid)->lti_toolurl;
|
||||
$DB->insert_record('ltiservice_gradebookservices', (object)array(
|
||||
'gradeitemid' => $gradeitem->id,
|
||||
'courseid' => $gradeitem->courseid,
|
||||
'typeid' => $ltiinstance->typeid,
|
||||
'baseurl' => $baseurl,
|
||||
'ltilinkid' => $ltiinstance->id,
|
||||
'resourceid' => $resourceid,
|
||||
'tag' => $tag
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes orphaned rows from the 'ltiservice_gradebookservices' table.
|
||||
*
|
||||
@@ -606,29 +694,34 @@ class gradebookservices extends service_base {
|
||||
return $gradableuser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the right element in the ltiservice_gradebookservice table for an lti instance
|
||||
*
|
||||
* @param string $instanceid The LTI module instance id
|
||||
* @return object gradebookservice for this line item
|
||||
*/
|
||||
public static function find_ltiservice_gradebookservice_for_lti($instanceid) {
|
||||
global $DB;
|
||||
|
||||
if ($instanceid) {
|
||||
$gradeitem = $DB->get_record('grade_items', array('itemmodule' => 'lti', 'iteminstance' => $instanceid));
|
||||
if ($gradeitem) {
|
||||
return self::find_ltiservice_gradebookservice_for_lineitem($gradeitem->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the right element in the ltiservice_gradebookservice table for a lineitem
|
||||
*
|
||||
* @param string $lineitemid The lineitem
|
||||
* @return object|bool gradebookservice id or false if none
|
||||
* @param string $lineitemid The lineitem (gradeitem) id
|
||||
* @return object gradebookservice if it exists
|
||||
*/
|
||||
public static function find_ltiservice_gradebookservice_for_lineitem($lineitemid) {
|
||||
global $DB;
|
||||
|
||||
if (!$lineitemid) {
|
||||
return false;
|
||||
}
|
||||
$gradeitem = $DB->get_record('grade_items', array('id' => $lineitemid));
|
||||
if ($gradeitem) {
|
||||
$gbs = $DB->get_record('ltiservice_gradebookservices',
|
||||
array('gradeitemid' => $gradeitem->id, 'courseid' => $gradeitem->courseid));
|
||||
if ($gbs) {
|
||||
return $gbs;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
if ($lineitemid) {
|
||||
return $DB->get_record('ltiservice_gradebookservices',
|
||||
array('gradeitemid' => $lineitemid));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<FIELD NAME="typeid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="ID of the LTI Type if not Proxy."/>
|
||||
<FIELD NAME="baseurl" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Lineitem URL that will be returned to the Tool provider"/>
|
||||
<FIELD NAME="ltilinkid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="ID of the LTI element related with this lineitem."/>
|
||||
<FIELD NAME="resourceid" TYPE="char" LENGTH="512" NOTNULL="false" SEQUENCE="false" COMMENT="Resource id for the line item"/>
|
||||
<FIELD NAME="tag" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Tag type specified for the line item"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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 defines tasks performed by the plugin.
|
||||
*
|
||||
* @package ltiservice_gradebookservices
|
||||
* @copyright 2020 Cengage Learning http://www.cengage.com
|
||||
* @author Claude Vervoort
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
/**
|
||||
* xmldb_ltiservice_gradebookservices_upgrade is the function that upgrades
|
||||
* the gradebook lti service subplugin database when is needed.
|
||||
*
|
||||
* This function is automatically called when version number in
|
||||
* version.php changes.
|
||||
*
|
||||
* @param int $oldversion New old version number.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function xmldb_ltiservice_gradebookservices_upgrade($oldversion) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
if ($oldversion < 2020020601) {
|
||||
// Define field typeid to be added to lti_tool_settings.
|
||||
$table = new xmldb_table('ltiservice_gradebookservices');
|
||||
$field = new xmldb_field('resourceid', XMLDB_TYPE_CHAR, "512", null, null, null, null);
|
||||
|
||||
// Conditionally launch add field typeid.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Lti savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2020020601, 'ltiservice', 'gradebookservices');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020020602) {
|
||||
// Now that we have added the new column let's migrate it'
|
||||
// Prior implementation was storing the resourceid under the grade item idnumber, so moving it to lti_gradebookservices.
|
||||
// We only care for mod/lti grade items as manual columns would already have a matching gradebookservices record.
|
||||
|
||||
$DB->execute("INSERT INTO {ltiservice_gradebookservices} (gradeitemid, courseid, typeid, resourceid, baseurl)
|
||||
SELECT gi.id, courseid, lti.typeid, gi.idnumber, t.baseurl
|
||||
FROM {grade_items} gi
|
||||
JOIN {lti} lti ON lti.id=gi.iteminstance AND gi.itemtype='mod' AND gi.itemmodule='lti'
|
||||
JOIN {lti_types} t ON t.id = lti.typeid
|
||||
WHERE gi.id NOT IN ( SELECT gradeitemid
|
||||
FROM {ltiservice_gradebookservices} )
|
||||
AND gi.idnumber IS NOT NULL
|
||||
AND gi.idnumber <> ''");
|
||||
|
||||
// Lti savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2020020602, 'ltiservice', 'gradebookservices');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020020603) {
|
||||
// Here updating the resourceid of pre-existing lti_gradebookservices.
|
||||
$DB->execute("UPDATE {ltiservice_gradebookservices}
|
||||
SET resourceid = (SELECT idnumber FROM {grade_items} WHERE id=gradeitemid)
|
||||
WHERE gradeitemid in (SELECT id FROM {grade_items}
|
||||
WHERE ((itemtype='mod' AND itemmodule='lti') OR itemtype='manual')
|
||||
AND idnumber IS NOT NULL
|
||||
AND idnumber <> '')
|
||||
AND (resourceid is null OR resourceid = '')");
|
||||
|
||||
// Lti savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2020020603, 'ltiservice', 'gradebookservices');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for mod_lti gradebookservices
|
||||
* @package ltiservice_gradebookservices
|
||||
* @category external
|
||||
* @copyright 2020 Claude Vervoort <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
use ltiservice_gradebookservices\local\service\gradebookservices;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Unit tests for lti gradebookservices.
|
||||
*/
|
||||
class mod_lti_gradebookservices_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test saving a graded LTI with resource and tag info (as a result of
|
||||
* content item selection) creates a gradebookservices record
|
||||
* that can be retrieved using the gradebook service API.
|
||||
*/
|
||||
public function test_lti_add_coupled_lineitem() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create a tool type, associated with that proxy.
|
||||
|
||||
$typeid = $this->create_type();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$resourceid = 'test-resource-id';
|
||||
$tag = 'tag';
|
||||
|
||||
$ltiinstance = $this->create_graded_lti($typeid, $course, $resourceid, $tag);
|
||||
|
||||
$this->assertNotNull($ltiinstance);
|
||||
|
||||
$gbs = gradebookservices::find_ltiservice_gradebookservice_for_lti($ltiinstance->id);
|
||||
|
||||
$this->assertNotNull($gbs);
|
||||
$this->assertEquals($resourceid, $gbs->resourceid);
|
||||
$this->assertEquals($tag, $gbs->tag);
|
||||
|
||||
$this->assert_lineitems($course, $typeid, $ltiinstance->name, $ltiinstance, $resourceid, $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test saving a standalone LTI lineitem with resource and tag info
|
||||
* that can be retrieved using the gradebook service API.
|
||||
*/
|
||||
public function test_lti_add_standalone_lineitem() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$resourceid = "test-resource-standalone";
|
||||
$tag = "test-tag-standalone";
|
||||
$typeid = $this->create_type();
|
||||
|
||||
$this->create_standalone_lineitem($course->id, $typeid, $resourceid, $tag);
|
||||
|
||||
$this->assert_lineitems($course, $typeid, "manualtest", null, $resourceid, $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test line item URL is populated for coupled line item only
|
||||
* if there is not another line item bound to the lti instance,
|
||||
* since in that case there would be no rule to define which of
|
||||
* the line items should be actually passed.
|
||||
*/
|
||||
public function test_get_launch_parameters_coupled() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create a tool type, associated with that proxy.
|
||||
|
||||
$typeid = $this->create_type();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$ltiinstance = $this->create_graded_lti($typeid, $course, 'resource-id', 'tag');
|
||||
|
||||
$this->assertNotNull($ltiinstance);
|
||||
|
||||
$gbservice = new gradebookservices();
|
||||
$params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
|
||||
$this->assertEquals('$LineItem.url', $params['lineitem_url']);
|
||||
$this->assertEquals('$LineItem.url', $params['lineitem_url']);
|
||||
|
||||
$this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag', $ltiinstance->id);
|
||||
$params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
|
||||
$this->assertEquals('$LineItems.url', $params['lineitems_url']);
|
||||
// 2 line items for a single link, we cannot return a single line item url.
|
||||
$this->assertFalse(array_key_exists('$LineItem.url', $params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test line item URL is populated for not coupled line item only
|
||||
* if there is a single line item attached to that lti instance.
|
||||
*/
|
||||
public function test_get_launch_parameters_decoupled() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create a tool type, associated with that proxy.
|
||||
|
||||
$typeid = $this->create_type();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$ltiinstance = $this->create_notgraded_lti($typeid, $course);
|
||||
|
||||
$this->assertNotNull($ltiinstance);
|
||||
|
||||
$gbservice = new gradebookservices();
|
||||
$params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
|
||||
$this->assertEquals('$LineItems.url', $params['lineitems_url']);
|
||||
$this->assertFalse(array_key_exists('$LineItem.url', $params));
|
||||
|
||||
$this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag', $ltiinstance->id);
|
||||
$params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
|
||||
$this->assertEquals('$LineItems.url', $params['lineitems_url']);
|
||||
$this->assertEquals('$LineItem.url', $params['lineitem_url']);
|
||||
|
||||
// 2 line items for a single link, we cannot return a single line item url.
|
||||
$this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag-2', $ltiinstance->id);
|
||||
$this->assertFalse(array_key_exists('$LineItem.url', $params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a matching gradebookservices record exist with the matching tag and resourceid.
|
||||
*
|
||||
* @param object $course current course
|
||||
* @param int $typeid Type id of the tool
|
||||
* @param string $label Label of the line item
|
||||
* @param object|null $ltiinstance lti instance related to that line item
|
||||
* @param string|null $resourceid resourceid the line item should have
|
||||
* @param string|null $tag tag the line item should have
|
||||
*/
|
||||
private function assert_lineitems(object $course,
|
||||
int $typeid,
|
||||
string $label,
|
||||
?object $ltiinstance,
|
||||
?string $resourceid,
|
||||
?string $tag) : void {
|
||||
$gbservice = new gradebookservices();
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, null, null, null, null, null, $typeid);
|
||||
|
||||
// The 1st item in the array is the items count.
|
||||
$this->assertEquals(1, $gradeitems[0]);
|
||||
|
||||
$lineitem = gradebookservices::item_for_json($gradeitems[1][0], '', $typeid);
|
||||
$this->assertEquals(10, $lineitem->scoreMaximum);
|
||||
$this->assertEquals($resourceid, $lineitem->resourceId);
|
||||
$this->assertEquals($tag, $lineitem->tag);
|
||||
$this->assertEquals($label, $lineitem->label);
|
||||
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, $resourceid, null, null, null, null, $typeid);
|
||||
$this->assertEquals(1, $gradeitems[0]);
|
||||
|
||||
if (isset($ltiinstance)) {
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, null, $ltiinstance->id, null, null, null, $typeid);
|
||||
$this->assertEquals(1, $gradeitems[0]);
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, null, $ltiinstance->id + 1, null, null, null, $typeid);
|
||||
$this->assertEquals(0, $gradeitems[0]);
|
||||
}
|
||||
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, null, null, $tag, null, null, $typeid);
|
||||
$this->assertEquals(1, $gradeitems[0]);
|
||||
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, 'an unknown resource id', null, null, null, null, $typeid);
|
||||
$this->assertEquals(0, $gradeitems[0]);
|
||||
|
||||
$gradeitems = $gbservice->get_lineitems($course->id, null, null, 'an unknown tag', null, null, $typeid);
|
||||
$this->assertEquals(0, $gradeitems[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a graded lti instance, which should create a grade_item and gradebookservices record.
|
||||
*
|
||||
* @param int $typeid Type ID of the LTI Tool.
|
||||
* @param object $course course where to add the lti instance.
|
||||
* @param string|null $resourceid resource id
|
||||
* @param string|null $tag tag
|
||||
*
|
||||
* @return object lti instance created
|
||||
*/
|
||||
private function create_graded_lti(int $typeid, object $course, ?string $resourceid, ?string $tag) : object {
|
||||
|
||||
$lti = ['course' => $course->id,
|
||||
'typeid' => $typeid,
|
||||
'instructorchoiceacceptgrades' => LTI_SETTING_ALWAYS,
|
||||
'grade' => 10,
|
||||
'lineitemresourceid' => $resourceid,
|
||||
'lineitemtag' => $tag];
|
||||
|
||||
return $this->getDataGenerator()->create_module('lti', $lti, array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an lti instance that is not graded.
|
||||
*
|
||||
* @param int $typeid Type Id of the LTI Tool.
|
||||
* @param object $course course where to add the lti instance.
|
||||
*
|
||||
* @return object lti instance created
|
||||
*/
|
||||
private function create_notgraded_lti(int $typeid, object $course) : object {
|
||||
|
||||
$lti = ['course' => $course->id,
|
||||
'typeid' => $typeid,
|
||||
'instructorchoiceacceptgrades' => LTI_SETTING_NEVER];
|
||||
|
||||
return $this->getDataGenerator()->create_module('lti', $lti, array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a standalone lineitem (gradeitem, gradebookservices entries).
|
||||
*
|
||||
* @param int $courseid Id of the course where the standalone line item will be added.
|
||||
* @param int $typeid of the LTI Tool
|
||||
* @param string|null $resourceid resource id
|
||||
* @param string|null $tag tag
|
||||
* @param int|null $ltiinstanceid Id of the LTI instance the standalone line item will be related to.
|
||||
*
|
||||
*/
|
||||
private function create_standalone_lineitem(int $courseid,
|
||||
int $typeid,
|
||||
?string $resourceid,
|
||||
?string $tag,
|
||||
int $ltiinstanceid = null) : void {
|
||||
$gbservice = new gradebookservices();
|
||||
$gbservice->add_standalone_lineitem($courseid,
|
||||
"manualtest",
|
||||
10,
|
||||
"https://test.phpunit",
|
||||
$ltiinstanceid,
|
||||
$resourceid,
|
||||
$tag,
|
||||
$typeid,
|
||||
null /*toolproxyid*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LTI Tool Type.
|
||||
*/
|
||||
private function create_type() {
|
||||
$type = new stdClass();
|
||||
$type->state = LTI_TOOL_STATE_CONFIGURED;
|
||||
$type->name = "Test tool";
|
||||
$type->description = "Example description";
|
||||
$type->clientid = "Test client ID";
|
||||
$type->baseurl = $this->getExternalTestFileUrl('/test.html');
|
||||
|
||||
$config = new stdClass();
|
||||
$config->ltiservice_gradesynchronization = 2;
|
||||
return lti_add_type($type, $config);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2019111800;
|
||||
$plugin->version = 2020020603;
|
||||
$plugin->requires = 2019111200;
|
||||
$plugin->component = 'ltiservice_gradebookservices';
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for mod_lti lib
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user