MDL-78909 mod_lti: Support coursevisibility override for courses

This commit is contained in:
Ilya Tregubov 2023-08-11 14:57:33 +08:00
parent b4c6ed3650
commit f9b1bac756
No known key found for this signature in database
GPG Key ID: 0F58186F748E55C1
21 changed files with 725 additions and 45 deletions

View File

@ -1,3 +1,3 @@
define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/str","core_table/dynamic","core_table/local/dynamic/selectors"],(function(_exports,_notification,_pending,_ajax,_toast,_str,_dynamic,Selectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const deleteBodyStringId=courseToolDelete.dataset.courseToolUsage>0?"deletecoursetoolwithusageconfirm":"deletecoursetoolconfirm",requiredStrings=[{key:"deletecoursetool",component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:deleteBodyStringId,component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:"delete",component:"core",param:courseToolDelete.dataset.courseToolName},{key:"coursetooldeleted",component:"mod_lti",param:courseToolDelete.dataset.courseToolName}],triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");(0,_str.getStrings)(requiredStrings).then((_ref=>{let[modalTitle,modalBody,deleteLabel]=_ref;return _notification.default.deleteCancelPromise(modalTitle,modalBody,deleteLabel,{triggerElement:triggerElement})})).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.getString)("coursetooldeleted","mod_lti",courseToolDelete.dataset.courseToolName))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}}))}}));
define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/str","core_table/dynamic","core_table/local/dynamic/selectors","./repository"],(function(_exports,_notification,_pending,_ajax,_toast,_str,_dynamic,Selectors,_repository){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const deleteBodyStringId=courseToolDelete.dataset.courseToolUsage>0?"deletecoursetoolwithusageconfirm":"deletecoursetoolconfirm",requiredStrings=[{key:"deletecoursetool",component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:deleteBodyStringId,component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:"delete",component:"core",param:courseToolDelete.dataset.courseToolName},{key:"coursetooldeleted",component:"mod_lti",param:courseToolDelete.dataset.courseToolName}],triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");(0,_str.getStrings)(requiredStrings).then((_ref=>{let[modalTitle,modalBody,deleteLabel]=_ref;return _notification.default.deleteCancelPromise(modalTitle,modalBody,deleteLabel,{triggerElement:triggerElement})})).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.getString)("coursetooldeleted","mod_lti",courseToolDelete.dataset.courseToolName))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}const courseShowInActivityChooser=event.target.closest('[data-action="showinactivitychooser-toggle"]');if(courseShowInActivityChooser){const showInActivityChooserStateToggle="0"===courseShowInActivityChooser.dataset.state?1:0;return(0,_repository.toggleShowInActivityChooser)(courseShowInActivityChooser.dataset.id,courseShowInActivityChooser.dataset.courseid,showInActivityChooserStateToggle)}}))}}));
//# sourceMappingURL=course_tools_list.min.js.map

File diff suppressed because one or more lines are too long

