MDL-68796 core_contentbank: Store view preferences

includes privacy export, privacy unit test
This commit is contained in:
Bas Brands 2020-05-21 16:53:12 +02:00
parent 68fd8d8bdf
commit c393d8185a
12 changed files with 179 additions and 8 deletions

View File

@ -1,2 +1,2 @@
define ("core_contentbank/sort",["exports","core_contentbank/selectors","core/str","core/prefetch"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=e(b);d=e(d);function e(a){return a&&a.__esModule?a:{default:a}}var f=function(){var a=document.querySelector(b.default.regions.contentbank);d.default.prefetchStrings("contentbank",["sortbyx","sortbyxreverse","contentname","lastmodified","size","type"]);g(a)};a.init=f;var g=function(a){var c=document.querySelector(b.default.regions.filearea),d=c.querySelectorAll(b.default.elements.listitem),e=a.querySelector(b.default.actions.viewgrid),f=a.querySelector(b.default.actions.viewlist);e.addEventListener("click",function(){a.classList.remove("view-list");a.classList.add("view-grid");e.classList.add("active");f.classList.remove("active")});f.addEventListener("click",function(){a.classList.remove("view-grid");a.classList.add("view-list");f.classList.add("active");e.classList.remove("active")});var g=a.querySelector(b.default.actions.sortname);g.addEventListener("click",function(){var b=h(a,g);j(c,d,"data-file",b)});var i=a.querySelector(b.default.actions.sortdate);i.addEventListener("click",function(){var b=h(a,i);j(c,d,"data-timemodified",b)});var k=a.querySelector(b.default.actions.sortsize);k.addEventListener("click",function(){var b=h(a,k);j(c,d,"data-bytes",b)});var l=a.querySelector(b.default.actions.sorttype);l.addEventListener("click",function(){var b=h(a,l);j(c,d,"data-type",b)})},h=function(a,c){var d=a.querySelectorAll(b.default.elements.sortbutton);d.forEach(function(a){if(a!==c){a.classList.remove("dir-asc");a.classList.remove("dir-desc");a.classList.add("dir-none");i(a,!1)}});var e=!0;if(c.classList.contains("dir-none")){c.classList.remove("dir-none");c.classList.add("dir-asc")}else if(c.classList.contains("dir-asc")){c.classList.remove("dir-asc");c.classList.add("dir-desc");e=!1}else if(c.classList.contains("dir-desc")){c.classList.remove("dir-desc");c.classList.add("dir-asc")}i(c,e);return e},i=function(a,b){var d=b?"sortbyxreverse":"sortbyx";return(0,c.get_string)(a.dataset.string,"contentbank").then(function(a){return(0,c.get_string)(d,"core",a)}).then(function(b){a.setAttribute("title",b);return b}).catch()},j=function(a,b,c,d){var e=[].slice.call(b).sort(function(e,a){var b=e.getAttribute(c),f=a.getAttribute(c);if(!isNaN(b)){b=parseInt(b);f=parseInt(f)}if(d){return b>f?1:-1}else{return b<f?1:-1}});e.forEach(function(b){return a.appendChild(b)})}});
define ("core_contentbank/sort",["exports","./selectors","core/str","core/prefetch","core/ajax","core/notification"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=g(b);d=g(d);e=g(e);f=g(f);function g(a){return a&&a.__esModule?a:{default:a}}var h=function(){var a=document.querySelector(b.default.regions.contentbank);d.default.prefetchStrings("contentbank",["sortbyx","sortbyxreverse","contentname","lastmodified","size","type"]);i(a)};a.init=h;var i=function(a){var c=document.querySelector(b.default.regions.filearea),d=c.querySelectorAll(b.default.elements.listitem),e=a.querySelector(b.default.actions.viewgrid),f=a.querySelector(b.default.actions.viewlist);e.addEventListener("click",function(){a.classList.remove("view-list");a.classList.add("view-grid");e.classList.add("active");f.classList.remove("active");j(!1)});f.addEventListener("click",function(){a.classList.remove("view-grid");a.classList.add("view-list");f.classList.add("active");e.classList.remove("active");j(!0)});var g=a.querySelector(b.default.actions.sortname);g.addEventListener("click",function(){var b=k(a,g);m(c,d,"data-file",b)});var h=a.querySelector(b.default.actions.sortdate);h.addEventListener("click",function(){var b=k(a,h);m(c,d,"data-timemodified",b)});var i=a.querySelector(b.default.actions.sortsize);i.addEventListener("click",function(){var b=k(a,i);m(c,d,"data-bytes",b)});var l=a.querySelector(b.default.actions.sorttype);l.addEventListener("click",function(){var b=k(a,l);m(c,d,"data-type",b)})},j=function(a){if(!1===a){a=null}var b={methodname:"core_user_update_user_preferences",args:{preferences:[{type:"core_contentbank_view_list",value:a}]}};return e.default.call([b])[0].catch(f.default.exception)},k=function(a,c){var d=a.querySelectorAll(b.default.elements.sortbutton);d.forEach(function(a){if(a!==c){a.classList.remove("dir-asc");a.classList.remove("dir-desc");a.classList.add("dir-none");l(a,!1)}});var e=!0;if(c.classList.contains("dir-none")){c.classList.remove("dir-none");c.classList.add("dir-asc")}else if(c.classList.contains("dir-asc")){c.classList.remove("dir-asc");c.classList.add("dir-desc");e=!1}else if(c.classList.contains("dir-desc")){c.classList.remove("dir-desc");c.classList.add("dir-asc")}l(c,e);return e},l=function(a,b){var d=b?"sortbyxreverse":"sortbyx";return(0,c.get_string)(a.dataset.string,"contentbank").then(function(a){return(0,c.get_string)(d,"core",a)}).then(function(b){a.setAttribute("title",b);return b}).catch()},m=function(a,b,c,d){var e=[].slice.call(b).sort(function(e,a){var b=e.getAttribute(c),f=a.getAttribute(c);if(!isNaN(b)){b=parseInt(b);f=parseInt(f)}if(d){return b>f?1:-1}else{return b<f?1:-1}});e.forEach(function(b){return a.appendChild(b)})}});
//# sourceMappingURL=sort.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -22,9 +22,11 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import selectors from 'core_contentbank/selectors';
import selectors from './selectors';
import {get_string as getString} from 'core/str';
import Prefetch from 'core/prefetch';
import Ajax from 'core/ajax';
import Notification from 'core/notification';
/**
* Set up the contentbank views.
@ -59,6 +61,7 @@ const registerListenerEvents = (contentBank) => {
contentBank.classList.add('view-grid');
viewGrid.classList.add('active');
viewList.classList.remove('active');
setViewListPreference(false);
});
viewList.addEventListener('click', () => {
@ -66,6 +69,7 @@ const registerListenerEvents = (contentBank) => {
contentBank.classList.add('view-list');
viewList.classList.add('active');
viewGrid.classList.remove('active');
setViewListPreference(true);
});
// Sort by file name alphabetical
@ -97,6 +101,35 @@ const registerListenerEvents = (contentBank) => {
});
};
/**
* Set the contentbank user preference in list view
*
* @param {Bool} viewList view ContentBank as list.
* @return {Promise} Repository promise.
*/
const setViewListPreference = function(viewList) {
// If the given status is not hidden, the preference has to be deleted with a null value.
if (viewList === false) {
viewList = null;
}
const request = {
methodname: 'core_user_update_user_preferences',
args: {
preferences: [
{
type: 'core_contentbank_view_list',
value: viewList
}
]
}
};
return Ajax.call([request])[0].catch(Notification.exception);
};
/**
* Update the sort button view.
*

View File

@ -97,6 +97,7 @@ class bankcontent implements renderable, templatable {
'type' => $mimetype
);
}
$data->viewlist = get_user_preferences('core_contentbank_view_list');
$data->contents = $contentdata;
$data->tools = $this->toolbar;
return $data;

View File

@ -44,7 +44,8 @@ use context_course;
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
\core_privacy\local\request\plugin\provider,
\core_privacy\local\request\user_preference_provider {
/**
* Returns meta data about this system.
@ -65,6 +66,26 @@ class provider implements
return $collection;
}
/**
* Export all user preferences for the contentbank
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$preference = get_user_preferences('core_contentbank_view_list', null, $userid);
if (isset($preference)) {
writer::export_user_preference(
'core_contentbank',
'core_contentbank_view_list',
$preference,
get_string('privacy:request:preference:set', 'core_contentbank', (object) [
'name' => 'core_contentbank_view_list',
'value' => $preference,
])
);
}
}
/**
* Get the list of contexts that contain user information for the specified user.
*

39
contentbank/lib.php Normal file
View File

@ -0,0 +1,39 @@
<?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/>.
/**
* Library functions for contentbank
*
* @package core_contentbank
* @copyright 2020 Bas Brands
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Get the current user preferences that are available
*
* @return Array preferences configuration
*/
function core_contentbank_user_preferences() {
return [
'core_contentbank_view_list' => [
'choices' => array(0, 1),
'type' => PARAM_INT,
'null' => NULL_NOT_ALLOWED,
'default' => 'none'
],
];
}

