first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
/**
* Javascript to initialise the Recently accessed items block.
*
* @module block_recentlyaccesseditems/main
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define("block_recentlyaccesseditems/main",["jquery","block_recentlyaccesseditems/repository","core/templates","core/notification"],(function($,Repository,Templates,Notification){var SELECTORS_CARDDECK_CONTAINER='[data-region="recentlyaccesseditems-view"]',SELECTORS_CARDDECK='[data-region="recentlyaccesseditems-view-content"]',SELECTORS_SHOWMORE_LINK='[data-region="recentlyaccesseditems-view"] [data-action="more-items"]';return{init:function(root){var limit,itemsContainer=(root=$(root)).find(SELECTORS_CARDDECK_CONTAINER),itemsContent=root.find(SELECTORS_CARDDECK);(limit=9,Repository.getRecentItems(limit)).then((function(items){var pageContentPromise=function(root,items){if(items.length>0){let hasmoreitems=!1;return items.length>3&&(hasmoreitems=!0),Templates.render("block_recentlyaccesseditems/view-cards",{items:items,hasmoreitems:hasmoreitems})}var noitemsimgurl=root.attr("data-noitemsimgurl");return Templates.render("block_recentlyaccesseditems/no-items",{noitemsimgurl:noitemsimgurl})}(itemsContainer,items);pageContentPromise.then((function(html,js){return Templates.replaceNodeContents(itemsContent,html,js),items.length>3&&(()=>{const showmoreLink=document.querySelector(SELECTORS_SHOWMORE_LINK);showmoreLink.addEventListener("click",(()=>{showmoreLink.classList.add("d-none");const hiddenItems=document.querySelector('[data-region="items-list"]').children;for(const hiddenItem of hiddenItems)hiddenItem.style="display: block"}))})(),null})).catch(Notification.exception)})).catch(Notification.exception)}}}));
//# sourceMappingURL=main.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
/**
* A javascript module to handle user ajax actions.
*
* @module block_recentlyaccesseditems/repository
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define("block_recentlyaccesseditems/repository",["core/ajax"],(function(Ajax){return{getRecentItems:function(limit){var args={};void 0!==limit&&(args.limit=limit);var request={methodname:"block_recentlyaccesseditems_get_recent_items",args:args};return Ajax.call([request])[0]}}}));
//# sourceMappingURL=repository.min.js.map
@@ -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 * A javascript module to handle user ajax actions.\n *\n * @module block_recentlyaccesseditems/repository\n * @copyright 2018 Victor Deniz <victor@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['core/ajax'], function(Ajax) {\n\n /**\n * Get the list of items that the user has most recently accessed.\n *\n * @method getRecentItems\n * @param {int} limit Only return this many results\n * @return {promise} Resolved with an array of items\n */\n var getRecentItems = function(limit) {\n var args = {};\n if (typeof limit !== 'undefined') {\n args.limit = limit;\n }\n var request = {\n methodname: 'block_recentlyaccesseditems_get_recent_items',\n args: args\n };\n return Ajax.call([request])[0];\n };\n return {\n getRecentItems: getRecentItems\n };\n});"],"names":["define","Ajax","getRecentItems","limit","args","request","methodname","call"],"mappings":";;;;;;;AAsBAA,gDAAO,CAAC,cAAc,SAASC,YAoBpB,CACHC,eAZiB,SAASC,WACtBC,KAAO,QACU,IAAVD,QACPC,KAAKD,MAAQA,WAEbE,QAAU,CACVC,WAAY,+CACZF,KAAMA,aAEHH,KAAKM,KAAK,CAACF,UAAU"}
@@ -0,0 +1,132 @@
// 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/>.
/**
* Javascript to initialise the Recently accessed items block.
*
* @module block_recentlyaccesseditems/main
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'block_recentlyaccesseditems/repository',
'core/templates',
'core/notification'
],
function(
$,
Repository,
Templates,
Notification
) {
var NUM_ITEMS = 9;
// Maximum number of elements to display in the block initially.
var NUM_ITEMS_INIT = 3;
var SELECTORS = {
CARDDECK_CONTAINER: '[data-region="recentlyaccesseditems-view"]',
CARDDECK: '[data-region="recentlyaccesseditems-view-content"]',
SHOWMORE_LINK: '[data-region="recentlyaccesseditems-view"] [data-action="more-items"]',
};
/**
* Register event listeners.
*/
const registerEventListeners = () => {
const showmoreLink = document.querySelector(SELECTORS.SHOWMORE_LINK);
// Hide "Show more" link and show additional items.
showmoreLink.addEventListener('click', () => {
showmoreLink.classList.add('d-none');
const hiddenItems = document.querySelector('[data-region="items-list"]').children;
for (const hiddenItem of hiddenItems) {
hiddenItem.style = "display: block";
}
});
};
/**
* Get recent items from backend.
*
* @method getRecentItems
* @param {int} limit Only return this many results
* @return {array} Items user most recently has accessed
*/
var getRecentItems = function(limit) {
return Repository.getRecentItems(limit);
};
/**
* Render the block content.
*
* @method renderItems
* @param {object} root The root element for the items view.
* @param {array} items containing array of returned items.
* @return {promise} Resolved with HTML and JS strings
*/
var renderItems = function(root, items) {
if (items.length > 0) {
let hasmoreitems = false;
if (items.length > NUM_ITEMS_INIT) {
hasmoreitems = true;
}
return Templates.render('block_recentlyaccesseditems/view-cards', {
items: items,
hasmoreitems: hasmoreitems
});
} else {
var noitemsimgurl = root.attr('data-noitemsimgurl');
return Templates.render('block_recentlyaccesseditems/no-items', {
noitemsimgurl: noitemsimgurl
});
}
};
/**
* Get and show the recent items into the block.
*
* @param {object} root The root element for the items block.
*/
var init = function(root) {
root = $(root);
var itemsContainer = root.find(SELECTORS.CARDDECK_CONTAINER);
var itemsContent = root.find(SELECTORS.CARDDECK);
var itemsPromise = getRecentItems(NUM_ITEMS);
itemsPromise.then(function(items) {
var pageContentPromise = renderItems(itemsContainer, items);
pageContentPromise.then(function(html, js) {
Templates.replaceNodeContents(itemsContent, html, js);
if (items.length > 3) {
registerEventListeners();
}
return null;
}).catch(Notification.exception);
}).catch(Notification.exception);
};
return {
init: init
};
});
@@ -0,0 +1,46 @@
// 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 user ajax actions.
*
* @module block_recentlyaccesseditems/repository
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/ajax'], function(Ajax) {
/**
* Get the list of items that the user has most recently accessed.
*
* @method getRecentItems
* @param {int} limit Only return this many results
* @return {promise} Resolved with an array of items
*/
var getRecentItems = function(limit) {
var args = {};
if (typeof limit !== 'undefined') {
args.limit = limit;
}
var request = {
methodname: 'block_recentlyaccesseditems_get_recent_items',
args: args
};
return Ajax.call([request])[0];
};
return {
getRecentItems: getRecentItems
};
});
@@ -0,0 +1,65 @@
<?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/>.
/**
* Class definition for the Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Recently accessed items block class.
*
* @package block_recentlyaccesseditems
* @copyright Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_recentlyaccesseditems extends block_base {
/**
* Initialize class member variables
*/
public function init() {
$this->title = get_string('pluginname', 'block_recentlyaccesseditems');
}
/**
* Returns the contents.
*
* @return stdClass contents of block
*/
public function get_content() {
if (isset($this->content)) {
return $this->content;
}
$renderable = new block_recentlyaccesseditems\output\main();
$renderer = $this->page->get_renderer('block_recentlyaccesseditems');
$this->content = new stdClass();
$this->content->text = $renderer->render($renderable);
$this->content->footer = '';
return $this->content;
}
/**
* Locations where block can be displayed.
*
* @return array
*/
public function applicable_formats() {
return array('my' => true);
}
}
@@ -0,0 +1,92 @@
<?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 block_recentlyaccesseditems;
use block_recentlyaccesseditems\external\recentlyaccesseditems_item_exporter;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_multiple_structure;
use core_external\external_value;
use context_user;
use context_module;
/**
* External API class.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class external extends external_api {
/**
* Returns description of method parameters
* @return external_function_parameters
*/
public static function get_recent_items_parameters() {
return new external_function_parameters(
array(
'limit' => new external_value(PARAM_INT, 'result set limit', VALUE_DEFAULT, 0)
)
);
}
/**
* Get last accessed items by the logged user (activities or resources).
*
* @param int $limit Max num of items to return
* @return array List of items
* @since Moodle 3.6
*/
public static function get_recent_items(int $limit = 0) {
global $USER, $PAGE;
$userid = $USER->id;
$params = self::validate_parameters(self::get_recent_items_parameters(),
array(
'limit' => $limit,
)
);
$limit = $params['limit'];
self::validate_context(context_user::instance($userid));
$items = helper::get_recent_items($limit);
$renderer = $PAGE->get_renderer('core');
$recentitems = array_map(function($item) use ($renderer) {
$context = context_module::instance($item->cmid);
$exporter = new recentlyaccesseditems_item_exporter($item, ['context' => $context]);
return $exporter->export($renderer);
}, $items);
return $recentitems;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.6
*/
public static function get_recent_items_returns() {
return new external_multiple_structure(recentlyaccesseditems_item_exporter::get_read_structure(),
'The most recently accessed activities/resources by the logged user');
}
}
@@ -0,0 +1,132 @@
<?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/>.
/**
* Class for exporting the data needed to render a recent accessed item.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems\external;
defined('MOODLE_INTERNAL') || die();
use renderer_base;
use moodle_url;
/**
* Class for exporting the data needed to render a recent accessed item.
*
* @copyright 2018 Victor Deniz
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class recentlyaccesseditems_item_exporter extends \core\external\exporter {
/**
* Returns a list of objects that are related to this persistent.
*
*/
protected static function define_related() {
// We cache the context so it does not need to be retrieved from the course.
return array('context' => '\\context');
}
/**
* Get the additional values to inject while exporting.
*
* @param renderer_base $output The renderer
* @return array Additional properties with values
*/
protected function get_other_values(renderer_base $output) {
global $CFG;
require_once($CFG->libdir.'/modinfolib.php');
$iconurl = get_fast_modinfo($this->data->courseid)->cms[$this->data->cmid]->get_icon_url();
$iconclass = $iconurl->get_param('filtericon') ? '' : 'nofilter';
$isbranded = component_callback('mod_' . $this->data->modname, 'is_branded') !== null ? : false;
return array(
'viewurl' => (new moodle_url('/mod/'.$this->data->modname.'/view.php',
array('id' => $this->data->cmid)))->out(false),
'courseviewurl' => (new moodle_url('/course/view.php', array('id' => $this->data->courseid)))->out(false),
'icon' => \html_writer::img(
$iconurl,
get_string('pluginname', $this->data->modname),
['title' => get_string('pluginname', $this->data->modname), 'class' => "icon $iconclass"]
),
'purpose' => plugin_supports('mod', $this->data->modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER),
'branded' => $isbranded,
);
}
/**
* Return the list of properties.
*
* @return array Properties.
*/
public static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
),
'courseid' => array(
'type' => PARAM_INT,
),
'cmid' => array(
'type' => PARAM_INT,
),
'userid' => array(
'type' => PARAM_INT,
),
'modname' => array(
'type' => PARAM_PLUGIN,
),
'name' => array(
'type' => PARAM_TEXT,
),
'coursename' => array(
'type' => PARAM_TEXT,
),
'timeaccess' => array(
'type' => PARAM_INT,
)
);
}
/**
* Return the list of additional properties.
*
* @return array Additional properties.
*/
public static function define_other_properties() {
return array(
'viewurl' => array(
'type' => PARAM_RAW,
),
'courseviewurl' => array(
'type' => PARAM_URL,
),
'icon' => array(
'type' => PARAM_RAW,
),
'purpose' => array(
'type' => PARAM_ALPHA,
),
'branded' => [
'type' => PARAM_BOOL,
'optional' => true,
],
);
}
}
@@ -0,0 +1,98 @@
<?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/>.
/**
* Recently accessed items helper.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems;
defined('MOODLE_INTERNAL') || die();
/**
* Recently accessed items helper.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Returns a list of the most recently items accessed by the logged user
*
* @param int $limit Restrict result set to this amount
* @return array List of recent items accessed by userid
*/
public static function get_recent_items(int $limit = 0) {
global $USER, $DB;
$userid = $USER->id;
$courses = array();
$recentitems = array();
if (!isloggedin() or \core\session\manager::is_loggedinas() or isguestuser()) {
// No access tracking.
return $recentitems;
}
$paramsql = array('userid' => $userid);
$sql = "SELECT rai.*
FROM {block_recentlyaccesseditems} rai
JOIN {course} c ON c.id = rai.courseid
WHERE userid = :userid
ORDER BY rai.timeaccess DESC, rai.id DESC";
$records = $DB->get_records_sql($sql, $paramsql);
$order = 0;
// Get array of items by course. Use $order index to keep sql sorted results.
foreach ($records as $record) {
$courses[$record->courseid][$order++] = $record;
}
// Group by courses to reduce get_fast_modinfo requests.
foreach ($courses as $key => $items) {
$modinfo = get_fast_modinfo($key);
if (!can_access_course($modinfo->get_course(), null, '', true)) {
continue;
}
foreach ($items as $key => $item) {
// Exclude not visible items.
if (!$modinfo->cms[$item->cmid]->uservisible) {
continue;
}
$item->modname = $modinfo->cms[$item->cmid]->modname;
$item->name = $modinfo->cms[$item->cmid]->name;
$item->coursename = get_course_display_name_for_list($modinfo->get_course());
$recentitems[$key] = $item;
}
}
ksort($recentitems);
// Apply limit.
if (!$limit) {
$limit = count($recentitems);
}
$recentitems = array_slice($recentitems, 0, $limit);
return $recentitems;
}
}
@@ -0,0 +1,105 @@
<?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/>.
/**
* Event observer.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems;
defined('MOODLE_INTERNAL') || die();
/**
* Events observer.
*
* Stores all actions about modules viewed in block_recentlyaccesseditems table.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class observer {
/**
* @var string Block table name.
*/
private static $table = 'block_recentlyaccesseditems';
/**
* Register items views in block_recentlyaccesseditems table.
*
* When the item is view for the first time, a new record is created. If the item was viewed before, the time is
* updated.
*
* @param \core\event\base $event
*/
public static function store(\core\event\base $event) {
global $DB;
if (!isloggedin() or \core\session\manager::is_loggedinas() or isguestuser()) {
// No access tracking.
return;
}
$conditions = [
'userid' => $event->userid
];
$records = $DB->get_records(self::$table, $conditions, "timeaccess DESC");
foreach ($records as $record) {
if (($record->userid == $event->userid) && ($record->cmid == $event->contextinstanceid)) {
$conditions = [
'userid' => $event->userid,
'cmid' => $event->contextinstanceid
];
$DB->set_field(self::$table, 'timeaccess', $event->timecreated, $conditions);
return;
}
}
if (count($records) >= 9) {
$conditions = [
'id' => end($records)->id,
];
$DB->delete_records(self::$table, $conditions);
}
$eventdata = new \stdClass();
$eventdata->cmid = $event->contextinstanceid;
$eventdata->timeaccess = $event->timecreated;
$eventdata->courseid = $event->courseid;
$eventdata->userid = $event->userid;
$DB->insert_record(self::$table, $eventdata);
}
/**
* Remove record when course module is deleted.
*
* @param \core\event\base $event
*/
public static function remove(\core\event\base $event) {
global $DB;
$DB->delete_records(self::$table, array('cmid' => $event->contextinstanceid));
}
}
@@ -0,0 +1,53 @@
<?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/>.
/**
* Class containing data for Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
/**
* Class containing data for Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class main implements renderable, templatable {
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param \renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
$noitemsimgurl = $output->image_url('items', 'block_recentlyaccesseditems')->out();
return [
'noitemsimgurl' => $noitemsimgurl
];
}
}
@@ -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/>.
/**
* Recently accessed items block renderer
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems\output;
defined('MOODLE_INTERNAL') || die;
use plugin_renderer_base;
/**
* Recently accessed items block renderer
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Return the main content for the Recently accessed items block.
*
* @param \renderer_base $main The main renderable
* @return string HTML string
*/
public function render_recentlyaccesseditems(renderer_base $main) {
return $this->render_from_template('block_recentlyaccesseditems/main', $main->export_for_template($this));
}
}
@@ -0,0 +1,193 @@
<?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/>.
/**
* Privacy Subsystem implementation for Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_recentlyaccesseditems\privacy;
defined('MOODLE_INTERNAL') || die();
use \core_privacy\local\metadata\collection;
use \core_privacy\local\request\transform;
use \core_privacy\local\request\contextlist;
use \core_privacy\local\request\userlist;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\approved_userlist;
use \core_privacy\local\request\writer;
/**
* Privacy Subsystem for block_recentlyaccesseditems.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
/**
* Returns information about the user data stored in this component.
*
* @param collection $collection A list of information about this component
* @return collection The collection object filled out with information about this component.
*/
public static function get_metadata(collection $collection): collection {
$recentitems = [
'userid' => 'privacy:metadata:userid',
'courseid' => 'privacy:metadata:courseid',
'cmid' => 'privacy:metadata:cmid',
'timeaccess' => 'privacy:metadata:timeaccess'
];
$collection->add_database_table('block_recentlyaccesseditems', $recentitems,
'privacy:metadata:block_recentlyaccesseditemstablesummary');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
$params = ['userid' => $userid, 'contextuser' => CONTEXT_USER];
$sql = "SELECT c.id
FROM {context} c
JOIN {block_recentlyaccesseditems} b
ON b.userid = c.instanceid
WHERE c.instanceid = :userid
AND c.contextlevel = :contextuser";
$contextlist = new contextlist();
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users within a specific context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
global $DB;
$context = $userlist->get_context();
if (!$context instanceof \context_user) {
return;
}
if ($DB->record_exists('block_recentlyaccesseditems', ['userid' => $context->instanceid])) {
$userlist->add_user($context->instanceid);
}
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
$context = $contextlist->current();
$user = \core_user::get_user($contextlist->get_user()->id);
static::export_recentitems($user->id, $context);
}
/**
* Export information about the most recently accessed items.
*
* @param int $userid The user ID.
* @param \context $context The user context.
*/
protected static function export_recentitems(int $userid, \context $context) {
global $DB;
$sql = "SELECT ra.id, c.fullname, ra.timeaccess, m.name, ra.cmid
FROM {block_recentlyaccesseditems} ra
JOIN {course} c ON c.id = ra.courseid
JOIN {course_modules} cm on cm.id = ra.cmid
JOIN {modules} m ON m.id = cm.module
WHERE ra.userid = :userid";
$params = ['userid' => $userid];
$records = $DB->get_records_sql($sql, $params);
if (!empty($records)) {
$recentitems = (object) array_map(function($record) use($context) {
return [
'course_name' => format_string($record->fullname, true, ['context' => $context]),
'module_name' => format_string($record->name),
'timeaccess' => transform::datetime($record->timeaccess)
];
}, $records);
writer::with_context($context)->export_data([get_string('privacy:recentlyaccesseditemspath',
'block_recentlyaccesseditems')], $recentitems);
}
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
// Only delete data for a user context.
if ($context->contextlevel == CONTEXT_USER) {
// Delete recent items access.
$DB->delete_records('block_recentlyaccesseditems', ['userid' => $context->instanceid]);
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
foreach ($contextlist as $context) {
// Let's be super certain that we have the right information for this user here.
if ($context->contextlevel == CONTEXT_USER && $contextlist->get_user()->id == $context->instanceid) {
$DB->delete_records('block_recentlyaccesseditems', ['userid' => $context->instanceid]);
}
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$context = $userlist->get_context();
if ($context instanceof \context_user && in_array($context->instanceid, $userlist->get_userids())) {
$DB->delete_records('block_recentlyaccesseditems', ['userid' => $context->instanceid]);
}
}
}
@@ -0,0 +1,33 @@
<?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/>.
/**
* Capabilities for the Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'block/recentlyaccesseditems:myaddinstance' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
'user' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/my:manageblocks'
)
);
@@ -0,0 +1,37 @@
<?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/>.
/**
* Recently accessed items event observer.
*
* @package block_recentlyaccesseditems
* @category event
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$observers = array (
array(
'eventname' => '\core\event\course_module_viewed',
'callback' => 'block_recentlyaccesseditems\observer::store',
),
array(
'eventname' => '\core\event\course_module_deleted',
'callback' => 'block_recentlyaccesseditems\observer::remove'
),
);
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="blocks/recentlyaccesseditems/db" VERSION="20181030" COMMENT="XMLDB file for Moodle blocks/recentlyaccesseditems"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="block_recentlyaccesseditems" COMMENT="Most recently accessed items accessed by a user">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course id the item belongs to"/>
<FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Item course module id"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User id that accessed the item"/>
<FIELD NAME="timeaccess" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time the user accessed the last time an item"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
<KEY NAME="courseid" TYPE="foreign" FIELDS="courseid" REFTABLE="course" REFFIELDS="id"/>
<KEY NAME="cmid" TYPE="foreign" FIELDS="cmid" REFTABLE="course_modules" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid-courseid-cmid" UNIQUE="true" FIELDS="userid, courseid, cmid"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
@@ -0,0 +1,38 @@
<?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/>.
/**
* Web service for Recently accessed items block
*
* @package block_recentlyaccesseditems
* @since Moodle 3.6
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$functions = array(
'block_recentlyaccesseditems_get_recent_items' => array(
'classname' => 'block_recentlyaccesseditems\external',
'methodname' => 'get_recent_items',
'classpath' => '',
'description' => 'List of items a user has accessed most recently.',
'type' => 'read',
'ajax' => true,
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
);
@@ -0,0 +1,59 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file keeps track of upgrades to the recentlyaccesseditems block
*
* Sometimes, changes between versions involve alterations to database structures
* and other major things that may break installations.
*
* The upgrade function in this file will attempt to perform all the necessary
* actions to upgrade your older installation to the current version.
*
* If there's something it cannot do itself, it will tell you what you need to do.
*
* The commands in here will all be database-neutral, using the methods of
* database_manager class
*
* Please do not forget to use upgrade_set_timeout()
* before any action that may take longer time to finish.
*
* @package block_recentlyaccesseditems
* @copyright 2019 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Upgrade the recentlyaccesseditems db table.
*
* @param $oldversion
* @return bool
*/
function xmldb_block_recentlyaccesseditems_upgrade($oldversion, $block) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -0,0 +1,32 @@
<?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/>.
/**
* Strings for the Recently accessed items block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['moreitems'] = 'Show more items';
$string['noitems'] = 'No recent items';
$string['pluginname'] = 'Recently accessed items';
$string['privacy:metadata:cmid'] = 'The ID of the activity or resource';
$string['privacy:metadata:courseid'] = 'Course the item belongs to';
$string['privacy:metadata:block_recentlyaccesseditemstablesummary'] = 'The Recently accessed items block stores information about items that the user accessed recently';
$string['privacy:metadata:timeaccess'] = 'The time when the user last accessed the item';
$string['privacy:metadata:userid'] = 'The ID of the user who accessed the item';
$string['privacy:recentlyaccesseditemspath'] = 'Recently accessed items';
$string['recentlyaccesseditems:myaddinstance'] = 'Add a new recently accessed items block to Dashboard';
+47
View File
@@ -0,0 +1,47 @@
<?php
// This file is part of Moodle - https://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/>.
/**
* The interface library between the core and the subsystem.
*
* @package block_recentlyaccesseditems
* @copyright 2019 Peter Dias <peter@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Pre-delete course module hook to cleanup any records with references to the deleted module.
*
* @param stdClass $cm The deleted course module
*/
function block_recentlyaccesseditems_pre_course_module_delete($cm) {
global $DB;
$DB->delete_records('block_recentlyaccesseditems', ['cmid' => $cm->id]);
}
/**
* Pre-delete course hook to cleanup any records with references to the deleted course.
*
* @param stdClass $course The deleted course
*/
function block_recentlyaccesseditems_pre_course_delete($course) {
global $DB;
$DB->delete_records('block_recentlyaccesseditems', ['courseid' => $course->id]);
}
@@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="157 -1509 148 125" preserveAspectRatio="xMinYMid meet">
<defs>
<style>
.cls-1 {
clip-path: url(#clip-Activities);
}
.cls-2 {
fill: #eee;
}
.cls-3 {
fill: #c4c8cc;
}
.cls-4 {
fill: #fff;
}
</style>
<clipPath id="clip-Activities">
<rect x="157" y="-1509" width="148" height="125"/>
</clipPath>
</defs>
<g id="Activities" class="cls-1">
<g id="Group_42" data-name="Group 42" transform="translate(-268 -1985)">
<ellipse id="Ellipse_37" data-name="Ellipse 37" class="cls-2" cx="74" cy="14.785" rx="74" ry="14.785" transform="translate(425 571.43)"/>
<rect id="Rectangle_80" data-name="Rectangle 80" class="cls-3" width="94.182" height="110.215" transform="translate(451.909 476)"/>
<g id="Group_41" data-name="Group 41" transform="translate(467.043 493)">
<rect id="Rectangle_81" data-name="Rectangle 81" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 0.549)"/>
<rect id="Rectangle_82" data-name="Rectangle 82" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 11.652)"/>
<rect id="Rectangle_83" data-name="Rectangle 83" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 30.772)"/>
<rect id="Rectangle_84" data-name="Rectangle 84" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 41.875)"/>
<rect id="Rectangle_85" data-name="Rectangle 85" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 61.291)"/>
<rect id="Rectangle_86" data-name="Rectangle 86" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 72.393)"/>
<ellipse id="Ellipse_38" data-name="Ellipse 38" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 0)"/>
<ellipse id="Ellipse_39" data-name="Ellipse 39" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 31)"/>
<ellipse id="Ellipse_40" data-name="Ellipse 40" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 61)"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -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/>.
}}
{{!
@template block_recentlyaccesseditems/main
This template renders the main content area for the Recently accessed itemes block.
Example context (json):
{}
}}
<div id="block-recentlyaccesseditems-{{uniqid}}" class="block-recentlyaccesseditems block-cards" data-region="recentlyaccesseditems">
<div class="container-fluid p-0">
{{> block_recentlyaccesseditems/recentlyaccesseditems-view }}
</div>
</div>
{{#js}}
require(
[
'jquery',
'block_recentlyaccesseditems/main',
],
function(
$,
Main
) {
var root = $('#block-recentlyaccesseditems-{{uniqid}}');
Main.init(root);
});
{{/js}}
@@ -0,0 +1,34 @@
{{!
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 block_recentlyaccesseditems/no-items
This template renders the no items message.
Example context (json):
{
"noitemsimgurl": "https://moodlesite/theme/image.php/boost/block_recentlyaccesseditems/1535727318/items"
}
}}
<div class="text-xs-center text-center mt-4" data-region="empty-message">
<img
src="{{noitemsimgurl}}"
alt=""
style="height: 70px; width: 70px;"
>
<p class="text-muted mt-3 mb-0">{{#str}} noitems, block_recentlyaccesseditems {{/str}}</p>
</div>
@@ -0,0 +1,35 @@
{{!
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 block_recentlyaccesseditems/placeholder-item
This template renders a card item loading placeholder for the Recently accessed items block.
Example context (json):
{}
}}
<div class="card mb-1">
<div class="card-body p-2 m-1">
<div class="d-flex flex-row mw-100 align-items-center">
<div class="bg-pulse-grey rounded-circle" style="height: 40px; width: 40px;"></div>
<div class="pl-2" style="flex: 1;">
<div class="bg-pulse-grey w-100" style="height: 1rem;"></div>
<div class="bg-pulse-grey w-75 mt-1" style="height: 0.8rem;"></div>
</div>
</div>
</div>
</div>
@@ -0,0 +1,40 @@
{{!
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 block_recentlyaccesseditems/recentlyaccesseditems-view
This template renders the items view for the Recently accessed items block.
Example context (json):
{
"noitemsimgurl": "https://moodlesite/theme/image.php/boost/block_recentactivities/1535727318/items"
}
}}
<div id="recentlyaccesseditems-view-{{uniqid}}"
data-region="recentlyaccesseditems-view"
data-noitemsimgurl="{{noitemsimgurl}}">
<div data-region="recentlyaccesseditems-view-content">
<div data-region="recentlyaccesseditems-loading-placeholder">
{{> block_recentlyaccesseditems/placeholder-item }}
{{> block_recentlyaccesseditems/placeholder-item }}
{{> block_recentlyaccesseditems/placeholder-item }}
{{> block_recentlyaccesseditems/placeholder-item }}
{{> block_recentlyaccesseditems/placeholder-item }}
</div>
</div>
</div>
@@ -0,0 +1,69 @@
{{!
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 Licensebllsdsadfasfd
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_recentlyaccesseditems/view-cards
This template renders the items cards of the Recently accessed items block.
Example context (json):
{
"items": [
{
"cmid": 64,
"courseid": 2,
"coursename": "Course",
"courseviewurl": "https://moodlesite/course/view.php?id=2",
"icon": "<img class=\"icon\" alt=\"Forum\" title=\"Forum\" src=\"http://moodlesite/theme/image.php/boost/forum/1539858121/icon\" />",
"name": "Assignment due 1",
"id": 17,
"modname": "Forum",
"name": "Forum",
"timeaccess": 1539848498,
"userid": 2,
"viewurl": "http://moodlesite/mod/forum?id=64",
"purpose": "assessment"
}
]
}
}}
<div data-region="items-list" role="list">
{{#items}}
<div class="card mb-1" role="listitem">
<a href="{{{viewurl}}}" title="{{{name}}}">
<div class="card-body p-2 m-1">
<div class="d-flex text-truncate">
<div class="d-flex align-self-center activityiconcontainer">
{{{icon}}}
</div>
<div class="w-100 line-height-3 text-truncate ml-2">
<h6 class="mb-0 text-truncate"><span class="clickable">{{{name}}}</span></h6>
<small class="text-truncate mb-0">{{{coursename}}}</small>
</div>
</div>
</div>
</a>
</div>
{{/items}}
</div>
{{#hasmoreitems}}
<div data-region="more-items-button-container" class="mt-2 px-1">
<button type="button" class="btn btn-secondary btn-sm" data-action="more-items">
{{#str}}moreitems, block_recentlyaccesseditems {{/str}}
</button>
</div>
{{/hasmoreitems}}
@@ -0,0 +1,65 @@
@block @block_recentlyaccesseditems @javascript
Feature: The recently accessed items block allows users to easily access their most recently visited items
In order to access the most recent items accessed
As a user
I can use the recently accessed items block in my dashboard
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
And the following "activity" exists:
| course | C1 |
| activity | forum |
| idnumber | Test forum name |
| name | Test forum name |
And I log in as "student1"
@accessibility
Scenario: User has not accessed any item
Then I should see "No recent items" in the "Recently accessed items" "block"
And the page should meet accessibility standards
@accessibility
Scenario: User has accessed some items
Given I change window size to "large"
When I am on the "Test forum name" "forum activity" page
And I follow "Dashboard"
Then I should see "Test forum name" in the "Recently accessed items" "block"
And I should not see "Show more items" in the "Recently accessed items" "block"
And the page should meet accessibility standards
Scenario: User has accessed more than 3 items
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| assign | Test assignment name | Test assignment description | C1 | assign1 |
| book | Test book name | | C1 | book1 |
| choice | Test choice name | Test choice description | C1 | choice1 |
| data | Test database name | Test database description | C1 | data1 |
And I change window size to "large"
And I am on the "Test forum name" "forum activity" page
And I am on the "Test database name" "data activity" page
And I am on the "Test assignment name" "assign activity" page
And I am on the "Test book name" "book activity" page
And I am on the "Test choice name" "choice activity" page
When I follow "Dashboard"
Then I should see "Show more items" in the "Recently accessed items" "block"
And I should not see "Test forum name" in the "Recently accessed items" "block"
And I click on "Show more items" "button" in the "Recently accessed items" "block"
And I should see "Test forum name" in the "Recently accessed items" "block"
And I turn editing mode on
And I am on homepage
And I configure the "Recently accessed items" block
And I set the following fields to these values:
| Region | content |
And I press "Save changes"
And I turn editing mode off
And I should not see "Show more items" in the "Recently accessed items" "block"
@@ -0,0 +1,128 @@
<?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 block_recentlyaccesseditems;
use externallib_advanced_testcase;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Test Recently accessed items block external functions
*
* @package block_recentlyaccesseditems
* @category external
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.6
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test the get_recent_items function.
*/
public function test_get_recent_items(): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$this->setAdminUser();
// Add courses.
$courses = array();
for ($i = 1; $i < 4; $i++) {
$courses[] = $generator->create_course();
};
// Add users.
$student = $generator->create_user();
$teacher = $generator->create_user();
// Enrol users and add items to courses.
foreach ($courses as $course) {
$generator->enrol_user($student->id, $course->id, 'student');
$forum[] = $this->getDataGenerator()->create_module('forum', array('course' => $course));
$glossary[] = $this->getDataGenerator()->create_module('glossary', array('course' => $course));
$assign[] = $this->getDataGenerator()->create_module('assign', ['course' => $course]);
$h5pactivity[] = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
}
$generator->enrol_user($teacher->id, $courses[0]->id, 'teacher');
$this->setUser($student);
// No recent items.
$result = \block_recentlyaccesseditems\external::get_recent_items();
$this->assertCount(0, $result);
// Student access all forums.
foreach ($forum as $module) {
$event = \mod_forum\event\course_module_viewed::create(array('context' => \context_module::instance($module->cmid),
'objectid' => $module->id));
$event->trigger();
$this->waitForSecond();
}
// Test that only access to forums are returned.
$result = \block_recentlyaccesseditems\external::get_recent_items();
$this->assertCount(count($forum), $result);
// Student access all assignments.
foreach ($assign as $module) {
$event = \mod_chat\event\course_module_viewed::create(array('context' => \context_module::instance($module->cmid),
'objectid' => $module->id));
$event->trigger();
$this->waitForSecond();
}
// Student access all h5p.
foreach ($h5pactivity as $module) {
$event = \mod_h5pactivity\event\course_module_viewed::create(
['context' => \context_module::instance($module->cmid), 'objectid' => $module->id]
);
$event->trigger();
$this->waitForSecond();
}
// Test that results are sorted by timeaccess DESC (default).
$result = \block_recentlyaccesseditems\external::get_recent_items();
$this->assertCount((count($forum) + count($assign) + count($h5pactivity)), $result);
foreach ($result as $key => $record) {
if ($key == 0) {
continue;
}
$this->assertTrue($record->timeaccess < $result[$key - 1]->timeaccess);
// Check that the branded property is set correctly.
if ($record->modname == 'h5pactivity') {
$this->assertTrue($record->branded);
} else {
$this->assertFalse($record->branded);
}
}
// Delete a course and confirm it's activities don't get returned.
delete_course($courses[0], false);
$result = \block_recentlyaccesseditems\external::get_recent_items();
$this->assertCount((count($forum) + count($assign) + count($h5pactivity)) - 3, $result);
// Delete a single course module should still return.
course_delete_module($forum[1]->cmid);
$result = \block_recentlyaccesseditems\external::get_recent_items();
$this->assertCount((count($forum) + count($assign) + count($h5pactivity)) - 4, $result);
}
}
@@ -0,0 +1,60 @@
<?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 block_recentlyaccesseditems;
/**
* Block Recently accessed helper class tests.
*
* @package block_recentlyaccesseditems
* @copyright 2019 University of Nottingham
* @author Neill Magill <neill.magill@nottingham.ac.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper_test extends \advanced_testcase {
/**
* Tests that the get recent items method can handle getting records when courses have been deleted.
*/
public function test_get_recent_items(): void {
$this->resetAfterTest();
$course = self::getDataGenerator()->create_course();
$coursetodelete = self::getDataGenerator()->create_course();
$user = self::getDataGenerator()->create_and_enrol($course, 'student');
self::getDataGenerator()->enrol_user($user->id, $coursetodelete->id, 'student');
// Add an activity to each course.
$forum = self::getDataGenerator()->create_module('forum', ['course' => $course]);
$glossary = self::getDataGenerator()->create_module('glossary', ['course' => $coursetodelete]);
self::setUser($user);
// Get the user to visit the activities.
$event1params = ['context' => \context_module::instance($forum->cmid), 'objectid' => $forum->id];
$event1 = \mod_forum\event\course_module_viewed::create($event1params);
$event1->trigger();
$event2params = ['context' => \context_module::instance($glossary->cmid), 'objectid' => $glossary->id];
$event2 = \mod_glossary\event\course_module_viewed::create($event2params);
$event2->trigger();
$recent1 = helper::get_recent_items();
self::assertCount(2, $recent1);
$recentlimited = helper::get_recent_items(1);
self::assertCount(1, $recentlimited);
delete_course($coursetodelete, false);
// There should be no errors if a course has been deleted.
$recent2 = helper::get_recent_items();
self::assertCount(1, $recent2);
}
}
@@ -0,0 +1,180 @@
<?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 block_recentlyaccesseditems;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
/**
* Block Recently accessed items observer tests.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.6
*/
class observer_test extends \advanced_testcase {
use \mod_assign_test_generator;
/** @var string Table name. */
protected $table;
/** @var \stdClass course data. */
protected $course;
/** @var \stdClass student data. */
protected $student;
/** @var \stdClass teacher data. */
protected $teacher;
/** @var \stdClass student role. */
protected $studentrole;
/** @var \stdClass teacher role. */
protected $teacherrole;
/** @var \stdClass course forum. */
protected $forum;
/** @var \stdClass course glossary. */
protected $glossary;
/** @var \stdClass course chat. */
protected $chat;
/**
* Set up for every test
*/
public function setUp(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Block table name.
$this->table = "block_recentlyaccesseditems";
// Setup test data.
$this->course = $this->getDataGenerator()->create_course();
// Create users.
$this->student = self::getDataGenerator()->create_user();
$this->teacher = self::getDataGenerator()->create_user();
// Users enrolments.
$this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
$this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
// Create items.
$this->forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course));
$this->glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $this->course));
$this->chat = $this->getDataGenerator()->create_module('chat', array('course' => $this->course));
}
/**
* Test items views are recorded
*
* When items events are triggered they are stored in the block_recentlyaccesseditems table.
*/
public function test_item_view_recorded_testcase(): void {
global $DB;
// Empty table at the beggining.
$records = $DB->count_records($this->table, array());
$this->assertEquals(0, $records);
// Teacher access forum activity.
$this->setUser($this->teacher);
$event = \mod_forum\event\course_module_viewed::create(array('context' => \context_module::instance($this->forum->cmid),
'objectid' => $this->forum->id));
$event->trigger();
// Student access chat activity.
$this->setUser($this->student);
$event1 = \mod_chat\event\course_module_viewed::create(array('context' => \context_module::instance($this->chat->cmid),
'objectid' => $this->chat->id));
$event1->trigger();
$records = $DB->count_records($this->table, array('userid' => $this->teacher->id, 'courseid' => $this->course->id,
'cmid' => $this->forum->cmid));
$this->assertEquals(1, $records);
$records = $DB->count_records($this->table, array('userid' => $this->student->id, 'courseid' => $this->course->id, 'cmid' =>
$this->chat->cmid));
$this->assertEquals(1, $records);
$this->waitForSecond();
// Student access chat activity again after 1 second (no new record created, timeaccess updated).
$event2 = \mod_chat\event\course_module_viewed::create(array('context' => \context_module::instance($this->chat->cmid),
'objectid' => $this->chat->id));
$event2->trigger();
$records = $DB->get_records($this->table, array('userid' => $this->student->id, 'courseid' => $this->course->id, 'cmid' =>
$this->chat->cmid));
$this->assertCount(1, $records);
$this->assertEquals($event2->timecreated, array_shift($records)->timeaccess);
}
/**
* Test removed items records are deleted.
*
* When a course module is removed, the records associated in the block_recentlyaccesseditems table are deleted.
*/
public function test_item_delete_record_testcase(): void {
global $DB;
// Empty table at the beggining.
$records = $DB->count_records($this->table, array());
$this->assertEquals(0, $records);
// Teacher access forum activity.
$this->setUser($this->teacher);
$event = \mod_forum\event\course_module_viewed::create(array('context' => \context_module::instance($this->forum->cmid),
'objectid' => $this->forum->id));
$event->trigger();
// Teacher access chat activity.
$event = \mod_chat\event\course_module_viewed::create(array('context' => \context_module::instance($this->chat->cmid),
'objectid' => $this->chat->id));
$event->trigger();
// Student access chat activity.
$this->setUser($this->student);
$event = \mod_chat\event\course_module_viewed::create(array('context' => \context_module::instance($this->chat->cmid),
'objectid' => $this->chat->id));
$event->trigger();
// Student access forum activity.
$event = \mod_forum\event\course_module_viewed::create(array('context' => \context_module::instance($this->forum->cmid),
'objectid' => $this->forum->id));
$event->trigger();
$records = $DB->count_records($this->table, array('cmid' => $this->forum->cmid));
$this->assertEquals(2, $records);
course_delete_module($this->forum->cmid);
$records = $DB->count_records($this->table, array('cmid' => $this->forum->cmid));
$this->assertEquals(0, $records);
$records = $DB->count_records($this->table, array('cmid' => $this->chat->cmid));
$this->assertEquals(2, $records);
}
}
@@ -0,0 +1,494 @@
<?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/>.
/**
* Block recentlyaccesseditems privacy provider tests.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Michael Hawkins <michaelh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.6
*/
namespace block_recentlyaccesseditems\privacy;
defined('MOODLE_INTERNAL') || die();
use block_recentlyaccesseditems\privacy\provider;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
/**
* Block Recently accessed items privacy provider tests.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Michael Hawkins <michaelh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.6
*/
class provider_test extends \core_privacy\tests\provider_testcase {
/**
* Test getting the context for the user ID related to this plugin.
*/
public function test_get_contexts_for_userid(): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
$teacher = $generator->create_user();
$teachercontext = \context_user::instance($teacher->id);
// Enrol users in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Check nothing is found before block is populated.
$contextlist1 = provider::get_contexts_for_userid($student->id);
$this->assertCount(0, $contextlist1);
$contextlist2 = provider::get_contexts_for_userid($teacher->id);
$this->assertCount(0, $contextlist2);
// Generate some recent activity for both users.
$this->setUser($student);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$this->setUser($teacher);
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
// Ensure provider only fetches the users's own context.
$contextlist1 = provider::get_contexts_for_userid($student->id);
$this->assertCount(1, $contextlist1);
$this->assertEquals($studentcontext, $contextlist1->current());
$contextlist2 = provider::get_contexts_for_userid($teacher->id);
$this->assertCount(1, $contextlist2);
$this->assertEquals($teachercontext, $contextlist2->current());
}
/**
* Test getting users in the context ID related to this plugin.
*/
public function test_get_users_in_context(): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$component = 'block_recentlyaccesseditems';
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
$teacher = $generator->create_user();
$teachercontext = \context_user::instance($teacher->id);
// Enrol users in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Check nothing is found before block is populated.
$userlist1 = new \core_privacy\local\request\userlist($studentcontext, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
$userlist2 = new \core_privacy\local\request\userlist($teachercontext, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(0, $userlist2);
// Generate some recent activity for both users.
$this->setUser($student);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
$this->setUser($teacher);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
// Ensure provider only fetches the user whose user context is checked.
$userlist1 = new \core_privacy\local\request\userlist($studentcontext, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
$this->assertEquals($student, $userlist1->current());
$userlist2 = new \core_privacy\local\request\userlist($teachercontext, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
$this->assertEquals($teacher, $userlist2->current());
}
/**
* Test fetching information about user data stored.
*/
public function test_get_metadata(): void {
$collection = new \core_privacy\local\metadata\collection('block_recentlyaccesseditems');
$newcollection = provider::get_metadata($collection);
$itemcollection = $newcollection->get_collection();
$this->assertCount(1, $itemcollection);
$table = reset($itemcollection);
$this->assertEquals('block_recentlyaccesseditems', $table->get_name());
$privacyfields = $table->get_privacy_fields();
$this->assertCount(4, $privacyfields);
$this->assertArrayHasKey('userid', $privacyfields);
$this->assertArrayHasKey('courseid', $privacyfields);
$this->assertArrayHasKey('cmid', $privacyfields);
$this->assertArrayHasKey('timeaccess', $privacyfields);
$this->assertEquals('privacy:metadata:block_recentlyaccesseditemstablesummary', $table->get_summary());
}
/**
* Test exporting data for an approved contextlist.
*/
public function test_export_user_data(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$component = 'block_recentlyaccesseditems';
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
// Enrol user in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Generate some recent activity.
$this->setUser($student);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
// Confirm data is present.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
// Export data for student.
$approvedlist = new approved_contextlist($student, $component, [$studentcontext->id]);
provider::export_user_data($approvedlist);
// Confirm student's data is exported.
$writer = \core_privacy\local\request\writer::with_context($studentcontext);
$this->assertTrue($writer->has_any_data());
delete_course($course, false);
$sc = \context_user::instance($student->id);
$approvedlist = new approved_contextlist($student, $component, [$sc->id]);
provider::export_user_data($approvedlist);
$writer = \core_privacy\local\request\writer::with_context($sc);
$this->assertTrue($writer->has_any_data());
}
/**
* Test exporting data for an approved contextlist with a deleted course
*/
public function test_export_user_data_with_deleted_course(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$component = 'block_recentlyaccesseditems';
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
// Enrol user in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Generate some recent activity.
$this->setUser($student);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
// Confirm data is present.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
delete_course($course, false);
// Export data for student.
$approvedlist = new approved_contextlist($student, $component, [$studentcontext->id]);
provider::export_user_data($approvedlist);
// Confirm student's data is exported.
$writer = \core_privacy\local\request\writer::with_context($studentcontext);
$this->assertFalse($writer->has_any_data());
}
/**
* Test deleting data for all users within an approved contextlist.
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
$teacher = $generator->create_user();
// Enrol users in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Generate some recent activity for both users.
$users = [$student, $teacher];
foreach ($users as $user) {
$this->setUser($user);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
}
// Confirm data is present for both users.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
// Attempt system context deletion (should have no effect).
$systemcontext = \context_system::instance();
provider::delete_data_for_all_users_in_context($systemcontext);
$params = ['courseid' => $course->id];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(4, $result);
// Delete all data in student context.
provider::delete_data_for_all_users_in_context($studentcontext);
// Confirm only student data is deleted.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(0, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
}
/**
* Test deleting data within an approved contextlist for a user.
*/
public function test_delete_data_for_user(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$component = 'block_recentlyaccesseditems';
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
$teacher = $generator->create_user();
$teachercontext = \context_user::instance($teacher->id);
// Enrol users in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Generate some recent activity for both users.
$users = [$student, $teacher];
foreach ($users as $user) {
$this->setUser($user);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
}
// Confirm data is present for both users.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
// Attempt system context deletion (should have no effect).
$systemcontext = \context_system::instance();
$approvedlist = new approved_contextlist($teacher, $component, [$systemcontext->id]);
provider::delete_data_for_user($approvedlist);
$params = ['courseid' => $course->id];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(4, $result);
// Attempt to delete teacher data in student user context (should have no effect).
$approvedlist = new approved_contextlist($teacher, $component, [$studentcontext->id]);
provider::delete_data_for_user($approvedlist);
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(4, $result);
// Delete teacher data in their own user context.
$approvedlist = new approved_contextlist($teacher, $component, [$teachercontext->id]);
provider::delete_data_for_user($approvedlist);
// Confirm only teacher data is deleted.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(0, $result);
}
/**
* Test deleting data within a context for an approved userlist.
*/
public function test_delete_data_for_users(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$component = 'block_recentlyaccesseditems';
$student = $generator->create_user();
$studentcontext = \context_user::instance($student->id);
$teacher = $generator->create_user();
$teachercontext = \context_user::instance($teacher->id);
// Enrol users in course and add course items.
$course = $generator->create_course();
$generator->enrol_user($student->id, $course->id, 'student');
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$forum = $generator->create_module('forum', ['course' => $course]);
$chat = $generator->create_module('chat', ['course' => $course]);
// Generate some recent activity for all users.
$users = [$student, $teacher];
foreach ($users as $user) {
$this->setUser($user);
$event = \mod_forum\event\course_module_viewed::create(['context' => \context_module::instance($forum->cmid),
'objectid' => $forum->id]);
$event->trigger();
$event = \mod_chat\event\course_module_viewed::create(['context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id]);
$event->trigger();
}
// Confirm data is present for all 3 users.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
// Attempt system context deletion (should have no effect).
$systemcontext = \context_system::instance();
$approvedlist = new approved_userlist($systemcontext, $component, [$student->id, $teacher->id]);
provider::delete_data_for_users($approvedlist);
$params = ['courseid' => $course->id];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(4, $result);
// Attempt to delete data in another user's context (should have no effect).
$approvedlist = new approved_userlist($studentcontext, $component, [$teacher->id]);
provider::delete_data_for_users($approvedlist);
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(4, $result);
// Delete users' data in teacher's context.
$approvedlist = new approved_userlist($teachercontext, $component, [$student->id, $teacher->id]);
provider::delete_data_for_users($approvedlist);
// Confirm only teacher data is deleted.
$params = [
'courseid' => $course->id,
'userid' => $student->id,
];
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(2, $result);
$params['userid'] = $teacher->id;
$result = $DB->count_records('block_recentlyaccesseditems', $params);
$this->assertEquals(0, $result);
}
}
+9
View File
@@ -0,0 +1,9 @@
This file describes API changes in the recentlyaccesseditems block code.
=== 4.4 ===
* The external function \block_recentlyaccesseditems\external\get_recent_items() now returns
a field called "branded" indicating whether the module is branded or not.
=== 3.7 ===
* The 'block/recentlyaccesseditems:addinstance' capability has been removed. It has never been used in code.
+27
View File
@@ -0,0 +1,27 @@
<?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/>.
/**
* Version details for the Recent activities block.
*
* @package block_recentlyaccesseditems
* @copyright 2018 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'block_recentlyaccesseditems'; // Full name of the plugin (used for diagnostics).