mirror of
https://github.com/moodle/moodle.git
synced 2025-04-25 10:26:17 +02:00
MDL-69762 core_contentbank: let users hide their content
This commit is contained in:
parent
41037efa7a
commit
3776fbafb2
admin/settings
contentbank
lang/en
lib
theme
user
version.php@ -87,6 +87,14 @@ if ($hassiteconfig
|
||||
$choices['1'] = new lang_string('trackforumsyes');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_trackforums', new lang_string('trackforums'),
|
||||
'', 0, $choices));
|
||||
|
||||
$choices = [];
|
||||
$choices[\core_contentbank\content::VISIBILITY_PUBLIC] = new lang_string('visibilitychoicepublic', 'core_contentbank');
|
||||
$choices[\core_contentbank\content::VISIBILITY_UNLISTED] = new lang_string('visibilitychoiceunlisted', 'core_contentbank');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_core_contentbank_visibility',
|
||||
new lang_string('visibilitypref', 'core_contentbank'),
|
||||
new lang_string('visibilitypref_help', 'core_contentbank'),
|
||||
\core_contentbank\content::VISIBILITY_PUBLIC, $choices));
|
||||
}
|
||||
$ADMIN->add('accounts', $temp);
|
||||
|
||||
|
2
contentbank/amd/build/actions.min.js
vendored
2
contentbank/amd/build/actions.min.js
vendored
@ -1,2 +1,2 @@
|
||||
define ("core_contentbank/actions",["jquery","core/ajax","core/notification","core/str","core/templates","core/url","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g,h){var k={DELETE_CONTENT:"[data-action=\"deletecontent\"]",RENAME_CONTENT:"[data-action=\"renamecontent\"]"},l=function(){this.registerEvents()};l.prototype.registerEvents=function(){a(k.DELETE_CONTENT).click(function(b){b.preventDefault();var e=a(this).data("contentname"),f=a(this).data("uses"),j=a(this).data("contentid"),k=a(this).data("contextid"),l="";d.get_strings([{key:"deletecontent",component:"core_contentbank"},{key:"deletecontentconfirm",component:"core_contentbank",param:{name:e}},{key:"deletecontentconfirmlinked",component:"core_contentbank"},{key:"delete",component:"core"}]).then(function(a){var b=a[0],c=a[1];if(0<f){c+=" "+a[2]}l=a[3];return g.create({title:b,body:c,type:g.types.SAVE_CANCEL,large:!0})}).done(function(a){a.setSaveButtonText(l);a.getRoot().on(h.save,function(){return i(j,k)});a.getRoot().on(h.hidden,function(){a.destroy()});a.show()}).catch(c.exception)});a(k.RENAME_CONTENT).click(function(b){b.preventDefault();var f=a(this).data("contentname"),i=a(this).data("contentid"),k="";d.get_strings([{key:"renamecontent",component:"core_contentbank"},{key:"rename",component:"core_contentbank"}]).then(function(a){var b=a[0];k=a[1];return g.create({title:b,body:e.render("core_contentbank/renamecontent",{contentid:i,name:f}),type:g.types.SAVE_CANCEL})}).then(function(b){b.setSaveButtonText(k);b.getRoot().on(h.save,function(b){var e=a("#newname").val().trim();if(e){j(i,e)}else{d.get_strings([{key:"error"},{key:"emptynamenotallowed",component:"core_contentbank"}]).then(function(a){c.alert(a[0],a[1])}).catch(c.exception);b.preventDefault()}});b.getRoot().on(h.hidden,function(){b.destroy()});b.show()}).catch(c.exception)})};function i(a,d){var e="success";b.call([{methodname:"core_contentbank_delete_content",args:{contentids:{contentid:a}}}])[0].then(function(a){if(a.result){return"contentdeleted"}e="error";return"contentnotdeleted"}).done(function(a){var b={contextid:d};if("success"==e){b.statusmsg=a}else{b.errormsg=a}window.location.href=f.relativeUrl("contentbank/index.php",b,!1)}).fail(c.exception)}function j(a,d){var e="success";b.call([{methodname:"core_contentbank_rename_content",args:{contentid:a,name:d}}])[0].then(function(a){if(a.result){return"contentrenamed"}e="error";return a.warnings[0].message}).then(function(b){var d=null;if("success"==e){d={id:a,statusmsg:b};window.location.href=f.relativeUrl("contentbank/view.php",d,!1)}else{c.addNotification({message:b,type:"error"});c.fetchNotifications()}}).catch(c.exception)}return{init:function init(){return new l}}});
|
||||
define ("core_contentbank/actions",["jquery","core/ajax","core/notification","core/str","core/templates","core/url","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g,h){var l={DELETE_CONTENT:"[data-action=\"deletecontent\"]",RENAME_CONTENT:"[data-action=\"renamecontent\"]",SET_CONTENT_VISIBILITY:"[data-action=\"setcontentvisibility\"]"},m=function(){this.registerEvents()};m.prototype.registerEvents=function(){a(l.DELETE_CONTENT).click(function(b){b.preventDefault();var e=a(this).data("contentname"),f=a(this).data("uses"),j=a(this).data("contentid"),k=a(this).data("contextid"),l="";d.get_strings([{key:"deletecontent",component:"core_contentbank"},{key:"deletecontentconfirm",component:"core_contentbank",param:{name:e}},{key:"deletecontentconfirmlinked",component:"core_contentbank"},{key:"delete",component:"core"}]).then(function(a){var b=a[0],c=a[1];if(0<f){c+=" "+a[2]}l=a[3];return g.create({title:b,body:c,type:g.types.SAVE_CANCEL,large:!0})}).done(function(a){a.setSaveButtonText(l);a.getRoot().on(h.save,function(){return i(j,k)});a.getRoot().on(h.hidden,function(){a.destroy()});a.show()}).catch(c.exception)});a(l.RENAME_CONTENT).click(function(b){b.preventDefault();var f=a(this).data("contentname"),i=a(this).data("contentid"),k="";d.get_strings([{key:"renamecontent",component:"core_contentbank"},{key:"rename",component:"core_contentbank"}]).then(function(a){var b=a[0];k=a[1];return g.create({title:b,body:e.render("core_contentbank/renamecontent",{contentid:i,name:f}),type:g.types.SAVE_CANCEL})}).then(function(b){b.setSaveButtonText(k);b.getRoot().on(h.save,function(b){var e=a("#newname").val().trim();if(e){j(i,e)}else{d.get_strings([{key:"error"},{key:"emptynamenotallowed",component:"core_contentbank"}]).then(function(a){c.alert(a[0],a[1])}).catch(c.exception);b.preventDefault()}});b.getRoot().on(h.hidden,function(){b.destroy()});b.show()}).catch(c.exception)});a(l.SET_CONTENT_VISIBILITY).click(function(b){b.preventDefault();var c=a(this).data("contentid"),d=a(this).data("visibility");k(c,d)})};function i(a,d){var e="success";b.call([{methodname:"core_contentbank_delete_content",args:{contentids:{contentid:a}}}])[0].then(function(a){if(a.result){return"contentdeleted"}e="error";return"contentnotdeleted"}).done(function(a){var b={contextid:d};if("success"==e){b.statusmsg=a}else{b.errormsg=a}window.location.href=f.relativeUrl("contentbank/index.php",b,!1)}).fail(c.exception)}function j(a,d){var e="success";b.call([{methodname:"core_contentbank_rename_content",args:{contentid:a,name:d}}])[0].then(function(a){if(a.result){return"contentrenamed"}e="error";return a.warnings[0].message}).then(function(b){var d=null;if("success"==e){d={id:a,statusmsg:b};window.location.href=f.relativeUrl("contentbank/view.php",d,!1)}else{c.addNotification({message:b,type:"error"});c.fetchNotifications()}}).catch(c.exception)}function k(a,d){var e="success";b.call([{methodname:"core_contentbank_set_content_visibility",args:{contentid:a,visibility:d}}])[0].then(function(a){if(a.result){return"contentvisibilitychanged"}e="error";return a.warnings[0].message}).then(function(b){var d=null;if("success"==e){d={id:a,statusmsg:b};window.location.href=f.relativeUrl("contentbank/view.php",d,!1)}else{c.addNotification({message:b,type:"error"});c.fetchNotifications()}}).catch(c.exception)}return{init:function init(){return new m}}});
|
||||
//# sourceMappingURL=actions.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -40,6 +40,7 @@ function($, Ajax, Notification, Str, Templates, Url, ModalFactory, ModalEvents)
|
||||
var ACTIONS = {
|
||||
DELETE_CONTENT: '[data-action="deletecontent"]',
|
||||
RENAME_CONTENT: '[data-action="renamecontent"]',
|
||||
SET_CONTENT_VISIBILITY: '[data-action="setcontentvisibility"]',
|
||||
};
|
||||
|
||||
/**
|
||||
@ -181,6 +182,15 @@ function($, Ajax, Notification, Str, Templates, Url, ModalFactory, ModalEvents)
|
||||
return;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
|
||||
$(ACTIONS.SET_CONTENT_VISIBILITY).click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var contentid = $(this).data('contentid');
|
||||
var visibility = $(this).data('visibility');
|
||||
|
||||
setContentVisibility(contentid, visibility);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -262,6 +272,49 @@ function($, Ajax, Notification, Str, Templates, Url, ModalFactory, ModalEvents)
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set content visibility in the content bank.
|
||||
*
|
||||
* @param {int} contentid The content to modify
|
||||
* @param {int} visibility The new visibility value
|
||||
*/
|
||||
function setContentVisibility(contentid, visibility) {
|
||||
var request = {
|
||||
methodname: 'core_contentbank_set_content_visibility',
|
||||
args: {
|
||||
contentid: contentid,
|
||||
visibility: visibility
|
||||
}
|
||||
};
|
||||
var requestType = 'success';
|
||||
Ajax.call([request])[0].then(function(data) {
|
||||
if (data.result) {
|
||||
return 'contentvisibilitychanged';
|
||||
}
|
||||
requestType = 'error';
|
||||
return data.warnings[0].message;
|
||||
|
||||
}).then(function(message) {
|
||||
var params = null;
|
||||
if (requestType == 'success') {
|
||||
params = {
|
||||
id: contentid,
|
||||
statusmsg: message
|
||||
};
|
||||
// Redirect to the content view page and display the message as a notification.
|
||||
window.location.href = Url.relativeUrl('contentbank/view.php', params, false);
|
||||
} else {
|
||||
// Fetch error notifications.
|
||||
Notification.addNotification({
|
||||
message: message,
|
||||
type: 'error'
|
||||
});
|
||||
Notification.fetchNotifications();
|
||||
}
|
||||
return;
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
|
||||
return /** @alias module:core_contentbank/actions */ {
|
||||
// Public variables and functions.
|
||||
|
||||
|
@ -40,6 +40,17 @@ use core\event\contentbank_content_updated;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class content {
|
||||
/**
|
||||
* @var int Visibility value. Public content is visible to all users with access to the content bank of the
|
||||
* appropriate context.
|
||||
*/
|
||||
public const VISIBILITY_PUBLIC = 1;
|
||||
|
||||
/**
|
||||
* @var int Visibility value. Unlisted content is only visible to the author and to users with
|
||||
* moodle/contentbank:viewunlistedcontent capability.
|
||||
*/
|
||||
public const VISIBILITY_UNLISTED = 2;
|
||||
|
||||
/** @var stdClass $content The content of the current instance. **/
|
||||
protected $content = null;
|
||||
@ -250,6 +261,30 @@ abstract class content {
|
||||
return $this->content->configdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new content visibility and saves it to database.
|
||||
*
|
||||
* @param int $visibility Must be self::PUBLIC or self::UNLISTED
|
||||
* @return bool
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function set_visibility(int $visibility): bool {
|
||||
if (!in_array($visibility, [self::VISIBILITY_PUBLIC, self::VISIBILITY_UNLISTED])) {
|
||||
return false;
|
||||
}
|
||||
$this->content->visibility = $visibility;
|
||||
return $this->update_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the content may be shown to other users in the content bank.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function get_visibility(): int {
|
||||
return $this->content->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a file as a valid content.
|
||||
*
|
||||
@ -356,8 +391,12 @@ abstract class content {
|
||||
* @return bool True if content could be accessed. False otherwise.
|
||||
*/
|
||||
public function is_view_allowed(): bool {
|
||||
// There's no capability at content level to check,
|
||||
// but plugins can overwrite this method in case they want to check something related to content properties.
|
||||
return true;
|
||||
// Plugins can overwrite this method in case they want to check something related to content properties.
|
||||
global $USER;
|
||||
$context = \context::instance_by_id($this->get_contextid());
|
||||
|
||||
return $USER->id == $this->content->usercreated ||
|
||||
$this->get_visibility() == self::VISIBILITY_PUBLIC ||
|
||||
has_capability('moodle/contentbank:viewunlistedcontent', $context);
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +75,16 @@ abstract class contenttype {
|
||||
* @return content Object with content bank information.
|
||||
*/
|
||||
public function create_content(\stdClass $record = null): content {
|
||||
global $USER, $DB;
|
||||
global $USER, $DB, $CFG;
|
||||
|
||||
$entry = new \stdClass();
|
||||
if (isset($record->visibility)) {
|
||||
$entry->visibility = $record->visibility;
|
||||
} else {
|
||||
$usercreated = $record->usercreated ?? $USER->id;
|
||||
$entry->visibility = get_user_preferences('core_contentbank_visibility',
|
||||
$CFG->defaultpreference_core_contentbank_visibility, $usercreated);
|
||||
}
|
||||
$entry->contenttype = $this->get_contenttype_name();
|
||||
$entry->contextid = $this->context->id;
|
||||
$entry->name = $record->name ?? '';
|
||||
|
130
contentbank/classes/external/set_content_visibility.php
vendored
Normal file
130
contentbank/classes/external/set_content_visibility.php
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
<?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 core_contentbank\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
use external_api;
|
||||
use external_function_parameters;
|
||||
use external_single_structure;
|
||||
use external_value;
|
||||
use external_warnings;
|
||||
|
||||
/**
|
||||
* External API to set the visibility of content bank content.
|
||||
*
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 François Moreau
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_content_visibility extends external_api {
|
||||
/**
|
||||
* set_content_visibility parameters.
|
||||
*
|
||||
* @since Moodle 3.11
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters(
|
||||
[
|
||||
'contentid' => new external_value(PARAM_INT, 'The content id to rename', VALUE_REQUIRED),
|
||||
'visibility' => new external_value(PARAM_INT, 'The new visibility for the content', VALUE_REQUIRED),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility of a content from the contentbank.
|
||||
*
|
||||
* @since Moodle 3.11
|
||||
* @param int $contentid The content id to rename.
|
||||
* @param int $visibility The new visibility.
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(int $contentid, int $visibility): array {
|
||||
global $DB;
|
||||
|
||||
$result = false;
|
||||
$warnings = [];
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), [
|
||||
'contentid' => $contentid,
|
||||
'visibility' => $visibility,
|
||||
]);
|
||||
|
||||
try {
|
||||
$record = $DB->get_record('contentbank_content', ['id' => $params['contentid']], '*', MUST_EXIST);
|
||||
$contenttypeclass = "\\$record->contenttype\\contenttype";
|
||||
if (class_exists($contenttypeclass)) {
|
||||
$context = \context::instance_by_id($record->contextid, MUST_EXIST);
|
||||
self::validate_context($context);
|
||||
$contenttype = new $contenttypeclass($context);
|
||||
$contentclass = "\\$record->contenttype\\content";
|
||||
$content = new $contentclass($record);
|
||||
// Check capability.
|
||||
if ($contenttype->can_manage($content)) {
|
||||
// This content's visibility can be changed.
|
||||
if ($content->set_visibility($params['visibility'])) {
|
||||
$result = true;
|
||||
} else {
|
||||
$warnings[] = [
|
||||
'item' => $params['contentid'],
|
||||
'warningcode' => 'contentvisibilitynotset',
|
||||
'message' => get_string('contentvisibilitynotset', 'core_contentbank')
|
||||
];
|
||||
}
|
||||
|
||||
} else {
|
||||
// The user has no permission to manage this content.
|
||||
$warnings[] = [
|
||||
'item' => $params['contentid'],
|
||||
'warningcode' => 'nopermissiontomanage',
|
||||
'message' => get_string('nopermissiontomanage', 'core_contentbank')
|
||||
];
|
||||
}
|
||||
}
|
||||
} catch (\moodle_exception $e) {
|
||||
// The content or the context don't exist.
|
||||
$warnings[] = [
|
||||
'item' => $params['contentid'],
|
||||
'warningcode' => 'exception',
|
||||
'message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'result' => $result,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* set_content_visibility return.
|
||||
*
|
||||
* @since Moodle 3.11
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([
|
||||
'result' => new external_value(PARAM_BOOL, 'The processing result'),
|
||||
'warnings' => new external_warnings()
|
||||
]);
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use core_contentbank\content;
|
||||
|
||||
/**
|
||||
* Class containing data for bank content
|
||||
@ -85,7 +86,11 @@ class bankcontent implements renderable, templatable {
|
||||
$mimetype = $file ? get_mimetype_description($file) : '';
|
||||
$contenttypeclass = $content->get_content_type().'\\contenttype';
|
||||
$contenttype = new $contenttypeclass($this->context);
|
||||
$name = $content->get_name();
|
||||
if ($content->get_visibility() == content::VISIBILITY_UNLISTED) {
|
||||
$name = get_string('visibilitytitleunlisted', 'contentbank', $content->get_name());
|
||||
} else {
|
||||
$name = $content->get_name();
|
||||
}
|
||||
$author = \core_user::get_user($content->get_content()->usercreated);
|
||||
$contentdata[] = array(
|
||||
'name' => $name,
|
||||
@ -98,6 +103,7 @@ class bankcontent implements renderable, templatable {
|
||||
'size' => display_size($filesize),
|
||||
'type' => $mimetype,
|
||||
'author' => fullname($author),
|
||||
'visibilityunlisted' => $content->get_visibility() == content::VISIBILITY_UNLISTED
|
||||
);
|
||||
}
|
||||
$data->viewlist = get_user_preferences('core_contentbank_view_list');
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use \core_contentbank\content;
|
||||
|
||||
/**
|
||||
* Get the current user preferences that are available
|
||||
*
|
||||
@ -35,5 +37,10 @@ function core_contentbank_user_preferences() {
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => 'none'
|
||||
],
|
||||
'core_contentbank_visibility' => [
|
||||
'choices' => [content::VISIBILITY_UNLISTED, content::VISIBILITY_PUBLIC],
|
||||
'type' => PARAM_INT,
|
||||
'null' => NULL_NOT_ALLOWED
|
||||
]
|
||||
];
|
||||
}
|
||||
|
@ -29,7 +29,8 @@
|
||||
"type": "Archive (H5P)",
|
||||
"author": "Admin user",
|
||||
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
||||
"icon" : "http://something/theme/image.php/boost/core/1581597850/f/h5p-64"
|
||||
"icon" : "http://something/theme/image.php/boost/core/1581597850/f/h5p-64",
|
||||
"visibilityunlisted": true
|
||||
},
|
||||
{
|
||||
"name": "resume.pdf",
|
||||
@ -40,7 +41,8 @@
|
||||
"bytes": 716126,
|
||||
"type": "Archive (PDF)",
|
||||
"author": "Admin user",
|
||||
"icon": "http://something/theme/image.php/boost/core/1584597850/f/pdf-64"
|
||||
"icon": "http://something/theme/image.php/boost/core/1584597850/f/pdf-64",
|
||||
"visibilityunlisted": false
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
@ -155,7 +157,7 @@ data-region="contentbank">
|
||||
</div>
|
||||
</div>
|
||||
{{#contents}}
|
||||
<div class="cb-listitem"
|
||||
<div class="cb-listitem {{#visibilityunlisted}}cb-unlisted{{/visibilityunlisted}}"
|
||||
data-file="{{ title }}"
|
||||
data-name="{{ name }}"
|
||||
data-bytes="{{ bytes }}"
|
||||
|
@ -27,7 +27,5 @@
|
||||
{{$label}}{{#str}}
|
||||
searchcontentbankbyname, contentbank
|
||||
{{/str}}{{/label}}
|
||||
{{$placeholder}}{{#str}}
|
||||
search, core
|
||||
{{/str}}{{/placeholder}}
|
||||
{{$placeholder}}{{#str}} search, core {{/str}}{{/placeholder}}
|
||||
{{/ core/search_input_auto }}
|
||||
|
148
contentbank/tests/behat/visibility.feature
Normal file
148
contentbank/tests/behat/visibility.feature
Normal file
@ -0,0 +1,148 @@
|
||||
@core @core_contentbank @contentbank_h5p @javascript
|
||||
Feature: Make content public or unlisted
|
||||
In order to make content public or unlisted
|
||||
As a user
|
||||
I need to be able to access the edition options
|
||||
|
||||
Background:
|
||||
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 configure the "Navigation" block
|
||||
And I set the following fields to these values:
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
|
||||
Scenario: Users can make their content public or unlisted
|
||||
Given the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
|
||||
| System | | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 1 |
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "filltheblanks.h5p" "link"
|
||||
And I wait until the page is ready
|
||||
And I should not see "filltheblanks.h5p (Unlisted)" in the "h1" "css_element"
|
||||
And I open the action menu in "region-main-settings-menu" "region"
|
||||
And I should see "Make unlisted"
|
||||
When I choose "Make unlisted" in the open action menu
|
||||
And I wait until the page is ready
|
||||
Then I should see "filltheblanks.h5p (Unlisted)" in the "h1" "css_element"
|
||||
And I open the action menu in "region-main-settings-menu" "region"
|
||||
And I should see "Make public"
|
||||
|
||||
Scenario: Unlisted content cannot be seen by other users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| teacher2 | Teacher | 2 | teacher2@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teacher2 | C1 | editingteacher |
|
||||
And the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
|
||||
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
Then I should see "filltheblanks.h5p (Unlisted)"
|
||||
And I log out
|
||||
And I log in as "teacher2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
Then I should not see "filltheblanks.h5p"
|
||||
|
||||
Scenario: Unlisted content is not found through search by other users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| teacher2 | Teacher | 2 | teacher2@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teacher2 | C1 | editingteacher |
|
||||
And the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
|
||||
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I set the field "Search" to "filltheblanks.h5p"
|
||||
And I should see "filltheblanks.h5p"
|
||||
And I log out
|
||||
And I log in as "teacher2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
When I set the field "Search" to "filltheblanks.h5p"
|
||||
Then I should not see "filltheblanks.h5p"
|
||||
|
||||
Scenario: Managers can see other users' unlisted content
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| manager1 | Manager | 1 | manager1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| manager1 | C1 | manager |
|
||||
And the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
|
||||
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
|
||||
And I log out
|
||||
And I log in as "manager1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I should see "filltheblanks.h5p (Unlisted)"
|
||||
And I set the field "Search" to "filltheblanks.h5p"
|
||||
And I should see "filltheblanks.h5p (Unlisted)"
|
||||
|
||||
@_file_upload
|
||||
Scenario: Default content visibility can be set to unlisted
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And I set the following administration settings values:
|
||||
| Default content visibility | 2 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "Upload" "link"
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Upload content" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
Then I should see "filltheblanks.h5p (Unlisted)" in the "h1" "css_element"
|
||||
|
||||
@_file_upload
|
||||
Scenario: User preference concerning content visibility overrides site-wide default content visibility
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And I set the following administration settings values:
|
||||
| Default content visibility | 2 |
|
||||
And the following "user preferences" exist:
|
||||
| user | preference | value |
|
||||
| admin | core_contentbank_visibility | 1 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "Upload" "link"
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Upload content" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
Then I should see "filltheblanks.h5p" in the "h1" "css_element"
|
||||
And I should not see "filltheblanks.h5p (Unlisted)" in the "h1" "css_element"
|
@ -192,6 +192,35 @@ class core_contenttype_content_testcase extends \advanced_testcase {
|
||||
$this->assertEquals($newcontext->id, $file->get_contextid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for set_visibility behaviour
|
||||
*
|
||||
* @covers ::set_visibility
|
||||
*/
|
||||
public function test_set_visibility() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
$context = context_system::instance();
|
||||
$oldvisibility = content::VISIBILITY_PUBLIC;
|
||||
$newvisibility = content::VISIBILITY_UNLISTED;
|
||||
$illegalvisibility = -1;
|
||||
|
||||
$record = new stdClass();
|
||||
$record->visibility = $oldvisibility;
|
||||
$contenttype = new contenttype($context);
|
||||
$content = $contenttype->create_content($record);
|
||||
|
||||
$this->assertEquals($oldvisibility, $content->get_visibility());
|
||||
|
||||
$content->set_visibility($newvisibility);
|
||||
|
||||
$this->assertEquals($newvisibility, $content->get_visibility());
|
||||
|
||||
$content->set_visibility($illegalvisibility);
|
||||
|
||||
$this->assertEquals($newvisibility, $content->get_visibility());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for 'import_file' behaviour when replacing a file.
|
||||
*
|
||||
@ -299,6 +328,44 @@ class core_contenttype_content_testcase extends \advanced_testcase {
|
||||
$this->assertInstanceOf(get_class($type), $contenttype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for 'is_view_allowed'.
|
||||
*
|
||||
* @covers ::is_view_allowed
|
||||
*/
|
||||
public function test_is_view_allowed() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
$context = context_system::instance();
|
||||
|
||||
$userauthor = $this->getDataGenerator()->create_user();
|
||||
$userother = $this->getDataGenerator()->create_user();
|
||||
|
||||
$contenttype = new contenttype($context);
|
||||
|
||||
$unlistedrecord = new stdClass();
|
||||
$unlistedrecord->visibility = content::VISIBILITY_UNLISTED;
|
||||
$unlistedrecord->usercreated = $userauthor->id;
|
||||
$unlistedcontent = $contenttype->create_content($unlistedrecord);
|
||||
|
||||
$publicrecord = new stdClass();
|
||||
$publicrecord->visibility = content::VISIBILITY_PUBLIC;
|
||||
$publicrecord->usercreated = $userauthor->id;
|
||||
$publiccontent = $contenttype->create_content($publicrecord);
|
||||
|
||||
$this->setUser($userother);
|
||||
$this->assertFalse($unlistedcontent->is_view_allowed());
|
||||
$this->assertTrue($publiccontent->is_view_allowed());
|
||||
|
||||
$this->setUser($userauthor);
|
||||
$this->assertTrue($unlistedcontent->is_view_allowed());
|
||||
$this->assertTrue($publiccontent->is_view_allowed());
|
||||
|
||||
$this->setAdminUser();
|
||||
$this->assertTrue($unlistedcontent->is_view_allowed());
|
||||
$this->assertTrue($publiccontent->is_view_allowed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for 'get_uses' behaviour.
|
||||
*
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @copyright 2020 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_contentbank\content;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
@ -46,11 +49,12 @@ class core_contentbank_generator extends \component_generator_base {
|
||||
* @param bool $convert2class Whether the class should return stdClass or plugin instance.
|
||||
* @param string $filepath The filepath of the file associated to the content to create.
|
||||
* @param string $contentname The name of the content that will be created.
|
||||
* @param int $visibility The visibility of the content that will be created.
|
||||
* @return array An array with all the records added to the content bank.
|
||||
*/
|
||||
public function generate_contentbank_data(?string $contenttype, int $itemstocreate = 1, int $userid = 0,
|
||||
?\context $context = null, bool $convert2class = true, string $filepath = 'contentfile.h5p',
|
||||
string $contentname = 'Test content '): array {
|
||||
string $contentname = 'Test content ', int $visibility = content::VISIBILITY_PUBLIC): array {
|
||||
global $DB, $USER;
|
||||
|
||||
$records = [];
|
||||
@ -73,6 +77,7 @@ class core_contentbank_generator extends \component_generator_base {
|
||||
$record->name = ($itemstocreate === 1) ? $contentname : $contentname . $i;
|
||||
$record->configdata = '';
|
||||
$record->usercreated = $userid ?? $USER->id;
|
||||
$record->visibility = $visibility;
|
||||
|
||||
$content = $type->create_content($record);
|
||||
$record = $content->get_content();
|
||||
|
@ -3,3 +3,4 @@ information provided here is intended especially for developers.
|
||||
|
||||
=== 3.11 ===
|
||||
* Added "get_uses()" method to content class to return places where a content is used.
|
||||
* Added set_visibility()/get_visibility() methods to let users decide if their content should be listed in the content bank.
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_contentbank\content;
|
||||
|
||||
require('../config.php');
|
||||
|
||||
require_login();
|
||||
@ -50,22 +52,61 @@ if ($PAGE->course) {
|
||||
require_login($PAGE->course->id);
|
||||
}
|
||||
|
||||
$PAGE->set_url(new \moodle_url('/contentbank/view.php', ['id' => $id]));
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->navbar->add($record->name);
|
||||
$PAGE->set_heading($record->name);
|
||||
$title .= ": ".$record->name;
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_pagetype('contentbank');
|
||||
|
||||
$cb = new \core_contentbank\contentbank();
|
||||
$content = $cb->get_content_from_id($record->id);
|
||||
$contenttype = $content->get_content_type_instance();
|
||||
$pageheading = $record->name;
|
||||
|
||||
if (!$content->is_view_allowed()) {
|
||||
print_error('notavailable', 'contentbank');
|
||||
}
|
||||
|
||||
if ($content->get_visibility() == content::VISIBILITY_UNLISTED) {
|
||||
$pageheading = get_string('visibilitytitleunlisted', 'contentbank', $record->name);
|
||||
}
|
||||
|
||||
$PAGE->set_url(new \moodle_url('/contentbank/view.php', ['id' => $id]));
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->navbar->add($record->name);
|
||||
$PAGE->set_heading($pageheading);
|
||||
$title .= ": ".$record->name;
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_pagetype('contentbank');
|
||||
|
||||
// Create the cog menu with all the secondary actions, such as delete, rename...
|
||||
$actionmenu = new action_menu();
|
||||
$actionmenu->set_alignment(action_menu::TR, action_menu::BR);
|
||||
if ($contenttype->can_manage($content)) {
|
||||
// Add the visibility item to the menu.
|
||||
switch($content->get_visibility()) {
|
||||
case content::VISIBILITY_UNLISTED:
|
||||
$visibilitylabel = get_string('visibilitysetpublic', 'core_contentbank');
|
||||
$newvisibility = content::VISIBILITY_PUBLIC;
|
||||
$visibilityicon = 't/hide';
|
||||
break;
|
||||
case content::VISIBILITY_PUBLIC:
|
||||
$visibilitylabel = get_string('visibilitysetunlisted', 'core_contentbank');
|
||||
$newvisibility = content::VISIBILITY_UNLISTED;
|
||||
$visibilityicon = 't/show';
|
||||
break;
|
||||
default:
|
||||
print_error('contentvisibilitynotfound', 'error', $returnurl, $content->get_visibility());
|
||||
break;
|
||||
}
|
||||
|
||||
$attributes = [
|
||||
'data-action' => 'setcontentvisibility',
|
||||
'data-visibility' => $newvisibility,
|
||||
'data-contentid' => $content->get_id(),
|
||||
];
|
||||
$actionmenu->add_secondary_action(new action_menu_link(
|
||||
new moodle_url('#'),
|
||||
new pix_icon($visibilityicon, $visibilitylabel),
|
||||
$visibilitylabel,
|
||||
false,
|
||||
$attributes
|
||||
));
|
||||
|
||||
// Add the rename content item to the menu.
|
||||
$attributes = [
|
||||
'data-action' => 'renamecontent',
|
||||
@ -130,7 +171,22 @@ if ($errormsg !== '' && get_string_manager()->string_exists($errormsg, 'core_con
|
||||
$errormsg = get_string($errormsg, 'core_contentbank');
|
||||
echo $OUTPUT->notification($errormsg);
|
||||
} else if ($statusmsg !== '' && get_string_manager()->string_exists($statusmsg, 'core_contentbank')) {
|
||||
$statusmsg = get_string($statusmsg, 'core_contentbank');
|
||||
if ($statusmsg == 'contentvisibilitychanged') {
|
||||
switch ($content->get_visibility()) {
|
||||
case content::VISIBILITY_PUBLIC:
|
||||
$visibilitymsg = get_string('public', 'core_contentbank');
|
||||
break;
|
||||
case content::VISIBILITY_UNLISTED:
|
||||
$visibilitymsg = get_string('unlisted', 'core_contentbank');
|
||||
break;
|
||||
default:
|
||||
print_error('contentvisibilitynotfound', 'error', $returnurl, $content->get_visibility());
|
||||
break;
|
||||
}
|
||||
$statusmsg = get_string($statusmsg, 'core_contentbank', $visibilitymsg);
|
||||
} else {
|
||||
$statusmsg = get_string($statusmsg, 'core_contentbank');
|
||||
}
|
||||
echo $OUTPUT->notification($statusmsg, 'notifysuccess');
|
||||
}
|
||||
if ($contenttype->can_access()) {
|
||||
|
@ -25,6 +25,7 @@
|
||||
$string['author'] = 'Author';
|
||||
$string['contentbank'] = 'Content bank';
|
||||
$string['close'] = 'Close';
|
||||
$string['contentbankpreferences'] = 'Content bank preferences';
|
||||
$string['contentdeleted'] = 'The content has been deleted.';
|
||||
$string['contentname'] = 'Content name';
|
||||
$string['contentnotdeleted'] = 'An error was encountered while trying to delete the content.';
|
||||
@ -33,6 +34,8 @@ $string['contentrenamed'] = 'The content has been renamed.';
|
||||
$string['contentsmoved'] = 'Content bank contents moved to {$a}.';
|
||||
$string['contenttypenoaccess'] = 'You cannot view this {$a} instance.';
|
||||
$string['contenttypenoedit'] = 'You can not edit this content';
|
||||
$string['contentvisibilitychanged'] = 'The content has been made {$a}.';
|
||||
$string['contentvisibilitynotset'] = 'An error was encountered while trying to set the content visibility.';
|
||||
$string['contextnotallowed'] = 'You are not allowed to access the content bank in this context.';
|
||||
$string['emptynamenotallowed'] = 'Empty name is not allowed';
|
||||
$string['eventcontentcreated'] = 'Content created';
|
||||
@ -55,6 +58,7 @@ $string['lastmodified'] = 'Last modified';
|
||||
$string['name'] = 'Content';
|
||||
$string['nocontentavailable'] = 'No content available';
|
||||
$string['nocontenttypes'] = 'No content types available';
|
||||
$string['notavailable'] = 'Sorry, this content is not available.';
|
||||
$string['nopermissiontodelete'] = 'You do not have permission to delete content.';
|
||||
$string['nopermissiontomanage'] = 'You do not have permission to manage content.';
|
||||
$string['privacy:metadata:content:contenttype'] = 'The contenttype plugin of the content in the content bank.';
|
||||
@ -76,3 +80,12 @@ $string['type'] = 'Type';
|
||||
$string['unsupported'] = 'This content type is not supported.';
|
||||
$string['upload'] = 'Upload';
|
||||
$string['uses'] = 'Places linked';
|
||||
$string['visibilitychoicepublic'] = 'Public';
|
||||
$string['visibilitychoiceunlisted'] = 'Unlisted';
|
||||
$string['public'] = 'public';
|
||||
$string['unlisted'] = 'unlisted';
|
||||
$string['visibilitypref'] = 'Default content visibility';
|
||||
$string['visibilitypref_help'] = 'Content you create in the content bank will use this visibility setting by default.';
|
||||
$string['visibilitysetpublic'] = 'Make public';
|
||||
$string['visibilitysetunlisted'] = 'Make unlisted';
|
||||
$string['visibilitytitleunlisted'] = '{$a} (Unlisted)';
|
||||
|
@ -182,6 +182,7 @@ $string['componentisuptodate'] = 'Component is up-to-date';
|
||||
$string['confirmationnotenabled'] = 'User confirmation is not enabled on this site';
|
||||
$string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirmed to carry out this action. This security feature prevents against accidental or malicious execution of important functions in your name. Please make sure you really wanted to execute this function.';
|
||||
$string['contenttypenotfound'] = 'The \'{$a}\' content bank type doesn\'t exist or is not recognised.';
|
||||
$string['contentvisibilitynotfound'] = 'The content visibility with value \'{$a}\' doesn\'t exist or is not recognised.';
|
||||
$string['couldnotassignrole'] = 'A serious but unspecified error occurred while trying to assign a role to you';
|
||||
$string['couldnotupdatenoexistinguser'] = 'Cannot update the user - user doesn\'t exist';
|
||||
$string['couldnotverifyagedigitalconsent'] = 'An error occurred while trying to verify the age of digital consent.<br />Please contact administrator.';
|
||||
|
@ -156,6 +156,7 @@ $string['contentbank:deleteowncontent'] = 'Delete content from own content bank'
|
||||
$string['contentbank:downloadcontent'] = 'Download content from the content bank';
|
||||
$string['contentbank:manageanycontent'] = 'Manage any content from the content bank';
|
||||
$string['contentbank:manageowncontent'] = 'Manage content from own content bank';
|
||||
$string['contentbank:viewunlistedcontent'] = 'View unlisted content from the content bank';
|
||||
$string['contentbank:upload'] = 'Upload new content to the content bank';
|
||||
$string['contentbank:useeditor'] = 'Create or edit content using a content type editor';
|
||||
$string['context'] = 'Context';
|
||||
|
@ -925,6 +925,9 @@ class behat_core_generator extends behat_generator_base {
|
||||
$record = new stdClass();
|
||||
$record->usercreated = $data['userid'];
|
||||
$record->name = $data['contentname'];
|
||||
if (isset($data['visibility'])) {
|
||||
$record->visibility = $data['visibility'];
|
||||
}
|
||||
$content = $contenttype->create_content($record);
|
||||
|
||||
if (!empty($data['filepath'])) {
|
||||
|
@ -2614,4 +2614,14 @@ $capabilities = array(
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [],
|
||||
],
|
||||
|
||||
// Allow users to view hidden content.
|
||||
'moodle/contentbank:viewunlistedcontent' => [
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [
|
||||
'manager' => CAP_ALLOW,
|
||||
'coursecreator' => CAP_ALLOW,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
@ -4271,6 +4271,7 @@
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="contenttype" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="References context.id."/>
|
||||
<FIELD NAME="visibility" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
|
||||
<FIELD NAME="instanceid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="configdata" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="usercreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The original author of the content"/>
|
||||
|
@ -2728,6 +2728,15 @@ $functions = array(
|
||||
'ajax' => 'true',
|
||||
'capabilities' => 'moodle/contentbank:manageowncontent',
|
||||
],
|
||||
'core_contentbank_set_content_visibility' => [
|
||||
'classname' => 'core_contentbank\external\set_content_visibility',
|
||||
'methodname' => 'execute',
|
||||
'classpath' => '',
|
||||
'description' => 'Set the visibility of a content in the content bank.',
|
||||
'type' => 'write',
|
||||
'ajax' => 'true',
|
||||
'capabilities' => 'moodle/contentbank:manageowncontent',
|
||||
],
|
||||
'core_create_userfeedback_action_record' => [
|
||||
'classname' => 'core\external\record_userfeedback_action',
|
||||
'methodname' => 'execute',
|
||||
|
@ -2393,5 +2393,19 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2021052500.55);
|
||||
}
|
||||
|
||||
if ($oldversion < 2021052500.59) {
|
||||
// Define field visibility to be added to contentbank_content.
|
||||
$table = new xmldb_table('contentbank_content');
|
||||
$field = new xmldb_field('visibility', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'contextid');
|
||||
|
||||
// Conditionally launch add field visibility.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2021052500.59);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -5104,12 +5104,22 @@ class settings_navigation extends navigation_node {
|
||||
}
|
||||
}
|
||||
|
||||
// Add "Content bank preferences" link.
|
||||
if (isloggedin() && !isguestuser($user)) {
|
||||
if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) ||
|
||||
has_capability('moodle/user:editprofile', $usercontext)) {
|
||||
$url = new moodle_url('/user/contentbank.php', ['id' => $user->id]);
|
||||
$useraccount->add(get_string('contentbankpreferences', 'core_contentbank'), $url, self::TYPE_SETTING,
|
||||
null, 'contentbankpreferences');
|
||||
}
|
||||
}
|
||||
|
||||
// View the roles settings.
|
||||
if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override',
|
||||
'moodle/role:manage'), $usercontext)) {
|
||||
if (has_any_capability(['moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override',
|
||||
'moodle/role:manage'], $usercontext)) {
|
||||
$roles = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING);
|
||||
|
||||
$url = new moodle_url('/admin/roles/usersroles.php', array('userid'=>$user->id, 'courseid'=>$course->id));
|
||||
$url = new moodle_url('/admin/roles/usersroles.php', ['userid' => $user->id, 'courseid' => $course->id]);
|
||||
$roles->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING);
|
||||
|
||||
$assignableroles = get_assignable_roles($usercontext, ROLENAME_BOTH);
|
||||
|
@ -18,6 +18,10 @@
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.cb-listitem.cb-unlisted {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.cb-listitem {
|
||||
flex-basis: 50%;
|
||||
@ -44,6 +48,24 @@
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.cb-unlisted .cb-thumbnail {
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
/* Display a centered eye slash on top of unlisted content icons. */
|
||||
.cb-unlisted::after {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
content: $fa-var-eye-slash;
|
||||
font-family: FontAwesome;
|
||||
font-size: 26px;
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.cb-heading,
|
||||
.cb-uses,
|
||||
.cb-date,
|
||||
@ -82,6 +104,15 @@
|
||||
border-right: $border-width solid $border-color;
|
||||
}
|
||||
|
||||
.cb-listitem.cb-unlisted .cb-thumbnail {
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
.cb-listitem.cb-unlisted .cb-column,
|
||||
.cb-listitem.cb-unlisted .cb-column a {
|
||||
color: $text-muted;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.cb-column {
|
||||
flex: 0 0 50%;
|
||||
|
@ -13109,38 +13109,48 @@ table.calendartable caption {
|
||||
background-position: center;
|
||||
background-size: cover; }
|
||||
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
margin-bottom: 0.5rem; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-grid {
|
||||
/* Display a centered eye slash on top of unlisted content icons. */ }
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
flex-basis: 50%; } }
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
max-width: 120px;
|
||||
min-width: 120px; } }
|
||||
|
||||
.content-bank-container.view-grid .cb-name {
|
||||
text-align: center; }
|
||||
|
||||
.content-bank-container.view-grid .cb-file {
|
||||
padding: 0.5rem; }
|
||||
|
||||
.content-bank-container.view-grid .cb-thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5rem; }
|
||||
|
||||
.content-bank-container.view-grid .cb-heading,
|
||||
.content-bank-container.view-grid .cb-uses,
|
||||
.content-bank-container.view-grid .cb-date,
|
||||
.content-bank-container.view-grid .cb-size,
|
||||
.content-bank-container.view-grid .cb-type,
|
||||
.content-bank-container.view-grid .cb-author {
|
||||
display: none; }
|
||||
margin-bottom: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-listitem.cb-unlisted {
|
||||
position: relative; }
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
flex-basis: 50%; } }
|
||||
@media (min-width: 576px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
max-width: 120px;
|
||||
min-width: 120px; } }
|
||||
.content-bank-container.view-grid .cb-name {
|
||||
text-align: center; }
|
||||
.content-bank-container.view-grid .cb-file {
|
||||
padding: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-unlisted .cb-thumbnail {
|
||||
opacity: .3; }
|
||||
.content-bank-container.view-grid .cb-unlisted::after {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
content: "";
|
||||
font-family: FontAwesome;
|
||||
font-size: 26px;
|
||||
text-align: center;
|
||||
opacity: 0.8; }
|
||||
.content-bank-container.view-grid .cb-heading,
|
||||
.content-bank-container.view-grid .cb-uses,
|
||||
.content-bank-container.view-grid .cb-date,
|
||||
.content-bank-container.view-grid .cb-size,
|
||||
.content-bank-container.view-grid .cb-type,
|
||||
.content-bank-container.view-grid .cb-author {
|
||||
display: none; }
|
||||
|
||||
.content-bank-container.view-list .cb-content-wrapper {
|
||||
padding: 0 0.5rem;
|
||||
@ -13164,6 +13174,13 @@ table.calendartable caption {
|
||||
.content-bank-container.view-list .cb-column {
|
||||
border-right: 1px solid #dee2e6; }
|
||||
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-thumbnail {
|
||||
opacity: .3; }
|
||||
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-column,
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-column a {
|
||||
color: #6c757d; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-list .cb-column {
|
||||
flex: 0 0 50%;
|
||||
|
@ -13323,38 +13323,48 @@ table.calendartable caption {
|
||||
background-position: center;
|
||||
background-size: cover; }
|
||||
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
margin-bottom: 0.5rem; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-grid {
|
||||
/* Display a centered eye slash on top of unlisted content icons. */ }
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
flex-basis: 50%; } }
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
max-width: 120px;
|
||||
min-width: 120px; } }
|
||||
|
||||
.content-bank-container.view-grid .cb-name {
|
||||
text-align: center; }
|
||||
|
||||
.content-bank-container.view-grid .cb-file {
|
||||
padding: 0.5rem; }
|
||||
|
||||
.content-bank-container.view-grid .cb-thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5rem; }
|
||||
|
||||
.content-bank-container.view-grid .cb-heading,
|
||||
.content-bank-container.view-grid .cb-uses,
|
||||
.content-bank-container.view-grid .cb-date,
|
||||
.content-bank-container.view-grid .cb-size,
|
||||
.content-bank-container.view-grid .cb-type,
|
||||
.content-bank-container.view-grid .cb-author {
|
||||
display: none; }
|
||||
margin-bottom: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-listitem.cb-unlisted {
|
||||
position: relative; }
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
flex-basis: 50%; } }
|
||||
@media (min-width: 576px) {
|
||||
.content-bank-container.view-grid .cb-listitem {
|
||||
max-width: 120px;
|
||||
min-width: 120px; } }
|
||||
.content-bank-container.view-grid .cb-name {
|
||||
text-align: center; }
|
||||
.content-bank-container.view-grid .cb-file {
|
||||
padding: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5rem; }
|
||||
.content-bank-container.view-grid .cb-unlisted .cb-thumbnail {
|
||||
opacity: .3; }
|
||||
.content-bank-container.view-grid .cb-unlisted::after {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
content: "";
|
||||
font-family: FontAwesome;
|
||||
font-size: 26px;
|
||||
text-align: center;
|
||||
opacity: 0.8; }
|
||||
.content-bank-container.view-grid .cb-heading,
|
||||
.content-bank-container.view-grid .cb-uses,
|
||||
.content-bank-container.view-grid .cb-date,
|
||||
.content-bank-container.view-grid .cb-size,
|
||||
.content-bank-container.view-grid .cb-type,
|
||||
.content-bank-container.view-grid .cb-author {
|
||||
display: none; }
|
||||
|
||||
.content-bank-container.view-list .cb-content-wrapper {
|
||||
padding: 0 0.5rem;
|
||||
@ -13378,6 +13388,13 @@ table.calendartable caption {
|
||||
.content-bank-container.view-list .cb-column {
|
||||
border-right: 1px solid #dee2e6; }
|
||||
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-thumbnail {
|
||||
opacity: .3; }
|
||||
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-column,
|
||||
.content-bank-container.view-list .cb-listitem.cb-unlisted .cb-column a {
|
||||
color: #6c757d; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.content-bank-container.view-list .cb-column {
|
||||
flex: 0 0 50%;
|
||||
|
53
user/classes/form/contentbank_user_preferences_form.php
Normal file
53
user/classes/form/contentbank_user_preferences_form.php
Normal file
@ -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/>.
|
||||
|
||||
namespace core_user\form;
|
||||
|
||||
use \core_contentbank\content;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->dirroot.'/lib/formslib.php');
|
||||
|
||||
/**
|
||||
* Form to edit a user's preferences concerning the content bank.
|
||||
*
|
||||
* @package core_user
|
||||
* @copyright 2020 François Moreau
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class contentbank_user_preferences_form extends \moodleform {
|
||||
|
||||
/**
|
||||
* Define the form.
|
||||
*/
|
||||
public function definition () {
|
||||
global $CFG, $USER;
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
$options = [
|
||||
content::VISIBILITY_PUBLIC => get_string('visibilitychoicepublic', 'core_contentbank'),
|
||||
content::VISIBILITY_UNLISTED => get_string('visibilitychoiceunlisted', 'core_contentbank')
|
||||
];
|
||||
$mform->addElement('select', 'contentvisibility', get_string('visibilitypref', 'core_contentbank'), $options);
|
||||
$mform->addHelpButton('contentvisibility', 'visibilitypref', 'core_contentbank');
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
}
|
||||
}
|
71
user/contentbank.php
Normal file
71
user/contentbank.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Allows you to edit a users profile
|
||||
*
|
||||
* @copyright 2020 François Moreau
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package core_user
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/user/editlib.php');
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
|
||||
require_login();
|
||||
|
||||
$userid = optional_param('id', $USER->id, PARAM_INT); // User id.
|
||||
|
||||
$PAGE->set_url('/user/contentbank.php', ['id' => $userid]);
|
||||
|
||||
list($user, $course) = useredit_setup_preference_page($userid, SITEID);
|
||||
|
||||
$form = new \core_user\form\contentbank_user_preferences_form(null, ['userid' => $user->id]);
|
||||
|
||||
$user->contentvisibility = get_user_preferences('core_contentbank_visibility',
|
||||
$CFG->defaultpreference_core_contentbank_visibility, $user->id);
|
||||
|
||||
$form->set_data($user);
|
||||
|
||||
$redirect = new moodle_url("/user/preferences.php", ['userid' => $user->id]);
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect($redirect);
|
||||
} else if ($data = $form->get_data()) {
|
||||
$data = $form->get_data();
|
||||
$usernew = [
|
||||
'id' => $user->id,
|
||||
'preference_core_contentbank_visibility' => $data->contentvisibility
|
||||
];
|
||||
useredit_update_user_preference($usernew);
|
||||
|
||||
\core\event\user_updated::create_from_userid($user->id)->trigger();
|
||||
redirect($redirect);
|
||||
}
|
||||
|
||||
$title = get_string('contentbankpreferences', 'core_contentbank');
|
||||
$userfullname = fullname($user, true);
|
||||
|
||||
$PAGE->navbar->includesettingsbase = true;
|
||||
|
||||
$PAGE->set_title("$course->shortname: $title");
|
||||
$PAGE->set_heading($userfullname);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($title);
|
||||
$form->display();
|
||||
echo $OUTPUT->footer();
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2021052500.58; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2021052500.59; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.0dev (Build: 20210211)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user