mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-67262 core_course: Added the ability to recommend activities.
This allows an adminsitrator or a user with 'moodle/course:recommendactivity' to recommend activities in the activity chooser.
This commit is contained in:
parent
37b2ee3f64
commit
cd09777dbd
@ -61,6 +61,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
array('moodle/restore:restorecourse')
|
||||
)
|
||||
);
|
||||
$ADMIN->add('courses',
|
||||
new admin_externalpage('activitychooser', new lang_string('activitychooser', 'course'),
|
||||
new moodle_url('/course/recommendations.php'),
|
||||
array('moodle/course:recommendactivity')
|
||||
)
|
||||
);
|
||||
|
||||
// Course Default Settings Page.
|
||||
// NOTE: these settings must be applied after all other settings because they depend on them.
|
||||
|
2
course/amd/build/recommendations.min.js
vendored
Normal file
2
course/amd/build/recommendations.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_course/recommendations",["exports","core/ajax","core/notification"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}var e=function(a){var d={methodname:"core_course_toggle_activity_recommendation",args:{area:a.currentTarget.dataset.area,id:a.currentTarget.dataset.id}};b.default.call([d])[0].fail(c.default.exception)};a.init=function init(){var a=document.querySelectorAll("[data-area]");a.forEach(function(a){a.addEventListener("change",e)})}});
|
||||
//# sourceMappingURL=recommendations.min.js.map
|
1
course/amd/build/recommendations.min.js.map
Normal file
1
course/amd/build/recommendations.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/recommendations.js"],"names":["toggleRecommendation","e","data","methodname","args","area","currentTarget","dataset","id","Ajax","call","fail","Notification","exception","init","checkboxelements","document","querySelectorAll","forEach","checkbox","addEventListener"],"mappings":"8KAuBA,OACA,O,sDAQMA,CAAAA,CAAoB,CAAG,SAACC,CAAD,CAAO,CAChC,GAAIC,CAAAA,CAAI,CAAG,CACPC,UAAU,CAAE,4CADL,CAEPC,IAAI,CAAE,CACFC,IAAI,CAAEJ,CAAC,CAACK,aAAF,CAAgBC,OAAhB,CAAwBF,IAD5B,CAEFG,EAAE,CAAEP,CAAC,CAACK,aAAF,CAAgBC,OAAhB,CAAwBC,EAF1B,CAFC,CAAX,CAOAC,UAAKC,IAAL,CAAU,CAACR,CAAD,CAAV,EAAkB,CAAlB,EAAqBS,IAArB,CAA0BC,UAAaC,SAAvC,CACH,C,QAOmB,QAAPC,CAAAA,IAAO,EAAM,CACtB,GAAMC,CAAAA,CAAgB,CAAGC,QAAQ,CAACC,gBAAT,CAA0B,aAA1B,CAAzB,CACAF,CAAgB,CAACG,OAAjB,CAAyB,SAACC,CAAD,CAAc,CACnCA,CAAQ,CAACC,gBAAT,CAA0B,QAA1B,CAAoCpB,CAApC,CACH,CAFD,CAGH,C","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 * A javascript module to handle toggling activity chooser recommendations.\n *\n * @module core_course/recommendations\n * @copyright 2020 Adrian Greeve <adrian@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\n\n/**\n * Do an ajax call to toggle the recommendation\n *\n * @param {object} e The event\n * @return {void}\n */\nconst toggleRecommendation = (e) => {\n let data = {\n methodname: 'core_course_toggle_activity_recommendation',\n args: {\n area: e.currentTarget.dataset.area,\n id: e.currentTarget.dataset.id\n }\n };\n Ajax.call([data])[0].fail(Notification.exception);\n};\n\n/**\n * Initialisation function\n *\n * @return {void}\n */\nexport const init = () => {\n const checkboxelements = document.querySelectorAll(\"[data-area]\");\n checkboxelements.forEach((checkbox) => {\n checkbox.addEventListener('change', toggleRecommendation);\n });\n};"],"file":"recommendations.min.js"}
|
54
course/amd/src/recommendations.js
Normal file
54
course/amd/src/recommendations.js
Normal file
@ -0,0 +1,54 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* A javascript module to handle toggling activity chooser recommendations.
|
||||
*
|
||||
* @module core_course/recommendations
|
||||
* @copyright 2020 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
import Notification from 'core/notification';
|
||||
|
||||
/**
|
||||
* Do an ajax call to toggle the recommendation
|
||||
*
|
||||
* @param {object} e The event
|
||||
* @return {void}
|
||||
*/
|
||||
const toggleRecommendation = (e) => {
|
||||
let data = {
|
||||
methodname: 'core_course_toggle_activity_recommendation',
|
||||
args: {
|
||||
area: e.currentTarget.dataset.area,
|
||||
id: e.currentTarget.dataset.id
|
||||
}
|
||||
};
|
||||
Ajax.call([data])[0].fail(Notification.exception);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialisation function
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
export const init = () => {
|
||||
const checkboxelements = document.querySelectorAll("[data-area]");
|
||||
checkboxelements.forEach((checkbox) => {
|
||||
checkbox.addEventListener('change', toggleRecommendation);
|
||||
});
|
||||
};
|
@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\external\exporter;
|
||||
use core_course\local\entity\content_item;
|
||||
use core_course\local\service\content_item_service;
|
||||
|
||||
/**
|
||||
* The course_content_item_exporter class.
|
||||
@ -82,7 +83,8 @@ class course_content_item_exporter extends exporter {
|
||||
'legacyitem' => [
|
||||
'type' => PARAM_BOOL,
|
||||
'description' => 'If this item was pulled from the old callback and has no item id.'
|
||||
]
|
||||
],
|
||||
'recommended' => ['type' => PARAM_BOOL, 'description' => 'Has this item been recommended'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -113,6 +115,16 @@ class course_content_item_exporter extends exporter {
|
||||
}
|
||||
}
|
||||
|
||||
$recommended = false;
|
||||
$itemtype = content_item_service::RECOMMENDATION_PREFIX . $this->contentitem->get_component_name();
|
||||
if (isset($this->related['recommended'])) {
|
||||
foreach ($this->related['recommended'] as $favobj) {
|
||||
if ($favobj->itemtype === $itemtype && in_array($this->contentitem->get_id(), $favobj->ids)) {
|
||||
$recommended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$properties = [
|
||||
'id' => $this->contentitem->get_id(),
|
||||
'name' => $this->contentitem->get_name(),
|
||||
@ -123,7 +135,8 @@ class course_content_item_exporter extends exporter {
|
||||
'archetype' => $this->contentitem->get_archetype(),
|
||||
'componentname' => $this->contentitem->get_component_name(),
|
||||
'favourite' => $favourite,
|
||||
'legacyitem' => ($this->contentitem->get_id() == -1)
|
||||
'legacyitem' => ($this->contentitem->get_id() == -1),
|
||||
'recommended' => $recommended
|
||||
];
|
||||
|
||||
return $properties;
|
||||
@ -137,7 +150,8 @@ class course_content_item_exporter extends exporter {
|
||||
protected static function define_related(): array {
|
||||
return [
|
||||
'context' => '\context',
|
||||
'favouriteitems' => '\stdClass[]?'
|
||||
'favouriteitems' => '\stdClass[]?',
|
||||
'recommended' => '\stdClass[]?'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ class course_content_items_exporter extends exporter {
|
||||
[
|
||||
'context' => $this->related['context'],
|
||||
'favouriteitems' => $this->related['favouriteitems'],
|
||||
'recommended' => $this->related['recommended']
|
||||
]
|
||||
);
|
||||
return $exporter->export($output);
|
||||
@ -100,7 +101,8 @@ class course_content_items_exporter extends exporter {
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'context' => '\context',
|
||||
'favouriteitems' => '\stdClass[]?'
|
||||
'favouriteitems' => '\stdClass[]?',
|
||||
'recommended' => '\stdClass[]?'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,15 @@ class content_item_service {
|
||||
/** @var content_item_readonly_repository_interface $repository a repository for content items. */
|
||||
private $repository;
|
||||
|
||||
/** string the component for this favourite. */
|
||||
public const COMPONENT = 'core_course';
|
||||
/** string the favourite prefix itemtype in the favourites table. */
|
||||
public const FAVOURITE_PREFIX = 'contentitem_';
|
||||
/** string the recommendation prefix itemtype in the favourites table. */
|
||||
public const RECOMMENDATION_PREFIX = 'recommend_';
|
||||
/** string the cache name for recommendations. */
|
||||
public const RECOMMENDATION_CACHE = 'recommendation_favourite_course_content_items';
|
||||
|
||||
/**
|
||||
* The content_item_service constructor.
|
||||
*
|
||||
@ -69,6 +78,47 @@ class content_item_service {
|
||||
return $favmods;
|
||||
}
|
||||
|
||||
$favourites = $this->get_content_favourites(self::FAVOURITE_PREFIX, \context_user::instance($user->id));
|
||||
|
||||
$favcache->set($key, $favourites);
|
||||
return $favourites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of objects representing recommended content items.
|
||||
*
|
||||
* Each object contains the following properties:
|
||||
* itemtype: a string containing the 'itemtype' key used by the favourites subsystem.
|
||||
* ids[]: an array of ids, representing the content items within a component.
|
||||
*
|
||||
* Since two components can return (via their hook implementation) the same id, the itemtype is used for uniqueness.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_recommendations(): array {
|
||||
global $CFG;
|
||||
|
||||
$recommendationcache = \cache::make('core', self::RECOMMENDATION_CACHE);
|
||||
$key = $CFG->siteguest;
|
||||
$favmods = $recommendationcache->get($key);
|
||||
if ($favmods !== false) {
|
||||
return $favmods;
|
||||
}
|
||||
|
||||
$favourites = $this->get_content_favourites(self::RECOMMENDATION_PREFIX, \context_user::instance($CFG->siteguest));
|
||||
|
||||
$recommendationcache->set($CFG->siteguest, $favourites);
|
||||
return $favourites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content favourites from the favourites system depending on the area.
|
||||
*
|
||||
* @param string $prefix Prefix for the item type.
|
||||
* @param \context_user $usercontext User context for the favourite
|
||||
* @return array An array of favourite objects.
|
||||
*/
|
||||
private function get_content_favourites(string $prefix, \context_user $usercontext): array {
|
||||
// Get all modules and any submodules which implement get_course_content_items() hook.
|
||||
// This gives us the set of all itemtypes which we'll use to register favourite content items.
|
||||
// The ids that each plugin returns will be used together with the itemtype to uniquely identify
|
||||
@ -78,25 +128,24 @@ class content_item_service {
|
||||
$itemtypes = [];
|
||||
foreach ($plugins as $plugin) {
|
||||
// Add the mod itself.
|
||||
$itemtypes[] = 'contentitem_mod_' . $plugin->name;
|
||||
$itemtypes[] = $prefix . 'mod_' . $plugin->name;
|
||||
|
||||
// Add any subplugins to the list of item types.
|
||||
$subplugins = $pluginmanager->get_subplugins_of_plugin('mod_' . $plugin->name);
|
||||
foreach ($subplugins as $subpluginname => $subplugininfo) {
|
||||
if (component_callback_exists($subpluginname, 'get_course_content_items')) {
|
||||
$itemtypes[] = 'contentitem_' . $subpluginname;
|
||||
$itemtypes[] = $prefix . $subpluginname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($user->id));
|
||||
$ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext);
|
||||
$favourites = [];
|
||||
foreach ($itemtypes as $itemtype) {
|
||||
$favs = $ufservice->find_favourites_by_type('core_course', $itemtype);
|
||||
$favs = $ufservice->find_favourites_by_type(self::COMPONENT, $itemtype);
|
||||
$favobj = (object) ['itemtype' => $itemtype, 'ids' => array_column($favs, 'itemid')];
|
||||
$favourites[] = $favobj;
|
||||
}
|
||||
$favcache->set($key, $favourites);
|
||||
return $favourites;
|
||||
}
|
||||
|
||||
@ -112,11 +161,13 @@ class content_item_service {
|
||||
|
||||
// Export the objects to get the formatted objects for transfer/display.
|
||||
$favourites = $this->get_favourite_content_items_for_user($user);
|
||||
$recommendations = $this->get_recommendations();
|
||||
$ciexporter = new course_content_items_exporter(
|
||||
$allcontentitems,
|
||||
[
|
||||
'context' => \context_system::instance(),
|
||||
'favouriteitems' => $favourites
|
||||
'favouriteitems' => $favourites,
|
||||
'recommended' => $recommendations
|
||||
]
|
||||
);
|
||||
$exported = $ciexporter->export($PAGE->get_renderer('core'));
|
||||
@ -186,11 +237,13 @@ class content_item_service {
|
||||
|
||||
// Export the objects to get the formatted objects for transfer/display.
|
||||
$favourites = $this->get_favourite_content_items_for_user($user);
|
||||
$recommended = $this->get_recommendations();
|
||||
$ciexporter = new course_content_items_exporter(
|
||||
$availablecontentitems,
|
||||
[
|
||||
'context' => \context_course::instance($course->id),
|
||||
'favouriteitems' => $favourites
|
||||
'favouriteitems' => $favourites,
|
||||
'recommended' => $recommended
|
||||
]
|
||||
);
|
||||
$exported = $ciexporter->export($PAGE->get_renderer('course'));
|
||||
@ -217,9 +270,9 @@ class content_item_service {
|
||||
|
||||
// Because each plugin decides its own ids for content items, a combination of
|
||||
// itemtype and id is used to guarantee uniqueness across all content items.
|
||||
$itemtype = 'contentitem_' . $componentname;
|
||||
$itemtype = self::FAVOURITE_PREFIX . $componentname;
|
||||
|
||||
$ufservice->create_favourite('core_course', $itemtype, $contentitemid, $usercontext);
|
||||
$ufservice->create_favourite(self::COMPONENT, $itemtype, $contentitemid, $usercontext);
|
||||
|
||||
$favcache = \cache::make('core', 'user_favourite_course_content_items');
|
||||
$favcache->delete($user->id);
|
||||
@ -242,9 +295,9 @@ class content_item_service {
|
||||
|
||||
// Because each plugin decides its own ids for content items, a combination of
|
||||
// itemtype and id is used to guarantee uniqueness across all content items.
|
||||
$itemtype = 'contentitem_' . $componentname;
|
||||
$itemtype = self::FAVOURITE_PREFIX . $componentname;
|
||||
|
||||
$ufservice->delete_favourite('core_course', $itemtype, $contentitemid, $usercontext);
|
||||
$ufservice->delete_favourite(self::COMPONENT, $itemtype, $contentitemid, $usercontext);
|
||||
|
||||
$favcache = \cache::make('core', 'user_favourite_course_content_items');
|
||||
$favcache->delete($user->id);
|
||||
@ -252,4 +305,36 @@ class content_item_service {
|
||||
$items = $this->get_all_content_items($user);
|
||||
return $items[array_search($contentitemid, array_column($items, 'id'))];
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle an activity to being recommended or not.
|
||||
*
|
||||
* @param string $itemtype The component such as mod_assign, or assignsubmission_file
|
||||
* @param int $itemid The id related to this component item.
|
||||
* @return bool True on creating a favourite, false on deleting it.
|
||||
*/
|
||||
public function toggle_recommendation(string $itemtype, int $itemid): bool {
|
||||
global $CFG;
|
||||
|
||||
$context = \context_system::instance();
|
||||
|
||||
$itemtype = self::RECOMMENDATION_PREFIX . $itemtype;
|
||||
|
||||
// Favourites are created using a user context. We'll use the site guest user ID as that should not change and there
|
||||
// can be only one.
|
||||
$usercontext = \context_user::instance($CFG->siteguest);
|
||||
|
||||
$recommendationcache = \cache::make('core', self::RECOMMENDATION_CACHE);
|
||||
|
||||
$favouritefactory = \core_favourites\service_factory::get_service_for_user_context($usercontext);
|
||||
if ($favouritefactory->favourite_exists(self::COMPONENT, $itemtype, $itemid, $context)) {
|
||||
$favouritefactory->delete_favourite(self::COMPONENT, $itemtype, $itemid, $context);
|
||||
$result = $recommendationcache->delete($CFG->siteguest);
|
||||
return false;
|
||||
} else {
|
||||
$favouritefactory->create_favourite(self::COMPONENT, $itemtype, $itemid, $context);
|
||||
$result = $recommendationcache->delete($CFG->siteguest);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
68
course/classes/output/recommendations/activity_list.php
Normal file
68
course/classes/output/recommendations/activity_list.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Contains renderers for the recommendations page.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2020 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_course\output\recommendations;
|
||||
|
||||
/**
|
||||
* Main renderer for the recommendations page.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2020 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class activity_list implements \renderable, \templatable {
|
||||
|
||||
/** @var array $modules activities to display in the recommendations page. */
|
||||
protected $modules;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*
|
||||
* @param array $modules Activities to display
|
||||
*/
|
||||
public function __construct(array $modules) {
|
||||
$this->modules = $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export method to configure information into something the template can use.
|
||||
*
|
||||
* @param \renderer_base $output Not actually used.
|
||||
* @return array Template context information.
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
|
||||
$info = array_map(function($module) {
|
||||
return [
|
||||
'id' => $module->id ?? '',
|
||||
'name' => $module->title,
|
||||
'componentname' => $module->componentname,
|
||||
'icon' => $module->icon,
|
||||
'recommended' => $module->recommended ?? ''
|
||||
];
|
||||
}, $this->modules);
|
||||
|
||||
return ['categories' => ['categoryname' => get_string('activities'), 'categorydata' => $info]];
|
||||
}
|
||||
}
|
46
course/classes/output/recommendations/renderer.php
Normal file
46
course/classes/output/recommendations/renderer.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Contains renderers for the recommendations page.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2020 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_course\output\recommendations;
|
||||
|
||||
/**
|
||||
* Main renderer for the recommendations page.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2020 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends \plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Render a list of activities to recommend.
|
||||
*
|
||||
* @param \core_course\output\recommendations\activity_list $page activity list renderable
|
||||
* @return string html for displaying.
|
||||
*/
|
||||
public function render_activity_list(\core_course\output\recommendations\activity_list $page): string {
|
||||
$data = $page->export_for_template($this);
|
||||
return parent::render_from_template('core_course/activity_list', $data);
|
||||
}
|
||||
}
|
@ -4287,4 +4287,53 @@ class core_course_external extends external_api {
|
||||
$contentitems = $contentitemservice->get_content_items_for_user_in_course($USER, $course);
|
||||
return ['content_items' => $contentitems];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function toggle_activity_recommendation_parameters() {
|
||||
return new external_function_parameters([
|
||||
'area' => new external_value(PARAM_TEXT, 'The favourite area (itemtype)', VALUE_REQUIRED),
|
||||
'id' => new external_value(PARAM_INT, 'id of the activity or whatever', VALUE_REQUIRED),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the recommendation for an activity item.
|
||||
*
|
||||
* @param string $area identifier for this activity.
|
||||
* @param int $id Associated id. This is needed in conjunction with the area to find the recommendation.
|
||||
* @return array some warnings or something.
|
||||
*/
|
||||
public static function toggle_activity_recommendation(string $area, int $id): array {
|
||||
['area' => $area, 'id' => $id] = self::validate_parameters(self::toggle_activity_recommendation_parameters(),
|
||||
['area' => $area, 'id' => $id]);
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
require_capability('moodle/course:recommendactivity', $context);
|
||||
|
||||
$manager = \core_course\local\factory\content_item_service_factory::get_content_item_service();
|
||||
|
||||
$status = $manager->toggle_recommendation($area, $id);
|
||||
return ['id' => $id, 'area' => $area, 'status' => $status];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns warnings.
|
||||
*
|
||||
* @return external_description
|
||||
*/
|
||||
public static function toggle_activity_recommendation_returns() {
|
||||
return new external_single_structure(
|
||||
[
|
||||
'id' => new external_value(PARAM_INT, 'id of the activity or whatever'),
|
||||
'area' => new external_value(PARAM_TEXT, 'The favourite area (itemtype)'),
|
||||
'status' => new external_value(PARAM_BOOL, 'If created or deleted'),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
54
course/recommendations.php
Normal file
54
course/recommendations.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Site recommendations for the activity chooser.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2020 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
|
||||
$context = context_system::instance();
|
||||
$url = new moodle_url('/course/recommendations.php');
|
||||
|
||||
$pageheading = format_string($SITE->fullname, true, ['context' => $context]);
|
||||
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
$PAGE->set_title(get_string('activitychoosertitle', 'course'));
|
||||
$PAGE->set_heading($pageheading);
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/course:recommendactivity', $context);
|
||||
|
||||
$renderer = $PAGE->get_renderer('core_course', 'recommendations');
|
||||
|
||||
echo $renderer->header();
|
||||
echo $renderer->heading(get_string('activitychooser', 'course'));
|
||||
|
||||
$manager = \core_course\local\factory\content_item_service_factory::get_content_item_service();
|
||||
$modules = $manager->get_all_content_items($USER);
|
||||
|
||||
$activitylist = new \core_course\output\recommendations\activity_list($modules);
|
||||
|
||||
echo $renderer->render_activity_list($activitylist);
|
||||
|
||||
echo $renderer->footer();
|
56
course/templates/activity_list.mustache
Normal file
56
course/templates/activity_list.mustache
Normal file
@ -0,0 +1,56 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_course/activity_list
|
||||
|
||||
Displays a list of activities to recommend in the activity chooser.
|
||||
|
||||
No example given as the js will fire and create records from the template library page.
|
||||
}}
|
||||
{{#categories}}
|
||||
<h3>{{categoryname}}</h3>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-7 c0">{{#str}}module, course{{/str}}</th>
|
||||
<th scope="col" class="col-5 c1">{{#str}}recommend, course{{/str}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#categorydata}}
|
||||
<tr class="d-flex">
|
||||
<td class="font-weight-bold col-7 c0"><span>{{{icon}}}</span>{{name}}</td>
|
||||
{{#id}}
|
||||
<td class="col-5 c1 colselect">
|
||||
<input class="activity-recommend-checkbox" type="checkbox" aria-label="{{#str}}recommendcheckbox, course, {{name}}{{/str}}" data-area="{{componentname}}" data-id="{{id}}" {{#recommended}}checked="checked"{{/recommended}} />
|
||||
</td>
|
||||
{{/id}}
|
||||
{{^id}}
|
||||
<td class="col-5"></td>
|
||||
{{/id}}
|
||||
</tr>
|
||||
{{/categorydata}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/categories}}
|
||||
{{#js}}
|
||||
require([
|
||||
'core_course/recommendations',
|
||||
], function(Recommendations) {
|
||||
Recommendations.init();
|
||||
});
|
||||
{{/js}}
|
@ -71,6 +71,7 @@ $string['cachedef_portfolio_add_button_portfolio_instances'] = 'Portfolio instan
|
||||
$string['cachedef_postprocessedcss'] = 'Post processed CSS';
|
||||
$string['cachedef_tagindexbuilder'] = 'Search results for tagged items';
|
||||
$string['cachedef_questiondata'] = 'Question definitions';
|
||||
$string['cachedef_recommendation_favourite_course_content_items'] = 'Recommendation of course content items';
|
||||
$string['cachedef_repositories'] = 'Repositories instances data';
|
||||
$string['cachedef_roledefs'] = 'Role definitions';
|
||||
$string['cachedef_grade_categories'] = 'Grade category queries';
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['activitychooser'] = 'Activity chooser';
|
||||
$string['activitychoosertitle'] = 'Recommendations for the activity chooser';
|
||||
$string['aria:coursecategory'] = 'Course category';
|
||||
$string['aria:courseimage'] = 'Course image';
|
||||
$string['aria:courseshortname'] = 'Course short name';
|
||||
@ -46,6 +48,7 @@ $string['errorendbeforestart'] = 'The end date ({$a}) is before the course start
|
||||
$string['favourite'] = 'Starred course';
|
||||
$string['gradetopassnotset'] = 'This course does not have a grade to pass set. It may be set in the grade item of the course (Gradebook setup).';
|
||||
$string['informationformodule'] = 'Information about the {$a} activity';
|
||||
$string['module'] = 'Module';
|
||||
$string['nocourseactivity'] = 'Not enough course activity between the start and the end of the course';
|
||||
$string['nocourseendtime'] = 'The course does not have an end time';
|
||||
$string['nocoursesections'] = 'No course sections';
|
||||
@ -65,6 +68,8 @@ $string['privacy:favouritespath'] = 'Course starred information';
|
||||
$string['privacy:metadata:activityfavouritessummary'] = 'The course system contains information about which items from the activity chooser have been starred by the user.';
|
||||
$string['privacy:metadata:completionsummary'] = 'The course contains completion information about the user.';
|
||||
$string['privacy:metadata:favouritessummary'] = 'The course contains information relating to the course being starred by the user.';
|
||||
$string['recommend'] = 'Recommend';
|
||||
$string['recommendcheckbox'] = 'Recommend activity: {$a}';
|
||||
$string['studentsatriskincourse'] = 'Students at risk in {$a} course';
|
||||
$string['studentsatriskinfomessage'] = 'Hi {$a->userfirstname},
|
||||
|
||||
|
@ -179,6 +179,7 @@ $string['course:markcomplete'] = 'Mark users as complete in course completion';
|
||||
$string['course:movesections'] = 'Move sections';
|
||||
$string['course:overridecompletion'] = 'Override activity completion status';
|
||||
$string['course:renameroles'] = 'Rename roles';
|
||||
$string['course:recommendactivity'] = 'Recommend activities to the activity chooser';
|
||||
$string['course:request'] = 'Request new courses';
|
||||
$string['course:reset'] = 'Reset course';
|
||||
$string['course:reviewotherusers'] = 'Review other users';
|
||||
|
@ -2471,4 +2471,13 @@ $capabilities = array(
|
||||
'manager' => CAP_ALLOW,
|
||||
]
|
||||
],
|
||||
|
||||
// Allow users to recommend activities in the activity chooser.
|
||||
'moodle/course:recommendactivity' => [
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_SYSTEM,
|
||||
'archetypes' => [
|
||||
'manager' => CAP_ALLOW,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
@ -427,4 +427,9 @@ $definitions = array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'simplekeys' => true,
|
||||
],
|
||||
|
||||
\core_course\local\service\content_item_service::RECOMMENDATION_CACHE => [
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'simplekeys' => true,
|
||||
],
|
||||
);
|
||||
|
@ -653,6 +653,14 @@ $functions = array(
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_course_toggle_activity_recommendation' => array(
|
||||
'classname' => 'core_course_external',
|
||||
'methodname' => 'toggle_activity_recommendation',
|
||||
'classpath' => 'course/externallib.php',
|
||||
'description' => 'Adds or removes an activity as a recommendation in the activity chooser.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_enrol_get_course_enrolment_methods' => array(
|
||||
'classname' => 'core_enrol_external',
|
||||
'methodname' => 'get_course_enrolment_methods',
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2020022100.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2020022100.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.9dev (Build: 20200221)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user