10
mod/lti/amd/build/repository.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
define("mod_lti/repository",["exports","core/ajax"],(function(_exports,_ajax){var obj;
/**
* Module to handle AJAX interactions.
*
* @module mod_lti/repository
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.toggleShowInActivityChooser=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.toggleShowInActivityChooser=(tooltypeid,courseid,coursevisible)=>_ajax.default.call([{methodname:"mod_lti_toggle_showinactivitychooser",args:{tooltypeid:tooltypeid,courseid:courseid,coursevisible:coursevisible}}])[0]}));
//# sourceMappingURL=repository.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"repository.min.js","sources":["../src/repository.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to handle AJAX interactions.\n *\n * @module mod_lti/repository\n * @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Toggle coursevisible of a tool\n *\n * @param {Number} tooltypeid Too type id\n * @param {Number} courseid Course ID\n * @param {Number} coursevisible coursevisible state\n * @return {Promise}\n */\nexport const toggleShowInActivityChooser = (\n tooltypeid,\n courseid,\n coursevisible,\n) => Ajax.call([{\n methodname: 'mod_lti_toggle_showinactivitychooser',\n args: {\n tooltypeid,\n courseid,\n coursevisible,\n },\n}])[0];\n"],"names":["tooltypeid","courseid","coursevisible","Ajax","call","methodname","args"],"mappings":";;;;;;;kMAiC2C,CACvCA,WACAC,SACAC,gBACCC,cAAKC,KAAK,CAAC,CACZC,WAAY,uCACZC,KAAM,CACFN,WAAAA,WACAC,SAAAA,SACAC,cAAAA,kBAEJ"}

View File

@ -30,6 +30,7 @@ import {add as addToast} from 'core/toast';
import {getString, getStrings} from 'core/str';
import {refreshTableContent} from 'core_table/dynamic';
import * as Selectors from 'core_table/local/dynamic/selectors';
import {toggleShowInActivityChooser} from "./repository";
/**
* Initialise module.
@ -78,5 +79,15 @@ export const init = () => {
return;
});
}
const courseShowInActivityChooser = event.target.closest('[data-action="showinactivitychooser-toggle"]');
if (courseShowInActivityChooser) {
const showInActivityChooserStateToggle = courseShowInActivityChooser.dataset.state === "0" ? 1 : 0;
return toggleShowInActivityChooser(
courseShowInActivityChooser.dataset.id,
courseShowInActivityChooser.dataset.courseid,
showInActivityChooserStateToggle,
);
}
});
};

View File

@ -0,0 +1,45 @@
// 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/>.
/**
* Module to handle AJAX interactions.
*
* @module mod_lti/repository
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Ajax from 'core/ajax';
/**
* Toggle coursevisible of a tool
*
* @param {Number} tooltypeid Too type id
* @param {Number} courseid Course ID
* @param {Number} coursevisible coursevisible state
* @return {Promise}
*/
export const toggleShowInActivityChooser = (
tooltypeid,
courseid,
coursevisible,
) => Ajax.call([{
methodname: 'mod_lti_toggle_showinactivitychooser',
args: {
tooltypeid,
courseid,
coursevisible,
},
}])[0];

View File

@ -146,6 +146,12 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
'state'
));
$lticoursevisible = new backup_nested_element('lticoursevisible', ['id'], [
'typeid',
'courseid',
'coursevisible',
]);
// Build the tree
$lti->add_child($ltitype);
$ltitype->add_child($ltitypesconfigs);
@ -156,6 +162,7 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
$ltitoolsettings->add_child($ltitoolsetting);
$lti->add_child($ltisubmissions);
$ltisubmissions->add_child($ltisubmission);
$lti->add_child($lticoursevisible);
// Define sources.
$ltirecord = $DB->get_record('lti', ['id' => $this->task->get_activityid()]);
@ -193,6 +200,9 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
$ltisubmission->set_source_table('lti_submission', array('ltiid' => backup::VAR_ACTIVITYID));
}
$lticoursevisibledata = $this->retrieve_lti_coursevisible($ltirecord);
$lticoursevisible->set_source_array($lticoursevisibledata ? [$lticoursevisibledata] : []);
// Define id annotations
$ltitype->annotate_ids('user', 'createdby');
$ltitype->annotate_ids('course', 'course');
@ -238,4 +248,18 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
return $record;
}
/**
* Retrieves a record from {lti_coursevisible} table associated with the current type
*
* @param stdClass $ltirecord record from {lti} table
* @return mixed
*/
protected function retrieve_lti_coursevisible(stdClass $ltirecord): mixed {
global $DB;
if (!$ltirecord->typeid) {
return null;
}
return $DB->get_record('lti_coursevisible', ['typeid' => $ltirecord->typeid, 'courseid' => $ltirecord->course]);
}
}

View File