View File

@ -48,7 +48,8 @@
}
}}
<div class="content-bank-container view-grid" data-region="contentbank">
<div class="content-bank-container {{#viewlist}}view-list{{/viewlist}} {{^viewlist}}view-grid{{/viewlist}}"
data-region="contentbank">
<div class="d-flex justify-content-between flex-column flex-sm-row">
<div class="cb-search-container mb-2">
{{>core_contentbank/bankcontent/search}}

View File

@ -38,12 +38,12 @@
{{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
</a>
{{/tools}}
<button class="icon-no-margin btn btn-secondary active ml-2"
<button class="icon-no-margin btn btn-secondary {{^viewlist}}active{{/viewlist}} ml-2"
title="{{#str}} displayicons, contentbank {{/str}}"
data-action="viewgrid">
{{#pix}}a/view_icon_active, core, {{#str}} displayicons, contentbank {{/str}} {{/pix}}
</button>
<button class="icon-no-margin btn btn-secondary"
<button class="icon-no-margin btn btn-secondary {{#viewlist}}active{{/viewlist}}"
title="{{#str}} displaydetails, contentbank {{/str}}"
data-action="viewlist">
{{#pix}}t/viewdetails, core, {{#str}} displaydetails, contentbank {{/str}} {{/pix}}

View File

@ -0,0 +1,28 @@
@core @core_contentbank @contentbank_h5p @javascript
Feature: Store the content bank view preference
In order to consistantly view the content bank in icons or details view
As an admin
I need to be able to store my view preference
Background:
Given the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname |
| System | | contenttype_h5p | admin | filltheblanks.h5p |
| System | | contenttype_h5p | admin | mathsbook.h5p |
Scenario: Admins can order content in the content bank
Given I log in as "admin"
And I am on site homepage
And I turn editing mode on
And I add the "Navigation" block if not present
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Display contentbank with file details" "button"
And I should see "Last modified"
And I follow "filltheblanks.h5p"
And I click on "Content bank" "link"
And I should see "Last modified"
And I click on "Display contentbank with icons" "button"
And I follow "filltheblanks.h5p"
And I click on "Content bank" "link"
And I should not see "Last modified"

View File

@ -29,6 +29,7 @@ use stdClass;
use context_system;
use context_coursecat;
use context_course;
use context_user;
use core_contentbank\privacy\provider;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\writer;
@ -361,4 +362,50 @@ class core_contentbank_privacy_testcase extends provider_testcase {
return $scenario;
}
/**
* Ensure that export_user_preferences returns no data if the user has not visited any content bank.
*/
public function test_export_user_preferences_no_pref() {
global $DB;
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
$this->getDataGenerator()->role_assign($managerroleid, $user->id);
provider::export_user_preferences($user->id);
$writer = writer::with_context(context_system::instance());
$this->assertFalse($writer->has_any_data());
}
/**
* Test for provider::test_export_user_preferences().
*/
public function test_export_user_preferences() {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
set_user_preference('core_contentbank_view_list', 1);
// Test the user preferences export contains 1 user preference record for the User.
provider::export_user_preferences($user->id);
$contextuser = context_user::instance($user->id);
$writer = writer::with_context($contextuser);
$this->assertTrue($writer->has_any_data());
$prefs = $writer->get_user_preferences('core_contentbank');
$this->assertCount(1, (array) $prefs);
$this->assertEquals(1, $prefs->core_contentbank_view_list->value);
$this->assertEquals(
get_string('privacy:request:preference:set', 'core_contentbank', (object) [
'name' => 'core_contentbank_view_list',
'value' => $prefs->core_contentbank_view_list->value,
]),
$prefs->core_contentbank_view_list->description
);
}
}

View File

@ -55,6 +55,7 @@ $string['privacy:metadata:content:usercreated'] = 'The user has created the cont
$string['privacy:metadata:content:usermodified'] = 'The last user who modified the content.';
$string['privacy:metadata:contentbankcontent'] = 'Stores the content of the content bank.';
$string['privacy:metadata:userid'] = 'The ID of the user creating or modifying content bank content.';
$string['privacy:request:preference:set'] = 'The value of the setting \'{$a->name}\' was \'{$a->value}\'';
$string['rename'] = 'Rename';
$string['renamecontent'] = 'Rename content';
$string['searchcontentbankbyname'] = 'Search for content by name';

View File

@ -997,7 +997,7 @@ class core_user {
// Core components that may want to define their preferences.
// List of core components implementing callback is hardcoded here for performance reasons.
// TODO MDL-58184 cache list of core components implementing a function.
$corecomponents = ['core_message', 'core_calendar'];
$corecomponents = ['core_message', 'core_calendar', 'core_contentbank'];
foreach ($corecomponents as $component) {
if (($pluginpreferences = component_callback($component, 'user_preferences')) && is_array($pluginpreferences)) {
$preferences += $pluginpreferences;