mirror of
https://github.com/moodle/moodle.git
synced 2025-08-06 17:36:38 +02:00
Merge branch 'MDL-69269-310' of git://github.com/sarjona/moodle into MOODLE_310_STABLE
This commit is contained in:
commit
66c757f689
9 changed files with 255 additions and 6 deletions
|
@ -46,6 +46,11 @@ abstract class contenttype {
|
||||||
/** Plugin implements edition feature */
|
/** Plugin implements edition feature */
|
||||||
const CAN_EDIT = 'edit';
|
const CAN_EDIT = 'edit';
|
||||||
|
|
||||||
|
/** Plugin implements download feature
|
||||||
|
* @since Moodle 3.10
|
||||||
|
*/
|
||||||
|
const CAN_DOWNLOAD = 'download';
|
||||||
|
|
||||||
/** @var \context This contenttype's context. **/
|
/** @var \context This contenttype's context. **/
|
||||||
protected $context = null;
|
protected $context = null;
|
||||||
|
|
||||||
|
@ -220,6 +225,31 @@ abstract class contenttype {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to download the content.
|
||||||
|
*
|
||||||
|
* @since Moodle 3.10
|
||||||
|
* @param content $content The content to be downloaded.
|
||||||
|
* @return string URL with the content to download.
|
||||||
|
*/
|
||||||
|
public function get_download_url(content $content): string {
|
||||||
|
$downloadurl = '';
|
||||||
|
$file = $content->get_file();
|
||||||
|
if (!empty($file)) {
|
||||||
|
$url = \moodle_url::make_pluginfile_url(
|
||||||
|
$file->get_contextid(),
|
||||||
|
$file->get_component(),
|
||||||
|
$file->get_filearea(),
|
||||||
|
$file->get_itemid(),
|
||||||
|
$file->get_filepath(),
|
||||||
|
$file->get_filename()
|
||||||
|
);
|
||||||
|
$downloadurl = $url->out(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $downloadurl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HTML code to render the icon for content bank contents.
|
* Returns the HTML code to render the icon for content bank contents.
|
||||||
*
|
*
|
||||||
|
@ -392,6 +422,38 @@ abstract class contenttype {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the user has permission to download the content.
|
||||||
|
*
|
||||||
|
* @since Moodle 3.10
|
||||||
|
* @param content $content The content to be downloaded.
|
||||||
|
* @return bool True if the user can download the content. False otherwise.
|
||||||
|
*/
|
||||||
|
final public function can_download(content $content): bool {
|
||||||
|
if (!$this->is_feature_supported(self::CAN_DOWNLOAD)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->can_access()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hascapability = has_capability('moodle/contentbank:downloadcontent', $this->context);
|
||||||
|
return $hascapability && $this->is_download_allowed($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns plugin allows downloading.
|
||||||
|
*
|
||||||
|
* @since Moodle 3.10
|
||||||
|
* @param content $content The content to be downloaed.
|
||||||
|
* @return bool True if plugin allows downloading. False otherwise.
|
||||||
|
*/
|
||||||
|
protected function is_download_allowed(content $content): bool {
|
||||||
|
// Plugins can overwrite this function to add any check they need.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin supports the feature.
|
* Returns the plugin supports the feature.
|
||||||
*
|
*
|
||||||
|
|
|
@ -110,7 +110,7 @@ class contenttype extends \core_contentbank\contenttype {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function get_implemented_features(): array {
|
protected function get_implemented_features(): array {
|
||||||
return [self::CAN_UPLOAD, self::CAN_EDIT];
|
return [self::CAN_UPLOAD, self::CAN_EDIT, self::CAN_DOWNLOAD];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -147,4 +147,40 @@ class contenttype_h5p_contenttype_plugin_testcase extends advanced_testcase {
|
||||||
$this->assertNotEquals($defaulticon, $findicon);
|
$this->assertNotEquals($defaulticon, $findicon);
|
||||||
$this->assertContains('find', $findicon, '', true);
|
$this->assertContains('find', $findicon, '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests get_download_url result.
|
||||||
|
*
|
||||||
|
* @covers ::get_download_url
|
||||||
|
*/
|
||||||
|
public function test_get_download_url() {
|
||||||
|
global $CFG;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$systemcontext = context_system::instance();
|
||||||
|
$this->setAdminUser();
|
||||||
|
$contenttype = new contenttype_h5p\contenttype($systemcontext);
|
||||||
|
|
||||||
|
// Add an H5P fill the blanks file to the content bank.
|
||||||
|
$filename = 'filltheblanks.h5p';
|
||||||
|
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename;
|
||||||
|
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
|
||||||
|
$contents = $generator->generate_contentbank_data('contenttype_h5p', 1, 0, $systemcontext, true, $filepath);
|
||||||
|
$filltheblanks = array_shift($contents);
|
||||||
|
|
||||||
|
// Check before deploying the URL is returned OK.
|
||||||
|
$url1 = $contenttype->get_download_url($filltheblanks);
|
||||||
|
$this->assertNotEmpty($url1);
|
||||||
|
$this->assertContains($filename, $url1);
|
||||||
|
|
||||||
|
// Deploy the contents though the player to create the H5P DB entries and know specific content type.
|
||||||
|
$h5pplayer = new \core_h5p\player($filltheblanks->get_file_url(), new \stdClass(), true);
|
||||||
|
$h5pplayer->add_assets_to_page();
|
||||||
|
$h5pplayer->output();
|
||||||
|
|
||||||
|
// Once the H5P has been deployed, the URL is still the same.
|
||||||
|
$url2 = $contenttype->get_download_url($filltheblanks);
|
||||||
|
$this->assertNotEmpty($url2);
|
||||||
|
$this->assertEquals($url1, $url2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
61
contentbank/tests/behat/download_content.feature
Normal file
61
contentbank/tests/behat/download_content.feature
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
@core @core_contentbank @contentbank_h5p @_file_upload @javascript
|
||||||
|
Feature: Download H5P content from the content bank
|
||||||
|
In order export H5P content from the content bank
|
||||||
|
As an admin
|
||||||
|
I need to be able to download any H5P content from the content bank
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the following "users" exist:
|
||||||
|
| username | firstname | lastname | email |
|
||||||
|
| manager | Max | Manager | man@example.com |
|
||||||
|
And the following "role assigns" exist:
|
||||||
|
| user | role | contextlevel | reference |
|
||||||
|
| manager | manager | System | |
|
||||||
|
And the following "contentbank content" exist:
|
||||||
|
| contextlevel | reference | contenttype | user | contentname | filepath |
|
||||||
|
| System | | contenttype_h5p | admin | filltheblanksadmin.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
|
||||||
|
| System | | contenttype_h5p | manager | filltheblanksmanager.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
|
||||||
|
And 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: Admins can download content from the content bank
|
||||||
|
Given I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||||
|
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||||
|
And I follow "filltheblanksmanager.h5p"
|
||||||
|
And I open the action menu in "region-main-settings-menu" "region"
|
||||||
|
And I should see "Download"
|
||||||
|
When I choose "Download" in the open action menu
|
||||||
|
Then I should see "filltheblanksmanager.h5p"
|
||||||
|
|
||||||
|
Scenario: Users can download content created by different users
|
||||||
|
Given the following "permission overrides" exist:
|
||||||
|
| capability | permission | role | contextlevel | reference |
|
||||||
|
| moodle/contentbank:manageanycontent | Prohibit | manager | System | |
|
||||||
|
And I log out
|
||||||
|
And I log in as "manager"
|
||||||
|
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||||
|
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||||
|
And I should see "filltheblanksadmin.h5p"
|
||||||
|
And I follow "filltheblanksadmin.h5p"
|
||||||
|
And I open the action menu in "region-main-settings-menu" "region"
|
||||||
|
Then I should see "Download"
|
||||||
|
And I should not see "Rename"
|
||||||
|
|
||||||
|
Scenario: Users without the required capability cannot download content
|
||||||
|
Given the following "permission overrides" exist:
|
||||||
|
| capability | permission | role | contextlevel | reference |
|
||||||
|
| moodle/contentbank:downloadcontent | Prohibit | manager | System | |
|
||||||
|
And I log out
|
||||||
|
And I log in as "manager"
|
||||||
|
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||||
|
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||||
|
And I should see "filltheblanksmanager.h5p"
|
||||||
|
And I follow "filltheblanksmanager.h5p"
|
||||||
|
And I open the action menu in "region-main-settings-menu" "region"
|
||||||
|
Then I should not see "Download"
|
|
@ -348,7 +348,7 @@ class core_contenttype_contenttype_testcase extends \advanced_testcase {
|
||||||
/**
|
/**
|
||||||
* Helper function to setup 3 users (manager1, manager2 and user) and 4 contents (3 created by manager1 and 1 by user).
|
* Helper function to setup 3 users (manager1, manager2 and user) and 4 contents (3 created by manager1 and 1 by user).
|
||||||
*/
|
*/
|
||||||
protected function contenttype_setup_scenario_data(): void {
|
protected function contenttype_setup_scenario_data(string $contenttype = 'contenttype_testable'): void {
|
||||||
global $DB;
|
global $DB;
|
||||||
$systemcontext = context_system::instance();
|
$systemcontext = context_system::instance();
|
||||||
|
|
||||||
|
@ -358,14 +358,17 @@ class core_contenttype_contenttype_testcase extends \advanced_testcase {
|
||||||
$this->managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
|
$this->managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
|
||||||
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager1->id);
|
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager1->id);
|
||||||
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager2->id);
|
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager2->id);
|
||||||
|
$editingteacherrolerid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
|
||||||
$this->user = $this->getDataGenerator()->create_user();
|
$this->user = $this->getDataGenerator()->create_user();
|
||||||
|
$this->getDataGenerator()->role_assign($editingteacherrolerid, $this->user->id);
|
||||||
|
|
||||||
// Add some content to the content bank.
|
// Add some content to the content bank.
|
||||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
|
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
|
||||||
$this->contents[$this->manager1->id] = $generator->generate_contentbank_data(null, 3, $this->manager1->id);
|
$this->contents[$this->manager1->id] = $generator->generate_contentbank_data($contenttype, 3, $this->manager1->id);
|
||||||
$this->contents[$this->user->id] = $generator->generate_contentbank_data(null, 1, $this->user->id);
|
$this->contents[$this->user->id] = $generator->generate_contentbank_data($contenttype, 1, $this->user->id);
|
||||||
|
|
||||||
$this->contenttype = new \contenttype_testable\contenttype($systemcontext);
|
$contenttypeclass = "\\$contenttype\\contenttype";
|
||||||
|
$this->contenttype = new $contenttypeclass($systemcontext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -510,4 +513,70 @@ class core_contenttype_contenttype_testcase extends \advanced_testcase {
|
||||||
$this->assertFalse($contenttype->can_manage($contentbyteacher));
|
$this->assertFalse($contenttype->can_manage($contentbyteacher));
|
||||||
$this->assertFalse($contenttype->can_manage($contentbyadmin));
|
$this->assertFalse($contenttype->can_manage($contentbyadmin));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the behaviour of can_download().
|
||||||
|
*
|
||||||
|
* @covers ::can_download
|
||||||
|
*/
|
||||||
|
public function test_can_download() {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->contenttype_setup_scenario_data('contenttype_h5p');
|
||||||
|
|
||||||
|
$managercontent = array_shift($this->contents[$this->manager1->id]);
|
||||||
|
$usercontent = array_shift($this->contents[$this->user->id]);
|
||||||
|
|
||||||
|
// Check the content has been created as expected.
|
||||||
|
$records = $DB->count_records('contentbank_content');
|
||||||
|
$this->assertEquals(4, $records);
|
||||||
|
|
||||||
|
// Check user can download content created by anybody.
|
||||||
|
$this->setUser($this->user);
|
||||||
|
$this->assertTrue($this->contenttype->can_download($usercontent));
|
||||||
|
$this->assertTrue($this->contenttype->can_download($managercontent));
|
||||||
|
|
||||||
|
// Check manager can download all the content too.
|
||||||
|
$this->setUser($this->manager1);
|
||||||
|
$this->assertTrue($this->contenttype->can_download($managercontent));
|
||||||
|
$this->assertTrue($this->contenttype->can_download($usercontent));
|
||||||
|
|
||||||
|
// Unassign capability to manager role and check she cannot download content anymore.
|
||||||
|
unassign_capability('moodle/contentbank:downloadcontent', $this->managerroleid);
|
||||||
|
$this->assertFalse($this->contenttype->can_download($managercontent));
|
||||||
|
$this->assertFalse($this->contenttype->can_download($usercontent));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests get_download_url result.
|
||||||
|
*
|
||||||
|
* @covers ::get_download_url
|
||||||
|
*/
|
||||||
|
public function test_get_download_url() {
|
||||||
|
global $CFG;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
$systemcontext = context_system::instance();
|
||||||
|
|
||||||
|
// Add some content to the content bank.
|
||||||
|
$filename = 'filltheblanks.h5p';
|
||||||
|
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename;
|
||||||
|
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
|
||||||
|
$contents = $generator->generate_contentbank_data('contenttype_testable', 1, 0, $systemcontext, true, $filepath);
|
||||||
|
$content = array_shift($contents);
|
||||||
|
|
||||||
|
// Check the URL is returned OK for a content with file.
|
||||||
|
$contenttype = new contenttype($systemcontext);
|
||||||
|
$url = $contenttype->get_download_url($content);
|
||||||
|
$this->assertNotEmpty($url);
|
||||||
|
$this->assertContains($filename, $url);
|
||||||
|
|
||||||
|
// Check the URL is empty when the content hasn't any file.
|
||||||
|
$record = new stdClass();
|
||||||
|
$content = $contenttype->create_content($record);
|
||||||
|
$url = $contenttype->get_download_url($content);
|
||||||
|
$this->assertEmpty($url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,15 @@ if ($contenttype->can_manage($content)) {
|
||||||
$attributes
|
$attributes
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if ($contenttype->can_download($content)) {
|
||||||
|
// Add the download content item to the menu.
|
||||||
|
$actionmenu->add_secondary_action(new action_menu_link(
|
||||||
|
new moodle_url($contenttype->get_download_url($content)),
|
||||||
|
new pix_icon('t/download', get_string('download')),
|
||||||
|
get_string('download'),
|
||||||
|
false
|
||||||
|
));
|
||||||
|
}
|
||||||
if ($contenttype->can_delete($content)) {
|
if ($contenttype->can_delete($content)) {
|
||||||
// Add the delete content item to the menu.
|
// Add the delete content item to the menu.
|
||||||
$attributes = [
|
$attributes = [
|
||||||
|
|
|
@ -153,6 +153,7 @@ $string['confirmunassignno'] = 'Cancel';
|
||||||
$string['contentbank:access'] = 'Access the content bank';
|
$string['contentbank:access'] = 'Access the content bank';
|
||||||
$string['contentbank:deleteanycontent'] = 'Delete any content from the content bank';
|
$string['contentbank:deleteanycontent'] = 'Delete any content from the content bank';
|
||||||
$string['contentbank:deleteowncontent'] = 'Delete content from own content bank';
|
$string['contentbank:deleteowncontent'] = 'Delete content from own content bank';
|
||||||
|
$string['contentbank:downloadcontent'] = 'Download a content from the content bank';
|
||||||
$string['contentbank:manageanycontent'] = 'Manage any content from the content bank';
|
$string['contentbank:manageanycontent'] = 'Manage any content from the content bank';
|
||||||
$string['contentbank:manageowncontent'] = 'Manage content from own content bank';
|
$string['contentbank:manageowncontent'] = 'Manage content from own content bank';
|
||||||
$string['contentbank:upload'] = 'Upload new content to the content bank';
|
$string['contentbank:upload'] = 'Upload new content to the content bank';
|
||||||
|
|
|
@ -2565,4 +2565,15 @@ $capabilities = array(
|
||||||
'editingteacher' => CAP_ALLOW,
|
'editingteacher' => CAP_ALLOW,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Allow users to download content.
|
||||||
|
'moodle/contentbank:downloadcontent' => [
|
||||||
|
'captype' => 'read',
|
||||||
|
'contextlevel' => CONTEXT_COURSE,
|
||||||
|
'archetypes' => [
|
||||||
|
'manager' => CAP_ALLOW,
|
||||||
|
'coursecreator' => CAP_ALLOW,
|
||||||
|
'editingteacher' => CAP_ALLOW,
|
||||||
|
]
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
defined('MOODLE_INTERNAL') || die();
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$version = 2020082700.00; // YYYYMMDD = weekly release date of this DEV branch.
|
$version = 2020082700.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||||
// RR = release increments - 00 in DEV branches.
|
// RR = release increments - 00 in DEV branches.
|
||||||
// .XX = incremental changes.
|
// .XX = incremental changes.
|
||||||
$release = '3.10dev (Build: 20200827)';// Human-friendly version name
|
$release = '3.10dev (Build: 20200827)';// Human-friendly version name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue