diff --git a/blocks/recentlyaccesseditems/amd/build/main.min.js b/blocks/recentlyaccesseditems/amd/build/main.min.js new file mode 100644 index 00000000000..d4daa0f0a5d --- /dev/null +++ b/blocks/recentlyaccesseditems/amd/build/main.min.js @@ -0,0 +1 @@ +define(["jquery","block_recentlyaccesseditems/repository","core/templates","core/notification"],function(a,b,c,d){var e=9,f={CARDDECK_CONTAINER:'[data-region="recentlyaccesseditems-view"]',CARDDECK:'[data-region="recentlyaccesseditems-view-content"]'},g=function(a){return b.getRecentItems(a)},h=function(a,b){if(b.length>0)return c.render("block_recentlyaccesseditems/view-cards",{items:b});var d=a.attr("data-noitemsimgurl");return c.render("block_recentlyaccesseditems/no-items",{noitemsimgurl:d})},i=function(b){b=a(b);var i=b.find(f.CARDDECK_CONTAINER),j=b.find(f.CARDDECK),k=g(e);k.then(function(a){var b=h(i,a);return b.then(function(a,b){return c.replaceNodeContents(j,a,b)})["catch"](d.exception),k})["catch"](d.exception)};return{init:i}}); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/amd/build/repository.min.js b/blocks/recentlyaccesseditems/amd/build/repository.min.js new file mode 100644 index 00000000000..fa504bbb655 --- /dev/null +++ b/blocks/recentlyaccesseditems/amd/build/repository.min.js @@ -0,0 +1 @@ +define(["core/ajax"],function(a){var b=function(b){var c={};"undefined"!=typeof b&&(c.limit=b);var d={methodname:"block_recentlyaccesseditems_get_recent_items",args:c};return a.call([d])[0]};return{getRecentItems:b}}); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/amd/src/main.js b/blocks/recentlyaccesseditems/amd/src/main.js new file mode 100644 index 00000000000..5d4fd16e5c3 --- /dev/null +++ b/blocks/recentlyaccesseditems/amd/src/main.js @@ -0,0 +1,105 @@ + +// 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 . + +/** + * Javascript to initialise the Recently accessed items block. + * + * @module block_recentlyaccesseditems/main + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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; + + var SELECTORS = { + CARDDECK_CONTAINER: '[data-region="recentlyaccesseditems-view"]', + CARDDECK: '[data-region="recentlyaccesseditems-view-content"]', + }; + + /** + * 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) { + return Templates.render('block_recentlyaccesseditems/view-cards', { + items: items + }); + } 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) { + return Templates.replaceNodeContents(itemsContent, html, js); + }).catch(Notification.exception); + return itemsPromise; + }).catch(Notification.exception); + }; + + return { + init: init + }; + }); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/amd/src/repository.js b/blocks/recentlyaccesseditems/amd/src/repository.js new file mode 100644 index 00000000000..cd76802a55b --- /dev/null +++ b/blocks/recentlyaccesseditems/amd/src/repository.js @@ -0,0 +1,47 @@ +// 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 . + +/** + * A javascript module to handle user ajax actions. + * + * @module block_recentlyaccesseditems/repository + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 + }; +}); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/block_recentlyaccesseditems.php b/blocks/recentlyaccesseditems/block_recentlyaccesseditems.php new file mode 100644 index 00000000000..d16c303bfc0 --- /dev/null +++ b/blocks/recentlyaccesseditems/block_recentlyaccesseditems.php @@ -0,0 +1,65 @@ +. +/** + * Class definition for the Recently accessed items block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 + * @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); + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/external.php b/blocks/recentlyaccesseditems/classes/external.php new file mode 100644 index 00000000000..ddfea0dfafd --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/external.php @@ -0,0 +1,102 @@ +. + +/** + * External API. + * + * @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(); + +require_once("$CFG->libdir/externallib.php"); + +use block_recentlyaccesseditems\external\recentlyaccesseditems_item_exporter; +use external_api; +use external_function_parameters; +use external_value; +use external_multiple_structure; +use context_user; +use context_module; + +/** + * External API class. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 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'); + } +} diff --git a/blocks/recentlyaccesseditems/classes/external/recentlyaccesseditems_item_exporter.php b/blocks/recentlyaccesseditems/classes/external/recentlyaccesseditems_item_exporter.php new file mode 100644 index 00000000000..f26b43d1efb --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/external/recentlyaccesseditems_item_exporter.php @@ -0,0 +1,114 @@ +. +/** + * Class for exporting the data needed to render a recent accessed item. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 $OUTPUT; + + 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' => $OUTPUT->image_icon('icon', get_string('pluginname', $this->data->modname), $this->data->modname) + ); + } + + /** + * 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_TEXT, + ), + '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_TEXT, + ), + 'courseviewurl' => array( + 'type' => PARAM_URL, + ), + 'icon' => array( + 'type' => PARAM_RAW, + ) + ); + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/helper.php b/blocks/recentlyaccesseditems/classes/helper.php new file mode 100644 index 00000000000..e7e204f4e6f --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/helper.php @@ -0,0 +1,93 @@ +. + +/** + * Recently accessed items helper. + * + * @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(); + +/** + * Recently accessed items helper. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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; + } + + // Determine sort sql clause. + $sort = 'timeaccess DESC'; + + $paramsql = array('userid' => $userid); + $records = $DB->get_records('block_recentlyaccesseditems', $paramsql, $sort); + $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); + 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; + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/observer.php b/blocks/recentlyaccesseditems/classes/observer.php new file mode 100644 index 00000000000..700ced816a8 --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/observer.php @@ -0,0 +1,105 @@ +. + +/** + * 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 + * @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)); + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/output/main.php b/blocks/recentlyaccesseditems/classes/output/main.php new file mode 100644 index 00000000000..27741967e8c --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/output/main.php @@ -0,0 +1,53 @@ +. +/** + * Class containing data for Recently accessed items block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 + * @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 stdClass + */ + public function export_for_template(renderer_base $output) { + + $noitemsimgurl = $output->image_url('items', 'block_recentlyaccesseditems')->out(); + + return [ + 'noitemsimgurl' => $noitemsimgurl + ]; + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/output/renderer.php b/blocks/recentlyaccesseditems/classes/output/renderer.php new file mode 100644 index 00000000000..ad69b664419 --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/output/renderer.php @@ -0,0 +1,46 @@ +. +/** + * Recently accessed items block renderer + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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 + * @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)); + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/classes/privacy/provider.php b/blocks/recentlyaccesseditems/classes/privacy/provider.php new file mode 100644 index 00000000000..f56589b7652 --- /dev/null +++ b/blocks/recentlyaccesseditems/classes/privacy/provider.php @@ -0,0 +1,151 @@ +. + +/** + * Privacy Subsystem implementation for Recently accessed items block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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\approved_contextlist; +use \core_privacy\local\request\writer; + +/** + * Privacy Subsystem for block_recentlyaccesseditems. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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\subsystem\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 id + FROM {context} + WHERE instanceid = :userid and contextlevel = :contextuser"; + $contextlist = new contextlist(); + $contextlist->add_from_sql($sql, $params); + return $contextlist; + } + + /** + * 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]); + } + } + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/db/access.php b/blocks/recentlyaccesseditems/db/access.php new file mode 100644 index 00000000000..99ef6dbfd97 --- /dev/null +++ b/blocks/recentlyaccesseditems/db/access.php @@ -0,0 +1,41 @@ +. +/** + * Capabilities for the Recently accessed items block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @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' + ), + 'block/recentlyaccesseditems:addinstance' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_BLOCK, + 'archetypes' => array( + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/site:manageblocks' + ) +); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/db/events.php b/blocks/recentlyaccesseditems/db/events.php new file mode 100644 index 00000000000..8f08ced3598 --- /dev/null +++ b/blocks/recentlyaccesseditems/db/events.php @@ -0,0 +1,37 @@ +. + +/** + * Recently accessed items event observer. + * + * @package block_recentlyaccesseditems + * @category event + * @copyright 2018 Victor Deniz + * @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' + ), +); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/db/install.xml b/blocks/recentlyaccesseditems/db/install.xml new file mode 100644 index 00000000000..2b6bf1058dd --- /dev/null +++ b/blocks/recentlyaccesseditems/db/install.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/blocks/recentlyaccesseditems/db/services.php b/blocks/recentlyaccesseditems/db/services.php new file mode 100644 index 00000000000..6caf09f8a6f --- /dev/null +++ b/blocks/recentlyaccesseditems/db/services.php @@ -0,0 +1,38 @@ +. + +/** + * Web service for Recently accessed items block + * + * @package block_recentlyaccesseditems + * @since Moodle 3.6 + * @copyright 2018 Victor Deniz + * @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), + ), +); \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/lang/en/block_recentlyaccesseditems.php b/blocks/recentlyaccesseditems/lang/en/block_recentlyaccesseditems.php new file mode 100644 index 00000000000..d9238f56f02 --- /dev/null +++ b/blocks/recentlyaccesseditems/lang/en/block_recentlyaccesseditems.php @@ -0,0 +1,32 @@ +. +/** + * Strings for the Recently accessed items block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +$string['noitems'] = 'No recent items'; +$string['pluginname'] = 'Recently accessed items'; +$string['privacy:metadata:cmid'] = 'The course module id'; +$string['privacy:metadata:courseid'] = 'Course the item belongs to'; +$string['privacy:metadata:block_recentlyaccesseditemstablesummary'] = 'Information about the last time a user accessed an item.'; +$string['privacy:metadata:timeaccess'] = 'The time of the last access to the item by the user.'; +$string['privacy:metadata:userid'] = 'User who accessed the item'; +$string['privacy:recentlyaccesseditemspath'] = 'Recently accessed items'; +$string['recentlyaccesseditems:addinstance'] = 'Add a new recently accessed items block'; +$string['recentlyaccesseditems:myaddinstance'] = 'Add a new recently accessed items block to Dashboard'; \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/pix/items.svg b/blocks/recentlyaccesseditems/pix/items.svg new file mode 100644 index 00000000000..ed7546ade4d --- /dev/null +++ b/blocks/recentlyaccesseditems/pix/items.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blocks/recentlyaccesseditems/templates/main.mustache b/blocks/recentlyaccesseditems/templates/main.mustache new file mode 100644 index 00000000000..2f2ce75db43 --- /dev/null +++ b/blocks/recentlyaccesseditems/templates/main.mustache @@ -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 . +}} +{{! + @template block_recentlyaccesseditems/main + + This template renders the main content area for the Recently accessed itemes block. + + Example context (json): + {} +}} + +
+
+ {{> block_recentlyaccesseditems/recentlyaccesseditems-view }} +
+
+{{#js}} +require( +[ + 'jquery', + 'block_recentlyaccesseditems/main', +], +function( + $, + Main +) { + var root = $('#block-recentlyaccesseditems-{{uniqid}}'); + + Main.init(root); +}); +{{/js}} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/templates/no-items.mustache b/blocks/recentlyaccesseditems/templates/no-items.mustache new file mode 100644 index 00000000000..794f42474c4 --- /dev/null +++ b/blocks/recentlyaccesseditems/templates/no-items.mustache @@ -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 . +}} +{{! + @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" + } +}} +
+ {{#str}} noitems, block_recentlyaccesseditems {{/str}} +

{{#str}} noitems, block_recentlyaccesseditems {{/str}}

+
\ No newline at end of file diff --git a/blocks/recentlyaccesseditems/templates/placeholder-item.mustache b/blocks/recentlyaccesseditems/templates/placeholder-item.mustache new file mode 100644 index 00000000000..e1bf6334f9e --- /dev/null +++ b/blocks/recentlyaccesseditems/templates/placeholder-item.mustache @@ -0,0 +1,33 @@ +{{! + 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 . +}} +{{! + @template block_recentlyaccesseditems/placeholder-item + + This template renders a card item loading placeholder for the Recently accessed items block. + + Example context (json): + {} +}} +
+
+
+
+
+
+
+
+
diff --git a/blocks/recentlyaccesseditems/templates/recentlyaccesseditems-view.mustache b/blocks/recentlyaccesseditems/templates/recentlyaccesseditems-view.mustache new file mode 100644 index 00000000000..6e4494f7c0c --- /dev/null +++ b/blocks/recentlyaccesseditems/templates/recentlyaccesseditems-view.mustache @@ -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 . +}} +{{! + @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" + } +}} +
+
+
+
+ {{> block_recentlyaccesseditems/placeholder-item }} + {{> block_recentlyaccesseditems/placeholder-item }} + {{> block_recentlyaccesseditems/placeholder-item }} +
+
+
+
+ diff --git a/blocks/recentlyaccesseditems/templates/view-cards.mustache b/blocks/recentlyaccesseditems/templates/view-cards.mustache new file mode 100644 index 00000000000..8b3619c2291 --- /dev/null +++ b/blocks/recentlyaccesseditems/templates/view-cards.mustache @@ -0,0 +1,63 @@ +{{! + 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 . +}} +{{! + @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": "\"Forum\"", + "name": "Assignment due 1", + "id": 17, + "modname": "Forum", + "name": "Forum", + "timeaccess": 1539848498, + "userid": 2, + "viewurl": "http://moodlesite/mod/forum?id=64" + } + ] + } +}} + + \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature b/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature new file mode 100644 index 00000000000..5aa383f09eb --- /dev/null +++ b/blocks/recentlyaccesseditems/tests/behat/block_recentlyaccesseditems_dashboard.feature @@ -0,0 +1,38 @@ +@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 I log in as "admin" + And I am on "Course 1" course homepage + And I turn editing mode on + And I add a "Forum" to section "1" and I fill the form with: + | Forum name | Test forum name | + | Forum type | Standard forum for general use | + | Description | Test forum description | + And I log out + And I log in as "student1" + When I press "Customise this page" + And I add the "Recently accessed items" block + + Scenario: User has not accessed any item + Then I should see "No recent items" in the "Recently accessed items" "block" + + Scenario: User has accessed some items + Given I am on "Course 1" course homepage + When I follow "Test forum name" + And I follow "Dashboard" in the user menu + Then I should see "Test forum name" in the "Recently accessed items" "block" \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/tests/externallib_test.php b/blocks/recentlyaccesseditems/tests/externallib_test.php new file mode 100644 index 00000000000..62de36a2340 --- /dev/null +++ b/blocks/recentlyaccesseditems/tests/externallib_test.php @@ -0,0 +1,107 @@ +. + +/** + * External block functions unit tests + * + * @package block_recentlyaccesseditems + * @category external + * @copyright 2018 Victor Deniz + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.6 + */ + +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 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.6 + */ +class block_recentlyaccesseditems_externallib_testcase extends externallib_advanced_testcase { + + /** + * Test the get_recent_items function. + */ + public function test_get_recent_items() { + + $this->resetAfterTest(); + $generator = $this->getDataGenerator(); + + // 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)); + $chat[] = $this->getDataGenerator()->create_module('chat', array('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 ($chat as $module) { + $event = \mod_chat\event\course_module_viewed::create(array('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($chat)), $result); + foreach ($result as $key => $record) { + if ($key == 0) { + continue; + } + $this->assertTrue($record->timeaccess < $result[$key - 1]->timeaccess); + } + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/tests/observer_test.php b/blocks/recentlyaccesseditems/tests/observer_test.php new file mode 100644 index 00000000000..fcc0eb25c56 --- /dev/null +++ b/blocks/recentlyaccesseditems/tests/observer_test.php @@ -0,0 +1,160 @@ +. + +/** + * Block recentlyaccesseditems observer tests. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.6 + */ + +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 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.6 + */ +class block_recentlyaccesseditems_observer_testcase extends advanced_testcase { + use mod_assign_test_generator; + + /** + * Set up for every test + */ + public function setUp() { + 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() { + 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() { + 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); + } +} \ No newline at end of file diff --git a/blocks/recentlyaccesseditems/version.php b/blocks/recentlyaccesseditems/version.php new file mode 100644 index 00000000000..198c33863a9 --- /dev/null +++ b/blocks/recentlyaccesseditems/version.php @@ -0,0 +1,27 @@ +. +/** + * Version details for the Recent activities block. + * + * @package block_recentlyaccesseditems + * @copyright 2018 Victor Deniz + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2018101705; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2018101900; // Requires this Moodle version. +$plugin->component = 'block_recentlyaccesseditems'; // Full name of the plugin (used for diagnostics). diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index ca1f30831ee..175582e95a1 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1718,7 +1718,7 @@ class core_plugin_manager { 'feedback', 'globalsearch', 'glossary_random', 'html', 'login', 'lp', 'mentees', 'mnet_hosts', 'myoverview', 'myprofile', 'navigation', 'news_items', 'online_users', 'participants', - 'private_files', 'quiz_results', 'recent_activity', + 'private_files', 'quiz_results', 'recent_activity', 'recentlyaccesseditems', 'rss_client', 'search_forums', 'section_links', 'selfcompletion', 'settings', 'site_main_menu', 'social_activities', 'starredcourses', 'tag_flickr', 'tag_youtube', 'tags', 'timeline' diff --git a/theme/boost/scss/moodle/blocks.scss b/theme/boost/scss/moodle/blocks.scss index 80df6e23e4d..09c47367bd7 100644 --- a/theme/boost/scss/moodle/blocks.scss +++ b/theme/boost/scss/moodle/blocks.scss @@ -125,6 +125,43 @@ $card-gutter : $card-deck-margin * 2; background-size: cover; } +[data-region="blocks-column"] { + .block_recentlyaccesseditems { + .dashboard-card-deck { + height: unset; + } + } +} + +.block_recentlyaccesseditems { + [data-region="recentlyaccesseditems-view-content"] { + overflow-x: hidden; + } + .dashboard-card { + height: 75px; + } + .dashboard-card-deck { + @include media-breakpoint-up(sm) { + height: 75px; + overflow: hidden; + } + } + .course-info-container { + padding: 0.8rem; + } + .empty-placeholder-image-lg { + height: 125px; + } + a, + a:hover { + text-decoration: none; + color: unset; + } + .block-controls ~ .content { + margin-top: 2rem !important; + } +} + .dashboard-card-deck .dashboard-card { margin-bottom: $card-gutter; flex-basis: 100%; diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 7dcd40610f8..31e8e8809fb 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -11201,6 +11201,34 @@ div.editor_atto_toolbar button .icon { background-position: center; background-size: cover; } +[data-region="blocks-column"] .block_recentlyaccesseditems .dashboard-card-deck { + height: unset; } + +.block_recentlyaccesseditems [data-region="recentlyaccesseditems-view-content"] { + overflow-x: hidden; } + +.block_recentlyaccesseditems .dashboard-card { + height: 75px; } + +@media (min-width: 576px) { + .block_recentlyaccesseditems .dashboard-card-deck { + height: 75px; + overflow: hidden; } } + +.block_recentlyaccesseditems .course-info-container { + padding: 0.8rem; } + +.block_recentlyaccesseditems .empty-placeholder-image-lg { + height: 125px; } + +.block_recentlyaccesseditems a, +.block_recentlyaccesseditems a:hover { + text-decoration: none; + color: unset; } + +.block_recentlyaccesseditems .block-controls ~ .content { + margin-top: 2rem !important; } + .dashboard-card-deck .dashboard-card { margin-bottom: 0.5rem; flex-basis: 100%; diff --git a/theme/bootstrapbase/less/moodle/blocks.less b/theme/bootstrapbase/less/moodle/blocks.less index e8df3e6b8dc..85ef79350ec 100644 --- a/theme/bootstrapbase/less/moodle/blocks.less +++ b/theme/bootstrapbase/less/moodle/blocks.less @@ -395,6 +395,51 @@ } } +.block_recentlyaccesseditems { + [data-region="recentlyaccesseditems-view-content"] { + overflow-x: hidden; + } + .dashboard-card { + height: 75px; + } + .dashboard-card-deck { + @media (min-width: 576px) { + height: 75px; + overflow: hidden; + } + } + .empty-placeholder-image-lg { + height: 125px; + } + .course-info-container { + flex: 1 1 auto; + padding: 0.8rem; + } + .icon-size-4 .icon { + height: auto; + width: auto; + background-image: unset; + box-sizing: unset; + } + .icon-size-4 { + background-image: unset; + height: unset; + width: unset; + } + .ml-1 { + margin-left: 10px; + } + h6 { + font-size: .9375rem; + margin-bottom: 0; + } + a, + a:hover { + text-decoration: none; + color: unset; + } +} + .dashboard-card-deck { box-sizing: border-box; *, @@ -433,8 +478,10 @@ } @media (min-width: 768px) { - #block-region-side-post .dashboard-card-deck { + #block-region-side-post .dashboard-card-deck, + #block-region-side-pre .dashboard-card-deck { margin: 0; + height: unset; .dashboard-card { flex-basis: 100%; margin-left: 0; @@ -458,4 +505,4 @@ .position-absolute { position: absolute; -} \ No newline at end of file +} diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index 61ae121d9c2..99854a3c4ae 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -16610,6 +16610,48 @@ body { flex-flow: nowrap; overflow-y: scroll; } +.block_recentlyaccesseditems [data-region="recentlyaccesseditems-view-content"] { + overflow-x: hidden; +} +.block_recentlyaccesseditems .dashboard-card { + height: 75px; +} +@media (min-width: 576px) { + .block_recentlyaccesseditems .dashboard-card-deck { + height: 75px; + overflow: hidden; + } +} +.block_recentlyaccesseditems .empty-placeholder-image-lg { + height: 125px; +} +.block_recentlyaccesseditems .course-info-container { + flex: 1 1 auto; + padding: 0.8rem; +} +.block_recentlyaccesseditems .icon-size-4 .icon { + height: auto; + width: auto; + background-image: unset; + box-sizing: unset; +} +.block_recentlyaccesseditems .icon-size-4 { + background-image: unset; + height: unset; + width: unset; +} +.block_recentlyaccesseditems .ml-1 { + margin-left: 10px; +} +.block_recentlyaccesseditems h6 { + font-size: .9375rem; + margin-bottom: 0; +} +.block_recentlyaccesseditems a, +.block_recentlyaccesseditems a:hover { + text-decoration: none; + color: unset; +} .dashboard-card-deck { box-sizing: border-box; display: flex; @@ -16647,10 +16689,13 @@ body { } } @media (min-width: 768px) { - #block-region-side-post .dashboard-card-deck { + #block-region-side-post .dashboard-card-deck, + #block-region-side-pre .dashboard-card-deck { margin: 0; + height: unset; } - #block-region-side-post .dashboard-card-deck .dashboard-card { + #block-region-side-post .dashboard-card-deck .dashboard-card, + #block-region-side-pre .dashboard-card-deck .dashboard-card { flex-basis: 100%; margin-left: 0; margin-right: 0; diff --git a/version.php b/version.php index 61e0e2b54bd..a721d34c4e6 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2018110100.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2018110100.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.