1
0
mirror of https://github.com/moodle/moodle.git synced 2025-04-25 10:26:17 +02:00

MDL-64254 mod_forum: New WS mod_forum_prepare_draft_area_for_post

This commit is contained in:
Juan Leyva 2019-08-23 19:53:52 +01:00
parent 9a023ef3b4
commit 131bfaa8cd
3 changed files with 248 additions and 0 deletions

@ -191,4 +191,12 @@ $functions = array(
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_forum_prepare_draft_area_for_post' => array(
'classname' => 'mod_forum_external',
'methodname' => 'prepare_draft_area_for_post',
'classpath' => 'mod/forum/externallib.php',
'description' => 'Prepares a draft area for editing a post.',
'type' => 'write',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
);

@ -2232,4 +2232,166 @@ class mod_forum_external extends external_api {
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.8
*/
public static function prepare_draft_area_for_post_parameters() {
return new external_function_parameters(
array(
'postid' => new external_value(PARAM_INT, 'Post to prepare the draft area for.'),
'area' => new external_value(PARAM_ALPHA, 'Area to prepare: attachment or post.'),
'draftitemid' => new external_value(PARAM_INT, 'The draft item id to use. 0 to generate one.',
VALUE_DEFAULT, 0),
'filestokeep' => new external_multiple_structure(
new external_single_structure(
array(
'filename' => new external_value(PARAM_FILE, 'File name.'),
'filepath' => new external_value(PARAM_PATH, 'File path.'),
)
), 'Only keep these files in the draft file area. Empty for keeping all.', VALUE_DEFAULT, []
),
)
);
}
/**
* Prepares a draft area for editing a post.
*
* @param int $postid post to prepare the draft area for
* @param string $area area to prepare attachment or post
* @param int $draftitemid the draft item id to use. 0 to generate a new one.
* @param array $filestokeep only keep these files in the draft file area. Empty for keeping all.
* @return array of files in the area, the area options and the draft item id
* @since Moodle 3.8
* @throws moodle_exception
*/
public static function prepare_draft_area_for_post($postid, $area, $draftitemid = 0, $filestokeep = []) {
global $USER;
$params = self::validate_parameters(
self::prepare_draft_area_for_post_parameters(),
array(
'postid' => $postid,
'area' => $area,
'draftitemid' => $draftitemid,
'filestokeep' => $filestokeep,
)
);
$directionallowedvalues = ['ASC', 'DESC'];
$allowedareas = ['attachment', 'post'];
if (!in_array($params['area'], $allowedareas)) {
throw new invalid_parameter_exception('Invalid value for area parameter
(value: ' . $params['area'] . '),' . 'allowed values are: ' . implode(', ', $allowedareas));
}
$warnings = array();
$vaultfactory = mod_forum\local\container::get_vault_factory();
$forumvault = $vaultfactory->get_forum_vault();
$discussionvault = $vaultfactory->get_discussion_vault();
$postvault = $vaultfactory->get_post_vault();
$postentity = $postvault->get_from_id($params['postid']);
if (empty($postentity)) {
throw new moodle_exception('invalidpostid', 'forum');
}
$discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
if (empty($discussionentity)) {
throw new moodle_exception('notpartofdiscussion', 'forum');
}
$forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
if (empty($forumentity)) {
throw new moodle_exception('invalidforumid', 'forum');
}
$context = $forumentity->get_context();
self::validate_context($context);
$managerfactory = mod_forum\local\container::get_manager_factory();
$capabilitymanager = $managerfactory->get_capability_manager($forumentity);
if (!$capabilitymanager->can_edit_post($USER, $discussionentity, $postentity)) {
throw new moodle_exception('noviewdiscussionspermission', 'forum');
}
if ($params['area'] == 'attachment') {
$legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
$forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper();
$forum = $forumdatamapper->to_legacy_object($forumentity);
$areaoptions = mod_forum_post_form::attachment_options($forum);
$messagetext = null;
} else {
$areaoptions = mod_forum_post_form::editor_options($context, $postentity->get_id());
$messagetext = $postentity->get_message();
}
$draftitemid = empty($params['draftitemid']) ? 0 : $params['draftitemid'];
$messagetext = file_prepare_draft_area($draftitemid, $context->id, 'mod_forum', $params['area'],
$postentity->get_id(), $areaoptions, $messagetext);
// Just get a structure compatible with external API.
array_walk($areaoptions, function(&$item, $key) {
$item = ['name' => $key, 'value' => $item];
});
// Do we need to keep only the given files?
$usercontext = context_user::instance($USER->id);
if (!empty($params['filestokeep'])) {
$fs = get_file_storage();
if ($areafiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid)) {
$filestokeep = [];
foreach ($params['filestokeep'] as $ftokeep) {
$filestokeep[$ftokeep['filepath']][$ftokeep['filename']] = $ftokeep;
}
foreach ($areafiles as $file) {
if ($file->is_directory()) {
continue;
}
if (!isset($filestokeep[$file->get_filepath()][$file->get_filename()])) {
$file->delete(); // Not in the list to be kept.
}
}
}
}
$result = array(
'draftitemid' => $draftitemid,
'files' => external_util::get_area_files($usercontext->id, 'user', 'draft',
$draftitemid),
'areaoptions' => $areaoptions,
'messagetext' => $messagetext,
'warnings' => $warnings,
);
return $result;
}
/**
* Returns description of method result value
*
* @return external_description
* @since Moodle 3.8
*/
public static function prepare_draft_area_for_post_returns() {
return new external_single_structure(
array(
'draftitemid' => new external_value(PARAM_INT, 'Draft item id for the file area.'),
'files' => new external_files('Draft area files.', VALUE_OPTIONAL),
'areaoptions' => new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_RAW, 'Name of option.'),
'value' => new external_value(PARAM_RAW, 'Value of option.'),
)
), 'Draft file area options.'
),
'messagetext' => new external_value(PARAM_RAW, 'Message text with URLs rewritten.'),
'warnings' => new external_warnings(),
)
);
}
}