@ -78,6 +78,8 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
$paths[] = $submission;
}
$paths[] = new restore_path_element('lticoursevisible', '/activity/lti/lticoursevisible');
// Add support for subplugin structures.
$this->add_subplugin_structure('ltisource', $lti);
$this->add_subplugin_structure('ltiservice', $lti);
@ -149,6 +151,23 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
$DB->update_record('lti', ['id' => $this->get_new_parentid('lti'), 'typeid' => $ltitypeid]);
}
/**
* Process an lti coursevisible restore
* @param mixed $data The data from backup XML file
* @return void
*/
protected function process_lticoursevisible($data) {
global $DB;
$data = (object)$data;
$data->typeid = $this->get_new_parentid('ltitype');
$data->courseid = $this->get_courseid();
if ($data->typeid) {
$DB->insert_record('lti_coursevisible', $data);
}
}
/**
* Attempts to find existing record in lti_type
* @param stdClass $data

View File

@ -0,0 +1,116 @@
<?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/>.
namespace mod_lti\external;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_value;
use mod_lti\local\ltiopenid\registration_helper;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/lti/locallib.php');
/**
* External function to toggle showinactivitychooser setting.
*
* @package mod_lti
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class toggle_showinactivitychooser extends external_api {
/**
* Get parameter definition.
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'tooltypeid' => new external_value(PARAM_INT, 'Tool type ID'),
'courseid' => new external_value(PARAM_INT, 'Course ID'),
'coursevisible' => new external_value(PARAM_BOOL, 'Show in activity chooser'),
]);
}
/**
* Toggles showinactivitychooser setting.
*
* @param int $tooltypeid the id of the course external tool type.
* @param int $courseid the id of the course we are in.
* @param bool $showinactivitychooser Show in activity chooser setting.
* @return bool true
*/
public static function execute(int $tooltypeid, int $courseid, bool $showinactivitychooser): bool {
global $DB;
[
'tooltypeid' => $tooltypeid,
'courseid' => $courseid,
'coursevisible' => $showinactivitychooser,
] = self::validate_parameters(self::execute_parameters(), [
'tooltypeid' => $tooltypeid,
'courseid' => $courseid,
'coursevisible' => $showinactivitychooser,
]);
$context = \context_course::instance($courseid);
self::validate_context($context);
require_capability('mod/lti:addcoursetool', $context);
if ($showinactivitychooser) {
$coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
} else {
$coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED;
}
$ltitype = $DB->get_record('lti_types', ['id' => $tooltypeid]);
$ltitype->coursevisible = $coursevisible;
$config = new \stdClass();
$config->lti_coursevisible = $coursevisible;
if (intval($ltitype->course) !== intval(get_site()->id)) {
// It is course tool - just update it.
lti_update_type($ltitype, $config);
} else {
// This is site tool, but we would like to have course level setting for it.
$lticoursevisible = $DB->get_record('lti_coursevisible', ['typeid' => $tooltypeid, 'courseid' => $courseid]);
if (!$lticoursevisible) {
$lticoursevisible = new \stdClass();
$lticoursevisible->typeid = $tooltypeid;
$lticoursevisible->courseid = $courseid;
$lticoursevisible->coursevisible = $coursevisible;
$DB->insert_record('lti_coursevisible', $lticoursevisible);
} else {
$lticoursevisible->coursevisible = $coursevisible;
$DB->update_record('lti_coursevisible', $lticoursevisible);
}
}
return true;
}
/**
* Get service returns definition.
*
* @return external_value
*/
public static function execute_returns(): external_value {
return new external_value(PARAM_BOOL, 'Success');
}
}

View File

@ -48,25 +48,36 @@ class types_helper {
if (empty($coursevisible)) {
$coursevisible = [LTI_COURSEVISIBLE_PRECONFIGURED, LTI_COURSEVISIBLE_ACTIVITYCHOOSER];
}
list($coursevisiblesql, $coursevisparams) = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible');
[$coursevisiblesql, $coursevisparams] = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible');
[$coursevisiblesql1, $coursevisparams1] = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible');
[$coursevisibleoverriddensql, $coursevisoverriddenparams] = $DB->get_in_or_equal(
$coursevisible,
SQL_PARAMS_NAMED,
'coursevisibleoverridden');
$coursecond = implode(" OR ", ["t.course = :courseid", "t.course = :siteid"]);
$coursecategory = $DB->get_field('course', 'category', ['id' => $courseid]);
$query = "SELECT t.*
FROM {lti_types} t
LEFT JOIN {lti_types_categories} tc ON t.id = tc.typeid
WHERE t.coursevisible $coursevisiblesql
AND ($coursecond)
AND t.state = :active
AND (tc.id IS NULL OR tc.categoryid = :categoryid)
ORDER BY t.name ASC";
$query = "SELECT *
FROM (SELECT t.*, c.coursevisible as coursevisibleoverridden
FROM {lti_types} t
LEFT JOIN {lti_types_categories} tc ON t.id = tc.typeid
LEFT JOIN {lti_coursevisible} c ON c.typeid = t.id AND c.courseid = $courseid
WHERE (t.coursevisible $coursevisiblesql OR c.coursevisible $coursevisiblesql1)
AND ($coursecond)
AND t.state = :active
AND (tc.id IS NULL OR tc.categoryid = :categoryid)) tt
WHERE tt.coursevisibleoverridden IS NULL
OR tt.coursevisibleoverridden $coursevisibleoverriddensql";
return $DB->get_records_sql($query,
return $DB->get_records_sql(
$query,
[
'siteid' => $SITE->id,
'courseid' => $courseid,
'active' => LTI_TOOL_STATE_CONFIGURED,
'categoryid' => $coursecategory
] + $coursevisparams);
'categoryid' => $coursecategory,
'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER,
] + $coursevisparams + $coursevisparams1 + $coursevisoverriddenparams
);
}
}

