Merge branch 'MDL-77958-master' of https://github.com/andrewnicols/moodle
This commit is contained in:
@@ -21,6 +21,7 @@ use backup_controller;
|
||||
use backup_root_task;
|
||||
use cm_info;
|
||||
use core\context\user;
|
||||
use stored_file;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -46,14 +47,14 @@ class activity_packager {
|
||||
*/
|
||||
public function __construct(
|
||||
protected cm_info $cminfo,
|
||||
protected int $userid
|
||||
protected int $userid,
|
||||
) {
|
||||
// Check backup/restore support.
|
||||
if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) {
|
||||
throw new \coding_exception("Cannot backup module $cminfo->modname. This module doesn't support the backup feature.");
|
||||
}
|
||||
|
||||
$this->controller = new backup_controller (
|
||||
$this->controller = new backup_controller(
|
||||
backup::TYPE_1ACTIVITY,
|
||||
$cminfo->id,
|
||||
backup::FORMAT_MOODLE,
|
||||
@@ -66,10 +67,9 @@ class activity_packager {
|
||||
/**
|
||||
* Prepare the backup file using appropriate setting overrides and return relevant information.
|
||||
*
|
||||
* @return array Array containing packaged file and stored_file object describing it.
|
||||
* Array in the format [storedfile => stored_file object, filecontents => raw file].
|
||||
* @return stored_file
|
||||
*/
|
||||
public function get_package(): array {
|
||||
public function get_package(): stored_file {
|
||||
$alltasksettings = $this->get_all_task_settings();
|
||||
|
||||
// Override relevant settings to remove user data when packaging to share to MoodleNet.
|
||||
@@ -106,7 +106,6 @@ class activity_packager {
|
||||
* @param array $alltasksettings All task settings.
|
||||
* @param string $settingname The name of the setting to be overridden (task class name format).
|
||||
* @param int $settingvalue Value to be given to the setting.
|
||||
* @return void
|
||||
*/
|
||||
protected function override_task_setting(array $alltasksettings, string $settingname, int $settingvalue): void {
|
||||
if (empty($rootsettings = $alltasksettings[backup_root_task::class])) {
|
||||
@@ -123,13 +122,12 @@ class activity_packager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Package the activity identified by CMID.
|
||||
* Package the activity identified by CMID into a new stored_file.
|
||||
*
|
||||
* @return array Array containing packaged file and stored_file object describing it.
|
||||
* Array in the format [storedfile => stored_file object, filecontents => raw file].
|
||||
* @throws \moodle_exception.
|
||||
* @return stored_file
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
protected function package(): array {
|
||||
protected function package(): stored_file {
|
||||
// Execute the backup and fetch the result.
|
||||
$this->controller->execute_plan();
|
||||
$result = $this->controller->get_results();
|
||||
@@ -147,7 +145,7 @@ class activity_packager {
|
||||
}
|
||||
|
||||
// Create the location we want to copy this file to.
|
||||
$fr = [
|
||||
$filerecord = [
|
||||
'contextid' => user::instance($this->userid)->id,
|
||||
'userid' => $this->userid,
|
||||
'component' => 'user',
|
||||
@@ -159,19 +157,11 @@ class activity_packager {
|
||||
|
||||
// Create the local file based on the backup.
|
||||
$fs = get_file_storage();
|
||||
$packagedfiledata = [
|
||||
'storedfile' => $fs->create_file_from_storedfile($fr, $backupfile),
|
||||
];
|
||||
$file = $fs->create_file_from_storedfile($filerecord, $backupfile);
|
||||
|
||||
// Delete the backup now it has been created in the file area.
|
||||
$backupfile->delete();
|
||||
|
||||
// Ensure we can handle files at the upper end of the limit supported by MoodleNet.
|
||||
raise_memory_limit(activity_sender::MAX_FILESIZE);
|
||||
|
||||
// Get the actual file content.
|
||||
$packagedfiledata['filecontents'] = $packagedfiledata['storedfile']->get_content();
|
||||
|
||||
return $packagedfiledata;
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ use core\event\moodlenet_resource_exported;
|
||||
use core\oauth2\client;
|
||||
use moodle_exception;
|
||||
use stdClass;
|
||||
use stored_file;
|
||||
|
||||
/**
|
||||
* API for sharing Moodle LMS activities to MoodleNet instances.
|
||||
@@ -65,9 +66,8 @@ class activity_sender {
|
||||
protected int $userid,
|
||||
protected moodlenet_client $moodlenetclient,
|
||||
protected client $oauthclient,
|
||||
protected int $shareformat = self::SHARE_FORMAT_BACKUP
|
||||
protected int $shareformat = self::SHARE_FORMAT_BACKUP,
|
||||
) {
|
||||
|
||||
[$this->course, $this->cminfo] = get_course_and_cm_from_cmid($cmid);
|
||||
|
||||
if (!in_array($shareformat, $this->get_allowed_share_formats())) {
|
||||
@@ -90,7 +90,7 @@ class activity_sender {
|
||||
$issuer = $this->oauthclient->get_issuer();
|
||||
|
||||
// Check user can share to the requested MoodleNet instance.
|
||||
$coursecontext = \context_course::instance($this->course->id);
|
||||
$coursecontext = \core\context\course::instance($this->course->id);
|
||||
$usercanshare = utilities::can_user_share($coursecontext, $this->userid);
|
||||
|
||||
if ($usercanshare && utilities::is_valid_instance($issuer) && $this->oauthclient->is_logged_in()) {
|
||||
@@ -108,17 +108,15 @@ class activity_sender {
|
||||
$filedata = $this->prepare_share_contents();
|
||||
|
||||
// If we have successfully prepared a file to share of permitted size, share it to MoodleNet.
|
||||
if (!empty($filedata['storedfile'])) {
|
||||
|
||||
if (!empty($filedata)) {
|
||||
// Avoid sending a file larger than the defined limit.
|
||||
$filesize = $filedata['storedfile']->get_filesize();
|
||||
$filesize = $filedata->get_filesize();
|
||||
if ($filesize > self::MAX_FILESIZE) {
|
||||
$filedata['storedfile']->delete();
|
||||
throw new moodle_exception('moodlenet:sharefilesizelimitexceeded', 'core', '',
|
||||
[
|
||||
'filesize' => $filesize,
|
||||
'filesizelimit' => self::MAX_FILESIZE,
|
||||
]);
|
||||
$filedata->delete();
|
||||
throw new moodle_exception('moodlenet:sharefilesizelimitexceeded', 'core', '', [
|
||||
'filesize' => $filesize,
|
||||
'filesizelimit' => self::MAX_FILESIZE,
|
||||
]);
|
||||
}
|
||||
|
||||
// MoodleNet only accept plaintext descriptions.
|
||||
@@ -130,7 +128,11 @@ class activity_sender {
|
||||
['context' => $coursecontext]
|
||||
);
|
||||
|
||||
$response = $this->moodlenetclient->create_resource_from_file($filedata, $this->cminfo->name, $resourcedescription);
|
||||
$response = $this->moodlenetclient->create_resource_from_stored_file(
|
||||
$filedata,
|
||||
$this->cminfo->name,
|
||||
$resourcedescription,
|
||||
);
|
||||
$responsecode = $response->getStatusCode();
|
||||
|
||||
$responsebody = json_decode($response->getBody());
|
||||
@@ -140,7 +142,7 @@ class activity_sender {
|
||||
|
||||
// Delete the generated file now it is no longer required.
|
||||
// (It has either been sent, or failed - retries not currently supported).
|
||||
$filedata['storedfile']->delete();
|
||||
$filedata->delete();
|
||||
}
|
||||
|
||||
// Log every attempt to share (and whether or not it was successful).
|
||||
@@ -155,20 +157,17 @@ class activity_sender {
|
||||
/**
|
||||
* Prepare the data for sharing, in the format specified.
|
||||
*
|
||||
* @return array Array of metadata about the file, as well as a stored_file object for the file.
|
||||
* @return stored_file
|
||||
*/
|
||||
protected function prepare_share_contents(): array {
|
||||
|
||||
protected function prepare_share_contents(): stored_file {
|
||||
switch ($this->shareformat) {
|
||||
case self::SHARE_FORMAT_BACKUP:
|
||||
default:
|
||||
// If sharing the activity as a backup, prepare the packaged backup.
|
||||
$packager = new activity_packager($this->cminfo, $this->userid);
|
||||
$filedata = $packager->get_package();
|
||||
break;
|
||||
return $packager->get_package();
|
||||
default:
|
||||
throw new \coding_exception("Unknown share format: {$this->shareformat}'");
|
||||
};
|
||||
|
||||
return $filedata;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,10 +180,10 @@ class activity_sender {
|
||||
* @return void
|
||||
*/
|
||||
protected function log_event(
|
||||
\context $coursecontext,
|
||||
\core\context $coursecontext,
|
||||
int $cmid,
|
||||
string $resourceurl,
|
||||
int $responsecode
|
||||
int $responsecode,
|
||||
): void {
|
||||
$event = moodlenet_resource_exported::create([
|
||||
'context' => $coursecontext,
|
||||
@@ -203,7 +202,6 @@ class activity_sender {
|
||||
* @return array Array of supported share format values.
|
||||
*/
|
||||
protected function get_allowed_share_formats(): array {
|
||||
|
||||
return [
|
||||
self::SHARE_FORMAT_BACKUP,
|
||||
];
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace core\moodlenet;
|
||||
|
||||
use core\http_client;
|
||||
use core\oauth2\client;
|
||||
use stored_file;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* MoodleNet client which handles direct outbound communication with MoodleNet instances.
|
||||
@@ -54,22 +57,31 @@ class moodlenet_client {
|
||||
/**
|
||||
* Create a resource on MoodleNet which includes a file.
|
||||
*
|
||||
* @param array $filedata The file data in the format [storedfile => stored_file object, filecontents => raw file].
|
||||
* @param stored_file $file The file data to send to MoodleNet.
|
||||
* @param string $resourcename The name of the resource being shared.
|
||||
* @param string $resourcedescription A description of the resource being shared.
|
||||
* @return Psr\Http\Message\ResponseInterface The HTTP client response from MoodleNet.
|
||||
* @return \Psr\Http\Message\ResponseInterface The HTTP client response from MoodleNet.
|
||||
*/
|
||||
public function create_resource_from_file(array $filedata, string $resourcename, $resourcedescription) {
|
||||
public function create_resource_from_stored_file(
|
||||
stored_file $file,
|
||||
string $resourcename,
|
||||
string $resourcedescription,
|
||||
): ResponseInterface {
|
||||
// This may take a long time if a lot of data is being shared.
|
||||
\core_php_time_limit::raise();
|
||||
|
||||
$moodleneturl = $this->oauthclient->get_issuer()->get('baseurl');
|
||||
$apiurl = rtrim($moodleneturl, '/') . self::API_CREATE_RESOURCE_URI;
|
||||
|
||||
$requestdata = $this->prepare_file_share_request_data($filedata, $resourcename, $resourcedescription);
|
||||
$requestdata = $this->prepare_file_share_request_data(
|
||||
$file->get_filename(),
|
||||
$file->get_mimetype(),
|
||||
$file->get_psr_stream(),
|
||||
$resourcename,
|
||||
$resourcedescription,
|
||||
);
|
||||
|
||||
return $this->httpclient->request('POST', $apiurl, $requestdata);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +93,13 @@ class moodlenet_client {
|
||||
* @param string $resourcedescription A description of the resource being shared.
|
||||
* @return array Data in the format required to send a file to MoodleNet using \core\httpclient.
|
||||
*/
|
||||
protected function prepare_file_share_request_data(array $filedata, string $resourcename, $resourcedescription): array {
|
||||
protected function prepare_file_share_request_data(
|
||||
string $filename,
|
||||
string $mimetype,
|
||||
StreamInterface $stream,
|
||||
string $resourcename,
|
||||
$resourcedescription,
|
||||
): array {
|
||||
return [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $this->oauthclient->get_accesstoken()->token,
|
||||
@@ -99,11 +117,10 @@ class moodlenet_client {
|
||||
],
|
||||
[
|
||||
'name' => 'filecontents',
|
||||
'contents' => $filedata['filecontents'],
|
||||
'contents' => $stream,
|
||||
'headers' => [
|
||||
'Content-Disposition' => 'form-data; name=".resource"; filename="' .
|
||||
$filedata['storedfile']->get_filename() . '"',
|
||||
'Content-Type' => $filedata['storedfile']->get_mimetype(),
|
||||
'Content-Disposition' => 'form-data; name=".resource"; filename="' . $filename . '"',
|
||||
'Content-Type' => $mimetype,
|
||||
'Content-Transfer-Encoding' => 'binary',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace core\moodlenet;
|
||||
|
||||
use context_course;
|
||||
use core\oauth2\issuer;
|
||||
|
||||
/**
|
||||
@@ -46,11 +45,11 @@ class utilities {
|
||||
/**
|
||||
* Check whether a user has the capabilities required to share activities from a given course to MoodleNet.
|
||||
*
|
||||
* @param context_course $coursecontext Course context where the activity would be shared from.
|
||||
* @param \core\context\course $coursecontext Course context where the activity would be shared from.
|
||||
* @param int $userid The user ID being checked.
|
||||
* @return boolean
|
||||
*/
|
||||
public static function can_user_share(context_course $coursecontext, int $userid): bool {
|
||||
public static function can_user_share(\core\context\course $coursecontext, int $userid): bool {
|
||||
return (has_capability('moodle/moodlenet:shareactivity', $coursecontext, $userid) &&
|
||||
has_capability('moodle/backup:backupactivity', $coursecontext, $userid));
|
||||
}
|
||||
|
||||
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Core file system class definition.
|
||||
*
|
||||
* @package core_files
|
||||
* @copyright 2017 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* File system class used for low level access to real files in filedir.
|
||||
@@ -631,6 +623,16 @@ abstract class file_system {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PSR7 Stream for the specified file which implements the PSR Message StreamInterface.
|
||||
*
|
||||
* @param stored_file $file
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function get_psr_stream(stored_file $file): StreamInterface {
|
||||
return \GuzzleHttp\Psr7\Utils::streamFor($this->get_content_file_handle($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the mime information for the specified stored file.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/lib/filestorage/file_progress.php');
|
||||
@@ -437,6 +439,18 @@ class stored_file {
|
||||
return $this->filesystem->get_content_file_handle($this, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a read-only PSR-7 stream for this file.
|
||||
*
|
||||
* Note: This stream is read-only. If you want to modify the file, create a new file and delete the old one.
|
||||
* The File API creates immutable files.
|
||||
*
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function get_psr_stream(): StreamInterface {
|
||||
return $this->filesystem->get_psr_stream($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps file content to page.
|
||||
*/
|
||||
|
||||
@@ -1077,6 +1077,24 @@ class file_system_test extends \advanced_testcase {
|
||||
$fs->get_content_file_handle($file, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that get_content_file_handle returns a valid file handle.
|
||||
*
|
||||
* @covers ::get_psr_stream
|
||||
*/
|
||||
public function test_get_psr_stream(): void {
|
||||
$file = $this->get_stored_file('');
|
||||
|
||||
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
||||
$fs->method('get_remote_path_from_storedfile')
|
||||
->willReturn(__FILE__);
|
||||
|
||||
$stream = $fs->get_psr_stream($file);
|
||||
$this->assertInstanceOf(\Psr\Http\Message\StreamInterface::class, $stream);
|
||||
$this->assertEquals(file_get_contents(__FILE__), $stream->getContents());
|
||||
$this->assertFalse($stream->isWritable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that mimetype_from_hash returns the correct mimetype with
|
||||
* a file whose filename suggests mimetype.
|
||||
@@ -1248,4 +1266,3 @@ class file_system_test extends \advanced_testcase {
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,4 +91,33 @@ class stored_file_test extends advanced_testcase {
|
||||
$this->assertEquals(1200, $size['width']);
|
||||
$this->assertEquals(297, $size['height']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that get_content_file_handle returns a valid file handle.
|
||||
*
|
||||
* @covers ::get_psr_stream
|
||||
*/
|
||||
public function test_get_psr_stream(): void {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$filename = 'testimage.jpg';
|
||||
$filepath = $CFG->dirroot . '/lib/filestorage/tests/fixtures/' . $filename;
|
||||
$filerecord = [
|
||||
'contextid' => context_system::instance()->id,
|
||||
'component' => 'core',
|
||||
'filearea' => 'unittest',
|
||||
'itemid' => 0,
|
||||
'filepath' => '/',
|
||||
'filename' => $filename,
|
||||
];
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->create_file_from_pathname($filerecord, $filepath);
|
||||
|
||||
$stream = $file->get_psr_stream();
|
||||
$this->assertInstanceOf(\Psr\Http\Message\StreamInterface::class, $stream);
|
||||
$this->assertEquals(file_get_contents($filepath), $stream->getContents());
|
||||
$this->assertFalse($stream->isWritable());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,9 +33,8 @@ class activity_packager_test extends \advanced_testcase {
|
||||
*
|
||||
* @covers ::override_task_setting
|
||||
* @covers ::get_all_task_settings
|
||||
* @return void
|
||||
*/
|
||||
public function test_override_task_setting() {
|
||||
public function test_override_task_setting(): void {
|
||||
global $USER;
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
@@ -99,9 +98,8 @@ class activity_packager_test extends \advanced_testcase {
|
||||
*
|
||||
* @covers ::get_package
|
||||
* @covers ::package
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_package() {
|
||||
public function test_get_package(): void {
|
||||
global $USER;
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
@@ -120,25 +118,18 @@ class activity_packager_test extends \advanced_testcase {
|
||||
$packager = new activity_packager($cminfo, $USER->id);
|
||||
$package = $packager->get_package();
|
||||
|
||||
$this->assertEquals(2, count($package));
|
||||
|
||||
// Confirm there are backup file contents returned.
|
||||
$this->assertTrue(array_key_exists('filecontents', $package));
|
||||
$this->assertNotEmpty($package['filecontents']);
|
||||
|
||||
// Confirm the expected stored_file object is returned.
|
||||
$this->assertTrue(array_key_exists('storedfile', $package));
|
||||
$this->assertInstanceOf(\stored_file::class, $package['storedfile']);
|
||||
$this->assertInstanceOf(\stored_file::class, $package);
|
||||
|
||||
// Check some known values in the returned stored_file object to confirm they match the file we have packaged.
|
||||
$this->assertNotEmpty($package['storedfile']->get_contenthash());
|
||||
$this->assertEquals(user::instance($USER->id)->id, $package['storedfile']->get_contextid());
|
||||
$this->assertEquals('user', $package['storedfile']->get_component());
|
||||
$this->assertEquals('draft', $package['storedfile']->get_filearea());
|
||||
$this->assertEquals('assign_backup.mbz', $package['storedfile']->get_filename());
|
||||
$this->assertGreaterThan(0, $package['storedfile']->get_filesize());
|
||||
$timecreated = $package['storedfile']->get_timecreated();
|
||||
$this->assertNotEmpty($package->get_contenthash());
|
||||
$this->assertEquals(user::instance($USER->id)->id, $package->get_contextid());
|
||||
$this->assertEquals('user', $package->get_component());
|
||||
$this->assertEquals('draft', $package->get_filearea());
|
||||
$this->assertEquals('assign_backup.mbz', $package->get_filename());
|
||||
$this->assertGreaterThan(0, $package->get_filesize());
|
||||
$timecreated = $package->get_timecreated();
|
||||
$this->assertGreaterThanOrEqual($currenttime, $timecreated);
|
||||
$this->assertEquals($timecreated, $package['storedfile']->get_timemodified());
|
||||
$this->assertEquals($timecreated, $package->get_timemodified());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,6 @@ use ReflectionMethod;
|
||||
use stdClass;
|
||||
use testing_data_generator;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once('helpers.php');
|
||||
|
||||
/**
|
||||
* Unit tests for {@see activity_sender}.
|
||||
*
|
||||
@@ -56,6 +52,12 @@ class activity_sender_test extends \advanced_testcase {
|
||||
/** @var MockObject $mockoauthclient Mock OAuth client. */
|
||||
private MockObject $mockoauthclient;
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
require_once(__DIR__ . '/helpers.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
@@ -83,9 +85,8 @@ class activity_sender_test extends \advanced_testcase {
|
||||
* Test prepare_share_contents method.
|
||||
*
|
||||
* @covers ::prepare_share_contents
|
||||
* @return void
|
||||
*/
|
||||
public function test_prepare_share_contents() {
|
||||
public function test_prepare_share_contents(): void {
|
||||
global $USER;
|
||||
$this->setAdminUser();
|
||||
|
||||
@@ -126,13 +127,9 @@ class activity_sender_test extends \advanced_testcase {
|
||||
activity_sender::SHARE_FORMAT_BACKUP
|
||||
));
|
||||
$this->assertNotEmpty($package);
|
||||
// Confirm there are backup file contents returned.
|
||||
$this->assertTrue(array_key_exists('filecontents', $package));
|
||||
$this->assertNotEmpty($package['filecontents']);
|
||||
|
||||
// Confirm the expected stored_file object is returned.
|
||||
$this->assertTrue(array_key_exists('storedfile', $package));
|
||||
$this->assertInstanceOf(\stored_file::class, $package['storedfile']);
|
||||
$this->assertInstanceOf(\stored_file::class, $package);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,13 +138,12 @@ class activity_sender_test extends \advanced_testcase {
|
||||
* @dataProvider share_activity_provider
|
||||
* @covers ::share_activity
|
||||
* @covers ::log_event
|
||||
* @covers \core\moodlenet\moodlenet_client::create_resource_from_file
|
||||
* @covers \core\moodlenet\moodlenet_client::create_resource_from_stored_file
|
||||
* @covers \core\moodlenet\moodlenet_client::prepare_file_share_request_data
|
||||
* @param ResponseInterface $httpresponse
|
||||
* @param array $expected
|
||||
* @return void
|
||||
*/
|
||||
public function test_share_activity(ResponseInterface $httpresponse, array $expected) {
|
||||
public function test_share_activity(ResponseInterface $httpresponse, array $expected): void {
|
||||
global $CFG, $USER;
|
||||
$this->setAdminUser();
|
||||
|
||||
|
||||
@@ -138,6 +138,8 @@ information provided here is intended especially for developers.
|
||||
- taskslimit - to limit the number of tasks in one run
|
||||
- failed - to limit the run to only the tasks that failed in their previous run
|
||||
Can be mixed, apart from 'id' of course.
|
||||
* The file_system class now declares a new, optional, `get_psr_stream` function which allows a Stream implementing `\Psr\Http\Message\StreamInterface` to be returned.
|
||||
A default implementation which uses the existing file handle resource is used by default, but this should be extended by file_system implementations where relevant.
|
||||
|
||||
=== 4.1 ===
|
||||
|
||||
|
||||
Reference in New Issue
Block a user