mirror of
https://github.com/moodle/moodle.git
synced 2025-02-13 12:34:28 +01:00
There were two major issues with the previous implementation: * The exported folder name was localised so it was "Files" or "Soubory" etc depending on the current language. Yet URLs referring to the files in that folder were always rewritten with hard-coded English "files". * Files from all fileareas and itemids were all exported to a single target directory. So if there were two files with the same name being exported from multiple areas (such as submission_content and submission_attachment in the workshop module), one would overwrite another. The patch addresses these issues as follows: * To unify the folder name and also to minimise the risk of conflict with a subcontext folder, we now always export stored files under "_files" folder. * Under that folder, there is a subdirectory with the area name and then eventually another subdirectory with non-zero itemid. And there finally the stored_file is exported to under its own file path.
900 lines
31 KiB
PHP
900 lines
31 KiB
PHP
<?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/>.
|
|
|
|
/**
|
|
* Unit Tests for the Moodle Content Writer.
|
|
*
|
|
* @package core_privacy
|
|
* @category test
|
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
global $CFG;
|
|
|
|
use \core_privacy\local\request\writer;
|
|
use \core_privacy\local\request\moodle_content_writer;
|
|
|
|
/**
|
|
* Tests for the \core_privacy API's moodle_content_writer functionality.
|
|
*
|
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
class moodle_content_writer_test extends advanced_testcase {
|
|
|
|
/**
|
|
* Test that exported data is saved correctly within the system context.
|
|
*
|
|
* @dataProvider export_data_provider
|
|
* @param \stdClass $data Data
|
|
*/
|
|
public function test_export_data($data) {
|
|
$context = \context_system::instance();
|
|
$subcontext = [];
|
|
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_data($subcontext, $data);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, $subcontext, 'data.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertEquals($data, $expanded);
|
|
}
|
|
|
|
/**
|
|
* Test that exported data is saved correctly for context/subcontext.
|
|
*
|
|
* @dataProvider export_data_provider
|
|
* @param \stdClass $data Data
|
|
*/
|
|
public function test_export_data_different_context($data) {
|
|
$context = \context_user::instance(\core_user::get_user_by_username('admin')->id);
|
|
$subcontext = ['sub', 'context'];
|
|
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_data($subcontext, $data);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, $subcontext, 'data.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertEquals($data, $expanded);
|
|
}
|
|
|
|
/**
|
|
* Test that exported is saved within the correct directory locations.
|
|
*/
|
|
public function test_export_data_writes_to_multiple_context() {
|
|
$subcontext = ['sub', 'context'];
|
|
|
|
$systemcontext = \context_system::instance();
|
|
$systemdata = (object) [
|
|
'belongsto' => 'system',
|
|
];
|
|
$usercontext = \context_user::instance(\core_user::get_user_by_username('admin')->id);
|
|
$userdata = (object) [
|
|
'belongsto' => 'user',
|
|
];
|
|
|
|
$writer = $this->get_writer_instance();
|
|
|
|
$writer
|
|
->set_context($systemcontext)
|
|
->export_data($subcontext, $systemdata);
|
|
|
|
$writer
|
|
->set_context($usercontext)
|
|
->export_data($subcontext, $userdata);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($systemcontext, $subcontext, 'data.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertEquals($systemdata, $expanded);
|
|
|
|
$contextpath = $this->get_context_path($usercontext, $subcontext, 'data.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertEquals($userdata, $expanded);
|
|
}
|
|
|
|
/**
|
|
* Test that multiple writes to the same location cause the latest version to be written.
|
|
*/
|
|
public function test_export_data_multiple_writes_same_context() {
|
|
$subcontext = ['sub', 'context'];
|
|
|
|
$systemcontext = \context_system::instance();
|
|
$originaldata = (object) [
|
|
'belongsto' => 'system',
|
|
];
|
|
|
|
$newdata = (object) [
|
|
'abc' => 'def',
|
|
];
|
|
|
|
$writer = $this->get_writer_instance();
|
|
|
|
$writer
|
|
->set_context($systemcontext)
|
|
->export_data($subcontext, $originaldata);
|
|
|
|
$writer
|
|
->set_context($systemcontext)
|
|
->export_data($subcontext, $newdata);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($systemcontext, $subcontext, 'data.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertEquals($newdata, $expanded);
|
|
}
|
|
|
|
/**
|
|
* Data provider for exporting user data.
|
|
*/
|
|
public function export_data_provider() {
|
|
return [
|
|
'basic' => [
|
|
(object) [
|
|
'example' => (object) [
|
|
'key' => 'value',
|
|
],
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test that metadata can be set.
|
|
*
|
|
* @dataProvider export_metadata_provider
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $description Description
|
|
*/
|
|
public function test_export_metadata($key, $value, $description) {
|
|
$context = \context_system::instance();
|
|
$subcontext = ['a', 'b', 'c'];
|
|
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_metadata($subcontext, $key, $value, $description);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, $subcontext, 'metadata.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$this->assertEquals($value, $expanded->$key->value);
|
|
$this->assertEquals($description, $expanded->$key->description);
|
|
}
|
|
|
|
/**
|
|
* Test that metadata can be set additively.
|
|
*/
|
|
public function test_export_metadata_additive() {
|
|
$context = \context_system::instance();
|
|
$subcontext = [];
|
|
|
|
$writer = $this->get_writer_instance();
|
|
|
|
$writer
|
|
->set_context($context)
|
|
->export_metadata($subcontext, 'firstkey', 'firstvalue', 'firstdescription');
|
|
|
|
$writer
|
|
->set_context($context)
|
|
->export_metadata($subcontext, 'secondkey', 'secondvalue', 'seconddescription');
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, $subcontext, 'metadata.json');
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
|
|
$this->assertTrue(isset($expanded->firstkey));
|
|
$this->assertEquals('firstvalue', $expanded->firstkey->value);
|
|
$this->assertEquals('firstdescription', $expanded->firstkey->description);
|
|
|
|
$this->assertTrue(isset($expanded->secondkey));
|
|
$this->assertEquals('secondvalue', $expanded->secondkey->value);
|
|
$this->assertEquals('seconddescription', $expanded->secondkey->description);
|
|
}
|
|
|
|
/**
|
|
* Test that metadata can be set additively.
|
|
*/
|
|
public function test_export_metadata_to_multiple_contexts() {
|
|
$systemcontext = \context_system::instance();
|
|
$usercontext = \context_user::instance(\core_user::get_user_by_username('admin')->id);
|
|
$subcontext = [];
|
|
|
|
$writer = $this->get_writer_instance();
|
|
|
|
$writer
|
|
->set_context($systemcontext)
|
|
->export_metadata($subcontext, 'firstkey', 'firstvalue', 'firstdescription')
|
|
->export_metadata($subcontext, 'secondkey', 'secondvalue', 'seconddescription');
|
|
|
|
$writer
|
|
->set_context($usercontext)
|
|
->export_metadata($subcontext, 'firstkey', 'alternativevalue', 'alternativedescription')
|
|
->export_metadata($subcontext, 'thirdkey', 'thirdvalue', 'thirddescription');
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$systemcontextpath = $this->get_context_path($systemcontext, $subcontext, 'metadata.json');
|
|
$this->assertTrue($fileroot->hasChild($systemcontextpath));
|
|
|
|
$json = $fileroot->getChild($systemcontextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
|
|
$this->assertTrue(isset($expanded->firstkey));
|
|
$this->assertEquals('firstvalue', $expanded->firstkey->value);
|
|
$this->assertEquals('firstdescription', $expanded->firstkey->description);
|
|
$this->assertTrue(isset($expanded->secondkey));
|
|
$this->assertEquals('secondvalue', $expanded->secondkey->value);
|
|
$this->assertEquals('seconddescription', $expanded->secondkey->description);
|
|
$this->assertFalse(isset($expanded->thirdkey));
|
|
|
|
$usercontextpath = $this->get_context_path($usercontext, $subcontext, 'metadata.json');
|
|
$this->assertTrue($fileroot->hasChild($usercontextpath));
|
|
|
|
$json = $fileroot->getChild($usercontextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
|
|
$this->assertTrue(isset($expanded->firstkey));
|
|
$this->assertEquals('alternativevalue', $expanded->firstkey->value);
|
|
$this->assertEquals('alternativedescription', $expanded->firstkey->description);
|
|
$this->assertFalse(isset($expanded->secondkey));
|
|
$this->assertTrue(isset($expanded->thirdkey));
|
|
$this->assertEquals('thirdvalue', $expanded->thirdkey->value);
|
|
$this->assertEquals('thirddescription', $expanded->thirdkey->description);
|
|
}
|
|
|
|
/**
|
|
* Data provider for exporting user metadata.
|
|
*
|
|
* return array
|
|
*/
|
|
public function export_metadata_provider() {
|
|
return [
|
|
'basic' => [
|
|
'key',
|
|
'value',
|
|
'This is a description',
|
|
],
|
|
'valuewithspaces' => [
|
|
'key',
|
|
'value has mixed',
|
|
'This is a description',
|
|
],
|
|
'encodedvalue' => [
|
|
'key',
|
|
base64_encode('value has mixed'),
|
|
'This is a description',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Exporting a single stored_file should cause that file to be output in the files directory.
|
|
*/
|
|
public function test_export_area_files() {
|
|
$this->resetAfterTest();
|
|
$context = \context_system::instance();
|
|
$fs = get_file_storage();
|
|
|
|
// Add two files to core_privacy::tests::0.
|
|
$files = [];
|
|
$file = (object) [
|
|
'component' => 'core_privacy',
|
|
'filearea' => 'tests',
|
|
'itemid' => 0,
|
|
'path' => '/',
|
|
'name' => 'a.txt',
|
|
'content' => 'Test file 0',
|
|
];
|
|
$files[] = $file;
|
|
|
|
$file = (object) [
|
|
'component' => 'core_privacy',
|
|
'filearea' => 'tests',
|
|
'itemid' => 0,
|
|
'path' => '/sub/',
|
|
'name' => 'b.txt',
|
|
'content' => 'Test file 1',
|
|
];
|
|
$files[] = $file;
|
|
|
|
// One with a different itemid.
|
|
$file = (object) [
|
|
'component' => 'core_privacy',
|
|
'filearea' => 'tests',
|
|
'itemid' => 1,
|
|
'path' => '/',
|
|
'name' => 'c.txt',
|
|
'content' => 'Other',
|
|
];
|
|
$files[] = $file;
|
|
|
|
// One with a different filearea.
|
|
$file = (object) [
|
|
'component' => 'core_privacy',
|
|
'filearea' => 'alternative',
|
|
'itemid' => 0,
|
|
'path' => '/',
|
|
'name' => 'd.txt',
|
|
'content' => 'Alternative',
|
|
];
|
|
$files[] = $file;
|
|
|
|
// One with a different component.
|
|
$file = (object) [
|
|
'component' => 'core',
|
|
'filearea' => 'tests',
|
|
'itemid' => 0,
|
|
'path' => '/',
|
|
'name' => 'e.txt',
|
|
'content' => 'Other tests',
|
|
];
|
|
$files[] = $file;
|
|
|
|
foreach ($files as $file) {
|
|
$record = [
|
|
'contextid' => $context->id,
|
|
'component' => $file->component,
|
|
'filearea' => $file->filearea,
|
|
'itemid' => $file->itemid,
|
|
'filepath' => $file->path,
|
|
'filename' => $file->name,
|
|
];
|
|
|
|
$file->namepath = '/' . $file->filearea . '/' . ($file->itemid ?: '') . $file->path . $file->name;
|
|
$file->storedfile = $fs->create_file_from_string($record, $file->content);
|
|
}
|
|
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_area_files([], 'core_privacy', 'tests', 0);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$firstfiles = array_slice($files, 0, 2);
|
|
foreach ($firstfiles as $file) {
|
|
$contextpath = $this->get_context_path($context, ['_files'], $file->namepath);
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
$this->assertEquals($file->content, $fileroot->getChild($contextpath)->getContent());
|
|
}
|
|
|
|
$otherfiles = array_slice($files, 2);
|
|
foreach ($otherfiles as $file) {
|
|
$contextpath = $this->get_context_path($context, ['_files'], $file->namepath);
|
|
$this->assertFalse($fileroot->hasChild($contextpath));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Exporting a single stored_file should cause that file to be output in the files directory.
|
|
*
|
|
* @dataProvider export_file_provider
|
|
* @param string $filepath File path
|
|
* @param string $filename File name
|
|
* @param string $content Content
|
|
*/
|
|
public function test_export_file($filearea, $itemid, $filepath, $filename, $content) {
|
|
$this->resetAfterTest();
|
|
$context = \context_system::instance();
|
|
$filenamepath = '/' . $filearea . '/' . ($itemid ?: '') . $filepath . $filename;
|
|
|
|
$filerecord = array(
|
|
'contextid' => $context->id,
|
|
'component' => 'core_privacy',
|
|
'filearea' => $filearea,
|
|
'itemid' => $itemid,
|
|
'filepath' => $filepath,
|
|
'filename' => $filename,
|
|
);
|
|
|
|
$fs = get_file_storage();
|
|
$file = $fs->create_file_from_string($filerecord, $content);
|
|
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_file([], $file);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, ['_files'], $filenamepath);
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
$this->assertEquals($content, $fileroot->getChild($contextpath)->getContent());
|
|
}
|
|
|
|
/**
|
|
* Data provider for the test_export_file function.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function export_file_provider() {
|
|
return [
|
|
'basic' => [
|
|
'intro',
|
|
0,
|
|
'/',
|
|
'testfile.txt',
|
|
'An example file content',
|
|
],
|
|
'longpath' => [
|
|
'attachments',
|
|
'12',
|
|
'/path/within/a/path/within/a/path/',
|
|
'testfile.txt',
|
|
'An example file content',
|
|
],
|
|
'pathwithspaces' => [
|
|
'intro',
|
|
0,
|
|
'/path with/some spaces/',
|
|
'testfile.txt',
|
|
'An example file content',
|
|
],
|
|
'filewithspaces' => [
|
|
'submission_attachments',
|
|
1,
|
|
'/path with/some spaces/',
|
|
'test file.txt',
|
|
'An example file content',
|
|
],
|
|
'image' => [
|
|
'intro',
|
|
0,
|
|
'/',
|
|
'logo.png',
|
|
file_get_contents(__DIR__ . '/fixtures/logo.png'),
|
|
],
|
|
'UTF8' => [
|
|
'submission_content',
|
|
2,
|
|
'/Žluťoučký/',
|
|
'koníček.txt',
|
|
'koníček',
|
|
],
|
|
'EUC-JP' => [
|
|
'intro',
|
|
0,
|
|
'/言語設定/',
|
|
'言語設定.txt',
|
|
'言語設定',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against a user.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_user($component, $key, $value, $desc) {
|
|
$admin = \core_user::get_user_by_username('admin');
|
|
|
|
$writer = $this->get_writer_instance();
|
|
|
|
$context = \context_user::instance($admin->id);
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against a course category.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_coursecat($component, $key, $value, $desc) {
|
|
global $DB;
|
|
|
|
$categories = $DB->get_records('course_categories');
|
|
$firstcategory = reset($categories);
|
|
|
|
$context = \context_coursecat::instance($firstcategory->id);
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against a course.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_course($component, $key, $value, $desc) {
|
|
global $DB;
|
|
|
|
$this->resetAfterTest();
|
|
|
|
$course = $this->getDataGenerator()->create_course();
|
|
|
|
$context = \context_course::instance($course->id);
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against a module context.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_module($component, $key, $value, $desc) {
|
|
global $DB;
|
|
|
|
$this->resetAfterTest();
|
|
|
|
$course = $this->getDataGenerator()->create_course();
|
|
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
|
|
|
|
$context = \context_module::instance($forum->cmid);
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can not be exported against a block context.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_block($component, $key, $value, $desc) {
|
|
global $DB;
|
|
|
|
$blocks = $DB->get_records('block_instances');
|
|
$block = reset($blocks);
|
|
|
|
$context = \context_block::instance($block->id);
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against the system.
|
|
*
|
|
* @dataProvider export_user_preference_provider
|
|
* @param string $component Component
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @param string $desc Description
|
|
*/
|
|
public function test_export_user_preference_context_system($component, $key, $value, $desc) {
|
|
$context = \context_system::instance();
|
|
$writer = $this->get_writer_instance()
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, $value, $desc);
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals($value, $data->value);
|
|
$this->assertEquals($desc, $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against the system.
|
|
*/
|
|
public function test_export_multiple_user_preference_context_system() {
|
|
$context = \context_system::instance();
|
|
$writer = $this->get_writer_instance();
|
|
$component = 'core_privacy';
|
|
|
|
$writer
|
|
->set_context($context)
|
|
->export_user_preference($component, 'key1', 'val1', 'desc1')
|
|
->export_user_preference($component, 'key2', 'val2', 'desc2');
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
|
|
$this->assertTrue(isset($expanded->key1));
|
|
$data = $expanded->key1;
|
|
$this->assertEquals('val1', $data->value);
|
|
$this->assertEquals('desc1', $data->description);
|
|
|
|
$this->assertTrue(isset($expanded->key2));
|
|
$data = $expanded->key2;
|
|
$this->assertEquals('val2', $data->value);
|
|
$this->assertEquals('desc2', $data->description);
|
|
}
|
|
|
|
/**
|
|
* User preferences can be exported against the system.
|
|
*/
|
|
public function test_export_user_preference_replace() {
|
|
$context = \context_system::instance();
|
|
$writer = $this->get_writer_instance();
|
|
$component = 'core_privacy';
|
|
$key = 'key';
|
|
|
|
$writer
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, 'val1', 'desc1');
|
|
|
|
$writer
|
|
->set_context($context)
|
|
->export_user_preference($component, $key, 'val2', 'desc2');
|
|
|
|
$fileroot = $this->fetch_exported_content($writer);
|
|
|
|
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
|
|
$this->assertTrue($fileroot->hasChild($contextpath));
|
|
|
|
$json = $fileroot->getChild($contextpath)->getContent();
|
|
$expanded = json_decode($json);
|
|
|
|
$this->assertTrue(isset($expanded->$key));
|
|
$data = $expanded->$key;
|
|
$this->assertEquals('val2', $data->value);
|
|
$this->assertEquals('desc2', $data->description);
|
|
}
|
|
|
|
/**
|
|
* Provider for various user preferences.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function export_user_preference_provider() {
|
|
return [
|
|
'basic' => [
|
|
'core_privacy',
|
|
'onekey',
|
|
'value',
|
|
'description',
|
|
],
|
|
'encodedvalue' => [
|
|
'core_privacy',
|
|
'donkey',
|
|
base64_encode('value'),
|
|
'description',
|
|
],
|
|
'long description' => [
|
|
'core_privacy',
|
|
'twokey',
|
|
'value',
|
|
'This is a much longer description which actually states what this is used for. Blah blah blah.',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get a fresh content writer.
|
|
*
|
|
* @return moodle_content_writer
|
|
*/
|
|
public function get_writer_instance() {
|
|
$factory = $this->createMock(writer::class);
|
|
return new moodle_content_writer($factory);
|
|
}
|
|
|
|
/**
|
|
* Fetch the exported content for inspection.
|
|
*
|
|
* @param moodle_content_writer $writer
|
|
* @return \org\bovigo\vfs\vfsStreamDirectory
|
|
*/
|
|
protected function fetch_exported_content(moodle_content_writer $writer) {
|
|
$export = $writer
|
|
->set_context(\context_system::instance())
|
|
->finalise_content();
|
|
|
|
$fileroot = \org\bovigo\vfs\vfsStream::setup('root');
|
|
|
|
$target = \org\bovigo\vfs\vfsStream::url('root');
|
|
$fp = get_file_packer();
|
|
$fp->extract_to_pathname($export, $target);
|
|
|
|
return $fileroot;
|
|
}
|
|
|
|
/**
|
|
* Determine the path for the current context.
|
|
*
|
|
* Note: This is a wrapper around the real function.
|
|
*
|
|
* @param \context $context The context being written
|
|
* @param array $subcontext The subcontext path
|
|
* @param string $name THe name of the file target
|
|
* @return array The context path.
|
|
*/
|
|
protected function get_context_path($context, $subcontext = null, $name = '') {
|
|
$rc = new ReflectionClass(moodle_content_writer::class);
|
|
$writer = $this->get_writer_instance();
|
|
$writer->set_context($context);
|
|
|
|
if (null === $subcontext) {
|
|
$rcm = $rc->getMethod('get_context_path');
|
|
$rcm->setAccessible(true);
|
|
return $rcm->invoke($writer);
|
|
} else {
|
|
$rcm = $rc->getMethod('get_path');
|
|
$rcm->setAccessible(true);
|
|
return $rcm->invoke($writer, $subcontext, $name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test correct rewriting of @@PLUGINFILE@@ in the exported contents.
|
|
*
|
|
* @dataProvider rewrite_pluginfile_urls_provider
|
|
* @param string $filearea The filearea within that component.
|
|
* @param int $itemid Which item those files belong to.
|
|
* @param string $input Raw text as stored in the database.
|
|
* @param string $expectedoutput Expected output of URL rewriting.
|
|
*/
|
|
public function test_rewrite_pluginfile_urls($filearea, $itemid, $input, $expectedoutput) {
|
|
|
|
$writer = $this->get_writer_instance();
|
|
$writer->set_context(\context_system::instance());
|
|
|
|
$realoutput = $writer->rewrite_pluginfile_urls([], 'core_test', $filearea, $itemid, $input);
|
|
|
|
$this->assertEquals($expectedoutput, $realoutput);
|
|
}
|
|
|
|
/**
|
|
* Provides testable sample data for {@link self::test_rewrite_pluginfile_urls()}.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function rewrite_pluginfile_urls_provider() {
|
|
return [
|
|
'zeroitemid' => [
|
|
'intro',
|
|
0,
|
|
'<p><img src="@@PLUGINFILE@@/hello.gif" /></p>',
|
|
'<p><img src="_files/intro/hello.gif" /></p>',
|
|
],
|
|
'nonzeroitemid' => [
|
|
'submission_content',
|
|
34,
|
|
'<p><img src="@@PLUGINFILE@@/first.png" alt="First" /></p>',
|
|
'<p><img src="_files/submission_content/34/first.png" alt="First" /></p>',
|
|
],
|
|
'withfilepath' => [
|
|
'post_content',
|
|
9889,
|
|
'<a href="@@PLUGINFILE@@/embedded/docs/muhehe.exe">Click here!</a>',
|
|
'<a href="_files/post_content/9889/embedded/docs/muhehe.exe">Click here!</a>',
|
|
],
|
|
];
|
|
}
|
|
}
|