View File

@ -20,6 +20,7 @@ use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\report\column;
use mod_lti\reportbuilder\local\entities\tool_types;
use core_reportbuilder\system_report;
use stdClass;
/**
* Course external tools list system report class implementation.
@ -109,6 +110,7 @@ class course_external_tools_list extends system_report {
*/
protected function add_columns(tool_types $tooltypesentity): void {
$entitymainalias = $tooltypesentity->get_table_alias('lti_types');
$courseid = $this->course->id;
$columns = [
'tool_types:name',
@ -129,6 +131,57 @@ class course_external_tools_list extends system_report {
->add_field("{$entitymainalias}.id")
->add_callback(fn() => $this->perrowtoolusage);
// Enable toggle column.
$this->add_column((new column(
'showinactivitychooser',
new \lang_string('showinactivitychooser', 'mod_lti'),
$tooltypesentity->get_entity_name()
))
// Site tools can be overridden on course level.
->add_join("LEFT JOIN {lti_coursevisible} lc ON lc.typeid = {$entitymainalias}.id AND lc.courseid = $courseid")
->set_type(column::TYPE_INTEGER)
->add_fields("{$entitymainalias}.id, {$entitymainalias}.coursevisible, lc.coursevisible as coursevisibleoverridden")
->set_is_sortable(false)
->set_callback(static function(int $id, stdClass $row): string {
global $PAGE, $COURSE;
$coursevisible = $row->coursevisible;
$courseid = $COURSE->id;
if (!empty($row->coursevisibleoverridden)) {
$coursevisible = $row->coursevisibleoverridden;
}
if ($coursevisible == LTI_COURSEVISIBLE_ACTIVITYCHOOSER) {
$coursevisible = true;
} else {
$coursevisible = false;
}
$renderer = $PAGE->get_renderer('core_reportbuilder');
$attributes = [
['name' => 'id', 'value' => $row->id],
['name' => 'courseid', 'value' => $courseid],
['name' => 'action', 'value' => 'showinactivitychooser-toggle'],
['name' => 'state', 'value' => $coursevisible],
];
$label = $coursevisible ? get_string('dontshowinactivitychooser', 'mod_lti')
: get_string('showinactivitychooser', 'mod_lti');
$disabled = false;
if (!has_capability('mod/lti:addcoursetool', \context_course::instance($courseid))) {
$disabled = true;
}
return $renderer->render_from_template('core/toggle', [
'id' => 'showinactivitychooser-toggle-' . $row->id,
'checked' => $coursevisible,
'disabled' => $disabled,
'dataattributes' => $attributes,
'label' => $label,
'labelclasses' => 'sr-only'
]);
})
);
// Attempt to create a dummy actions column, working around the limitations of the official actions feature.
$this->add_column(new column(
'actions', new \lang_string('actions'),

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/lti/db" VERSION="20230725" COMMENT="XMLDB file for Moodle mod/lti"
<XMLDB PATH="mod/lti/db" VERSION="20230814" COMMENT="XMLDB file for Moodle mod/lti"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -175,5 +175,20 @@
<KEY NAME="categoryid" TYPE="foreign" FIELDS="categoryid" REFTABLE="course_categories" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="lti_coursevisible" COMMENT="Table to store coursevisible setting for site tool on course level">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="typeid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course ID"/>
<FIELD NAME="coursevisible" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
<INDEX NAME="typeid" UNIQUE="false" FIELDS="typeid"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>

View File

@ -154,6 +154,14 @@ $functions = array(
'ajax' => true
),
'mod_lti_toggle_showinactivitychooser' => array(
'classname' => 'mod_lti\external\toggle_showinactivitychooser',
'description' => 'Toggle showinactivitychooser for a course tool type',
'type' => 'write',
'capabilities' => 'mod/lti:addcoursetool',
'ajax' => true
),
'mod_lti_is_cartridge' => array(
'classname' => 'mod_lti_external',
'methodname' => 'is_cartridge',

View File

@ -133,10 +133,31 @@ function xmldb_lti_upgrade($oldversion) {
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Lti savepoint reached.
upgrade_mod_savepoint(true, 2023070501, 'lti');
}
if ($oldversion < 2023081101) {
// Define communication table.
$table = new xmldb_table('lti_coursevisible');
// Adding fields to table lti_coursevisible.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
$table->add_field('typeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
$table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'typeid');
$table->add_field('coursevisible', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'courseid');
// Add key.
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
// Conditionally launch create table for communication.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Lti savepoint reached.
upgrade_mod_savepoint(true, 2023081101, 'lti');
}
return true;
}

View File

@ -523,6 +523,8 @@ $string['share_roster_help'] = 'Specify whether the tool can access the list of
Note that this setting may be overridden in the tool configuration.';
$string['show_in_course_activity_chooser'] = 'Show in activity chooser and as a preconfigured tool';
$string['showinactivitychooser'] = 'Show in activity chooser';
$string['dontshowinactivitychooser'] = 'Don\'t show in activity chooser';
$string['show_in_course_lti1'] = 'Tool configuration usage';
$string['show_in_course_lti1_help'] = 'This tool may be shown in the activity chooser for a teacher to select to add to a course. Alternatively, it may be shown in the preconfigured tool drop-down menu when adding an external tool to a course. A further option is for the tool configuration to only be used if the exact tool URL is entered when adding an external tool to a course.';
$string['show_in_course_lti2'] = 'Tool configuration usage';

View File

@ -147,3 +147,136 @@ Feature: Manage course tools
And the field "Tool URL" matches value "http://www.example.com/lti/provider.php"
And the field "Icon URL" matches value "http://download.moodle.org/unittest/test.jpg"
And the field "Secure icon URL" matches value "https://download.moodle.org/unittest/test.jpg"
@javascript
Scenario: Site tool appearing in activity chooser according to settings
Given the following "mod_lti > tool types" exist:
| name | baseurl | coursevisible | state |
| Teaching Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | 2 | 1 |
| Teaching Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | 1 | 1 |
| Teaching Tool 3 | /mod/lti/tests/fixtures/tool_provider.php | 0 | 1 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 2 | C2 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C2 | editingteacher |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should see "Teaching Tool 1" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 2" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 3" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
And I navigate to "LTI External tools" in current page administration
And I should not see "Teaching Tool 3"
And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 1" "table_row"
And I click on "Show in activity chooser" "field" in the "Teaching Tool 2" "table_row"
And I am on "Course 1" course homepage
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should not see "Teaching Tool 1" in the ".modal-body" "css_element"
And I should see "Teaching Tool 2" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 3" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
# Should not affect other courses.
And I am on "Course 2" course homepage
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should see "Teaching Tool 1" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 2" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 3" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
And I am on "Course 1" course homepage
And I navigate to "LTI External tools" in current page administration
And I click on "Show in activity chooser" "field" in the "Teaching Tool 1" "table_row"
And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 2" "table_row"
And I am on "Course 1" course homepage
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should see "Teaching Tool 1" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 2" in the ".modal-body" "css_element"
And I should not see "Teaching Tool 3" in the ".modal-body" "css_element"
When the following "role capability" exists:
| role | editingteacher |
| mod/lti:addcoursetool | prohibit |
And I am on "Course 1" course homepage with editing mode on
And I navigate to "LTI External tools" in current page administration
Then the "Don't show in activity chooser" "field" should be disabled
And the "Show in activity chooser" "field" should be disabled
@javascript
Scenario: Course tool appearing in activity chooser according to settings
Given the following "mod_lti > course tools" exist:
| name | baseurl | course | coursevisible |
| Course Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | C1 | 2 |
| Course Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | C1 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should see "Course Tool 1" in the ".modal-body" "css_element"
And I should not see "Course Tool 2" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
And I navigate to "LTI External tools" in current page administration
And I click on "Don't show in activity chooser" "field" in the "Course Tool 1" "table_row"
And I click on "Show in activity chooser" "field" in the "Course Tool 2" "table_row"
And I am on "Course 1" course homepage
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should not see "Course Tool 1" in the ".modal-body" "css_element"
And I should see "Course Tool 2" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
And I navigate to "LTI External tools" in current page administration
And I click on "Show in activity chooser" "field" in the "Course Tool 1" "table_row"
And I click on "Don't show in activity chooser" "field" in the "Course Tool 2" "table_row"
And I am on "Course 1" course homepage
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
And I should see "Course Tool 1" in the ".modal-body" "css_element"
And I should not see "Course Tool 2" in the ".modal-body" "css_element"
When the following "role capability" exists:
| role | editingteacher |
| mod/lti:addcoursetool | prohibit |
And I am on "Course 1" course homepage with editing mode on
And I navigate to "LTI External tools" in current page administration
Then the "Don't show in activity chooser" "field" should be disabled
And the "Show in activity chooser" "field" should be disabled
@javascript
Scenario: Site and course tools settings are preserved when backup and restore
Given the following "mod_lti > tool types" exist:
| name | baseurl | coursevisible | state |
| Teaching Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | 2 | 1 |
| Teaching Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | 1 | 1 |
And the following "mod_lti > course tools" exist:
| name | description | baseurl | course |
| Course Tool 1 | Example description | https://example.com/tool | C1 |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add a "Teaching Tool 1" to section "1"
And I set the field "Activity name" to "Test tool activity 1"
And I press "Save and return to course"
And I add a "Course Tool 1" to section "1"
And I set the field "Activity name" to "Course tool activity 1"
And I press "Save and return to course"
And I navigate to "LTI External tools" in current page administration
And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 1" "table_row"
And I click on "Show in activity chooser" "field" in the "Teaching Tool 2" "table_row"
And I click on "Don't show in activity chooser" "field" in the "Course Tool 1" "table_row"
And I am on "Course 1" course homepage
And I add a "Teaching Tool 2" to section "1"
And I set the field "Activity name" to "Test tool activity 2"
And I press "Save and return to course"
When I backup "Course 1" course using this options:
| Confirmation | Filename | test_backup.mbz |
And I restore "test_backup.mbz" backup into a new course using this options:
| Schema | Course name | Restored course |
And I should see "Restored course"
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
Then I should not see "Teaching Tool 1" in the ".modal-body" "css_element"
And I should see "Teaching Tool 2" in the ".modal-body" "css_element"
And I should not see "Course Tool 2" in the ".modal-body" "css_element"
And I click on "Close" "button" in the ".modal-dialog" "css_element"
And I navigate to "LTI External tools" in current page administration
And I should see "Show in activity chooser" in the "Teaching Tool 1" "table_row"
And I should see "Don't show in activity chooser" in the "Teaching Tool 2" "table_row"
And I should see "Show in activity chooser" in the "Course Tool 1" "table_row"

View File

@ -0,0 +1,111 @@
<?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/>.
namespace mod_lti\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/lti/tests/mod_lti_testcase.php');
/**
* PHPUnit tests for toggle_showinactivitychooser external function.
*
* @package mod_lti
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_lti\external\toggle_showinactivitychooser
*/
class toggle_showinactivitychooser_test extends \mod_lti_testcase {
/**
* Test toggle_showinactivitychooser for course tool.
* @covers ::execute
*/
public function test_toggle_showinactivitychooser_course_tool() {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$this->setUser($editingteacher);
$typeid = lti_add_type(
(object) [
'state' => LTI_TOOL_STATE_CONFIGURED,
'course' => $course->id,
'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER
],
(object) [
'lti_typename' => "My course tool",
'lti_toolurl' => 'http://example.com',
'lti_ltiversion' => 'LTI-1p0',
'lti_coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER
]
);
toggle_showinactivitychooser::execute($typeid, $course->id, false);
$sql = "SELECT lt.coursevisible coursevisible1, ltc.value AS coursevisible2
FROM {lti_types} lt
LEFT JOIN {lti_types_config} ltc ON lt.id = ltc.typeid
WHERE lt.id = ?
AND ltc.name = 'coursevisible'";
$actual = $DB->get_record_sql($sql, [$typeid]);
$this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible1);
$this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible2);
toggle_showinactivitychooser::execute($typeid, $course->id, true);
$actual = $DB->get_record_sql($sql, [$typeid]);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2);
}
/**
* Test toggle_showinactivitychooser for site tool.
* @covers ::execute
*/
public function test_toggle_showinactivitychooser_site_tool() {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$this->setUser($editingteacher);
$type = $this->generate_tool_type(123); // Creates a site tool.
toggle_showinactivitychooser::execute($type->id, $course->id, false);
$sql = "SELECT lt.coursevisible coursevisible1, ltc.value AS coursevisible2, lc.coursevisible AS coursevisible3
FROM {lti_types} lt
LEFT JOIN {lti_types_config} ltc ON lt.id = ltc.typeid
LEFT JOIN {lti_coursevisible} lc ON lt.id = lc.typeid
WHERE lt.id = ?
AND lc.courseid = ?
AND ltc.name = 'coursevisible'";
$actual = $DB->get_record_sql($sql, [$type->id, $course->id]);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2);
$this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible3);
toggle_showinactivitychooser::execute($type->id, $course->id, true);
$actual = $DB->get_record_sql($sql, [$type->id, $course->id]);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2);
$this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible3);
}
}

