mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
MDL-67810 core_contentbank: added dropdown menu to create content
This commit is contained in:
parent
68fd8d8bdf
commit
75f58cbfa2
16 changed files with 437 additions and 14 deletions
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
namespace core_contentbank;
|
namespace core_contentbank;
|
||||||
|
|
||||||
|
use core_plugin_manager;
|
||||||
use stored_file;
|
use stored_file;
|
||||||
use context;
|
use context;
|
||||||
|
|
||||||
|
@ -35,6 +36,8 @@ use context;
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
*/
|
*/
|
||||||
class contentbank {
|
class contentbank {
|
||||||
|
/** @var array Enabled content types. */
|
||||||
|
private $enabledcontenttypes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the list of core_contentbank_content objects currently active.
|
* Obtains the list of core_contentbank_content objects currently active.
|
||||||
|
@ -44,16 +47,20 @@ class contentbank {
|
||||||
* @return string[] Array of contentbank contenttypes.
|
* @return string[] Array of contentbank contenttypes.
|
||||||
*/
|
*/
|
||||||
public function get_enabled_content_types(): array {
|
public function get_enabled_content_types(): array {
|
||||||
|
if (!is_null($this->enabledcontenttypes)) {
|
||||||
|
return $this->enabledcontenttypes;
|
||||||
|
}
|
||||||
|
|
||||||
$enabledtypes = \core\plugininfo\contenttype::get_enabled_plugins();
|
$enabledtypes = \core\plugininfo\contenttype::get_enabled_plugins();
|
||||||
$types = [];
|
$types = [];
|
||||||
foreach ($enabledtypes as $name) {
|
foreach ($enabledtypes as $name) {
|
||||||
$contenttypeclassname = "\\contenttype_$name\\contenttype";
|
$contenttypeclassname = "\\contenttype_$name\\contenttype";
|
||||||
$contentclassname = "\\contenttype_$name\\content";
|
$contentclassname = "\\contenttype_$name\\content";
|
||||||
if (class_exists($contenttypeclassname) && class_exists($contentclassname)) {
|
if (class_exists($contenttypeclassname) && class_exists($contentclassname)) {
|
||||||
$types[] = $name;
|
$types[$contenttypeclassname] = $name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $types;
|
return $this->enabledcontenttypes = $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,4 +299,37 @@ class contentbank {
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of content types that have the requested feature.
|
||||||
|
*
|
||||||
|
* @param string $feature Feature code e.g CAN_UPLOAD.
|
||||||
|
* @param null|\context $context Optional context to check the permission to use the feature.
|
||||||
|
* @param bool $enabled Whether check only the enabled content types or all of them.
|
||||||
|
*
|
||||||
|
* @return string[] List of content types where the user has permission to access the feature.
|
||||||
|
*/
|
||||||
|
public function get_contenttypes_with_capability_feature(string $feature, \context $context = null, bool $enabled = true): array {
|
||||||
|
$contenttypes = [];
|
||||||
|
// Check enabled content types or all of them.
|
||||||
|
if ($enabled) {
|
||||||
|
$contenttypestocheck = $this->get_enabled_content_types();
|
||||||
|
} else {
|
||||||
|
$plugins = core_plugin_manager::instance()->get_plugins_of_type('contenttype');
|
||||||
|
foreach ($plugins as $plugin) {
|
||||||
|
$contenttypeclassname = "\\{$plugin->type}_{$plugin->name}\\contenttype";
|
||||||
|
$contenttypestocheck[$contenttypeclassname] = $plugin->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($contenttypestocheck as $classname => $name) {
|
||||||
|
$contenttype = new $classname($context);
|
||||||
|
// The method names that check the features permissions must follow the pattern can_feature.
|
||||||
|
if ($contenttype->{"can_$feature"}()) {
|
||||||
|
$contenttypes[$classname] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contenttypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,10 @@ abstract class contenttype {
|
||||||
/** Plugin implements uploading feature */
|
/** Plugin implements uploading feature */
|
||||||
const CAN_UPLOAD = 'upload';
|
const CAN_UPLOAD = 'upload';
|
||||||
|
|
||||||
/** @var context This contenttype's context. **/
|
/** Plugin implements edition feature */
|
||||||
|
const CAN_EDIT = 'edit';
|
||||||
|
|
||||||
|
/** @var \context This contenttype's context. **/
|
||||||
protected $context = null;
|
protected $context = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,7 +62,7 @@ abstract class contenttype {
|
||||||
/**
|
/**
|
||||||
* Fills content_bank table with appropiate information.
|
* Fills content_bank table with appropiate information.
|
||||||
*
|
*
|
||||||
* @param stdClass $record An optional content record compatible object (default null)
|
* @param \stdClass $record An optional content record compatible object (default null)
|
||||||
* @return content Object with content bank information.
|
* @return content Object with content bank information.
|
||||||
*/
|
*/
|
||||||
public function create_content(\stdClass $record = null): ?content {
|
public function create_content(\stdClass $record = null): ?content {
|
||||||
|
@ -127,7 +130,7 @@ abstract class contenttype {
|
||||||
* This method can be overwritten by the plugins if they need to change some other specific information.
|
* This method can be overwritten by the plugins if they need to change some other specific information.
|
||||||
*
|
*
|
||||||
* @param content $content The content to rename.
|
* @param content $content The content to rename.
|
||||||
* @param string $name The name of the content.
|
* @param string $name The name of the content.
|
||||||
* @return boolean true if the content has been renamed; false otherwise.
|
* @return boolean true if the content has been renamed; false otherwise.
|
||||||
*/
|
*/
|
||||||
public function rename_content(content $content, string $name): bool {
|
public function rename_content(content $content, string $name): bool {
|
||||||
|
@ -139,7 +142,7 @@ abstract class contenttype {
|
||||||
* This method can be overwritten by the plugins if they need to change some other specific information.
|
* This method can be overwritten by the plugins if they need to change some other specific information.
|
||||||
*
|
*
|
||||||
* @param content $content The content to rename.
|
* @param content $content The content to rename.
|
||||||
* @param context $context The new context.
|
* @param \context $context The new context.
|
||||||
* @return boolean true if the content has been renamed; false otherwise.
|
* @return boolean true if the content has been renamed; false otherwise.
|
||||||
*/
|
*/
|
||||||
public function move_content(content $content, \context $context): bool {
|
public function move_content(content $content, \context $context): bool {
|
||||||
|
@ -325,6 +328,37 @@ abstract class contenttype {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the user has permission to use the editor.
|
||||||
|
*
|
||||||
|
* @return bool True if the user can edit content. False otherwise.
|
||||||
|
*/
|
||||||
|
final public function can_edit(): bool {
|
||||||
|
if (!$this->is_feature_supported(self::CAN_EDIT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->can_access()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classname = 'contenttype/'.$this->get_plugin_name();
|
||||||
|
|
||||||
|
$editioncap = $classname.':useeditor';
|
||||||
|
$hascapabilities = has_all_capabilities(['moodle/contentbank:useeditor', $editioncap], $this->context);
|
||||||
|
return $hascapabilities && $this->is_edit_allowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns plugin allows edition.
|
||||||
|
*
|
||||||
|
* @return bool True if plugin allows edition. False otherwise.
|
||||||
|
*/
|
||||||
|
protected function is_edit_allowed(): bool {
|
||||||
|
// Plugins can overwrite this function to add any check they need.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin supports the feature.
|
* Returns the plugin supports the feature.
|
||||||
*
|
*
|
||||||
|
@ -348,4 +382,17 @@ abstract class contenttype {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function get_manageable_extensions(): array;
|
abstract public function get_manageable_extensions(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of different types of the given content type.
|
||||||
|
*
|
||||||
|
* A content type can have one or more options for creating content. This method will report all of them or only the content
|
||||||
|
* type itself if it has no other options.
|
||||||
|
*
|
||||||
|
* @return array An object for each type:
|
||||||
|
* - string typename: descriptive name of the type.
|
||||||
|
* - string typeeditorparams: params required by this content type editor.
|
||||||
|
* - url typeicon: this type icon.
|
||||||
|
*/
|
||||||
|
abstract public function get_contenttype_types(): array;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,56 @@ class bankcontent implements renderable, templatable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$data->contents = $contentdata;
|
$data->contents = $contentdata;
|
||||||
$data->tools = $this->toolbar;
|
// The tools are displayed in the action bar on the index page.
|
||||||
|
foreach ($this->toolbar as $tool) {
|
||||||
|
// Customize the output of a tool, like dropdowns.
|
||||||
|
$method = 'export_tool_'.$tool['name'];
|
||||||
|
if (method_exists($this, $method)) {
|
||||||
|
$this->$method($tool);
|
||||||
|
}
|
||||||
|
$data->tools[] = $tool;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the content type items to display to the Add dropdown.
|
||||||
|
*
|
||||||
|
* Each content type is represented as an object with the properties:
|
||||||
|
* - name: the name of the content type.
|
||||||
|
* - baseurl: the base content type editor URL.
|
||||||
|
* - types: different types of the content type to display as dropdown items.
|
||||||
|
*
|
||||||
|
* @param array $tool Data for rendering the Add dropdown, including the editable content types.
|
||||||
|
*/
|
||||||
|
private function export_tool_add(array &$tool) {
|
||||||
|
$editabletypes = $tool['contenttypes'];
|
||||||
|
|
||||||
|
$addoptions = [];
|
||||||
|
foreach ($editabletypes as $class => $type) {
|
||||||
|
$contentype = new $class($this->context);
|
||||||
|
// Get the creation options of each content type.
|
||||||
|
$types = $contentype->get_contenttype_types();
|
||||||
|
if ($types) {
|
||||||
|
// Add a text describing the content type as first option. This will be displayed in the drop down to
|
||||||
|
// separate the options for the different content types.
|
||||||
|
$contentdesc = new stdClass();
|
||||||
|
$contentdesc->typename = get_string('description', $contentype->get_contenttype_name());
|
||||||
|
array_unshift($types, $contentdesc);
|
||||||
|
// Context data for the template.
|
||||||
|
$addcontenttype = new stdClass();
|
||||||
|
// Content type name.
|
||||||
|
$addcontenttype->name = $type;
|
||||||
|
// Content type editor base URL.
|
||||||
|
$tool['link']->param('plugin', $type);
|
||||||
|
$addcontenttype->baseurl = $tool['link']->out();
|
||||||
|
// Different types of the content type.
|
||||||
|
$addcontenttype->types = $types;
|
||||||
|
$addoptions[] = $addcontenttype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$tool['contenttypes'] = $addoptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,19 @@ $foldercontents = $cb->search_contents($search, $contextid, $contenttypes);
|
||||||
|
|
||||||
// Get the toolbar ready.
|
// Get the toolbar ready.
|
||||||
$toolbar = array ();
|
$toolbar = array ();
|
||||||
|
|
||||||
|
// Place the Add button in the toolbar.
|
||||||
|
if (has_capability('moodle/contentbank:useeditor', $context)) {
|
||||||
|
// Get the content types for which the user can use an editor.
|
||||||
|
$editabletypes = $cb->get_contenttypes_with_capability_feature(\core_contentbank\contenttype::CAN_EDIT, $context);
|
||||||
|
if (!empty($editabletypes)) {
|
||||||
|
// Editor base URL.
|
||||||
|
$editbaseurl = new moodle_url('/contentbank/edit.php', ['contextid' => $contextid]);
|
||||||
|
$toolbar[] = ['name' => get_string('add'), 'link' => $editbaseurl, 'dropdown' => true, 'contenttypes' => $editabletypes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the Upload button in the toolbar.
|
||||||
if (has_capability('moodle/contentbank:upload', $context)) {
|
if (has_capability('moodle/contentbank:upload', $context)) {
|
||||||
// Don' show upload button if there's no plugin to support any file extension.
|
// Don' show upload button if there's no plugin to support any file extension.
|
||||||
$accepted = $cb->get_supported_extensions_as_string($context);
|
$accepted = $cb->get_supported_extensions_as_string($context);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
}}
|
}}
|
||||||
{{!
|
{{!
|
||||||
@template core_contentbank/list
|
@template core_contentbank/bankcontent
|
||||||
|
|
||||||
Example context (json):
|
Example context (json):
|
||||||
{
|
{
|
||||||
|
@ -32,10 +32,36 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "resume.pdf",
|
"name": "resume.pdf",
|
||||||
|
"title": "resume",
|
||||||
|
"timemodified": 1589792039,
|
||||||
|
"size": "699.3KB",
|
||||||
|
"bytes": 716126,
|
||||||
|
"type": "Archive (PDF)",
|
||||||
"icon": "http://something/theme/image.php/boost/core/1584597850/f/pdf-64"
|
"icon": "http://something/theme/image.php/boost/core/1584597850/f/pdf-64"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tools": [
|
"tools": [
|
||||||
|
{
|
||||||
|
"name": "Add",
|
||||||
|
"dropdown": true,
|
||||||
|
"link": "http://something/contentbank/edit.php?contextid=1",
|
||||||
|
"contenttypes": [
|
||||||
|
{
|
||||||
|
"name": "H5P Interactive Content",
|
||||||
|
"baseurl": "http://something/contentbank/edit.php?contextid=1&plugin=h5p",
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"typename": "H5P Interactive Content"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"typename": "Accordion",
|
||||||
|
"typeeditorparams": "library=Accordion-1.4",
|
||||||
|
"typeicon": "http://something/pluginfile.php/1/core_h5p/libraries/13/H5P.Accordion-1.4/icon.svg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Upload",
|
"name": "Upload",
|
||||||
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
||||||
|
|
|
@ -20,6 +20,27 @@
|
||||||
Example context (json):
|
Example context (json):
|
||||||
{
|
{
|
||||||
"tools": [
|
"tools": [
|
||||||
|
{
|
||||||
|
"name": "Add",
|
||||||
|
"dropdown": true,
|
||||||
|
"link": "http://something/contentbank/edit.php?contextid=1",
|
||||||
|
"contenttypes": [
|
||||||
|
{
|
||||||
|
"name": "h5p",
|
||||||
|
"baseurl": "http://something/contentbank/edit.php?contextid=1&plugin=h5p",
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"typename": "H5P Interactive Content"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"typename": "Accordion",
|
||||||
|
"typeeditorparams": "library=Accordion-1.4",
|
||||||
|
"typeicon": "http://something/pluginfile.php/1/core_h5p/libraries/13/H5P.Accordion-1.4/icon.svg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Upload",
|
"name": "Upload",
|
||||||
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
||||||
|
@ -34,9 +55,14 @@
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{#tools}}
|
{{#tools}}
|
||||||
<a href="{{{ link }}}" class="icon-no-margin btn btn-secondary" title="{{{ name }}}">
|
{{#dropdown}}
|
||||||
{{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
|
{{>core_contentbank/bankcontent/toolbar_dropdown}}
|
||||||
</a>
|
{{/dropdown}}
|
||||||
|
{{^dropdown}}
|
||||||
|
<a href="{{{ link }}}" class="icon-no-margin btn btn-secondary" title="{{{ name }}}">
|
||||||
|
{{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
|
||||||
|
</a>
|
||||||
|
{{/dropdown}}
|
||||||
{{/tools}}
|
{{/tools}}
|
||||||
<button class="icon-no-margin btn btn-secondary active ml-2"
|
<button class="icon-no-margin btn btn-secondary active ml-2"
|
||||||
title="{{#str}} displayicons, contentbank {{/str}}"
|
title="{{#str}} displayicons, contentbank {{/str}}"
|
||||||
|
@ -47,4 +73,4 @@ data-action="viewgrid">
|
||||||
title="{{#str}} displaydetails, contentbank {{/str}}"
|
title="{{#str}} displaydetails, contentbank {{/str}}"
|
||||||
data-action="viewlist">
|
data-action="viewlist">
|
||||||
{{#pix}}t/viewdetails, core, {{#str}} displaydetails, contentbank {{/str}} {{/pix}}
|
{{#pix}}t/viewdetails, core, {{#str}} displaydetails, contentbank {{/str}} {{/pix}}
|
||||||
</button>
|
</button>
|
||||||
|
|
64
contentbank/templates/bankcontent/toolbar_dropdown.mustache
Normal file
64
contentbank/templates/bankcontent/toolbar_dropdown.mustache
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
{{!
|
||||||
|
This file is part of Moodle - http://moodle.org/
|
||||||
|
|
||||||
|
Moodle is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Moodle is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
}}
|
||||||
|
{{!
|
||||||
|
@template core_contentbank/bankcontent/toolbar_dropdown
|
||||||
|
|
||||||
|
Example context (json):
|
||||||
|
{
|
||||||
|
"name": "Add",
|
||||||
|
"dropdown": true,
|
||||||
|
"link": "http://something/contentbank/edit.php?contextid=1",
|
||||||
|
"contenttypes": [
|
||||||
|
{
|
||||||
|
"name": "h5p",
|
||||||
|
"baseurl": "http://something/contentbank/edit.php?contextid=1&plugin=h5p",
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"typename": "H5P Interactive Content"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"typename": "Accordion",
|
||||||
|
"typeeditorparams": "library=Accordion-1.4",
|
||||||
|
"typeicon": "http://something/pluginfile.php/1/core_h5p/libraries/13/H5P.Accordion-1.4/icon.svg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
|
<div class="btn-group mr-1" role="group">
|
||||||
|
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" data-action="{{name}}-content"
|
||||||
|
aria-haspopup="true" aria-expanded="false" {{^contenttypes}}title="{{#str}}nocontenttypes, core_contentbank{{/str}}"
|
||||||
|
disabled{{/contenttypes}}>
|
||||||
|
{{#name}} {{name}} {{/name}}
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu dropdown-scrollable dropdown-menu-right">
|
||||||
|
{{#contenttypes}}
|
||||||
|
{{#types}}
|
||||||
|
{{^typeeditorparams}}
|
||||||
|
<h6 class="dropdown-header">{{ typename }}</h6>
|
||||||
|
{{/typeeditorparams}}
|
||||||
|
{{#typeeditorparams}}
|
||||||
|
<a class="dropdown-item icon-size-4" href="{{{ baseurl }}}&{{{ typeeditorparams }}}">
|
||||||
|
<img alt="" class="icon" src="{{{ typeicon }}}"> {{ typename }}
|
||||||
|
</a>
|
||||||
|
{{/typeeditorparams}}
|
||||||
|
{{/types}}
|
||||||
|
{{/contenttypes}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -507,4 +507,100 @@ class core_contentbank_testcase extends advanced_testcase {
|
||||||
// Check there's no error when trying to move content context from an empty content bank.
|
// Check there's no error when trying to move content context from an empty content bank.
|
||||||
$this->assertTrue($cb->delete_contents($systemcontext, $coursecontext));
|
$this->assertTrue($cb->delete_contents($systemcontext, $coursecontext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for get_contenttypes_with_capability_feature.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_contenttypes_with_capability_feature_provider(): array {
|
||||||
|
return [
|
||||||
|
'no-contenttypes_enabled' => [
|
||||||
|
'contenttypesenabled' => [],
|
||||||
|
'contenttypescanfeature' => [],
|
||||||
|
],
|
||||||
|
'contenttype_enabled_noeditable' => [
|
||||||
|
'contenttypesenabled' => ['testable'],
|
||||||
|
'contenttypescanfeature' => [],
|
||||||
|
],
|
||||||
|
'contenttype_enabled_editable' => [
|
||||||
|
'contenttypesenabled' => ['testable'],
|
||||||
|
'contenttypescanfeature' => ['testable'],
|
||||||
|
],
|
||||||
|
'no-contenttype_enabled_editable' => [
|
||||||
|
'contenttypesenabled' => [],
|
||||||
|
'contenttypescanfeature' => ['testable'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for get_contenttypes_with_capability_feature() function.
|
||||||
|
*
|
||||||
|
* @dataProvider get_contenttypes_with_capability_feature_provider
|
||||||
|
* @param array $contenttypesenabled Content types enabled.
|
||||||
|
* @param array $contenttypescanfeature Content types the user has the permission to use the feature.
|
||||||
|
*
|
||||||
|
* @covers ::get_contenttypes_with_capability_feature
|
||||||
|
*/
|
||||||
|
public function test_get_contenttypes_with_capability_feature(array $contenttypesenabled, array $contenttypescanfeature): void {
|
||||||
|
$this->resetAfterTest();
|
||||||
|
|
||||||
|
$cb = new contentbank();
|
||||||
|
|
||||||
|
$plugins = [];
|
||||||
|
|
||||||
|
// Content types not enabled where the user has permission to use a feature.
|
||||||
|
if (empty($contenttypesenabled) && !empty($contenttypescanfeature)) {
|
||||||
|
$enabled = false;
|
||||||
|
|
||||||
|
// Mock core_plugin_manager class and the method get_plugins_of_type.
|
||||||
|
$pluginmanager = $this->getMockBuilder(\core_plugin_manager::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(['get_plugins_of_type'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
// Replace protected singletoninstance reference (core_plugin_manager property) with mock object.
|
||||||
|
$ref = new \ReflectionProperty(\core_plugin_manager::class, 'singletoninstance');
|
||||||
|
$ref->setAccessible(true);
|
||||||
|
$ref->setValue(null, $pluginmanager);
|
||||||
|
|
||||||
|
// Return values of get_plugins_of_type method.
|
||||||
|
foreach ($contenttypescanfeature as $contenttypepluginname) {
|
||||||
|
$contenttypeplugin = new \stdClass();
|
||||||
|
$contenttypeplugin->name = $contenttypepluginname;
|
||||||
|
$contenttypeplugin->type = 'contenttype';
|
||||||
|
// Add the feature to the fake content type.
|
||||||
|
$classname = "\\contenttype_$contenttypepluginname\\contenttype";
|
||||||
|
$classname::$featurestotest = ['test2'];
|
||||||
|
$plugins[] = $contenttypeplugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set expectations and return values.
|
||||||
|
$pluginmanager->expects($this->once())
|
||||||
|
->method('get_plugins_of_type')
|
||||||
|
->with('contenttype')
|
||||||
|
->willReturn($plugins);
|
||||||
|
} else {
|
||||||
|
$enabled = true;
|
||||||
|
// Get access to private property enabledcontenttypes.
|
||||||
|
$rc = new \ReflectionClass(\core_contentbank\contentbank::class);
|
||||||
|
$rcp = $rc->getProperty('enabledcontenttypes');
|
||||||
|
$rcp->setAccessible(true);
|
||||||
|
|
||||||
|
foreach ($contenttypesenabled as $contenttypename) {
|
||||||
|
$plugins["\\contenttype_$contenttypename\\contenttype"] = $contenttypename;
|
||||||
|
// Add to the testable contenttype the feature to test.
|
||||||
|
if (in_array($contenttypename, $contenttypescanfeature)) {
|
||||||
|
$classname = "\\contenttype_$contenttypename\\contenttype";
|
||||||
|
$classname::$featurestotest = ['test2'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set as enabled content types only those in the test.
|
||||||
|
$rcp->setValue($cb, $plugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
$actual = $cb->get_contenttypes_with_capability_feature('test2', null, $enabled);
|
||||||
|
$this->assertEquals($contenttypescanfeature, array_values($actual));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ class contenttype extends \core_contentbank\contenttype {
|
||||||
/** Feature for testing */
|
/** Feature for testing */
|
||||||
const CAN_TEST = 'test';
|
const CAN_TEST = 'test';
|
||||||
|
|
||||||
|
/** @var array Additional features for testing */
|
||||||
|
public static $featurestotest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HTML code to render the icon for content bank contents.
|
* Returns the HTML code to render the icon for content bank contents.
|
||||||
*
|
*
|
||||||
|
@ -55,7 +58,13 @@ class contenttype extends \core_contentbank\contenttype {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function get_implemented_features(): array {
|
protected function get_implemented_features(): array {
|
||||||
return [self::CAN_TEST];
|
$features = [self::CAN_TEST];
|
||||||
|
|
||||||
|
if (!empty(self::$featurestotest)) {
|
||||||
|
$features = array_merge($features, self::$featurestotest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $features;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,4 +75,29 @@ class contenttype extends \core_contentbank\contenttype {
|
||||||
public function get_manageable_extensions(): array {
|
public function get_manageable_extensions(): array {
|
||||||
return ['.txt', '.png', '.h5p'];
|
return ['.txt', '.png', '.h5p'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of different types of the given content type.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_contenttype_types(): array {
|
||||||
|
$type = new \stdClass();
|
||||||
|
$type->typename = 'testable';
|
||||||
|
|
||||||
|
return [$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true, so the user has permission on the feature.
|
||||||
|
*
|
||||||
|
* @return bool True if content could be edited or created. False otherwise.
|
||||||
|
*/
|
||||||
|
final public function can_test2(): bool {
|
||||||
|
if (!$this->is_feature_supported('test2')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
$string['author'] = 'Author';
|
$string['author'] = 'Author';
|
||||||
$string['contentbank'] = 'Content bank';
|
$string['contentbank'] = 'Content bank';
|
||||||
|
$string['close'] = 'Close';
|
||||||
$string['contentdeleted'] = 'The content has been deleted.';
|
$string['contentdeleted'] = 'The content has been deleted.';
|
||||||
$string['contentname'] = 'Content name';
|
$string['contentname'] = 'Content name';
|
||||||
$string['contentnotdeleted'] = 'An error was encountered while trying to delete the content.';
|
$string['contentnotdeleted'] = 'An error was encountered while trying to delete the content.';
|
||||||
|
@ -45,6 +46,7 @@ $string['file_help'] = 'Files may be stored in the content bank for use in cours
|
||||||
$string['itemsfound'] = '{$a} items found';
|
$string['itemsfound'] = '{$a} items found';
|
||||||
$string['lastmodified'] = 'Last modified';
|
$string['lastmodified'] = 'Last modified';
|
||||||
$string['name'] = 'Content';
|
$string['name'] = 'Content';
|
||||||
|
$string['nocontenttypes'] = 'No content types available';
|
||||||
$string['nopermissiontodelete'] = 'You do not have permission to delete content.';
|
$string['nopermissiontodelete'] = 'You do not have permission to delete content.';
|
||||||
$string['nopermissiontomanage'] = 'You do not have permission to manage 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.';
|
$string['privacy:metadata:content:contenttype'] = 'The contenttype plugin of the content in the content bank.';
|
||||||
|
|
|
@ -156,6 +156,7 @@ $string['contentbank:deleteowncontent'] = 'Delete content from own content bank'
|
||||||
$string['contentbank:manageanycontent'] = 'Manage any content from the content bank (rename, move, publish, share, etc.)';
|
$string['contentbank:manageanycontent'] = 'Manage any content from the content bank (rename, move, publish, share, etc.)';
|
||||||
$string['contentbank:manageowncontent'] = 'Manage content from own content bank (rename, move, publish, share, etc.)';
|
$string['contentbank:manageowncontent'] = 'Manage content from own content bank (rename, move, publish, share, etc.)';
|
||||||
$string['contentbank:upload'] = 'Upload new content in the content bank';
|
$string['contentbank:upload'] = 'Upload new content in the content bank';
|
||||||
|
$string['contentbank:useeditor'] = 'Create or edit content using a content type editor';
|
||||||
$string['context'] = 'Context';
|
$string['context'] = 'Context';
|
||||||
$string['course:activityvisibility'] = 'Hide/show activities';
|
$string['course:activityvisibility'] = 'Hide/show activities';
|
||||||
$string['course:bulkmessaging'] = 'Send a message to many people';
|
$string['course:bulkmessaging'] = 'Send a message to many people';
|
||||||
|
|
|
@ -2544,4 +2544,16 @@ $capabilities = array(
|
||||||
'editingteacher' => CAP_ALLOW,
|
'editingteacher' => CAP_ALLOW,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Allow users to create/edit content within the content bank.
|
||||||
|
'moodle/contentbank:useeditor' => [
|
||||||
|
'riskbitmask' => RISK_SPAM,
|
||||||
|
'captype' => 'write',
|
||||||
|
'contextlevel' => CONTEXT_COURSE,
|
||||||
|
'archetypes' => array(
|
||||||
|
'manager' => CAP_ALLOW,
|
||||||
|
'coursecreator' => CAP_ALLOW,
|
||||||
|
'editingteacher' => CAP_ALLOW,
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -120,4 +120,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cb-toolbar .dropdown-scrollable {
|
||||||
|
max-height: 190px;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
|
@ -12944,6 +12944,10 @@ table.calendartable caption {
|
||||||
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
||||||
display: block; }
|
display: block; }
|
||||||
|
|
||||||
|
.cb-toolbar .dropdown-scrollable {
|
||||||
|
max-height: 190px;
|
||||||
|
overflow-y: auto; }
|
||||||
|
|
||||||
/* course.less */
|
/* course.less */
|
||||||
/* COURSE CONTENT */
|
/* COURSE CONTENT */
|
||||||
.section_add_menus {
|
.section_add_menus {
|
||||||
|
|
|
@ -13156,6 +13156,10 @@ table.calendartable caption {
|
||||||
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
||||||
display: block; }
|
display: block; }
|
||||||
|
|
||||||
|
.cb-toolbar .dropdown-scrollable {
|
||||||
|
max-height: 190px;
|
||||||
|
overflow-y: auto; }
|
||||||
|
|
||||||
/* course.less */
|
/* course.less */
|
||||||
/* COURSE CONTENT */
|
/* COURSE CONTENT */
|
||||||
.section_add_menus {
|
.section_add_menus {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
defined('MOODLE_INTERNAL') || die();
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$version = 2020052700.00; // YYYYMMDD = weekly release date of this DEV branch.
|
$version = 2020052700.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||||
// RR = release increments - 00 in DEV branches.
|
// RR = release increments - 00 in DEV branches.
|
||||||
// .XX = incremental changes.
|
// .XX = incremental changes.
|
||||||
$release = '3.9dev+ (Build: 20200527)'; // Human-friendly version name
|
$release = '3.9dev+ (Build: 20200527)'; // Human-friendly version name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue