mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 04:30:15 +01:00
Merge branch 'MDL-67810-master' of git://github.com/vmdef/moodle
This commit is contained in:
commit
0a1b55ce36
@ -24,6 +24,7 @@
|
||||
|
||||
namespace core_contentbank;
|
||||
|
||||
use core_plugin_manager;
|
||||
use stored_file;
|
||||
use context;
|
||||
|
||||
@ -35,6 +36,8 @@ use context;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class contentbank {
|
||||
/** @var array Enabled content types. */
|
||||
private $enabledcontenttypes = null;
|
||||
|
||||
/**
|
||||
* Obtains the list of core_contentbank_content objects currently active.
|
||||
@ -44,16 +47,20 @@ class contentbank {
|
||||
* @return string[] Array of contentbank contenttypes.
|
||||
*/
|
||||
public function get_enabled_content_types(): array {
|
||||
if (!is_null($this->enabledcontenttypes)) {
|
||||
return $this->enabledcontenttypes;
|
||||
}
|
||||
|
||||
$enabledtypes = \core\plugininfo\contenttype::get_enabled_plugins();
|
||||
$types = [];
|
||||
foreach ($enabledtypes as $name) {
|
||||
$contenttypeclassname = "\\contenttype_$name\\contenttype";
|
||||
$contentclassname = "\\contenttype_$name\\content";
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -59,7 +62,7 @@ abstract class contenttype {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function move_content(content $content, \context $context): bool {
|
||||
@ -325,6 +328,37 @@ abstract class contenttype {
|
||||
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.
|
||||
*
|
||||
@ -348,4 +382,17 @@ abstract class contenttype {
|
||||
* @return 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;
|
||||
}
|
||||
|
90
contentbank/classes/form/edit_content.php
Normal file
90
contentbank/classes/form/edit_content.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Provides {@see \core_contentbank\form\edit_content} class.
|
||||
*
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_contentbank\form;
|
||||
|
||||
use moodleform;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
/**
|
||||
* Defines the form for editing a content.
|
||||
*
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class edit_content extends moodleform {
|
||||
|
||||
/** @var int Context the content belongs to. */
|
||||
protected $contextid;
|
||||
|
||||
/** @var string Content type plugin name. */
|
||||
protected $plugin;
|
||||
|
||||
/** @var int Content id in the content bank. */
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $action The action attribute for the form.
|
||||
* @param array $customdata Data to set during instance creation.
|
||||
* @param string $method Form method.
|
||||
*/
|
||||
public function __construct(string $action = null, array $customdata = null, string $method = 'post') {
|
||||
parent::__construct($action, $customdata, $method);
|
||||
$this->contextid = $customdata['contextid'];
|
||||
$this->plugin = $customdata['plugin'];
|
||||
$this->id = $customdata['id'];
|
||||
|
||||
$mform =& $this->_form;
|
||||
$mform->addElement('hidden', 'contextid', $this->contextid);
|
||||
$this->_form->setType('contextid', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'plugin', $this->plugin);
|
||||
$this->_form->setType('plugin', PARAM_PLUGIN);
|
||||
|
||||
$mform->addElement('hidden', 'id', $this->id);
|
||||
$this->_form->setType('id', PARAM_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides formslib's add_action_buttons() method.
|
||||
*
|
||||
*
|
||||
* @param bool $cancel
|
||||
* @param string|null $submitlabel
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_action_buttons($cancel = true, $submitlabel = null): void {
|
||||
if (is_null($submitlabel)) {
|
||||
$submitlabel = get_string('save');
|
||||
}
|
||||
parent::add_action_buttons($cancel, $submitlabel);
|
||||
}
|
||||
}
|
@ -98,7 +98,56 @@ class bankcontent implements renderable, templatable {
|
||||
);
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
94
contentbank/classes/output/viewcontent.php
Normal file
94
contentbank/classes/output/viewcontent.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class containing data for a content view.
|
||||
*
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_contentbank\output;
|
||||
|
||||
use core_contentbank\content;
|
||||
use core_contentbank\contenttype;
|
||||
use moodle_url;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Class containing data for the content view.
|
||||
*
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class viewcontent implements renderable, templatable {
|
||||
/**
|
||||
* @var contenttype Content bank content type.
|
||||
*/
|
||||
private $contenttype;
|
||||
|
||||
/**
|
||||
* @var stdClass Record of the contentbank_content table.
|
||||
*/
|
||||
private $content;
|
||||
|
||||
/**
|
||||
* Construct this renderable.
|
||||
*
|
||||
* @param contenttype $contenttype Content bank content type.
|
||||
* @param content $content Record of the contentbank_content table.
|
||||
*/
|
||||
public function __construct(contenttype $contenttype, content $content) {
|
||||
$this->contenttype = $contenttype;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
$data = new stdClass();
|
||||
|
||||
// Get the content type html.
|
||||
$contenthtml = $this->contenttype->get_view_content($this->content);
|
||||
$data->contenthtml = $contenthtml;
|
||||
|
||||
// Check if the user can edit this content type.
|
||||
if ($this->contenttype->can_edit()) {
|
||||
$data->usercanedit = true;
|
||||
$urlparams = [
|
||||
'contextid' => $this->content->get_contextid(),
|
||||
'plugin' => $this->contenttype->get_plugin_name(),
|
||||
'id' => $this->content->get_id()
|
||||
];
|
||||
$editcontenturl = new moodle_url('/contentbank/edit.php', $urlparams);
|
||||
$data->editcontenturl = $editcontenturl->out(false);
|
||||
}
|
||||
|
||||
$closeurl = new moodle_url('/contentbank/index.php', ['contextid' => $this->content->get_contextid()]);
|
||||
$data->closeurl = $closeurl->out(false);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -25,7 +25,11 @@
|
||||
namespace contenttype_h5p;
|
||||
|
||||
use core\event\contentbank_content_viewed;
|
||||
use html_writer;
|
||||
use stdClass;
|
||||
use core_h5p\editor_ajax;
|
||||
use core_h5p\file_storage;
|
||||
use core_h5p\local\library\autoloader;
|
||||
use H5PCore;
|
||||
|
||||
/**
|
||||
* H5P content bank manager class
|
||||
@ -65,8 +69,7 @@ class contenttype extends \core_contentbank\contenttype {
|
||||
$event->trigger();
|
||||
|
||||
$fileurl = $content->get_file_url();
|
||||
$html = html_writer::tag('h2', $content->get_name());
|
||||
$html .= \core_h5p\player::display($fileurl, new \stdClass(), true);
|
||||
$html = \core_h5p\player::display($fileurl, new \stdClass(), true);
|
||||
return $html;
|
||||
}
|
||||
|
||||
@ -107,7 +110,7 @@ class contenttype extends \core_contentbank\contenttype {
|
||||
* @return array
|
||||
*/
|
||||
protected function get_implemented_features(): array {
|
||||
return [self::CAN_UPLOAD];
|
||||
return [self::CAN_UPLOAD, self::CAN_EDIT];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,4 +130,42 @@ class contenttype extends \core_contentbank\contenttype {
|
||||
protected function is_access_allowed(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of different H5P content types the user can create.
|
||||
*
|
||||
* @return array An object for each H5P content type:
|
||||
* - string typename: descriptive name of the H5P content type.
|
||||
* - string typeeditorparams: params required by the H5P editor.
|
||||
* - url typeicon: H5P content type icon.
|
||||
*/
|
||||
public function get_contenttype_types(): array {
|
||||
// Get the H5P content types available.
|
||||
autoloader::register();
|
||||
$editorajax = new editor_ajax();
|
||||
$h5pcontenttypes = $editorajax->getLatestLibraryVersions();
|
||||
|
||||
$types = [];
|
||||
$h5pfilestorage = new file_storage();
|
||||
foreach ($h5pcontenttypes as $h5pcontenttype) {
|
||||
$library = [
|
||||
'name' => $h5pcontenttype->machine_name,
|
||||
'majorVersion' => $h5pcontenttype->major_version,
|
||||
'minorVersion' => $h5pcontenttype->minor_version,
|
||||
];
|
||||
$key = H5PCore::libraryToString($library);
|
||||
$type = new stdClass();
|
||||
$type->key = $key;
|
||||
$type->typename = $h5pcontenttype->title;
|
||||
$type->typeeditorparams = 'library=' . $key;
|
||||
$type->typeicon = $h5pfilestorage->get_icon_url(
|
||||
$h5pcontenttype->id,
|
||||
$h5pcontenttype->machine_name,
|
||||
$h5pcontenttype->major_version,
|
||||
$h5pcontenttype->minor_version);
|
||||
$types[] = $type;
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
}
|
||||
|
152
contentbank/contenttype/h5p/classes/form/editor.php
Normal file
152
contentbank/contenttype/h5p/classes/form/editor.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Provides the class that defines the form for the H5P authoring tool.
|
||||
*
|
||||
* @package contenttype_h5p
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace contenttype_h5p\form;
|
||||
|
||||
use contenttype_h5p\content;
|
||||
use contenttype_h5p\contenttype;
|
||||
use core_contentbank\form\edit_content;
|
||||
use core_h5p\api;
|
||||
use core_h5p\editor as h5peditor;
|
||||
use core_h5p\factory;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Defines the form for editing an H5P content.
|
||||
*
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class editor extends edit_content {
|
||||
|
||||
/** @var $h5peditor H5P editor object */
|
||||
private $h5peditor;
|
||||
|
||||
/** @var $content The content being edited */
|
||||
private $content;
|
||||
|
||||
/**
|
||||
* Defines the form fields.
|
||||
*/
|
||||
protected function definition() {
|
||||
global $DB;
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
// Id of the content to edit.
|
||||
$id = $this->_customdata['id'];
|
||||
// H5P content type to create.
|
||||
$library = optional_param('library', null, PARAM_TEXT);
|
||||
|
||||
if (empty($id) && empty($library)) {
|
||||
$returnurl = new \moodle_url('/contentbank/index.php', ['contextid' => $this->_customdata['contextid']]);
|
||||
print_error('invalidcontentid', 'error', $returnurl);
|
||||
}
|
||||
|
||||
$this->h5peditor = new h5peditor();
|
||||
|
||||
if ($id) {
|
||||
// The H5P editor needs the H5P content id (h5p table).
|
||||
$record = $DB->get_record('contentbank_content', ['id' => $id]);
|
||||
$this->content = new content($record);
|
||||
$file = $this->content->get_file();
|
||||
|
||||
$h5p = api::get_content_from_pathnamehash($file->get_pathnamehash());
|
||||
$mform->addElement('hidden', 'h5pid', $h5p->id);
|
||||
$mform->setType('h5pid', PARAM_INT);
|
||||
$this->h5peditor->set_content($h5p->id);
|
||||
} else {
|
||||
// The H5P editor needs the H5P content type library name for a new content.
|
||||
$mform->addElement('hidden', 'library', $library);
|
||||
$mform->setType('library', PARAM_TEXT);
|
||||
$this->h5peditor->set_library($library, $this->_customdata['contextid'], 'contentbank', 'public');
|
||||
}
|
||||
|
||||
$mformid = 'coolh5peditor';
|
||||
$mform->setAttributes(array('id' => $mformid) + $mform->getAttributes());
|
||||
|
||||
$this->add_action_buttons();
|
||||
|
||||
$this->h5peditor->add_editor_to_form($mform);
|
||||
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify or create an H5P content from the form data.
|
||||
*
|
||||
* @param stdClass $data Form data to create or modify an H5P content.
|
||||
*
|
||||
* @return int The id of the edited or created content.
|
||||
*/
|
||||
public function save_content(stdClass $data): int {
|
||||
global $DB;
|
||||
|
||||
// The H5P libraries expect data->id as the H5P content id.
|
||||
// The method \H5PCore::saveContent throws an error if id is set but empty.
|
||||
if (empty($data->id)) {
|
||||
unset($data->id);
|
||||
} else {
|
||||
// The H5P libraries save in $data->id the H5P content id (h5p table), so the content id is saved in another var.
|
||||
$contentid = $data->id;
|
||||
}
|
||||
|
||||
$h5pcontentid = $this->h5peditor->save_content($data);
|
||||
|
||||
$factory = new factory();
|
||||
$h5pfs = $factory->get_framework();
|
||||
|
||||
// Needs the H5P file id to create or update the content bank record.
|
||||
$h5pcontent = $h5pfs->loadContent($h5pcontentid);
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file_by_hash($h5pcontent['pathnamehash']);
|
||||
// Creating new content.
|
||||
if (!isset($data->h5pid)) {
|
||||
// The initial name of the content is the title of the H5P content.
|
||||
$cbrecord = new stdClass();
|
||||
$cbrecord->name = json_decode($data->h5pparams)->metadata->title;
|
||||
$context = \context::instance_by_id($data->contextid, MUST_EXIST);
|
||||
// Create entry in content bank.
|
||||
$contenttype = new contenttype($context);
|
||||
$newcontent = $contenttype->create_content($cbrecord);
|
||||
if ($file && $newcontent) {
|
||||
$updatedfilerecord = new stdClass();
|
||||
$updatedfilerecord->id = $file->get_id();
|
||||
$updatedfilerecord->itemid = $newcontent->get_id();
|
||||
// As itemid changed, the pathnamehash has to be updated in the file table.
|
||||
$pathnamehash = \file_storage::get_pathname_hash($file->get_contextid(), $file->get_component(),
|
||||
$file->get_filearea(), $updatedfilerecord->itemid, $file->get_filepath(), $file->get_filename());
|
||||
$updatedfilerecord->pathnamehash = $pathnamehash;
|
||||
$DB->update_record('files', $updatedfilerecord);
|
||||
// The pathnamehash in the h5p table must match the file pathnamehash.
|
||||
$h5pfs->updateContentFields($h5pcontentid, ['pathnamehash' => $pathnamehash]);
|
||||
}
|
||||
} else {
|
||||
// Update content.
|
||||
$this->content->update_content();
|
||||
}
|
||||
|
||||
return $contentid ?? $newcontent->get_id();
|
||||
}
|
||||
}
|
@ -44,4 +44,14 @@ $capabilities = [
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
]
|
||||
],
|
||||
'contenttype/h5p:useeditor' => [
|
||||
'riskbitmask' => RISK_SPAM,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [
|
||||
'manager' => CAP_ALLOW,
|
||||
'coursecreator' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
]
|
||||
],
|
||||
];
|
||||
|
@ -22,8 +22,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['description'] = 'H5P Interactive Content';
|
||||
$string['pluginname'] = 'H5P';
|
||||
$string['pluginname_help'] = 'Content bank to upload and share H5P content';
|
||||
$string['privacy:metadata'] = 'The H5P content bank plugin does not store any personal data.';
|
||||
$string['h5p:access'] = 'Access H5P content in the content bank';
|
||||
$string['h5p:upload'] = 'Upload new H5P content';
|
||||
$string['h5p:useeditor'] = 'Create or edit content using the H5P editor';
|
||||
|
@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020041500.00; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2020051500.01; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2020041500.00; // Requires this Moodle version
|
||||
$plugin->component = 'contenttype_h5p'; // Full name of the plugin (used for diagnostics).
|
||||
|
110
contentbank/edit.php
Normal file
110
contentbank/edit.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Create or update contents through the specific content type editor
|
||||
*
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require('../config.php');
|
||||
|
||||
require_login();
|
||||
|
||||
$contextid = required_param('contextid', PARAM_INT);
|
||||
$pluginname = required_param('plugin', PARAM_PLUGIN);
|
||||
$id = optional_param('id', null, PARAM_INT);
|
||||
$context = context::instance_by_id($contextid, MUST_EXIST);
|
||||
require_capability('moodle/contentbank:access', $context);
|
||||
|
||||
$returnurl = new \moodle_url('/contentbank/view.php', ['id' => $id]);
|
||||
|
||||
if (!empty($id)) {
|
||||
$record = $DB->get_record('contentbank_content', ['id' => $id], '*', MUST_EXIST);
|
||||
$contentclass = "$record->contenttype\\content";
|
||||
$content = new $contentclass($record);
|
||||
// Set the heading title.
|
||||
$heading = $content->get_name();
|
||||
// The content type of the content overwrites the pluginname param value.
|
||||
$contenttypename = $content->get_content_type();
|
||||
} else {
|
||||
$contenttypename = "contenttype_$pluginname";
|
||||
$heading = get_string('addinganew', 'moodle', get_string('description', $contenttypename));
|
||||
}
|
||||
|
||||
// Check plugin is enabled.
|
||||
$plugin = core_plugin_manager::instance()->get_plugin_info($contenttypename);
|
||||
if (!$plugin || !$plugin->is_enabled()) {
|
||||
print_error('unsupported', 'core_contentbank', $returnurl);
|
||||
}
|
||||
|
||||
// Create content type instance.
|
||||
$contenttypeclass = "$contenttypename\\contenttype";
|
||||
if (class_exists($contenttypeclass)) {
|
||||
$contenttype = new $contenttypeclass($context);
|
||||
} else {
|
||||
print_error('unsupported', 'core_contentbank', $returnurl);
|
||||
}
|
||||
|
||||
// Checks the user can edit this content type.
|
||||
if (!$contenttype->can_edit()) {
|
||||
print_error('contenttypenoedit', 'core_contentbank', $returnurl, $contenttype->get_plugin_name());
|
||||
}
|
||||
|
||||
$values = [
|
||||
'contextid' => $contextid,
|
||||
'plugin' => $pluginname,
|
||||
'id' => $id
|
||||
];
|
||||
|
||||
$title = get_string('contentbank');
|
||||
\core_contentbank\helper::get_page_ready($context, $title, true);
|
||||
if ($PAGE->course) {
|
||||
require_login($PAGE->course->id);
|
||||
}
|
||||
|
||||
$PAGE->set_url(new \moodle_url('/contentbank/edit.php', $values));
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->navbar->add(get_string('edit'));
|
||||
$PAGE->set_title($title);
|
||||
|
||||
$PAGE->set_heading($heading);
|
||||
|
||||
// Instantiate the content type form.
|
||||
$editorclass = "$contenttypename\\form\\editor";
|
||||
if (!class_exists($editorclass)) {
|
||||
print_error('noformdesc');
|
||||
}
|
||||
|
||||
$editorform = new $editorclass(null, $values);
|
||||
|
||||
if ($editorform->is_cancelled()) {
|
||||
if (empty($id)) {
|
||||
$returnurl = new \moodle_url('/contentbank/index.php', ['contextid' => $context->id]);
|
||||
}
|
||||
redirect($returnurl);
|
||||
} else if ($data = $editorform->get_data()) {
|
||||
$id = $editorform->save_content($data);
|
||||
// Just in case we've created a new content.
|
||||
$returnurl->param('id', $id);
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$editorform->display();
|
||||
echo $OUTPUT->footer();
|
@ -62,6 +62,19 @@ $foldercontents = $cb->search_contents($search, $contextid, $contenttypes);
|
||||
|
||||
// Get the toolbar ready.
|
||||
$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)) {
|
||||
// Don' show upload button if there's no plugin to support any file extension.
|
||||
$accepted = $cb->get_supported_extensions_as_string($context);
|
||||
|
@ -15,7 +15,7 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_contentbank/list
|
||||
@template core_contentbank/bankcontent
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@ -32,10 +32,36 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"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",
|
||||
"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):
|
||||
{
|
||||
"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",
|
||||
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
|
||||
@ -34,9 +55,14 @@
|
||||
}}
|
||||
|
||||
{{#tools}}
|
||||
<a href="{{{ link }}}" class="icon-no-margin btn btn-secondary" title="{{{ name }}}">
|
||||
{{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
|
||||
</a>
|
||||
{{#dropdown}}
|
||||
{{>core_contentbank/bankcontent/toolbar_dropdown}}
|
||||
{{/dropdown}}
|
||||
{{^dropdown}}
|
||||
<a href="{{{ link }}}" class="icon-no-margin btn btn-secondary" title="{{{ name }}}">
|
||||
{{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
|
||||
</a>
|
||||
{{/dropdown}}
|
||||
{{/tools}}
|
||||
<button class="icon-no-margin btn btn-secondary active ml-2"
|
||||
title="{{#str}} displayicons, contentbank {{/str}}"
|
||||
@ -47,4 +73,4 @@ data-action="viewgrid">
|
||||
title="{{#str}} displaydetails, contentbank {{/str}}"
|
||||
data-action="viewlist">
|
||||
{{#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>
|
52
contentbank/templates/viewcontent.mustache
Normal file
52
contentbank/templates/viewcontent.mustache
Normal file
@ -0,0 +1,52 @@
|
||||
{{!
|
||||
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 comments.
|
||||
|
||||
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/view_content
|
||||
|
||||
View content page.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* contenthtml - string - content html.
|
||||
* usercanedit - boolean - whether the user has permission to edit the content.
|
||||
* editcontenturl - string - edit page URL.
|
||||
* closeurl - string - close landing page.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"contenthtml" : "<iframe src=\"http://something/h5p/embed.php?url=h5pfileurl\"></iframe>",
|
||||
"usercanedit" : true,
|
||||
"editcontenturl" : "http://something/contentbank/edit.php?contextid=1&plugin=h5p&id=1",
|
||||
"closeurl" : "http://moodle.test/h5pcb/moodle/contentbank/index.php"
|
||||
}
|
||||
}}
|
||||
<div class="core_contentbank_viewcontent">
|
||||
<div class="d-flex justify-content-end flex-column flex-sm-row">
|
||||
{{>core_contentbank/viewcontent/toolbarview}}
|
||||
</div>
|
||||
<div class="container mt-1 mb-1" data-region="viewcontent-content">
|
||||
{{{ contenthtml }}}
|
||||
</div>
|
||||
<div class="d-flex justify-content-end flex-column flex-sm-row">
|
||||
{{>core_contentbank/viewcontent/toolbarview}}
|
||||
</div>
|
||||
</div>
|
50
contentbank/templates/viewcontent/toolbarview.mustache
Normal file
50
contentbank/templates/viewcontent/toolbarview.mustache
Normal file
@ -0,0 +1,50 @@
|
||||
{{!
|
||||
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 comments.
|
||||
|
||||
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/viewcontent/toolbarview
|
||||
|
||||
Contentbank view toolbar.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* contenthtml - string - content html.
|
||||
* usercanedit - boolean - whether the user has permission to edit the content.
|
||||
* editcontenturl - string - edit page URL.
|
||||
* closeurl - string - close landing page.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"usercanedit" : true,
|
||||
"editcontenturl" : "http://something/contentbank/edit.php?contextid=1&plugin=h5p&id=1",
|
||||
"closeurl" : "http://moodle.test/h5pcb/moodle/contentbank/index.php"
|
||||
}
|
||||
}}
|
||||
{{#usercanedit}}
|
||||
<div class="cb-toolbar-container mb-2">
|
||||
<a href="{{editcontenturl}}" class="btn btn-primary" data-action="edit-content">
|
||||
{{#str}}edit{{/str}}
|
||||
</a>
|
||||
<a href="{{closeurl}}" class="btn btn-secondary" data-action="close-content">
|
||||
{{#str}}close, core_contentbank{{/str}}
|
||||
</a>
|
||||
</div>
|
||||
{{/usercanedit}}
|
99
contentbank/tests/behat/edit_content.feature
Normal file
99
contentbank/tests/behat/edit_content.feature
Normal file
@ -0,0 +1,99 @@
|
||||
@core @core_contentbank @contentbank_h5p @_file_upload @javascript
|
||||
Feature: Content bank use editor feature
|
||||
In order to add/edit content
|
||||
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 see the Add button disabled if there is no content type available for creation
|
||||
Given I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
When I click on "Content bank" "link"
|
||||
Then the "[data-action=Add-content]" "css_element" should be disabled
|
||||
|
||||
Scenario: Users can see the Add button if there is content type available for creation
|
||||
Given I follow "Dashboard" in the user menu
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
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 click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "filltheblanks.h5p" "link"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Content bank" "link"
|
||||
And I click on "filltheblanks.h5p" "link"
|
||||
And I click on "Close" "link"
|
||||
Then I click on "[data-action=Add-content]" "css_element"
|
||||
And I should see "Fill in the Blanks"
|
||||
|
||||
Scenario: Users can edit content if they have the required permission
|
||||
Given I follow "Dashboard" in the user menu
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
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 click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "filltheblanks.h5p" "link"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Content bank" "link"
|
||||
And I click on "filltheblanks.h5p" "link"
|
||||
Then I click on "Edit" "link"
|
||||
And I switch to "h5p-editor-iframe" class iframe
|
||||
And I switch to the main frame
|
||||
And I click on "Cancel" "button"
|
||||
And I should see "filltheblanks.h5p" in the "h1" "css_element"
|
||||
|
||||
Scenario: Users can create new content if they have the required permission
|
||||
Given I navigate to "H5P > Manage H5P content types" in site administration
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
|
||||
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
|
||||
And I should see "H5P content types uploaded successfully"
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
When I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "[data-action=Add-content]" "css_element"
|
||||
Then I click on "Fill in the Blanks" "link"
|
||||
And I switch to "h5p-editor-iframe" class iframe
|
||||
And I switch to the main frame
|
||||
And I click on "Cancel" "button"
|
||||
|
||||
Scenario: Users can't edit content if they don't have the required permission
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | user1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I navigate to "H5P > Manage H5P content types" in site administration
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
|
||||
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
|
||||
And I should see "H5P content types uploaded successfully"
|
||||
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"
|
||||
And "[data-action=Add-content]" "css_element" should exist
|
||||
When the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/contentbank:useeditor | Prohibit | editingteacher | System | |
|
||||
And I reload the page
|
||||
Then "[data-action=Add-content]" "css_element" should not exist
|
@ -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.
|
||||
$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 */
|
||||
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.
|
||||
*
|
||||
@ -55,7 +58,13 @@ class contenttype extends \core_contentbank\contenttype {
|
||||
* @return 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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ if ($PAGE->course) {
|
||||
$PAGE->set_url(new \moodle_url('/contentbank/view.php', ['id' => $id]));
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->navbar->add($record->name);
|
||||
$PAGE->set_heading($title);
|
||||
$PAGE->set_heading($record->name);
|
||||
$title .= ": ".$record->name;
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_pagetype('contenbank');
|
||||
@ -109,7 +109,6 @@ $PAGE->add_header_action(html_writer::div(
|
||||
));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->box_start('generalbox');
|
||||
|
||||
// If needed, display notifications.
|
||||
if ($errormsg !== '') {
|
||||
@ -118,8 +117,11 @@ if ($errormsg !== '') {
|
||||
echo $OUTPUT->notification($statusmsg, 'notifysuccess');
|
||||
}
|
||||
if ($contenttype->can_access()) {
|
||||
echo $contenttype->get_view_content($content);
|
||||
$viewcontent = new core_contentbank\output\viewcontent($contenttype, $content);
|
||||
echo $OUTPUT->render($viewcontent);
|
||||
} else {
|
||||
$message = get_string('contenttypenoaccess', 'core_contentbank', $record->contenttype);
|
||||
echo $OUTPUT->notification($message, 'error');
|
||||
}
|
||||
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -24,12 +24,15 @@
|
||||
|
||||
$string['author'] = 'Author';
|
||||
$string['contentbank'] = 'Content bank';
|
||||
$string['close'] = 'Close';
|
||||
$string['contentdeleted'] = 'The content has been deleted.';
|
||||
$string['contentname'] = 'Content name';
|
||||
$string['contentnotdeleted'] = 'An error was encountered while trying to delete the content.';
|
||||
$string['contentnotrenamed'] = 'An error was encountered while trying to rename the content.';
|
||||
$string['contentrenamed'] = 'The content has been renamed.';
|
||||
$string['contentsmoved'] = 'Content bank contents moved to {$a}.';
|
||||
$string['contenttypenoaccess'] = 'You can not view this {$a} instance';
|
||||
$string['contenttypenoedit'] = 'You can not edit contents of the {$a} content type';
|
||||
$string['eventcontentcreated'] = 'Content created';
|
||||
$string['eventcontentdeleted'] = 'Content deleted';
|
||||
$string['eventcontentupdated'] = 'Content updated';
|
||||
@ -45,6 +48,7 @@ $string['file_help'] = 'Files may be stored in the content bank for use in cours
|
||||
$string['itemsfound'] = '{$a} items found';
|
||||
$string['lastmodified'] = 'Last modified';
|
||||
$string['name'] = 'Content';
|
||||
$string['nocontenttypes'] = 'No content types 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.';
|
||||
|
@ -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:manageowncontent'] = 'Manage content from own content bank (rename, move, publish, share, etc.)';
|
||||
$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['course:activityvisibility'] = 'Hide/show activities';
|
||||
$string['course:bulkmessaging'] = 'Send a message to many people';
|
||||
|
@ -2544,4 +2544,16 @@ $capabilities = array(
|
||||
'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;
|
||||
}
|
@ -13031,6 +13031,10 @@ table.calendartable caption {
|
||||
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
||||
display: block; }
|
||||
|
||||
.cb-toolbar .dropdown-scrollable {
|
||||
max-height: 190px;
|
||||
overflow-y: auto; }
|
||||
|
||||
/* course.less */
|
||||
/* COURSE CONTENT */
|
||||
.section_add_menus {
|
||||
|
@ -13246,6 +13246,10 @@ table.calendartable caption {
|
||||
.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
|
||||
display: block; }
|
||||
|
||||
.cb-toolbar .dropdown-scrollable {
|
||||
max-height: 190px;
|
||||
overflow-y: auto; }
|
||||
|
||||
/* course.less */
|
||||
/* COURSE CONTENT */
|
||||
.section_add_menus {
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
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.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.9dev+ (Build: 20200527)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user