@ -2703,4 +2703,82 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
$this->assertTrue($result['post']['hasparent']);
$this->assertEquals($post->message, $result['post']['message']);
}
/**
* Test prepare_draft_area_for_post a different user post.
*/
public function test_prepare_draft_area_for_post() {
global $DB;
$this->resetAfterTest(true);
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
$user = $this->getDataGenerator()->create_user();
$role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
// Add a discussion.
$record = array();
$record['course'] = $course->id;
$record['forum'] = $forum->id;
$record['userid'] = $user->id;
$discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
$parentpost = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
// Add a post.
$record = new stdClass();
$record->course = $course->id;
$record->userid = $user->id;
$record->forum = $forum->id;
$record->discussion = $discussion->id;
$record->parent = $parentpost->id;
$post = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
// Add some files only in the attachment area.
$filename = 'faketxt.txt';
$filerecordinline = array(
'contextid' => context_module::instance($forum->cmid)->id,
'component' => 'mod_forum',
'filearea' => 'attachment',
'itemid' => $post->id,
'filepath' => '/',
'filename' => $filename,
);
$fs = get_file_storage();
$fs->create_file_from_string($filerecordinline, 'fake txt contents 1.');
$filerecordinline['filename'] = 'otherfaketxt.txt';
$fs->create_file_from_string($filerecordinline, 'fake txt contents 2.');
$this->setUser($user);
// Check attachment area.
$result = mod_forum_external::prepare_draft_area_for_post($post->id, 'attachment');
$result = external_api::clean_returnvalue(mod_forum_external::prepare_draft_area_for_post_returns(), $result);
$this->assertCount(2, $result['files']);
$this->assertEquals($filename, $result['files'][0]['filename']);
$this->assertCount(5, $result['areaoptions']);
$this->assertEmpty($result['messagetext']);
// Check again using existing draft item id.
$result = mod_forum_external::prepare_draft_area_for_post($post->id, 'attachment', $result['draftitemid']);
$result = external_api::clean_returnvalue(mod_forum_external::prepare_draft_area_for_post_returns(), $result);
$this->assertCount(2, $result['files']);
// Keep only certain files in the area.
$filestokeep = array(array('filename' => $filename, 'filepath' => '/'));
$result = mod_forum_external::prepare_draft_area_for_post($post->id, 'attachment', $result['draftitemid'], $filestokeep);
$result = external_api::clean_returnvalue(mod_forum_external::prepare_draft_area_for_post_returns(), $result);
$this->assertCount(1, $result['files']);
$this->assertEquals($filename, $result['files'][0]['filename']);
// Check editor (post) area.
$filerecordinline['filearea'] = 'post';
$filerecordinline['filename'] = 'fakeimage.png';
$fs->create_file_from_string($filerecordinline, 'fake image.');
$result = mod_forum_external::prepare_draft_area_for_post($post->id, 'post');
$result = external_api::clean_returnvalue(mod_forum_external::prepare_draft_area_for_post_returns(), $result);
$this->assertCount(1, $result['files']);
$this->assertEquals($filerecordinline['filename'], $result['files'][0]['filename']);
$this->assertCount(5, $result['areaoptions']);
$this->assertEquals($post->message, $result['messagetext']);
}
}