mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-71885-master' of git://github.com/sarjona/moodle
This commit is contained in:
commit
2d3798bd39
@ -217,6 +217,101 @@ class api {
|
||||
return [$file, $h5p];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original file and H5P DB instance for a given H5P pluginfile URL. If it doesn't exist, it's not created.
|
||||
* If the file has been added as a reference, this method will return the original linked file.
|
||||
*
|
||||
* @param string $url H5P pluginfile URL.
|
||||
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions.
|
||||
* @param bool $skipcapcheck Whether capabilities should be checked or not to get the pluginfile URL because sometimes they
|
||||
* might be controlled before calling this method.
|
||||
*
|
||||
* @return array of [\stored_file|false, \stdClass|false, \stored_file|false]:
|
||||
* - \stored_file: original local file for the given url (if it has been added as a reference, this method
|
||||
* will return the linked file) or false if there isn't any H5P file with this URL.
|
||||
* - \stdClass: an H5P object or false if there isn't any H5P with this URL.
|
||||
* - \stored_file: file associated to the given url (if it's different from original) or false when both files
|
||||
* (original and file) are the same.
|
||||
* @since Moodle 4.0
|
||||
*/
|
||||
public static function get_original_content_from_pluginfile_url(string $url, bool $preventredirect = true,
|
||||
bool $skipcapcheck = false): array {
|
||||
|
||||
$file = false;
|
||||
list($originalfile, $h5p) = self::get_content_from_pluginfile_url($url, $preventredirect, $skipcapcheck);
|
||||
if ($originalfile) {
|
||||
if ($reference = $originalfile->get_reference()) {
|
||||
$file = $originalfile;
|
||||
// If the file has been added as a reference to any other file, get it.
|
||||
$fs = new \file_storage();
|
||||
$referenced = \file_storage::unpack_reference($reference);
|
||||
$originalfile = $fs->get_file(
|
||||
$referenced['contextid'],
|
||||
$referenced['component'],
|
||||
$referenced['filearea'],
|
||||
$referenced['itemid'],
|
||||
$referenced['filepath'],
|
||||
$referenced['filename']
|
||||
);
|
||||
$h5p = self::get_content_from_pathnamehash($originalfile->get_pathnamehash());
|
||||
if (empty($h5p)) {
|
||||
$h5p = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$originalfile, $h5p, $file];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user can edit an H5P file. It will return true in the following situations:
|
||||
* - The user is the author of the file.
|
||||
* - The component is different from user (i.e. private files).
|
||||
* - If the component is contentbank, the user can edit this file (calling the ContentBank API).
|
||||
* - If the component is mod_h5pactivity, the user has the addinstance capability.
|
||||
*
|
||||
* @param \stored_file $file The H5P file to check.
|
||||
*
|
||||
* @return boolean Whether the user can edit or not the given file.
|
||||
* @since Moodle 4.0
|
||||
*/
|
||||
public static function can_edit_content(\stored_file $file): bool {
|
||||
global $USER;
|
||||
|
||||
// Private files.
|
||||
$currentuserisauthor = $file->get_userid() == $USER->id;
|
||||
$isuserfile = $file->get_component() === 'user';
|
||||
if ($currentuserisauthor && $isuserfile) {
|
||||
// The user can edit the content because it's a private user file and she is the owner.
|
||||
return true;
|
||||
}
|
||||
|
||||
// For mod_h5pactivity, check whether the user can add/edit them.
|
||||
if ($file->get_component() === 'mod_h5pactivity') {
|
||||
$context = \context::instance_by_id($file->get_contextid());
|
||||
if (has_capability("mod/h5pactivity:addinstance", $context)) {
|
||||
// The user can edit the content because she has the capability for creating H5P activities where the file belongs.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// For contentbank files, use the API to check if the user has access.
|
||||
if ($file->get_component() == 'contentbank') {
|
||||
$cb = new \core_contentbank\contentbank();
|
||||
$content = $cb->get_content_from_id($file->get_itemid());
|
||||
$contenttype = $content->get_content_type_instance();
|
||||
if ($contenttype instanceof \contenttype_h5p\contenttype) {
|
||||
// Only H5P contenttypes should be considered here.
|
||||
if ($contenttype->can_edit($content)) {
|
||||
// The user has permissions to edit the H5P in the content bank.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, if it doesn't exist, the H5P DB instance id for a H5P pluginfile URL. If it exists:
|
||||
* - If the content is not the same, remove the existing content and re-deploy the H5P content again.
|
||||
|
83
h5p/classes/form/editcontent_form.php
Normal file
83
h5p/classes/form/editcontent_form.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?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_h5p\form;
|
||||
|
||||
use core_h5p\editor;
|
||||
|
||||
/**
|
||||
* Form to edit an existing H5P content.
|
||||
*
|
||||
* @package core_h5p
|
||||
* @copyright 2020 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class editcontent_form extends \moodleform {
|
||||
|
||||
/** @var editor H5P editor object */
|
||||
private $editor;
|
||||
|
||||
/**
|
||||
* The form definition.
|
||||
*/
|
||||
public function definition() {
|
||||
|
||||
$mform = $this->_form;
|
||||
$id = $this->_customdata['id'] ?? null;
|
||||
$contenturl = $this->_customdata['contenturl'] ?? null;
|
||||
$returnurl = $this->_customdata['returnurl'] ?? null;
|
||||
|
||||
$editor = new editor();
|
||||
|
||||
if ($id) {
|
||||
$mform->addElement('hidden', 'id', $id);
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
$editor->set_content($id);
|
||||
}
|
||||
|
||||
if ($contenturl) {
|
||||
$mform->addElement('hidden', 'url', $contenturl);
|
||||
$mform->setType('url', PARAM_LOCALURL);
|
||||
}
|
||||
|
||||
if ($returnurl) {
|
||||
$mform->addElement('hidden', 'returnurl', $returnurl);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
}
|
||||
|
||||
$this->editor = $editor;
|
||||
$mformid = 'h5peditor';
|
||||
$mform->setAttributes(array('id' => $mformid) + $mform->getAttributes());
|
||||
|
||||
$this->add_action_buttons();
|
||||
|
||||
$editor->add_editor_to_form($mform);
|
||||
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an H5P content.
|
||||
*
|
||||
* @param \stdClass $data Object with all the H5P data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_h5p(\stdClass $data): void {
|
||||
$this->editor->save_content($data);
|
||||
}
|
||||
}
|
@ -153,12 +153,14 @@ class player {
|
||||
* @param stdClass $config Configuration for H5P buttons.
|
||||
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
|
||||
* @param string $component optional moodle component to sent xAPI tracking
|
||||
* @param bool $displayedit Whether the edit button should be displayed below the H5P content.
|
||||
*
|
||||
* @return string The embedable code to display a H5P file.
|
||||
*/
|
||||
public static function display(string $url, \stdClass $config, bool $preventredirect = true,
|
||||
string $component = ''): string {
|
||||
global $OUTPUT;
|
||||
string $component = '', bool $displayedit = false): string {
|
||||
global $OUTPUT, $CFG;
|
||||
|
||||
$params = [
|
||||
'url' => $url,
|
||||
'preventredirect' => $preventredirect,
|
||||
@ -176,6 +178,16 @@ class player {
|
||||
$template = new \stdClass();
|
||||
$template->embedurl = $fileurl->out(false);
|
||||
|
||||
if ($displayedit) {
|
||||
list($originalfile, $h5p) = api::get_original_content_from_pluginfile_url($url, $preventredirect, true);
|
||||
if ($originalfile) {
|
||||
// Check if the user can edit this content.
|
||||
if (api::can_edit_content($originalfile)) {
|
||||
$template->editurl = $CFG->wwwroot . '/h5p/edit.php?url=' . $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = $OUTPUT->render_from_template('core_h5p/h5pembed', $template);
|
||||
$result .= self::get_resize_code();
|
||||
return $result;
|
||||
|
114
h5p/edit.php
Normal file
114
h5p/edit.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Open the editor to modify an H5P content from a given H5P URL.
|
||||
*
|
||||
* @package core_h5p
|
||||
* @copyright 2021 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once("$CFG->libdir/formslib.php");
|
||||
require_once("$CFG->libdir/filestorage/file_storage.php");
|
||||
|
||||
require_login(null, false);
|
||||
|
||||
$contenturl = required_param('url', PARAM_LOCALURL);
|
||||
$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
|
||||
|
||||
// If no returnurl is defined, use local_referer.
|
||||
if (empty($returnurl)) {
|
||||
$returnurl = get_local_referer(false);
|
||||
if (empty($returnurl)) {
|
||||
// If local referer is empty, returnurl will be set to default site page.
|
||||
$returnurl = new \moodle_url('/');
|
||||
}
|
||||
}
|
||||
|
||||
$contentid = null;
|
||||
$isreferenced = false;
|
||||
$context = \context_system::instance();
|
||||
if (!empty($contenturl)) {
|
||||
list($originalfile, $h5p, $file) = \core_h5p\api::get_original_content_from_pluginfile_url($contenturl);
|
||||
$isreferenced = ($file !== false);
|
||||
if ($originalfile) {
|
||||
// Check if the user can edit the content behind the given URL.
|
||||
if (\core_h5p\api::can_edit_content($originalfile)) {
|
||||
if (!$h5p) {
|
||||
// This H5P file hasn't been deployed yet, so it should be saved to create the entry into the H5P DB.
|
||||
\core_h5p\local\library\autoloader::register();
|
||||
$factory = new \core_h5p\factory();
|
||||
$config = new \stdClass();
|
||||
$onlyupdatelibs = !\core_h5p\helper::can_update_library($originalfile);
|
||||
$contentid = \core_h5p\helper::save_h5p($factory, $originalfile, $config, $onlyupdatelibs, false);
|
||||
} else {
|
||||
// The H5P content exists. Update the contentid value.
|
||||
$contentid = $h5p->id;
|
||||
}
|
||||
}
|
||||
if ($file) {
|
||||
list($context, $course, $cm) = get_context_info_array($file->get_contextid());
|
||||
if ($course) {
|
||||
$context = \context_course::instance($course->id);
|
||||
}
|
||||
} else {
|
||||
list($context, $course, $cm) = get_context_info_array($originalfile->get_contextid());
|
||||
if ($course) {
|
||||
$context = \context_course::instance($course->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($contentid)) {
|
||||
throw new \moodle_exception('error:emptycontentid', 'core_h5p', $returnurl);
|
||||
}
|
||||
|
||||
$pagetitle = get_string('h5peditor', 'core_h5p');
|
||||
$url = new \moodle_url("/h5p/edit.php");
|
||||
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_title($pagetitle);
|
||||
$PAGE->set_heading($pagetitle);
|
||||
|
||||
$values = [
|
||||
'id' => $contentid,
|
||||
'contenturl' => $contenturl,
|
||||
'returnurl' => $returnurl,
|
||||
];
|
||||
|
||||
$form = new \core_h5p\form\editcontent_form(null, $values);
|
||||
if ($form->is_cancelled()) {
|
||||
redirect($returnurl);
|
||||
} else if ($data = $form->get_data()) {
|
||||
$form->save_h5p($data);
|
||||
if (!empty($returnurl)) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
if ($isreferenced) {
|
||||
echo $OUTPUT->notification(get_string('contentinuse', 'core_h5p'), 'info');
|
||||
}
|
||||
|
||||
$form->display();
|
||||
|
||||
echo $OUTPUT->footer();
|
@ -24,6 +24,7 @@
|
||||
|
||||
Variables required for this template:
|
||||
* embedurl - The URL with the H5P file to embed
|
||||
* editurl - The URL for the edit button; if it's empty, the edit button won't be displayed.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@ -35,3 +36,7 @@
|
||||
allowfullscreen="allowfullscreen" class="h5p-player w-100 border-0"
|
||||
style="height: 0px;" id="{{uniqid}}-h5player">
|
||||
</iframe>
|
||||
|
||||
{{#editurl}}
|
||||
<a href="{{editurl}}">{{#str}}editcontent, core_h5p{{/str}}</a>
|
||||
{{/editurl}}
|
||||
|
@ -333,6 +333,330 @@ class api_test extends \advanced_testcase {
|
||||
$this->assertFalse($h5p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of get_original_content_from_pluginfile_url().
|
||||
*
|
||||
* @covers ::get_original_content_from_pluginfile_url
|
||||
*/
|
||||
public function test_get_original_content_from_pluginfile_url(): void {
|
||||
$this->setRunTestInSeparateProcess(true);
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$factory = new factory();
|
||||
$syscontext = \context_system::instance();
|
||||
|
||||
// Create the original file.
|
||||
$filename = 'greeting-card-887.h5p';
|
||||
$path = __DIR__ . '/fixtures/' . $filename;
|
||||
$originalfile = helper::create_fake_stored_file_from_path($path);
|
||||
$originalfilerecord = [
|
||||
'contextid' => $originalfile->get_contextid(),
|
||||
'component' => $originalfile->get_component(),
|
||||
'filearea' => $originalfile->get_filearea(),
|
||||
'itemid' => $originalfile->get_itemid(),
|
||||
'filepath' => $originalfile->get_filepath(),
|
||||
'filename' => $originalfile->get_filename(),
|
||||
];
|
||||
|
||||
$config = (object)[
|
||||
'frame' => 1,
|
||||
'export' => 1,
|
||||
'embed' => 0,
|
||||
'copyright' => 0,
|
||||
];
|
||||
|
||||
$originalurl = \moodle_url::make_pluginfile_url(
|
||||
$originalfile->get_contextid(),
|
||||
$originalfile->get_component(),
|
||||
$originalfile->get_filearea(),
|
||||
$originalfile->get_itemid(),
|
||||
$originalfile->get_filepath(),
|
||||
$originalfile->get_filename()
|
||||
);
|
||||
|
||||
// Create a reference to the original file.
|
||||
$reffilerecord = [
|
||||
'contextid' => $syscontext->id,
|
||||
'component' => 'core',
|
||||
'filearea' => 'phpunit',
|
||||
'itemid' => 0,
|
||||
'filepath' => '/',
|
||||
'filename' => $filename
|
||||
];
|
||||
|
||||
$fs = get_file_storage();
|
||||
$ref = $fs->pack_reference($originalfilerecord);
|
||||
$repos = \repository::get_instances(['type' => 'user']);
|
||||
$userrepository = reset($repos);
|
||||
$referencedfile = $fs->create_file_from_reference($reffilerecord, $userrepository->id, $ref);
|
||||
$this->assertEquals($referencedfile->get_contenthash(), $originalfile->get_contenthash());
|
||||
|
||||
$referencedurl = \moodle_url::make_pluginfile_url(
|
||||
$syscontext->id,
|
||||
'core',
|
||||
'phpunit',
|
||||
0,
|
||||
'/',
|
||||
$filename
|
||||
);
|
||||
|
||||
// Scenario 1: Original file (without any reference).
|
||||
$originalh5pid = helper::save_h5p($factory, $originalfile, $config);
|
||||
list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($originalurl->out());
|
||||
$this->assertEquals($originalfile->get_pathnamehash(), $source->get_pathnamehash());
|
||||
$this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash());
|
||||
$this->assertEquals($originalh5pid, $h5p->id);
|
||||
$this->assertFalse($file);
|
||||
|
||||
// Scenario 2: Referenced file (alias to originalfile).
|
||||
list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($referencedurl->out());
|
||||
$this->assertEquals($originalfile->get_pathnamehash(), $source->get_pathnamehash());
|
||||
$this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash());
|
||||
$this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash());
|
||||
$this->assertEquals($originalh5pid, $h5p->id);
|
||||
$this->assertEquals($referencedfile->get_pathnamehash(), $file->get_pathnamehash());
|
||||
$this->assertEquals($referencedfile->get_contenthash(), $file->get_contenthash());
|
||||
$this->assertEquals($referencedfile->get_contenthash(), $file->get_contenthash());
|
||||
|
||||
// Scenario 3: Unexisting file.
|
||||
$unexistingurl = \moodle_url::make_pluginfile_url(
|
||||
$syscontext->id,
|
||||
'core',
|
||||
'phpunit',
|
||||
0,
|
||||
'/',
|
||||
'unexisting.h5p'
|
||||
);
|
||||
list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($unexistingurl->out());
|
||||
$this->assertFalse($source);
|
||||
$this->assertFalse($h5p);
|
||||
$this->assertFalse($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of can_edit_content().
|
||||
*
|
||||
* @covers ::can_edit_content
|
||||
* @dataProvider can_edit_content_provider
|
||||
*
|
||||
* @param string $currentuser User who will call the method.
|
||||
* @param string $fileauthor Author of the file to check.
|
||||
* @param string $filecomponent Component of the file to check.
|
||||
* @param bool $expected Expected result after calling the can_edit_content method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_can_edit_content(string $currentuser, string $fileauthor, string $filecomponent, bool $expected): void {
|
||||
global $USER;
|
||||
|
||||
$this->setRunTestInSeparateProcess(true);
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$context = \context_course::instance($course->id);
|
||||
|
||||
// Create some users.
|
||||
$this->setAdminUser();
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
|
||||
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$users = [
|
||||
'admin' => $USER,
|
||||
'teacher' => $teacher,
|
||||
'student' => $student,
|
||||
];
|
||||
|
||||
// Set current user.
|
||||
if ($currentuser !== 'admin') {
|
||||
$this->setUser($users[$currentuser]);
|
||||
}
|
||||
|
||||
// Create the file.
|
||||
$filename = 'greeting-card-887.h5p';
|
||||
$path = __DIR__ . '/fixtures/' . $filename;
|
||||
if ($filecomponent === 'contentbank') {
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
|
||||
$contents = $generator->generate_contentbank_data(
|
||||
'contenttype_h5p',
|
||||
1,
|
||||
(int)$users[$fileauthor]->id,
|
||||
$context,
|
||||
true,
|
||||
$path
|
||||
);
|
||||
$content = array_shift($contents);
|
||||
$file = $content->get_file();
|
||||
} else {
|
||||
$filerecord = [
|
||||
'contextid' => $context->id,
|
||||
'component' => $filecomponent,
|
||||
'filearea' => 'unittest',
|
||||
'itemid' => rand(),
|
||||
'filepath' => '/',
|
||||
'filename' => basename($path),
|
||||
'userid' => $users[$fileauthor]->id,
|
||||
];
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->create_file_from_pathname($filerecord, $path);
|
||||
}
|
||||
|
||||
// Check if the currentuser can edit the file.
|
||||
$result = api::can_edit_content($file);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_can_edit_content().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function can_edit_content_provider(): array {
|
||||
return [
|
||||
// Component = user.
|
||||
'user: Admin user is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => true,
|
||||
],
|
||||
'user: Admin user, teacher is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => false,
|
||||
],
|
||||
'user: Teacher user, teacher is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => true,
|
||||
],
|
||||
'user: Teacher user, admin is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => false,
|
||||
],
|
||||
'user: Student user, student is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'student',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => true,
|
||||
],
|
||||
'user: Student user, teacher is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'user',
|
||||
'expected' => false,
|
||||
],
|
||||
|
||||
// Component = mod_h5pactivity.
|
||||
'mod_h5pactivity: Admin user is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => true,
|
||||
],
|
||||
'mod_h5pactivity: Admin user, teacher is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => true,
|
||||
],
|
||||
'mod_h5pactivity: Teacher user, teacher is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => true,
|
||||
],
|
||||
'mod_h5pactivity: Teacher user, admin is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => true,
|
||||
],
|
||||
'mod_h5pactivity: Student user, student is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'student',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => false,
|
||||
],
|
||||
'mod_h5pactivity: Student user, teacher is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'mod_h5pactivity',
|
||||
'expected' => false,
|
||||
],
|
||||
|
||||
// Component = mod_forum.
|
||||
'mod_forum: Admin user is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'mod_forum',
|
||||
'expected' => false,
|
||||
],
|
||||
'mod_forum: Admin user, teacher is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'mod_forum',
|
||||
'expected' => false,
|
||||
],
|
||||
|
||||
// Component = contentbank.
|
||||
'contentbank: Admin user is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => true,
|
||||
],
|
||||
'contentbank: Admin user, teacher is author' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => true,
|
||||
],
|
||||
'contentbank: Teacher user, teacher is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => true,
|
||||
],
|
||||
'contentbank: Teacher user, admin is author' => [
|
||||
'currentuser' => 'teacher',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => false,
|
||||
],
|
||||
'contentbank: Student user, student is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'student',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => false,
|
||||
],
|
||||
'contentbank: Student user, teacher is author' => [
|
||||
'currentuser' => 'student',
|
||||
'fileauthor' => 'teacher',
|
||||
'filecomponent' => 'contentbank',
|
||||
'expected' => false,
|
||||
],
|
||||
|
||||
// Unexisting components.
|
||||
'Unexisting component' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'unexisting_component',
|
||||
'expected' => false,
|
||||
],
|
||||
'Unexisting module activity' => [
|
||||
'currentuser' => 'admin',
|
||||
'fileauthor' => 'admin',
|
||||
'filecomponent' => 'mod_unexisting',
|
||||
'expected' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of create_content_from_pluginfile_url().
|
||||
*/
|
||||
|
@ -1,6 +1,12 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.0 ===
|
||||
* Added new methods to api: get_original_content_from_pluginfile_url and can_edit_content.
|
||||
* Added edit.php and editcontent_form class, for modifying H5P content given an H5P identifier (from the h5p table).
|
||||
* Added a new parameter to the player::display method, to define whether the edit button should be displayed below the
|
||||
H5P content or not. Default value for this parameter is false.
|
||||
|
||||
=== 3.11 ===
|
||||
* Added $skipcapcheck parameter to H5P constructor, api::create_content_from_pluginfile_url() and
|
||||
api::get_content_from_pluginfile_url() to let skip capabilities check to get the pluginfile URL.
|
||||
|
@ -59,6 +59,7 @@ $string['connectionLost'] = 'Connection lost. Results will be stored and sent wh
|
||||
$string['connectionReestablished'] = 'Connection reestablished.';
|
||||
$string['contentCopied'] = 'Content is copied to the clipboard';
|
||||
$string['contentchanged'] = 'This content has changed since you last used it.';
|
||||
$string['contentinuse'] = 'This content may be in use in other places.';
|
||||
$string['contenttype'] = 'Content type';
|
||||
$string['copyright'] = 'Rights of use';
|
||||
$string['copyrightinfo'] = 'Copyright information';
|
||||
@ -75,9 +76,11 @@ $string['description'] = 'Description';
|
||||
$string['disablefullscreen'] = 'Disable fullscreen';
|
||||
$string['download'] = 'Download';
|
||||
$string['downloadtitle'] = 'Download this content as a H5P file.';
|
||||
$string['editcontent'] = 'Edit H5P content';
|
||||
$string['editor'] = 'Editor';
|
||||
$string['embed'] = 'Embed';
|
||||
$string['embedtitle'] = 'View the embed code for this content.';
|
||||
$string['error:emptycontentid'] = 'The given URL is incorrect or you cannot edit this file.';
|
||||
$string['eventh5pviewed'] = 'H5P content viewed';
|
||||
$string['eventh5pdeleted'] = 'H5P deleted';
|
||||
$string['feature'] = 'Feature';
|
||||
@ -88,6 +91,7 @@ $string['filter_displayh5p_description'] = 'The Display H5P filter converts URLs
|
||||
$string['fullscreen'] = 'Fullscreen';
|
||||
$string['gpl'] = 'General Public License v3';
|
||||
$string['h5p'] = 'H5P';
|
||||
$string['h5peditor'] = 'H5P Editor';
|
||||
$string['h5ptitle'] = 'Visit h5p.org to check out more content.';
|
||||
$string['h5pfilenotfound'] = 'H5P file not found';
|
||||
$string['h5pinvalidurl'] = 'Invalid H5P content URL.';
|
||||
|
210
mod/h5pactivity/tests/behat/inline_editing_content.feature
Normal file
210
mod/h5pactivity/tests/behat/inline_editing_content.feature
Normal file
@ -0,0 +1,210 @@
|
||||
@mod @mod_h5pactivity @core_h5p @_file_upload @_switch_iframe
|
||||
Feature: Inline editing H5P content
|
||||
In order to edit an existing H5P activity file
|
||||
As a teacher
|
||||
I need to see the button and access to the H5P editor
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| teacher2 | Teacher | 2 | teacher2@example.com |
|
||||
| student1 | Student | 1 | student1@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 |
|
||||
| teacher2 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/h5p:updatelibraries | Allow | editingteacher | System | |
|
||||
|
||||
@javascript
|
||||
Scenario: Add H5P activity using link to content bank file
|
||||
Given the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath |
|
||||
| Course | C1 | contenttype_h5p | teacher1 | Greeting card | /h5p/tests/fixtures/greeting-card-887.h5p |
|
||||
And I log in as "admin"
|
||||
# Add the navigation block.
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Navigation" block if not present
|
||||
# Create an H5P activity with a link to the content-bank file.
|
||||
And I add a "H5P" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | H5P package added as link to content bank |
|
||||
| Description | Description |
|
||||
And I click on "Add..." "button" in the "Package file" "form_row"
|
||||
And I select "Content bank" repository in file picker
|
||||
And I click on "Greeting card" "file" in repository content area
|
||||
And I click on "Link to the file" "radio"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save and display" "button"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should see "Hello world!"
|
||||
And I switch to the main frame
|
||||
# Modify the H5P content using the edit button (which opens the H5P editor).
|
||||
And I follow "Edit H5P content"
|
||||
And I should see "This content may be in use in other places."
|
||||
And I switch to "h5p-editor-iframe" class iframe
|
||||
And I set the field "Greeting text" to "It's a Wonderful Life!"
|
||||
And I switch to the main frame
|
||||
And I click on "Save changes" "button"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
# Check the H5P content has changed.
|
||||
And I should not see "Hello world!"
|
||||
And I should see "It's a Wonderful Life!"
|
||||
And I switch to the main frame
|
||||
# Check the H5P has also changed into the content bank.
|
||||
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 "Greeting card" "link"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should not see "Hello world!"
|
||||
And I should see "It's a Wonderful Life!"
|
||||
And I switch to the main frame
|
||||
And I log out
|
||||
# Check teacher1 can see the Edit button (because she is the author of this file in the content bank).
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as link to content bank"
|
||||
And I should see "Edit H5P content"
|
||||
And I log out
|
||||
# Check teacher2 can't see the Edit button (because the file was created by the teacher1).
|
||||
And I log in as "teacher2"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "H5P package added as link to content bank"
|
||||
Then I should not see "Edit H5P content"
|
||||
And I log out
|
||||
# Check student1 can't see the Edit button.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as link to content bank"
|
||||
And I should not see "Edit H5P content"
|
||||
|
||||
@javascript
|
||||
Scenario: Add H5P activity using copy to content bank file
|
||||
Given the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath |
|
||||
| Course | C1 | contenttype_h5p | admin | Greeting card | /h5p/tests/fixtures/greeting-card-887.h5p |
|
||||
And I log in as "admin"
|
||||
# Add the navigation block.
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Navigation" block if not present
|
||||
# Create an H5P activity with a copy to the content-bank file.
|
||||
And I add a "H5P" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | H5P package added as copy to content bank |
|
||||
| Description | Description |
|
||||
And I click on "Add..." "button" in the "Package file" "form_row"
|
||||
And I select "Content bank" repository in file picker
|
||||
And I click on "Greeting card" "file" in repository content area
|
||||
And I click on "Make a copy of the file" "radio"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save and display" "button"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should see "Hello world!"
|
||||
And I switch to the main frame
|
||||
# Modify the H5P content using the edit button (which opens the H5P editor).
|
||||
And I follow "Edit H5P content"
|
||||
And I should not see "This content may be in use in other places."
|
||||
And I switch to "h5p-editor-iframe" class iframe
|
||||
And I set the field "Greeting text" to "The nightmare before Christmas"
|
||||
And I switch to the main frame
|
||||
And I click on "Save changes" "button"
|
||||
# Check the H5P content has changed.
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should not see "Hello world!"
|
||||
And I should see "The nightmare before Christmas"
|
||||
And I switch to the main frame
|
||||
# Check the H5P has also changed into the content bank.
|
||||
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 "Greeting card" "link"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should see "Hello world!"
|
||||
And I should not see "The nightmare before Christmas"
|
||||
And I switch to the main frame
|
||||
And I log out
|
||||
# Check teacher1 can see the Edit button (because the file is a copy).
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as copy to content bank"
|
||||
And I should see "Edit H5P content"
|
||||
And I log out
|
||||
# Check teacher2 can also see the Edit button (because the file is a copy).
|
||||
And I log in as "teacher2"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "H5P package added as copy to content bank"
|
||||
Then I should see "Edit H5P content"
|
||||
And I log out
|
||||
# Check student1 can't see the Edit button.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as copy to content bank"
|
||||
And I should not see "Edit H5P content"
|
||||
|
||||
@javascript
|
||||
Scenario: Add H5P activity using private user file
|
||||
Given I log in as "teacher1"
|
||||
# Upload the H5P to private user files.
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/greeting-card-887.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
# Create an H5P activity with a private user file.
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "H5P" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | H5P package added as private user file |
|
||||
| Description | Description |
|
||||
And I click on "Add..." "button" in the "Package file" "form_row"
|
||||
And I select "Private files" repository in file picker
|
||||
And I click on "greeting-card-887.h5p" "file" in repository content area
|
||||
And I click on "Link to the file" "radio"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save and display" "button"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should see "Hello world!"
|
||||
And I switch to the main frame
|
||||
# Modify the H5P content using the edit button (which opens the H5P editor).
|
||||
And I follow "Edit H5P content"
|
||||
And I should see "This content may be in use in other places."
|
||||
And I switch to "h5p-editor-iframe" class iframe
|
||||
And I set the field "Greeting text" to "Little women"
|
||||
And I switch to the main frame
|
||||
And I click on "Save changes" "button"
|
||||
# Check the H5P content has changed.
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should not see "Hello world!"
|
||||
And I should see "Little women"
|
||||
And I switch to the main frame
|
||||
And I log out
|
||||
# Check admin can't see the Edit button (because the file belongs to teacher1).
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as private user file"
|
||||
And I should not see "Edit H5P content"
|
||||
And I log out
|
||||
# Check teacher2 can't see the Edit button (because the file belongs to teacher1).
|
||||
And I log in as "teacher2"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "H5P package added as private user file"
|
||||
Then I should not see "Edit H5P content"
|
||||
And I log out
|
||||
# Check student1 can't see the Edit button.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "H5P package added as private user file"
|
||||
And I should not see "Edit H5P content"
|
@ -98,6 +98,6 @@ if (!$manager->is_tracking_enabled()) {
|
||||
echo $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
|
||||
}
|
||||
|
||||
echo player::display($fileurl, $config, true, 'mod_h5pactivity');
|
||||
echo player::display($fileurl, $config, true, 'mod_h5pactivity', true);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
Loading…
x
Reference in New Issue
Block a user