Merge branch 'MDL-71956-master' of https://github.com/sarjona/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2021-11-10 16:04:14 +01:00
8 changed files with 834 additions and 17 deletions
+61 -5
View File
@@ -49,7 +49,7 @@ class filter_displayh5p extends moodle_text_filter {
* @return string
*/
public function filter($text, array $options = array()) {
global $CFG;
global $CFG, $USER;
if (!is_string($text) or empty($text)) {
// Non string data can not be filtered anyway.
@@ -83,7 +83,10 @@ class filter_displayh5p extends moodle_text_filter {
// It is needed to add "/embed" at the end of URLs like https:://*.h5p.com/content/12345 (H5P.com).
$params['urlmodifier'] = '';
if (($source == $localsource)) {
// Local files may display a button below the content to modify it when editing mode is on. This button will appear
// only if the user has the proper capabilities.
$params['canbeedited'] = (!empty($USER->editing)) && ($source == $localsource);
if ($source == $localsource) {
$params['tagbegin'] = '<iframe src="'.$CFG->wwwroot.'/h5p/embed.php?url=';
$escapechars = $source;
$ultimatepattern = $source;
@@ -103,7 +106,7 @@ class filter_displayh5p extends moodle_text_filter {
}
$h5pcontenturl = new filterobject($source, null, null, false,
false, null, [$this, 'filterobject_prepare_replacement_callback'], $params);
false, null, [$this, 'filterobject_prepare_replacement_callback'], $params + ['ish5plink' => false]);
$h5pcontenturl->workregexp = '#'.$ultimatepattern.'#';
$h5pcontents[] = $h5pcontenturl;
@@ -112,7 +115,7 @@ class filter_displayh5p extends moodle_text_filter {
$linkregexp = '~<a [^>]*href=["\']('.$escapechars.'[^"\']*)["\'][^>]*>([^<]*)</a>~is';
$h5plinkurl = new filterobject($linkregexp, null, null, false,
false, null, [$this, 'filterobject_prepare_replacement_callback'], $params);
false, null, [$this, 'filterobject_prepare_replacement_callback'], $params + ['ish5plink' => true]);
$h5plinkurl->workregexp = $linkregexp;
$h5plinks[] = $h5plinkurl;
}
@@ -135,7 +138,52 @@ class filter_displayh5p extends moodle_text_filter {
return $matches[0];
}
}, $text);
}
// The "Edit" button below each H5P content will be displayed only for users with permissions to edit the content (to
// avoid confusion). So the original H5P file behind this URL will be obtained and checked using the methods in the API.
// As the H5P URL is required in order to get this information, this action can be done only here(the
// prepare_replacement_callback method has only the placeholders).
foreach ($h5pcontents as $h5pcontent) {
$text = preg_replace_callback($h5pcontent->workregexp,
function ($matches) use ($h5pcontent) {
global $USER, $CFG;
// The Edit button placeholder has been added only if the file can be edited.
if ($h5pcontent->replacementcallbackdata['canbeedited']) {
// If the content was originally a link, ignore it (it won't have the placeholder).
$matchurl = new \moodle_url($matches[0]);
if (strpos($matchurl->get_path(), 'h5p/embed.php') !== false) {
return $matches[0];
}
$contenturl = $matches[0];
list($file, $h5p) = \core_h5p\api::get_original_content_from_pluginfile_url($contenturl, true, true);
if ($file) {
filter_prepare_phrase_for_replacement($h5pcontent);
// Check if the user can edit this content.
if (\core_h5p\api::can_edit_content($file)) {
// If the user can modify the content, replace the placeholder with a link to the editor.
$title = get_string('editcontent', 'core_h5p');
$editorurl = $CFG->wwwroot . '/h5p/edit.php?url=' . $contenturl;
$htmlcode = html_writer::start_tag(
'a',
['class' => 'autolink', 'title' => $title, 'href' => $editorurl]
);
$htmlcode .= $title . html_writer::end_tag('a');
$content = str_replace('$2', $htmlcode, $h5pcontent->workreplacementphrase);
} else {
// If the user can't edit the content, remove the placeholder.
$content = str_replace('$2', '', $h5pcontent->workreplacementphrase);
}
return str_replace('$1', $contenturl, $content);
}
}
return $matches[0];
}, $text);
}
$result = filter_phrases($text, $h5pcontents, null, null, false, true);
@@ -166,9 +214,12 @@ class filter_displayh5p extends moodle_text_filter {
* @param string $tagbegin HTML to insert before any match
* @param string $tagend HTML to insert after any match
* @param string $urlmodifier string to add to the match URL
* @param bool $canbeedited Whether the content can be modified or not (to display a link to edit it or not).
* @param bool $ish5plink Whether the original content comes from an H5P link or not.
* @return array [$hreftagbegin, $hreftagend, $replacementphrase] for filterobject.
*/
public function filterobject_prepare_replacement_callback($tagbegin, $tagend, $urlmodifier) {
public function filterobject_prepare_replacement_callback($tagbegin, $tagend, $urlmodifier, $canbeedited, $ish5plink) {
$sourceurl = "$1";
if ($urlmodifier !== "") {
$sourceurl .= $urlmodifier;
@@ -184,6 +235,11 @@ class filter_displayh5p extends moodle_text_filter {
self::$loadresizerjs = false;
}
if ($canbeedited && !$ish5plink) {
// Placeholder to be replaced by the edit content button (depending on the user permissions).
$tagend .= "$2";
}
return [$tagbegin, $tagend, $h5piframesrc];
}
}
@@ -0,0 +1,255 @@
@editor @editor_atto @atto @atto_h5p @filter @filter_displayh5p @core_h5p @_file_upload @_switch_iframe
Feature: Inline editing H5P content anywhere
In order to edit an existing H5P content
As a user
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 | teacher |
| student1 | C1 | student |
And 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 the following "activities" exist:
| activity | name | intro | introformat | course | content | contentformat | idnumber |
| page | PageName1 | PageDesc1 | 1 | C1 | H5Ptest | 1 | 1 |
And the "displayh5p" filter is "on"
# Override this capability to let teachers and students to Turn editing on.
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/course:update | Allow | teacher | System | |
| moodle/course:update | Allow | student | System | |
@javascript @mod @mod_page
Scenario: Edit H5P content from a page using link to private file
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/h5p:updatelibraries | Allow | editingteacher | System | |
And 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"
# Add H5P content to the page.
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And I navigate to "Settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
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 "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I click on "Save and display" "button"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should not see "Edit H5P content"
And I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
Then I should see "Edit H5P content"
And I log out
# Check admin can't see the Edit button (it's a private file and only the author can edit it).
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
@javascript @mod @mod_page @repository_contentbank
Scenario: Edit H5P content from a page using link to content bank file
Given I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to the page.
And I am on the "PageName1" "page activity" page
And I navigate to "Settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
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 "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I click on "Save and display" "button"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should not see "Edit H5P content"
When I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
Then I should see "Edit H5P content"
And I log out
# Check teacher1 can see the Edit button too.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
@javascript @mod @mod_page @repository_contentbank
Scenario: Edit H5P content from a page using copy to content bank file
Given I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to the page.
And I am on the "PageName1" "page activity" page
And I navigate to "Settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
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 "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I click on "Save and display" "button"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should not see "Edit H5P content"
When I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
Then I should see "Edit H5P content"
And I log out
# Check teacher1 can see the Edit button too.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
And I should see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
@javascript @mod @mod_page
Scenario: Edit H5P content from a page using external URL
Given the following config values are set as admin:
| allowedsources | https://moodle.h5p.com/content/[id] | filter_displayh5p |
And I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to the page.
And I am on the "PageName1" "page activity" page
And I navigate to "Settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1290772960722742119"
And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I click on "Save and display" "button"
And ".h5p-placeholder" "css_element" should exist
And I switch to "h5pcontent" iframe
And I should see "Lorum ipsum"
And I switch to the main frame
# The Edit button is never displayed (because it's not a local file).
And I should not see "Edit H5P content"
When I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
Then I should not see "Edit H5P content"
And I log out
# Check teacher1 can't see the Edit button.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "PageName1" "page activity" page
And I should not see "Edit H5P content"
@javascript @block @block_html @core_block @repository_contentbank
Scenario: Edit H5P content from a block using copy to content bank file
Given I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to the block.
And I turn editing mode on
And I add the "Text" block
And I configure the "(new text block)" block
And I click on "Insert H5P" "button" in the "#fitem_id_config_text" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
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 "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I press "Save changes"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should see "Edit H5P content"
When I turn editing mode off
Then I should not see "Edit H5P content"
And I log out
# Check teacher1 can see the Edit button too.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I should see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I should not see "Edit H5P content"
+20 -7
View File
@@ -267,7 +267,8 @@ class api {
* - 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.
* - If the component is mod_xxx or block_xxx, the user has the addinstance capability.
* - If the component implements the can_edit_content in the h5p\canedit class and the callback to this method returns true.
*
* @param \stored_file $file The H5P file to check.
*
@@ -277,25 +278,37 @@ class api {
public static function can_edit_content(\stored_file $file): bool {
global $USER;
list($type, $component) = \core_component::normalize_component($file->get_component());
// Private files.
$currentuserisauthor = $file->get_userid() == $USER->id;
$isuserfile = $file->get_component() === 'user';
$isuserfile = $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') {
// Check if the plugin where the file belongs implements the custom can_edit_content method and call it if that's the case.
$classname = '\\' . $file->get_component() . '\\h5p\\canedit';
$methodname = 'can_edit_content';
if (method_exists($classname, $methodname)) {
return $classname::{$methodname}($file);
}
// For mod/block files, check if the user has the addinstance capability of the component where the file belongs.
if ($type === 'mod' || $type === 'block') {
// For any other component, check whether the user can add/edit them.
$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.
$plugins = \core_component::get_plugin_list($type);
$isvalid = array_key_exists($component, $plugins);
if ($isvalid && has_capability("$type/$component:addinstance", $context)) {
// The user can edit the content because she has the capability for creating instances where the file belongs.
return true;
}
}
// For contentbank files, use the API to check if the user has access.
if ($file->get_component() == 'contentbank') {
if ($component == 'contentbank') {
$cb = new \core_contentbank\contentbank();
$content = $cb->get_content_from_id($file->get_itemid());
$contenttype = $content->get_content_type_instance();
+90 -5
View File
@@ -27,6 +27,8 @@ declare(strict_types = 1);
namespace core_h5p;
use stdClass;
defined('MOODLE_INTERNAL') || die();
/**
@@ -444,11 +446,13 @@ class api_test extends \advanced_testcase {
* @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.
* @param string $filearea Area of the file to check.
*
* @return void
*/
public function test_can_edit_content(string $currentuser, string $fileauthor, string $filecomponent, bool $expected): void {
global $USER;
public function test_can_edit_content(string $currentuser, string $fileauthor, string $filecomponent, bool $expected,
$filearea = 'unittest'): void {
global $USER, $DB;
$this->setRunTestInSeparateProcess(true);
$this->resetAfterTest();
@@ -472,6 +476,20 @@ class api_test extends \advanced_testcase {
$this->setUser($users[$currentuser]);
}
$itemid = rand();
if ($filearea === 'post') {
// Create a forum and add a discussion.
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
$record = new stdClass();
$record->course = $course->id;
$record->userid = $users[$fileauthor]->id;
$record->forum = $forum->id;
$discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
$post = $DB->get_record('forum_posts', ['discussion' => $discussion->id]);
$itemid = $post->id;
}
// Create the file.
$filename = 'greeting-card-887.h5p';
$path = __DIR__ . '/fixtures/' . $filename;
@@ -491,8 +509,8 @@ class api_test extends \advanced_testcase {
$filerecord = [
'contextid' => $context->id,
'component' => $filecomponent,
'filearea' => 'unittest',
'itemid' => rand(),
'filearea' => $filearea,
'itemid' => $itemid,
'filepath' => '/',
'filename' => basename($path),
'userid' => $users[$fileauthor]->id,
@@ -589,19 +607,80 @@ class api_test extends \advanced_testcase {
'expected' => false,
],
// Component = mod_book.
'mod_book: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_book',
'expected' => true,
],
'mod_book: Admin user, teacher is author' => [
'currentuser' => 'admin',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_book',
'expected' => true,
],
// Component = mod_forum.
'mod_forum: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => false,
'expected' => true,
],
'mod_forum: Admin user, teacher is author' => [
'currentuser' => 'admin',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => true,
],
'mod_forum: Teacher user, admin is author' => [
'currentuser' => 'teacher',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
],
'mod_forum: Student user, teacher is author' => [
'currentuser' => 'student',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => false,
],
'mod_forum/post: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
'filearea' => 'post',
],
'mod_forum/post: Teacher user, admin is author' => [
'currentuser' => 'teacher',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
'filearea' => 'post',
],
'mod_forum/post: Student user, teacher is author' => [
'currentuser' => 'student',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => false,
'filearea' => 'post',
],
// Component = block_html.
'block_html: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'block_html',
'expected' => true,
],
'block_html: Admin user, teacher is author' => [
'currentuser' => 'admin',
'fileauthor' => 'teacher',
'filecomponent' => 'block_html',
'expected' => true,
],
// Component = contentbank.
'contentbank: Admin user is author' => [
@@ -654,6 +733,12 @@ class api_test extends \advanced_testcase {
'filecomponent' => 'mod_unexisting',
'expected' => false,
],
'Unexisting block' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'block_unexisting',
'expected' => false,
],
];
}
+3
View File
@@ -6,6 +6,9 @@ information provided here is intended especially for developers.
* 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.
* H5P subsystem is allowed to act as an API (level 2) too.
* Plugins can now implement h5p\canedit::can_edit_content method to define, if required, any custom behaviour for deciding
whether an H5P content can be edited or not. The specific plugin check will completely override the generic check.
=== 3.11 ===
* Added $skipcapcheck parameter to H5P constructor, api::create_content_from_pluginfile_url() and
+75
View File
@@ -0,0 +1,75 @@
<?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 mod_forum\h5p;
/**
* Class to check if the H5P content can be edited for this plugin.
*
* @package mod_forum
* @copyright 2021 Sara Arjona ([email protected])
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class canedit {
/**
* Check if the user can edit an H5P file. In that case, this method will return true if the file belongs to mod_forum
* filearea is post and the user can edit the post where the H5P is.
*
* @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;
list($type, $component) = \core_component::normalize_component($file->get_component());
if ($type === 'mod' && $component === 'forum') {
// For mod_forum files in posts, check if the user can edit the post where the H5P is.
if ($file->get_filearea() === 'post') {
// Check if the user can edit the forum post.
$vaultfactory = \mod_forum\local\container::get_vault_factory();
$forumvault = $vaultfactory->get_forum_vault();
$discussionvault = $vaultfactory->get_discussion_vault();
$postvault = $vaultfactory->get_post_vault();
$postid = $file->get_itemid();
$postentity = $postvault->get_from_id($postid);
if (!empty($postentity)) {
$discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
$managerfactory = \mod_forum\local\container::get_manager_factory();
$forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
$capabilitymanager = $managerfactory->get_capability_manager($forumentity);
if ($capabilitymanager->can_edit_post($USER, $discussionentity, $postentity)) {
return true;
}
}
} else {
// For any other fileare, check whether the user can add/edit them.
$context = \context::instance_by_id($file->get_contextid());
$plugins = \core_component::get_plugin_list($type);
$isvalid = array_key_exists($component, $plugins);
if ($isvalid && has_capability("$type/$component:addinstance", $context)) {
// The user can edit the content because she has the capability for creating instances where the file belongs.
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,126 @@
@mod @mod_forum @editor @editor_atto @atto @atto_h5p @filter @filter_displayh5p @core_h5p @_file_upload @_switch_iframe
Feature: Inline editing H5P content in mod_forum
In order to edit an existing H5P content
As a user
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 | teacher |
| student1 | C1 | student |
And 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 the following "activities" exist:
| activity | name | intro | introformat | course | content | contentformat | idnumber |
| forum | ForumName1 | PageDesc1 | 1 | C1 | H5Ptest | 1 | 1 |
And the "displayh5p" filter is "on"
# Override this capability to let teachers and students to Turn editing on.
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/course:update | Allow | teacher | System | |
| moodle/course:update | Allow | student | System | |
@javascript @repository_contentbank
Scenario: Edit H5P content from a forum intro using copy to content bank file
Given I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to the forum description.
And I am on the "ForumName1" "forum activity" page
And I navigate to "Settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_introeditor" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
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 "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I click on "Save and display" "button"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should not see "Edit H5P content"
When I am on "Course 1" course homepage with editing mode on
And I am on the "ForumName1" "forum activity" page
Then I should see "Edit H5P content"
And I log out
# Check teacher1 can see the Edit button too.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "ForumName1" "forum activity" page
And I should see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can't see the Edit button, because she can't edit the forum activity.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "ForumName1" "forum activity" page
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "ForumName1" "forum activity" page
And I should not see "Edit H5P content"
@javascript @repository_contentbank
Scenario: Edit H5P content from a forum post
Given I am on the "C1" "Course" page logged in as "admin"
# Add H5P content to a forum post as admin.
And I am on the "ForumName1" "forum activity" page
And I click on "Add a new discussion topic" "link"
And I set the following fields to these values:
| Subject | Forum post by admin |
And I click on "Insert H5P" "button" in the "#fitem_id_message" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
And I select "Content bank" repository in file picker
And I click on "Greeting card" "file" in repository content area
And I click on "Select this file" "button"
And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I press "Post to forum"
And I follow "Forum post by admin"
And I switch to "h5p-iframe" class iframe
And I switch to "h5p-iframe" class iframe
And I should see "Hello world!"
And I switch to the main frame
# The Edit button is only displayed when editing mode is on.
And I should not see "Edit H5P content"
When I am on "Course 1" course homepage with editing mode on
And I am on the "ForumName1" "forum activity" page
And I follow "Forum post by admin"
Then I should see "Edit H5P content"
And I log out
# Check teacher1 can see the Edit button because she can edit the post too.
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "ForumName1" "forum activity" page
And I follow "Forum post by admin"
And I should see "Edit H5P content"
And I log out
# Check teacher2 (non-editing teacher) can see the Edit button because she can edit the post too.
And I log in as "teacher2"
And I turn editing mode on
And I am on "Course 1" course homepage
And I am on the "ForumName1" "forum activity" page
And I follow "Forum post by admin"
And 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 turn editing mode on
And I am on "Course 1" course homepage
And I am on the "ForumName1" "forum activity" page
And I follow "Forum post by admin"
And I should not see "Edit H5P content"
+204
View File
@@ -0,0 +1,204 @@
<?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/>.
declare(strict_types = 1);
namespace mod_forum\h5p;
use stdClass;
/**
* Test class covering the H5P canedit class.
*
* @package mod_forum
* @copyright 2021 Sara Arjona <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_forum\h5p\canedit
*/
class h5p_canedit_test extends \advanced_testcase {
/**
* 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.
* @param string $filearea Area of the file to check.
*
* @return void
*/
public function test_can_edit_content(string $currentuser, string $fileauthor, string $filecomponent, bool $expected,
$filearea = 'unittest'): void {
global $USER, $DB;
$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]);
}
$itemid = rand();
if ($filearea === 'post') {
// Create a forum and add a discussion.
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
$record = new stdClass();
$record->course = $course->id;
$record->userid = $users[$fileauthor]->id;
$record->forum = $forum->id;
$discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
$post = $DB->get_record('forum_posts', ['discussion' => $discussion->id]);
$itemid = $post->id;
}
// Create the file.
$filename = 'greeting-card-887.h5p';
$path = __DIR__ . '/../../../h5p/tests/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' => $filearea,
'itemid' => $itemid,
'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 = \mod_forum\h5p\canedit::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 = mod_forum.
'mod_forum: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
],
'mod_forum: Admin user, teacher is author' => [
'currentuser' => 'admin',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => true,
],
'mod_forum: Teacher user, admin is author' => [
'currentuser' => 'teacher',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
],
'mod_forum: Student user, teacher is author' => [
'currentuser' => 'student',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => false,
],
'mod_forum/post: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
'filearea' => 'post',
],
'mod_forum/post: Teacher user, admin is author' => [
'currentuser' => 'teacher',
'fileauthor' => 'admin',
'filecomponent' => 'mod_forum',
'expected' => true,
'filearea' => 'post',
],
'mod_forum/post: Student user, teacher is author' => [
'currentuser' => 'student',
'fileauthor' => 'teacher',
'filecomponent' => 'mod_forum',
'expected' => false,
'filearea' => 'post',
],
// Component <> mod_forum.
'mod_page: Admin user is author' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'mod_page',
'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,
],
'Unexisting block' => [
'currentuser' => 'admin',
'fileauthor' => 'admin',
'filecomponent' => 'block_unexisting',
'expected' => false,
],
];
}
}