View File

@ -151,13 +151,14 @@ class mod_lti_generator extends testing_module_generator {
}
$type['baseurl'] = (new moodle_url($type['baseurl']))->out(false); // Permits relative URLs in behat features.
$type['coursevisible'] = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; // The default for course tools.
$type['coursevisible'] = $type['coursevisible'] ?? LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
$type['state'] = LTI_TOOL_STATE_CONFIGURED; // The default for course tools.
// Sensible defaults permitting the tool type to be used in a launch.
$type['lti_acceptgrades'] = $type['lti_acceptgrades'] ?? LTI_SETTING_ALWAYS;
$type['lti_sendname'] = $type['lti_sendname'] ?? LTI_SETTING_ALWAYS;
$type['lti_sendemailaddr'] = $type['lti_sendemailaddr'] ?? LTI_SETTING_ALWAYS;
$type['lti_coursevisible'] = $type['coursevisible'] ?? LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
// Required for cartridge processing support.
$type['lti_toolurl'] = $type['baseurl'];

View File

@ -69,12 +69,20 @@ class types_helper_test extends mod_lti_testcase {
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$teacher2 = $this->getDataGenerator()->create_and_enrol($course2, 'editingteacher');
// Create the following tool types for testing:
// - Site tool configured as "Do not show" (LTI_COURSEVISIBLE_NO).
// - Site tool configured as "Show as a preconfigured tool only" (LTI_COURSEVISIBLE_PRECONFIGURED).
// - Site tool configured as "Show as a preconfigured tool and in the activity chooser" (LTI_COURSEVISIBLE_ACTIVITYCHOOSER).
// - Course tool which, by default, is configured as LTI_COURSEVISIBLE_ACTIVITYCHOOSER).
// - Site tool configured to "Show as a preconfigured tool and in the activity chooser" but restricted to a category.
/*
Create the following tool types for testing:
| tooltype | sitecoursevisible | coursecoursevisible | restrictedtocategory |
| site | LTI_COURSEVISIBLE_NO | | |
| site | LTI_COURSEVISIBLE_PRECONFIGURED | | |
| site | LTI_COURSEVISIBLE_PRECONFIGURED | LTI_COURSEVISIBLE_PRECONFIGURED | |
| site | LTI_COURSEVISIBLE_PRECONFIGURED | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | |
| site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | |
| site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | |
| site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_PRECONFIGURED | |
| site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | yes |
| course | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | |
| course | LTI_COURSEVISIBLE_PRECONFIGURED | | |
*/
/** @var \mod_lti_generator $ltigenerator */
$ltigenerator = $this->getDataGenerator()->get_plugin_generator('mod_lti');
@ -108,41 +116,129 @@ class types_helper_test extends mod_lti_testcase {
'state' => LTI_TOOL_STATE_CONFIGURED,
'lti_coursecategories' => $coursecat2->id
]);
$ltigenerator->create_tool_types([
'name' => 'site tool preconfigured only, overridden to preconfigured only in course',
'baseurl' => 'http://example.com/tool/6',
'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED,
'state' => LTI_TOOL_STATE_CONFIGURED
]);
$tool = $DB->get_record('lti_types',
['name' => 'site tool preconfigured only, overridden to preconfigured only in course']);
$record = new \stdClass();
$record->typeid = $tool->id;
$record->courseid = $course->id;
$record->coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED;
$DB->insert_record('lti_coursevisible', $record);
$ltigenerator->create_tool_types([
'name' => 'site tool preconfigured only, overridden to activity chooser in course',
'baseurl' => 'http://example.com/tool/7',
'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED,
'state' => LTI_TOOL_STATE_CONFIGURED
]);
$tool = $DB->get_record('lti_types', ['name' => 'site tool preconfigured only, overridden to activity chooser in course']);
$record = new \stdClass();
$record->typeid = $tool->id;
$record->courseid = $course->id;
$record->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
$DB->insert_record('lti_coursevisible', $record);
$ltigenerator->create_tool_types([
'name' => 'site tool preconfigured and activity chooser, overridden to activity chooser in course',
'baseurl' => 'http://example.com/tool/8',
'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER,
'state' => LTI_TOOL_STATE_CONFIGURED
]);
$tool = $DB->get_record('lti_types',
['name' => 'site tool preconfigured and activity chooser, overridden to activity chooser in course']);
$record = new \stdClass();
$record->typeid = $tool->id;
$record->courseid = $course->id;
$record->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
$DB->insert_record('lti_coursevisible', $record);
$ltigenerator->create_tool_types([
'name' => 'site tool preconfigured and activity chooser, overridden to preconfigured in course',
'baseurl' => 'http://example.com/tool/9',
'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER,
'state' => LTI_TOOL_STATE_CONFIGURED
]);
$tool = $DB->get_record('lti_types',
['name' => 'site tool preconfigured and activity chooser, overridden to preconfigured in course']);
$record = new \stdClass();
$record->typeid = $tool->id;
$record->courseid = $course->id;
$record->coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED;
$DB->insert_record('lti_coursevisible', $record);
$ltigenerator->create_course_tool_types([
'name' => 'course tool preconfigured',
'baseurl' => 'http://example.com/tool/91',
'course' => $course->id,
'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED
]);
// Request using the default 'coursevisible' param will include all tools except the one configured as "Do not show" and
// the tool restricted to category 2.
$coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id);
$this->assertCount(3, $coursetooltypes);
$this->assertEmpty(array_diff(
['http://example.com/tool/2', 'http://example.com/tool/3', 'http://example.com/tool/4'],
array_column($coursetooltypes, 'baseurl')
));
$this->assertCount(8, $coursetooltypes);
$this->assertEmpty(array_diff([
'http://example.com/tool/2',
'http://example.com/tool/3',
'http://example.com/tool/4',
'http://example.com/tool/6',
'http://example.com/tool/7',
'http://example.com/tool/8',
'http://example.com/tool/9',
'http://example.com/tool/91',
], array_column($coursetooltypes, 'baseurl')));
// Request for only those tools configured to show in the activity chooser for the teacher.
$coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id,
[LTI_COURSEVISIBLE_ACTIVITYCHOOSER]);
$this->assertCount(2, $coursetooltypes);
$this->assertEmpty(array_diff(
['http://example.com/tool/3', 'http://example.com/tool/4'],
array_column($coursetooltypes, 'baseurl')
));
$this->assertCount(4, $coursetooltypes);
$expected = [
'http://example.com/tool/3',
'http://example.com/tool/4',
'http://example.com/tool/7',
'http://example.com/tool/8'
];
sort($expected);
$actual = array_column($coursetooltypes, 'baseurl');
sort($actual);
$this->assertEquals($expected, $actual);
// Request for only those tools configured to show as a preconfigured tool for the teacher.
$coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id,
[LTI_COURSEVISIBLE_PRECONFIGURED]);
$this->assertCount(1, $coursetooltypes);
$this->assertEmpty(array_diff(
['http://example.com/tool/2'],
array_column($coursetooltypes, 'baseurl')
));
$this->assertCount(4, $coursetooltypes);
$expected = [
'http://example.com/tool/2',
'http://example.com/tool/6',
'http://example.com/tool/9',
'http://example.com/tool/91'
];
sort($expected);
$actual = array_column($coursetooltypes, 'baseurl');
sort($actual);
$this->assertEquals($expected, $actual);
// Request for teacher2 in course2 (course category 2).
$coursetooltypes = types_helper::get_lti_types_by_course($course2->id, $teacher2->id);
$this->assertCount(3, $coursetooltypes);
$this->assertEmpty(array_diff(
['http://example.com/tool/2', 'http://example.com/tool/3', 'http://example.com/tool/5'],
array_column($coursetooltypes, 'baseurl')
));
$this->assertCount(7, $coursetooltypes);
$expected = [
'http://example.com/tool/2',
'http://example.com/tool/3',
'http://example.com/tool/5',
'http://example.com/tool/6',
'http://example.com/tool/7',
'http://example.com/tool/8',
'http://example.com/tool/9'
];
sort($expected);
$actual = array_column($coursetooltypes, 'baseurl');
sort($actual);
$this->assertEquals($expected, $actual);
// Request for a teacher who cannot use preconfigured tools in the course.
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));

View File

@ -48,8 +48,11 @@ abstract class mod_lti_testcase extends externallib_advanced_testcase {
$type->description = "Example description $uniqueid";
$type->toolproxyid = $toolproxyid;
$type->baseurl = $this->getExternalTestFileUrl("/test$uniqueid.html");
$type->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
$config = new stdClass();
$config->lti_coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER;
$type->id = lti_add_type($type, new stdClass());
$type->id = lti_add_type($type, $config);
return $type;
}

View File

@ -48,7 +48,7 @@
defined('MOODLE_INTERNAL') || die;
$plugin->version = 2023081100; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2023081101; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2023041800; // Requires this Moodle version.
$plugin->component = 'mod_lti'; // Full name of the plugin (used for diagnostics).
$plugin->cron = 0;