Merge branch 'MDL-65252-master' of git://github.com/lameze/moodle
This commit is contained in:
@@ -32,10 +32,9 @@ use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
||||
use mod_forum\local\factories\exporter as exporter_factory;
|
||||
use mod_forum\local\factories\vault as vault_factory;
|
||||
use context;
|
||||
use mod_forum\local\factories\manager as manager_factory;
|
||||
use core_tag_tag;
|
||||
use moodle_exception;
|
||||
use rating_manager;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
@@ -72,6 +71,9 @@ class exported_posts {
|
||||
/** @var rating_manager $ratingmanager Rating manager */
|
||||
private $ratingmanager;
|
||||
|
||||
/** @var manager_factory $managerfactory Manager factory */
|
||||
private $managerfactory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -79,20 +81,21 @@ class exported_posts {
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
||||
* @param exporter_factory $exporterfactory Exporter factory
|
||||
* @param vault_factory $vaultfactory Vault factory
|
||||
* @param rating_manager $ratingmanager Rating manager
|
||||
* @param manager_factory $managerfactory Manager factory
|
||||
*/
|
||||
public function __construct(
|
||||
renderer_base $renderer,
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
rating_manager $ratingmanager
|
||||
manager_factory $managerfactory
|
||||
) {
|
||||
$this->renderer = $renderer;
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->ratingmanager = $ratingmanager;
|
||||
$this->managerfactory = $managerfactory;
|
||||
$this->ratingmanager = $managerfactory->get_rating_manager();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,6 +142,7 @@ class exported_posts {
|
||||
$authorsbyid = $this->get_authors_for_posts($posts);
|
||||
$authorcontextids = $this->get_author_context_ids(array_keys($authorsbyid));
|
||||
$attachmentsbypostid = $this->get_attachments_for_posts($groupedposts);
|
||||
$inlineattachments = $this->get_inline_attachments_for_posts($groupedposts);
|
||||
$groupsbycourseandauthorid = $this->get_author_groups_from_posts($groupedposts);
|
||||
$tagsbypostid = $this->get_tags_from_posts($posts);
|
||||
$ratingbypostid = $this->get_ratings_from_posts($user, $groupedposts);
|
||||
@@ -154,6 +158,12 @@ class exported_posts {
|
||||
'posts' => $groupedposts
|
||||
] = $grouping;
|
||||
|
||||
// Exclude posts the user cannot see, such as certain posts in Q and A forums.
|
||||
$capabilitymanager = $this->managerfactory->get_capability_manager($forum);
|
||||
$groupedposts = array_filter($groupedposts, function($post) use ($capabilitymanager, $user, $discussion) {
|
||||
return $capabilitymanager->can_view_post($user, $discussion, $post);
|
||||
});
|
||||
|
||||
$forumid = $forum->get_id();
|
||||
$courseid = $forum->get_course_record()->id;
|
||||
$postsexporter = $this->exporterfactory->get_posts_exporter(
|
||||
@@ -168,7 +178,8 @@ class exported_posts {
|
||||
$readreceiptcollectionbyforumid[$forumid] ?? null,
|
||||
$tagsbypostid,
|
||||
$ratingbypostid,
|
||||
true
|
||||
true,
|
||||
$inlineattachments
|
||||
);
|
||||
['posts' => $exportedgroupedposts] = (array) $postsexporter->export($this->renderer);
|
||||
$exportedposts = array_merge($exportedposts, $exportedgroupedposts);
|
||||
@@ -261,6 +272,44 @@ class exported_posts {
|
||||
return $authorvault->get_context_ids_for_author_ids($authorids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the list of all inline attachments for the posts. The list of attachments will be
|
||||
* indexed by the post id.
|
||||
*
|
||||
* @param array $groupedposts List of posts grouped by discussions.
|
||||
* @return stored_file[]
|
||||
*/
|
||||
private function get_inline_attachments_for_posts(array $groupedposts) : array {
|
||||
$inlineattachmentsbypostid = [];
|
||||
$postattachmentvault = $this->vaultfactory->get_post_attachment_vault();
|
||||
$postsbyforum = array_reduce($groupedposts, function($carry, $grouping) {
|
||||
['forum' => $forum, 'posts' => $posts] = $grouping;
|
||||
|
||||
$forumid = $forum->get_id();
|
||||
if (!isset($carry[$forumid])) {
|
||||
$carry[$forumid] = [
|
||||
'forum' => $forum,
|
||||
'posts' => []
|
||||
];
|
||||
}
|
||||
|
||||
$carry[$forumid]['posts'] = array_merge($carry[$forumid]['posts'], $posts);
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
foreach ($postsbyforum as $grouping) {
|
||||
['forum' => $forum, 'posts' => $posts] = $grouping;
|
||||
$inlineattachments = $postattachmentvault->get_inline_attachments_for_posts($forum->get_context(), $posts);
|
||||
|
||||
// Have to loop in order to maintain the correct indexes since they are numeric.
|
||||
foreach ($inlineattachments as $postid => $attachment) {
|
||||
$inlineattachmentsbypostid[$postid] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
return $inlineattachmentsbypostid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the list of all attachments for the posts. The list of attachments will be
|
||||
* indexed by the post id.
|
||||
|
||||
@@ -273,6 +273,10 @@ class post extends exporter {
|
||||
'multiple' => true,
|
||||
'type' => $attachmentdefinition
|
||||
],
|
||||
'messageinlinefiles' => [
|
||||
'multiple' => true,
|
||||
'type' => stored_file_exporter::read_properties_definition(),
|
||||
],
|
||||
'tags' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
@@ -366,6 +370,7 @@ class post extends exporter {
|
||||
$rating = $this->related['rating'];
|
||||
$tags = $this->related['tags'];
|
||||
$attachments = $this->related['attachments'];
|
||||
$inlineattachments = $this->related['messageinlinefiles'];
|
||||
$includehtml = $this->related['includehtml'];
|
||||
$isdeleted = $post->is_deleted();
|
||||
$isprivatereply = $post->is_private_reply();
|
||||
@@ -409,6 +414,7 @@ class post extends exporter {
|
||||
// Only bother loading the content if the user can see it.
|
||||
$loadcontent = $canview && !$isdeleted;
|
||||
$exportattachments = $loadcontent && !empty($attachments);
|
||||
$exportinlineattachments = $loadcontent && !empty($inlineattachments);
|
||||
|
||||
if ($loadcontent) {
|
||||
$subject = $post->get_subject();
|
||||
@@ -478,6 +484,8 @@ class post extends exporter {
|
||||
'discuss' => $discussurl ? $discussurl->out(false) : null,
|
||||
],
|
||||
'attachments' => ($exportattachments) ? $this->export_attachments($attachments, $post, $output, $canexport) : [],
|
||||
'messageinlinefiles' => ($exportinlineattachments) ? $this->export_inline_attachments($inlineattachments,
|
||||
$post, $output) : [],
|
||||
'tags' => ($loadcontent && $hastags) ? $this->export_tags($tags) : [],
|
||||
'html' => $includehtml ? [
|
||||
'rating' => ($loadcontent && $hasrating) ? $output->render($rating) : null,
|
||||
@@ -505,6 +513,7 @@ class post extends exporter {
|
||||
'context' => 'context',
|
||||
'authorgroups' => 'stdClass[]',
|
||||
'attachments' => '\stored_file[]?',
|
||||
'messageinlinefiles' => '\stored_file[]?',
|
||||
'tags' => '\core_tag_tag[]?',
|
||||
'rating' => 'rating?',
|
||||
'includehtml' => 'bool'
|
||||
@@ -612,6 +621,25 @@ class post extends exporter {
|
||||
}, $attachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exported inline attachments for a post.
|
||||
*
|
||||
* @param array $inlineattachments The list of inline attachments for the post
|
||||
* @param post_entity $post The post being exported
|
||||
* @param renderer_base $output Renderer base
|
||||
* @return array
|
||||
*/
|
||||
private function export_inline_attachments(array $inlineattachments, post_entity $post, renderer_base $output) : array {
|
||||
|
||||
return array_map(function($attachment) use (
|
||||
$output,
|
||||
$post
|
||||
) {
|
||||
$exporter = new stored_file_exporter($attachment, ['context' => $this->related['context']]);
|
||||
return $exporter->export($output);;
|
||||
}, $inlineattachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the list of tags.
|
||||
*
|
||||
|
||||
@@ -49,6 +49,8 @@ class posts extends exporter {
|
||||
private $authorcontextids;
|
||||
/** @var array $attachmentsbypostid List of attachments indexed by post id */
|
||||
private $attachmentsbypostid;
|
||||
/** @var array $inlineattachmentsbypostid List of inline attachments indexed by post id */
|
||||
private $inlineattachmentsbypostid;
|
||||
/** @var array $groupsbyauthorid List of author's groups indexed by author id */
|
||||
private $groupsbyauthorid;
|
||||
/** @var array $tagsbypostid List of tags indexed by post id */
|
||||
@@ -67,6 +69,7 @@ class posts extends exporter {
|
||||
* @param array $tagsbypostid List of tags indexed by post id
|
||||
* @param array $ratingbypostid List of ratings indexed by post id
|
||||
* @param array $related The related objects for exporting
|
||||
* @param array $inlineattachmentsbypostid List of inline attachments indexed by post id
|
||||
*/
|
||||
public function __construct(
|
||||
array $posts,
|
||||
@@ -76,12 +79,14 @@ class posts extends exporter {
|
||||
array $groupsbyauthorid = [],
|
||||
array $tagsbypostid = [],
|
||||
array $ratingbypostid = [],
|
||||
array $related = []
|
||||
array $related = [],
|
||||
array $inlineattachmentsbypostid = []
|
||||
) {
|
||||
$this->posts = $posts;
|
||||
$this->authorsbyid = $authorsbyid;
|
||||
$this->authorcontextids = $authorcontextids;
|
||||
$this->attachmentsbypostid = $attachmentsbypostid;
|
||||
$this->inlineattachmentsbypostid = $inlineattachmentsbypostid;
|
||||
$this->groupsbyauthorid = $groupsbyauthorid;
|
||||
$this->tagsbypostid = $tagsbypostid;
|
||||
$this->ratingbypostid = $ratingbypostid;
|
||||
@@ -113,6 +118,7 @@ class posts extends exporter {
|
||||
$authorsbyid = $this->authorsbyid;
|
||||
$authorcontextids = $this->authorcontextids;
|
||||
$attachmentsbypostid = $this->attachmentsbypostid;
|
||||
$inlineattachmentsbypostid = $this->inlineattachmentsbypostid;
|
||||
$groupsbyauthorid = $this->groupsbyauthorid;
|
||||
$tagsbypostid = $this->tagsbypostid;
|
||||
$ratingbypostid = $this->ratingbypostid;
|
||||
@@ -125,13 +131,15 @@ class posts extends exporter {
|
||||
$groupsbyauthorid,
|
||||
$tagsbypostid,
|
||||
$ratingbypostid,
|
||||
$output
|
||||
$output,
|
||||
$inlineattachmentsbypostid
|
||||
) {
|
||||
$authorid = $post->get_author_id();
|
||||
$postid = $post->get_id();
|
||||
$author = isset($authorsbyid[$authorid]) ? $authorsbyid[$authorid] : [];
|
||||
$authorcontextid = isset($authorcontextids[$authorid]) ? $authorcontextids[$authorid] : null;
|
||||
$attachments = isset($attachmentsbypostid[$postid]) ? $attachmentsbypostid[$postid] : [];
|
||||
$inlineattachments = isset($inlineattachmentsbypostid[$postid]) ? $inlineattachmentsbypostid[$postid] : [];
|
||||
$authorgroups = isset($groupsbyauthorid[$authorid]) ? $groupsbyauthorid[$authorid] : [];
|
||||
$tags = isset($tagsbypostid[$postid]) ? $tagsbypostid[$postid] : [];
|
||||
$rating = isset($ratingbypostid[$postid]) ? $ratingbypostid[$postid] : null;
|
||||
@@ -139,6 +147,7 @@ class posts extends exporter {
|
||||
'author' => $author,
|
||||
'authorcontextid' => $authorcontextid,
|
||||
'attachments' => $attachments,
|
||||
'messageinlinefiles' => $inlineattachments,
|
||||
'authorgroups' => $authorgroups,
|
||||
'tags' => $tags,
|
||||
'rating' => $rating
|
||||
|
||||
@@ -91,7 +91,7 @@ class builder {
|
||||
$this->legacydatamapperfactory,
|
||||
$this->exporterfactory,
|
||||
$this->vaultfactory,
|
||||
$this->managerfactory->get_rating_manager()
|
||||
$this->managerfactory
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,8 @@ class exporter {
|
||||
* @param array $tagsbypostid List of tags for each post indexed by post id
|
||||
* @param rating[] $ratingbypostid List of ratings for each post indexed by post id
|
||||
* @param bool $includehtml Include some pre-constructed HTML in the export
|
||||
* @return post_exporter
|
||||
* @param array $inlineattachmentsbypostid List of attachments for each post indexed by post id
|
||||
* @return posts_exporter
|
||||
*/
|
||||
public function get_posts_exporter(
|
||||
stdClass $user,
|
||||
@@ -238,7 +239,8 @@ class exporter {
|
||||
post_read_receipt_collection_entity $readreceiptcollection = null,
|
||||
array $tagsbypostid = [],
|
||||
array $ratingbypostid = [],
|
||||
bool $includehtml = false
|
||||
bool $includehtml = false,
|
||||
array $inlineattachmentsbypostid = []
|
||||
) : posts_exporter {
|
||||
return new posts_exporter(
|
||||
$posts,
|
||||
@@ -257,7 +259,8 @@ class exporter {
|
||||
'context' => $forum->get_context(),
|
||||
'readreceiptcollection' => $readreceiptcollection,
|
||||
'includehtml' => $includehtml
|
||||
]
|
||||
],
|
||||
$inlineattachmentsbypostid
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ use file_storage;
|
||||
class post_attachment {
|
||||
/** The component for attachments */
|
||||
private const COMPONENT = 'mod_forum';
|
||||
/** File area for attachments */
|
||||
private const FILE_AREA = 'attachment';
|
||||
/** Sort the attachments by filename */
|
||||
private const SORT = 'filename';
|
||||
/** Don't include directories */
|
||||
@@ -68,9 +66,10 @@ class post_attachment {
|
||||
*
|
||||
* @param context $context The (forum) context that the posts are in
|
||||
* @param post_entity[] $posts The list of posts to load attachments for
|
||||
* @param string $area The file storage area, can be 'attachment' or 'post' for inline attachments.
|
||||
* @return array Post attachments indexed by post id
|
||||
*/
|
||||
public function get_attachments_for_posts(context $context, array $posts) {
|
||||
private function get_area_attachments_for_posts(context $context, array $posts, string $area) {
|
||||
$itemids = array_map(function($post) {
|
||||
return $post->get_id();
|
||||
}, $posts);
|
||||
@@ -78,7 +77,7 @@ class post_attachment {
|
||||
$files = $this->filestorage->get_area_files(
|
||||
$context->id,
|
||||
self::COMPONENT,
|
||||
self::FILE_AREA,
|
||||
$area,
|
||||
$itemids,
|
||||
self::SORT,
|
||||
self::INCLUDE_DIRECTORIES
|
||||
@@ -95,4 +94,27 @@ class post_attachment {
|
||||
return $carry;
|
||||
}, $filesbyid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment for posts.
|
||||
*
|
||||
* @param context $context The (forum) context that the posts are in
|
||||
* @param post_entity[] $posts The list of posts to load attachments for
|
||||
* @return array Post attachments indexed by post id
|
||||
*/
|
||||
public function get_attachments_for_posts(context $context, array $posts) {
|
||||
return $this->get_area_attachments_for_posts($context, $posts, 'attachment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inline attachments for posts.
|
||||
*
|
||||
* @param context $context The (forum) context that the posts are in
|
||||
* @param post_entity[] $posts The list of posts to load attachments for
|
||||
* @return array Post attachments indexed by post id
|
||||
*/
|
||||
public function get_inline_attachments_for_posts(context $context, array $posts) {
|
||||
return $this->get_area_attachments_for_posts($context, $posts, 'post');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,16 +48,6 @@ $functions = array(
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
|
||||
'mod_forum_get_forum_discussion_posts' => array(
|
||||
'classname' => 'mod_forum_external',
|
||||
'methodname' => 'get_forum_discussion_posts',
|
||||
'classpath' => 'mod/forum/externallib.php',
|
||||
'description' => 'Returns a list of forum posts for a discussion.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/forum:viewdiscussion, mod/forum:viewqandawithoutposting',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
|
||||
'mod_forum_get_forum_discussions_paginated' => array(
|
||||
'classname' => 'mod_forum_external',
|
||||
'methodname' => 'get_forum_discussions_paginated',
|
||||
|
||||
@@ -1621,34 +1621,11 @@ function forum_print_latest_discussions($course, $forum, $maxdiscussions = -1, $
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of replies to the specified post.
|
||||
*
|
||||
* @param object $post
|
||||
* @param bool $children
|
||||
* @return int
|
||||
* @deprecated since Moodle 3.7
|
||||
* @todo MDL-65252 This will be removed in Moodle 3.11
|
||||
*/
|
||||
function forum_count_replies($post, $children = true) {
|
||||
global $USER;
|
||||
debugging('forum_count_replies has been deprecated. Please use the Post vault instead.', DEBUG_DEVELOPER);
|
||||
|
||||
if (!$children) {
|
||||
return $DB->count_records('forum_posts', array('parent' => $post->id));
|
||||
}
|
||||
|
||||
$entityfactory = mod_forum\local\container::get_entity_factory();
|
||||
$postentity = $entityfactory->get_post_from_stdclass($post);
|
||||
|
||||
$vaultfactory = mod_forum\local\container::get_vault_factory();
|
||||
$postvault = $vaultfactory->get_post_vault();
|
||||
|
||||
return $postvault->get_reply_count_for_post_id_in_discussion_id(
|
||||
$USER,
|
||||
$postentity->get_id(),
|
||||
$postentity->get_discussion_id(),
|
||||
true
|
||||
);
|
||||
function forum_count_replies() {
|
||||
throw new coding_exception(__FUNCTION__ . ' has been removed. Please use get_reply_count_for_post_id_in_discussion_id in
|
||||
the post vault.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -267,243 +267,6 @@ class mod_forum_external extends external_api {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for get_forum_discussion_posts.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 2.7
|
||||
*/
|
||||
public static function get_forum_discussion_posts_parameters() {
|
||||
return new external_function_parameters (
|
||||
array(
|
||||
'discussionid' => new external_value(PARAM_INT, 'discussion ID', VALUE_REQUIRED),
|
||||
'sortby' => new external_value(PARAM_ALPHA,
|
||||
'sort by this element: id, created or modified', VALUE_DEFAULT, 'created'),
|
||||
'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of forum posts for a discussion
|
||||
*
|
||||
* @param int $discussionid the post ids
|
||||
* @param string $sortby sort by this element (id, created or modified)
|
||||
* @param string $sortdirection sort direction: ASC or DESC
|
||||
*
|
||||
* @return array the forum post details
|
||||
* @since Moodle 2.7
|
||||
* @todo MDL-65252 This will be removed in Moodle 3.11
|
||||
*/
|
||||
public static function get_forum_discussion_posts($discussionid, $sortby = "created", $sortdirection = "DESC") {
|
||||
global $CFG, $DB, $USER, $PAGE;
|
||||
|
||||
$posts = array();
|
||||
$warnings = array();
|
||||
|
||||
// Validate the parameter.
|
||||
$params = self::validate_parameters(self::get_forum_discussion_posts_parameters(),
|
||||
array(
|
||||
'discussionid' => $discussionid,
|
||||
'sortby' => $sortby,
|
||||
'sortdirection' => $sortdirection));
|
||||
|
||||
// Compact/extract functions are not recommended.
|
||||
$discussionid = $params['discussionid'];
|
||||
$sortby = $params['sortby'];
|
||||
$sortdirection = $params['sortdirection'];
|
||||
|
||||
$sortallowedvalues = array('id', 'created', 'modified');
|
||||
if (!in_array($sortby, $sortallowedvalues)) {
|
||||
throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
|
||||
'allowed values are: ' . implode(',', $sortallowedvalues));
|
||||
}
|
||||
|
||||
$sortdirection = strtoupper($sortdirection);
|
||||
$directionallowedvalues = array('ASC', 'DESC');
|
||||
if (!in_array($sortdirection, $directionallowedvalues)) {
|
||||
throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
|
||||
'allowed values are: ' . implode(',', $directionallowedvalues));
|
||||
}
|
||||
|
||||
$discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST);
|
||||
$forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST);
|
||||
|
||||
// Validate the module context. It checks everything that affects the module visibility (including groupings, etc..).
|
||||
$modcontext = context_module::instance($cm->id);
|
||||
self::validate_context($modcontext);
|
||||
|
||||
// This require must be here, see mod/forum/discuss.php.
|
||||
require_once($CFG->dirroot . "/mod/forum/lib.php");
|
||||
|
||||
// Check they have the view forum capability.
|
||||
require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum');
|
||||
|
||||
if (! $post = forum_get_post_full($discussion->firstpost)) {
|
||||
throw new moodle_exception('notexists', 'forum');
|
||||
}
|
||||
|
||||
// This function check groups, qanda, timed discussions, etc.
|
||||
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
|
||||
throw new moodle_exception('noviewdiscussionspermission', 'forum');
|
||||
}
|
||||
|
||||
$canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext);
|
||||
|
||||
// We will add this field in the response.
|
||||
$canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
|
||||
|
||||
$forumtracked = forum_tp_is_tracked($forum);
|
||||
|
||||
$sort = 'p.' . $sortby . ' ' . $sortdirection;
|
||||
$allposts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
|
||||
|
||||
foreach ($allposts as $post) {
|
||||
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
|
||||
$warning = array();
|
||||
$warning['item'] = 'post';
|
||||
$warning['itemid'] = $post->id;
|
||||
$warning['warningcode'] = '1';
|
||||
$warning['message'] = 'You can\'t see this post';
|
||||
$warnings[] = $warning;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Function forum_get_all_discussion_posts adds postread field.
|
||||
// Note that the value returned can be a boolean or an integer. The WS expects a boolean.
|
||||
if (empty($post->postread)) {
|
||||
$post->postread = false;
|
||||
} else {
|
||||
$post->postread = true;
|
||||
}
|
||||
|
||||
$post->isprivatereply = !empty($post->privatereplyto);
|
||||
|
||||
$post->canreply = $canreply;
|
||||
if (!empty($post->children)) {
|
||||
$post->children = array_keys($post->children);
|
||||
} else {
|
||||
$post->children = array();
|
||||
}
|
||||
|
||||
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
|
||||
// The post is available, but has been marked as deleted.
|
||||
// It will still be available but filled with a placeholder.
|
||||
$post->userid = null;
|
||||
$post->userfullname = null;
|
||||
$post->userpictureurl = null;
|
||||
|
||||
$post->subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
|
||||
$post->message = get_string('privacy:request:delete:post:message', 'mod_forum');
|
||||
|
||||
$post->deleted = true;
|
||||
$posts[] = $post;
|
||||
|
||||
continue;
|
||||
}
|
||||
$post->deleted = false;
|
||||
|
||||
if (forum_is_author_hidden($post, $forum)) {
|
||||
$post->userid = null;
|
||||
$post->userfullname = null;
|
||||
$post->userpictureurl = null;
|
||||
} else {
|
||||
$user = new stdclass();
|
||||
$user->id = $post->userid;
|
||||
$user = username_load_fields_from_object($user, $post, null, array('picture', 'imagealt', 'email'));
|
||||
$post->userfullname = fullname($user, $canviewfullname);
|
||||
|
||||
$userpicture = new user_picture($user);
|
||||
$userpicture->size = 1; // Size f1.
|
||||
$post->userpictureurl = $userpicture->get_url($PAGE)->out(false);
|
||||
}
|
||||
|
||||
$post->subject = external_format_string($post->subject, $modcontext->id);
|
||||
// Rewrite embedded images URLs.
|
||||
$options = array('trusted' => $post->messagetrust);
|
||||
list($post->message, $post->messageformat) =
|
||||
external_format_text($post->message, $post->messageformat, $modcontext->id, 'mod_forum', 'post', $post->id,
|
||||
$options);
|
||||
|
||||
// List attachments.
|
||||
if (!empty($post->attachment)) {
|
||||
$post->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', 'attachment', $post->id);
|
||||
}
|
||||
$messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', $post->id);
|
||||
if (!empty($messageinlinefiles)) {
|
||||
$post->messageinlinefiles = $messageinlinefiles;
|
||||
}
|
||||
// Post tags.
|
||||
$post->tags = \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $post->id);
|
||||
|
||||
$posts[] = $post;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$result['posts'] = $posts;
|
||||
$result['ratinginfo'] = \core_rating\external\util::get_rating_info($forum, $modcontext, 'mod_forum', 'post', $posts);
|
||||
$result['warnings'] = $warnings;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the get_forum_discussion_posts return value.
|
||||
*
|
||||
* @return external_single_structure
|
||||
* @since Moodle 2.7
|
||||
*/
|
||||
public static function get_forum_discussion_posts_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'posts' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'Post id'),
|
||||
'discussion' => new external_value(PARAM_INT, 'Discussion id'),
|
||||
'parent' => new external_value(PARAM_INT, 'Parent id'),
|
||||
'userid' => new external_value(PARAM_INT, 'User id'),
|
||||
'created' => new external_value(PARAM_INT, 'Creation time'),
|
||||
'modified' => new external_value(PARAM_INT, 'Time modified'),
|
||||
'mailed' => new external_value(PARAM_INT, 'Mailed?'),
|
||||
'subject' => new external_value(PARAM_RAW, 'The post subject'),
|
||||
'message' => new external_value(PARAM_RAW, 'The post message'),
|
||||
'messageformat' => new external_format_value('message'),
|
||||
'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'),
|
||||
'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL),
|
||||
'attachment' => new external_value(PARAM_RAW, 'Has attachments?'),
|
||||
'attachments' => new external_files('attachments', VALUE_OPTIONAL),
|
||||
'totalscore' => new external_value(PARAM_INT, 'The post message total score'),
|
||||
'mailnow' => new external_value(PARAM_INT, 'Mail now?'),
|
||||
'children' => new external_multiple_structure(new external_value(PARAM_INT, 'children post id')),
|
||||
'canreply' => new external_value(PARAM_BOOL, 'The user can reply to posts?'),
|
||||
'postread' => new external_value(PARAM_BOOL, 'The post was read'),
|
||||
'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'),
|
||||
'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL),
|
||||
'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'),
|
||||
'isprivatereply' => new external_value(PARAM_BOOL, 'The post is a private reply'),
|
||||
'tags' => new external_multiple_structure(
|
||||
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
|
||||
),
|
||||
), 'post'
|
||||
)
|
||||
),
|
||||
'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
|
||||
'warnings' => new external_warnings()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the get_forum_discussion_posts web service as deprecated.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function get_forum_discussion_posts_is_deprecated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the get_forum_discussions_paginated web service as deprecated.
|
||||
*
|
||||
|
||||
@@ -150,9 +150,10 @@ class mod_forum_builders_exported_posts_testcase extends advanced_testcase {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$user1 = $datagenerator->create_and_enrol($course);
|
||||
$user2 = $datagenerator->create_and_enrol($course);
|
||||
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1);
|
||||
|
||||
@@ -51,6 +51,51 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
\mod_forum\subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expected attachment.
|
||||
*
|
||||
* @param stored_file $file
|
||||
* @param array $values
|
||||
* @param moodle_url|null $url
|
||||
* @return array
|
||||
*/
|
||||
protected function get_expected_attachment(stored_file $file, array $values = [], ?moodle_url $url = null): array {
|
||||
if (!$url) {
|
||||
$url = moodle_url::make_pluginfile_url(
|
||||
$file->get_contextid(),
|
||||
$file->get_component(),
|
||||
$file->get_filearea(),
|
||||
$file->get_itemid(),
|
||||
$file->get_filepath(),
|
||||
$file->get_filename()
|
||||
);
|
||||
$url->param('forcedownload', 1);
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
[
|
||||
'contextid' => $file->get_contextid(),
|
||||
'component' => $file->get_component(),
|
||||
'filearea' => $file->get_filearea(),
|
||||
'itemid' => $file->get_itemid(),
|
||||
'filepath' => $file->get_filepath(),
|
||||
'filename' => $file->get_filename(),
|
||||
'isdir' => $file->is_directory(),
|
||||
'isimage' => $file->is_valid_image(),
|
||||
'timemodified' => $file->get_timemodified(),
|
||||
'timecreated' => $file->get_timecreated(),
|
||||
'filesize' => $file->get_filesize(),
|
||||
'author' => $file->get_author(),
|
||||
'license' => $file->get_license(),
|
||||
'filenameshort' => $file->get_filename(),
|
||||
'filesizeformatted' => display_size((int) $file->get_filesize()),
|
||||
'icon' => $file->is_directory() ? file_folder_icon(128) : file_file_icon($file, 128),
|
||||
'timecreatedformatted' => userdate($file->get_timecreated()),
|
||||
'timemodifiedformatted' => userdate($file->get_timemodified()),
|
||||
'url' => $url->out(),
|
||||
], $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get forums
|
||||
*/
|
||||
@@ -274,253 +319,6 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertFalse($response['pinned']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get forum posts
|
||||
*/
|
||||
public function test_mod_forum_get_forum_discussion_posts() {
|
||||
global $CFG, $PAGE;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Set the CFG variable to allow track forums.
|
||||
$CFG->forum_trackreadposts = true;
|
||||
|
||||
// Create a user who can track forums.
|
||||
$record = new stdClass();
|
||||
$record->trackforums = true;
|
||||
$user1 = self::getDataGenerator()->create_user($record);
|
||||
// Create a bunch of other users to post.
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
$user3 = self::getDataGenerator()->create_user();
|
||||
|
||||
// Set the first created user to the test user.
|
||||
self::setUser($user1);
|
||||
|
||||
// Create course to add the module.
|
||||
$course1 = self::getDataGenerator()->create_course();
|
||||
|
||||
// Forum with tracking off.
|
||||
$record = new stdClass();
|
||||
$record->course = $course1->id;
|
||||
$record->trackingtype = FORUM_TRACKING_OFF;
|
||||
$forum1 = self::getDataGenerator()->create_module('forum', $record);
|
||||
$forum1context = context_module::instance($forum1->cmid);
|
||||
|
||||
// Forum with tracking enabled.
|
||||
$record = new stdClass();
|
||||
$record->course = $course1->id;
|
||||
$forum2 = self::getDataGenerator()->create_module('forum', $record);
|
||||
$forum2cm = get_coursemodule_from_id('forum', $forum2->cmid);
|
||||
$forum2context = context_module::instance($forum2->cmid);
|
||||
|
||||
// Add discussions to the forums.
|
||||
$record = new stdClass();
|
||||
$record->course = $course1->id;
|
||||
$record->userid = $user1->id;
|
||||
$record->forum = $forum1->id;
|
||||
$discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
|
||||
|
||||
$record = new stdClass();
|
||||
$record->course = $course1->id;
|
||||
$record->userid = $user2->id;
|
||||
$record->forum = $forum1->id;
|
||||
$discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
|
||||
|
||||
$record = new stdClass();
|
||||
$record->course = $course1->id;
|
||||
$record->userid = $user2->id;
|
||||
$record->forum = $forum2->id;
|
||||
$discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
|
||||
|
||||
// Add 2 replies to the discussion 1 from different users.
|
||||
$record = new stdClass();
|
||||
$record->discussion = $discussion1->id;
|
||||
$record->parent = $discussion1->firstpost;
|
||||
$record->userid = $user2->id;
|
||||
$discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
|
||||
$filename = 'shouldbeanimage.jpg';
|
||||
// Add a fake inline image to the post.
|
||||
$filerecordinline = array(
|
||||
'contextid' => $forum1context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'post',
|
||||
'itemid' => $discussion1reply1->id,
|
||||
'filepath' => '/',
|
||||
'filename' => $filename,
|
||||
);
|
||||
$fs = get_file_storage();
|
||||
$timepost = time();
|
||||
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
|
||||
$record->parent = $discussion1reply1->id;
|
||||
$record->userid = $user3->id;
|
||||
$record->tags = array('Cats', 'Dogs');
|
||||
$discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
|
||||
|
||||
// Enrol the user in the course.
|
||||
$enrol = enrol_get_plugin('manual');
|
||||
// Following line enrol and assign default role id to the user.
|
||||
// So the user automatically gets mod/forum:viewdiscussion on all forums of the course.
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course1->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course1->id);
|
||||
|
||||
// Delete one user, to test that we still receive posts by this user.
|
||||
delete_user($user3);
|
||||
|
||||
// Create what we expect to be returned when querying the discussion.
|
||||
$expectedposts = array(
|
||||
'posts' => array(),
|
||||
'ratinginfo' => array(
|
||||
'contextid' => $forum1context->id,
|
||||
'component' => 'mod_forum',
|
||||
'ratingarea' => 'post',
|
||||
'canviewall' => null,
|
||||
'canviewany' => null,
|
||||
'scales' => array(),
|
||||
'ratings' => array(),
|
||||
),
|
||||
'warnings' => array(),
|
||||
);
|
||||
|
||||
// User pictures are initially empty, we should get the links once the external function is called.
|
||||
$expectedposts['posts'][] = array(
|
||||
'id' => $discussion1reply2->id,
|
||||
'discussion' => $discussion1reply2->discussion,
|
||||
'parent' => $discussion1reply2->parent,
|
||||
'userid' => (int) $discussion1reply2->userid,
|
||||
'created' => $discussion1reply2->created,
|
||||
'modified' => $discussion1reply2->modified,
|
||||
'mailed' => $discussion1reply2->mailed,
|
||||
'subject' => $discussion1reply2->subject,
|
||||
'message' => file_rewrite_pluginfile_urls($discussion1reply2->message, 'pluginfile.php',
|
||||
$forum1context->id, 'mod_forum', 'post', $discussion1reply2->id),
|
||||
'messageformat' => 1, // This value is usually changed by external_format_text() function.
|
||||
'messagetrust' => $discussion1reply2->messagetrust,
|
||||
'attachment' => $discussion1reply2->attachment,
|
||||
'totalscore' => $discussion1reply2->totalscore,
|
||||
'mailnow' => $discussion1reply2->mailnow,
|
||||
'children' => array(),
|
||||
'canreply' => true,
|
||||
'postread' => false,
|
||||
'userfullname' => fullname($user3),
|
||||
'userpictureurl' => '',
|
||||
'deleted' => false,
|
||||
'isprivatereply' => false,
|
||||
'tags' => \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $discussion1reply2->id),
|
||||
);
|
||||
// Cast to expected.
|
||||
$this->assertCount(2, $expectedposts['posts'][0]['tags']);
|
||||
$expectedposts['posts'][0]['tags'][0]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][0]['isstandard'];
|
||||
$expectedposts['posts'][0]['tags'][1]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][1]['isstandard'];
|
||||
|
||||
$expectedposts['posts'][] = array(
|
||||
'id' => $discussion1reply1->id,
|
||||
'discussion' => $discussion1reply1->discussion,
|
||||
'parent' => $discussion1reply1->parent,
|
||||
'userid' => (int) $discussion1reply1->userid,
|
||||
'created' => $discussion1reply1->created,
|
||||
'modified' => $discussion1reply1->modified,
|
||||
'mailed' => $discussion1reply1->mailed,
|
||||
'subject' => $discussion1reply1->subject,
|
||||
'message' => file_rewrite_pluginfile_urls($discussion1reply1->message, 'pluginfile.php',
|
||||
$forum1context->id, 'mod_forum', 'post', $discussion1reply1->id),
|
||||
'messageformat' => 1, // This value is usually changed by external_format_text() function.
|
||||
'messagetrust' => $discussion1reply1->messagetrust,
|
||||
'attachment' => $discussion1reply1->attachment,
|
||||
'messageinlinefiles' => array(
|
||||
array(
|
||||
'filename' => $filename,
|
||||
'filepath' => '/',
|
||||
'filesize' => '27',
|
||||
'fileurl' => moodle_url::make_webservice_pluginfile_url($forum1context->id, 'mod_forum', 'post',
|
||||
$discussion1reply1->id, '/', $filename),
|
||||
'timemodified' => $timepost,
|
||||
'mimetype' => 'image/jpeg',
|
||||
'isexternalfile' => false,
|
||||
)
|
||||
),
|
||||
'totalscore' => $discussion1reply1->totalscore,
|
||||
'mailnow' => $discussion1reply1->mailnow,
|
||||
'children' => array($discussion1reply2->id),
|
||||
'canreply' => true,
|
||||
'postread' => false,
|
||||
'userfullname' => fullname($user2),
|
||||
'userpictureurl' => '',
|
||||
'deleted' => false,
|
||||
'isprivatereply' => false,
|
||||
'tags' => array(),
|
||||
);
|
||||
|
||||
// Test a discussion with two additional posts (total 3 posts).
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(3, count($posts['posts']));
|
||||
|
||||
// Generate here the pictures because we need to wait to the external function to init the theme.
|
||||
$userpicture = new user_picture($user3);
|
||||
$userpicture->size = 1; // Size f1.
|
||||
$expectedposts['posts'][0]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
|
||||
|
||||
$userpicture = new user_picture($user2);
|
||||
$userpicture->size = 1; // Size f1.
|
||||
$expectedposts['posts'][1]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
|
||||
|
||||
// Unset the initial discussion post.
|
||||
array_pop($posts['posts']);
|
||||
$this->assertEquals($expectedposts, $posts);
|
||||
|
||||
// Check we receive the unread count correctly on tracked forum.
|
||||
forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
|
||||
$result = mod_forum_external::get_forums_by_courses(array($course1->id));
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
|
||||
foreach ($result as $f) {
|
||||
if ($f['id'] == $forum2->id) {
|
||||
$this->assertEquals(1, $f['unreadpostscount']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test discussion without additional posts. There should be only one post (the one created by the discussion).
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion2->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(1, count($posts['posts']));
|
||||
|
||||
// Test discussion tracking on not tracked forum.
|
||||
$result = mod_forum_external::view_forum_discussion($discussion1->id);
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
|
||||
$this->assertTrue($result['status']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
// Test posts have not been marked as read.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
foreach ($posts['posts'] as $post) {
|
||||
$this->assertFalse($post['postread']);
|
||||
}
|
||||
|
||||
// Test discussion tracking on tracked forum.
|
||||
$result = mod_forum_external::view_forum_discussion($discussion3->id);
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
|
||||
$this->assertTrue($result['status']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
// Test posts have been marked as read.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion3->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
foreach ($posts['posts'] as $post) {
|
||||
$this->assertTrue($post['postread']);
|
||||
}
|
||||
|
||||
// Check we receive 0 unread posts.
|
||||
forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
|
||||
$result = mod_forum_external::get_forums_by_courses(array($course1->id));
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
|
||||
foreach ($result as $f) {
|
||||
if ($f['id'] == $forum2->id) {
|
||||
$this->assertEquals(0, $f['unreadpostscount']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get forum posts
|
||||
*
|
||||
@@ -631,7 +429,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
);
|
||||
$fs = get_file_storage();
|
||||
$timepost = time();
|
||||
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
$file = $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
|
||||
$record->parent = $discussion1reply1->id;
|
||||
$record->userid = $user3->id;
|
||||
@@ -698,6 +496,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'charcount' => count_letters($message),
|
||||
'author'=> $exporteduser3,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -756,6 +555,9 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'charcount' => count_letters($message),
|
||||
'author'=> $exporteduser2,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [
|
||||
0 => $this->get_expected_attachment($file)
|
||||
],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -854,7 +656,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test get forum posts
|
||||
*/
|
||||
public function test_mod_forum_get_forum_discussion_posts_deleted() {
|
||||
public function test_mod_forum_get_discussion_posts_deleted() {
|
||||
global $CFG, $PAGE;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
@@ -874,57 +676,57 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// Create test data.
|
||||
$forum1 = self::getDataGenerator()->create_module('forum', (object) [
|
||||
'course' => $course1->id,
|
||||
]);
|
||||
'course' => $course1->id,
|
||||
]);
|
||||
$forum1context = context_module::instance($forum1->cmid);
|
||||
|
||||
// Add discussions to the forum.
|
||||
$discussion = $generator->create_discussion((object) [
|
||||
'course' => $course1->id,
|
||||
'userid' => $user1->id,
|
||||
'forum' => $forum1->id,
|
||||
]);
|
||||
'course' => $course1->id,
|
||||
'userid' => $user1->id,
|
||||
'forum' => $forum1->id,
|
||||
]);
|
||||
|
||||
$discussion2 = $generator->create_discussion((object) [
|
||||
'course' => $course1->id,
|
||||
'userid' => $user2->id,
|
||||
'forum' => $forum1->id,
|
||||
]);
|
||||
'course' => $course1->id,
|
||||
'userid' => $user2->id,
|
||||
'forum' => $forum1->id,
|
||||
]);
|
||||
|
||||
// Add replies to the discussion.
|
||||
$discussionreply1 = $generator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussion->firstpost,
|
||||
'userid' => $user2->id,
|
||||
]);
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussion->firstpost,
|
||||
'userid' => $user2->id,
|
||||
]);
|
||||
$discussionreply2 = $generator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussionreply1->id,
|
||||
'userid' => $user2->id,
|
||||
'subject' => '',
|
||||
'message' => '',
|
||||
'messageformat' => FORMAT_PLAIN,
|
||||
'deleted' => 1,
|
||||
]);
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussionreply1->id,
|
||||
'userid' => $user2->id,
|
||||
'subject' => '',
|
||||
'message' => '',
|
||||
'messageformat' => FORMAT_PLAIN,
|
||||
'deleted' => 1,
|
||||
]);
|
||||
$discussionreply3 = $generator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussion->firstpost,
|
||||
'userid' => $user2->id,
|
||||
]);
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => $discussion->firstpost,
|
||||
'userid' => $user2->id,
|
||||
]);
|
||||
|
||||
// Test where some posts have been marked as deleted.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$deletedsubject = get_string('privacy:request:delete:post:subject', 'mod_forum');
|
||||
$deletedmessage = get_string('privacy:request:delete:post:message', 'mod_forum');
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$deletedsubject = get_string('forumsubjectdeleted', 'mod_forum');
|
||||
$deletedmessage = get_string('forumbodydeleted', 'mod_forum');
|
||||
|
||||
foreach ($posts['posts'] as $post) {
|
||||
if ($post['id'] == $discussionreply2->id) {
|
||||
$this->assertTrue($post['deleted']);
|
||||
$this->assertTrue($post['isdeleted']);
|
||||
$this->assertEquals($deletedsubject, $post['subject']);
|
||||
$this->assertEquals($deletedmessage, $post['message']);
|
||||
} else {
|
||||
$this->assertFalse($post['deleted']);
|
||||
$this->assertFalse($post['isdeleted']);
|
||||
$this->assertNotEquals($deletedsubject, $post['subject']);
|
||||
$this->assertNotEquals($deletedmessage, $post['message']);
|
||||
}
|
||||
@@ -934,7 +736,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test get forum posts (qanda forum)
|
||||
*/
|
||||
public function test_mod_forum_get_forum_discussion_posts_qanda() {
|
||||
public function test_mod_forum_get_discussion_posts_qanda() {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
@@ -973,8 +775,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
|
||||
|
||||
// We still see only the original post.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(1, count($posts['posts']));
|
||||
|
||||
// Add a new reply, the user is going to be able to see only the original post and their new post.
|
||||
@@ -984,16 +786,16 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$record->userid = $user1->id;
|
||||
$discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
|
||||
// Now, we can fake the time of the user post, so he can se the rest of the discussion posts.
|
||||
$discussion1reply2->created -= $CFG->maxeditingtime * 2;
|
||||
$DB->update_record('forum_posts', $discussion1reply2);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(3, count($posts['posts']));
|
||||
}
|
||||
|
||||
@@ -1597,8 +1399,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$createdpost = mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
|
||||
$createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
|
||||
@@ -1676,16 +1478,16 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$dummytext, $options);
|
||||
$createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
// Can't guarantee order of posts during tests.
|
||||
$postfound = false;
|
||||
foreach ($posts['posts'] as $thispost) {
|
||||
if ($createdpost['postid'] == $thispost['id']) {
|
||||
$this->assertEquals($createdpost['postid'], $thispost['id']);
|
||||
$this->assertEquals($thispost['attachment'], 1, "There should be a non-inline attachment");
|
||||
$this->assertCount(1, $thispost['attachments'], "There should be 1 attachment");
|
||||
$this->assertCount(1, $thispost['attachments']);
|
||||
$this->assertEquals('attachment.txt', $thispost['attachments'][0]['filename']);
|
||||
$this->assertEquals($thispost['attachments'][0]['filename'], $attachfilename, "There should be 1 attachment");
|
||||
$this->assertStringContainsString('pluginfile.php', $thispost['message']);
|
||||
$postfound = true;
|
||||
@@ -1751,8 +1553,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
// Add a discussion post in a forum discussion where the user is not subscribed (auto-subscribe preference enabled).
|
||||
mod_forum_external::add_discussion_post($discussion1->firstpost, 'some subject', 'some text here...');
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
// The user should be subscribed to the discussion after adding a discussion post.
|
||||
@@ -1764,8 +1566,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
// Add a discussion post in a forum discussion where the user is subscribed (auto-subscribe preference disabled).
|
||||
mod_forum_external::add_discussion_post($discussion1->firstpost, 'some subject 1', 'some text here 1...');
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
$this->assertEquals(3, count($posts['posts']));
|
||||
// The user should still be subscribed to the discussion after adding a discussion post.
|
||||
@@ -1775,8 +1577,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
// Add a discussion post in a forum discussion where the user is not subscribed (auto-subscribe preference disabled).
|
||||
mod_forum_external::add_discussion_post($discussion2->firstpost, 'some subject 2', 'some text here 2...');
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion2->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion2->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
// The user should still not be subscribed to the discussion after adding a discussion post.
|
||||
@@ -1791,8 +1593,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
mod_forum_external::add_discussion_post($discussion2->firstpost, 'some subject 2', 'some text here 2...',
|
||||
$options);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion2->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion2->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// We receive the discussion and the post.
|
||||
$this->assertEquals(3, count($posts['posts']));
|
||||
// The user should now be subscribed to the discussion after adding a discussion post.
|
||||
@@ -2139,12 +1941,12 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get forum posts discussions including rating information.
|
||||
* Test get posts discussions including rating information.
|
||||
*/
|
||||
public function test_mod_forum_get_forum_discussion_rating_information() {
|
||||
global $DB, $CFG;
|
||||
public function test_mod_forum_get_discussion_rating_information() {
|
||||
global $DB, $CFG, $PAGE;
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
@@ -2209,8 +2011,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// Retrieve the rating for the post as student.
|
||||
$this->setUser($user1);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertCount(1, $posts['ratinginfo']['ratings']);
|
||||
$this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']);
|
||||
$this->assertFalse($posts['ratinginfo']['canviewall']);
|
||||
@@ -2220,8 +2022,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// Retrieve the rating for the post as teacher.
|
||||
$this->setUser($teacher);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertCount(1, $posts['ratinginfo']['ratings']);
|
||||
$this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']);
|
||||
$this->assertTrue($posts['ratinginfo']['canviewall']);
|
||||
@@ -2340,29 +2142,29 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// The teacher will receive their private reply.
|
||||
self::setUser($teacher1);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
$this->assertTrue($posts['posts'][0]['isprivatereply']);
|
||||
|
||||
// Another teacher on the course will also receive the private reply.
|
||||
self::setUser($teacher2);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
$this->assertTrue($posts['posts'][0]['isprivatereply']);
|
||||
|
||||
// The student will receive the private reply.
|
||||
self::setUser($student1);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(2, count($posts['posts']));
|
||||
$this->assertTrue($posts['posts'][0]['isprivatereply']);
|
||||
|
||||
// Another student will not receive the private reply.
|
||||
self::setUser($student2);
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion->id, 'id', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
$this->assertEquals(1, count($posts['posts']));
|
||||
$this->assertFalse($posts['posts'][0]['isprivatereply']);
|
||||
|
||||
@@ -2427,16 +2229,14 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertEquals($cleantext, $discussions['discussions'][1]['message']);
|
||||
|
||||
// Get posts now.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion2->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion2->id, 'modified', 'DESC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// Admin message is fully trusted.
|
||||
$this->assertEquals(1, $posts['posts'][0]['messagetrust']);
|
||||
$this->assertEquals($dangeroustext, $posts['posts'][0]['message']);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// Student message is not trusted.
|
||||
$this->assertEquals(0, $posts['posts'][0]['messagetrust']);
|
||||
$this->assertEquals($cleantext, $posts['posts'][0]['message']);
|
||||
}
|
||||
|
||||
@@ -2490,16 +2290,14 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertEquals($cleantext, $discussions['discussions'][1]['message']);
|
||||
|
||||
// Get posts now.
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion2->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion2->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// Admin message is not trusted because enabletrusttext is disabled.
|
||||
$this->assertEquals(0, $posts['posts'][0]['messagetrust']);
|
||||
$this->assertEquals($cleantext, $posts['posts'][0]['message']);
|
||||
|
||||
$posts = mod_forum_external::get_forum_discussion_posts($discussion1->id);
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
|
||||
$posts = mod_forum_external::get_discussion_posts($discussion1->id, 'modified', 'ASC');
|
||||
$posts = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $posts);
|
||||
// Student message is not trusted.
|
||||
$this->assertEquals(0, $posts['posts'][0]['messagetrust']);
|
||||
$this->assertEquals($cleantext, $posts['posts'][0]['message']);
|
||||
}
|
||||
|
||||
@@ -2703,7 +2501,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'filename' => $filename,
|
||||
);
|
||||
$fs = get_file_storage();
|
||||
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
$file1 = $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
|
||||
// Add 1 reply to the discussion 2 from a different user.
|
||||
$record = new stdClass();
|
||||
@@ -2722,7 +2520,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'filename' => $filename,
|
||||
);
|
||||
$fs = get_file_storage();
|
||||
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
$file2 = $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
|
||||
// Following line enrol and assign default role id to the user.
|
||||
// So the user automatically gets mod/forum:viewdiscussion on all forums of the course.
|
||||
@@ -2776,6 +2574,9 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'wordcount' => null,
|
||||
'author' => $exporteduser2,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [
|
||||
0 => $this->get_expected_attachment($file1),
|
||||
],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -2841,6 +2642,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'wordcount' => null,
|
||||
'author' => $exporteduser1,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -2917,6 +2719,9 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'wordcount' => null,
|
||||
'author' => $exporteduser2,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [
|
||||
0 => $this->get_expected_attachment($file2),
|
||||
],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -2982,6 +2787,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
'wordcount' => null,
|
||||
'author' => $exporteduser1,
|
||||
'attachments' => [],
|
||||
'messageinlinefiles' => [],
|
||||
'tags' => [],
|
||||
'html' => [
|
||||
'rating' => null,
|
||||
@@ -3289,24 +3095,33 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$newpost = $result['post'];
|
||||
$this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id, $cm));
|
||||
|
||||
// Add files in the different areas.
|
||||
// Test inline and regular attachment in post
|
||||
// Create a file in a draft area for inline attachments.
|
||||
$draftidinlineattach = file_get_unused_draft_itemid();
|
||||
$draftidattach = file_get_unused_draft_itemid();
|
||||
self::setUser($user);
|
||||
$usercontext = context_user::instance($user->id);
|
||||
$filepath = '/';
|
||||
$filearea = 'draft';
|
||||
$component = 'user';
|
||||
$filenameimg = 'fakeimage.png';
|
||||
$filerecordinline = array(
|
||||
'contextid' => context_user::instance($user->id)->id,
|
||||
'component' => 'user',
|
||||
'filearea' => 'draft',
|
||||
'itemid' => $draftidattach,
|
||||
'filepath' => '/',
|
||||
'filename' => 'faketxt.txt',
|
||||
'contextid' => $usercontext->id,
|
||||
'component' => $component,
|
||||
'filearea' => $filearea,
|
||||
'itemid' => $draftidinlineattach,
|
||||
'filepath' => $filepath,
|
||||
'filename' => $filenameimg,
|
||||
);
|
||||
$fs = get_file_storage();
|
||||
$fs->create_file_from_string($filerecordinline, 'fake txt contents 1.');
|
||||
|
||||
// Create files in post area (inline).
|
||||
$draftidinlineattach = file_get_unused_draft_itemid();
|
||||
$filerecordinline['itemid'] = $draftidinlineattach;
|
||||
$filerecordinline['filename'] = 'fakeimage.png';
|
||||
$fs->create_file_from_string($filerecordinline, 'img...');
|
||||
// Create a file in a draft area for regular attachments.
|
||||
$filerecordattach = $filerecordinline;
|
||||
$attachfilename = 'faketxt.txt';
|
||||
$filerecordattach['filename'] = $attachfilename;
|
||||
$filerecordattach['itemid'] = $draftidattach;
|
||||
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
|
||||
$fs->create_file_from_string($filerecordattach, 'simple text attachment');
|
||||
|
||||
// Do not update subject.
|
||||
$message = 'Hey message updated';
|
||||
@@ -3324,8 +3139,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id, $cm));
|
||||
|
||||
// Get the post from WS.
|
||||
$result = mod_forum_external::get_forum_discussion_posts($discussion->id);
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $result);
|
||||
$result = mod_forum_external::get_discussion_posts($discussion->id, 'modified', 'DESC');
|
||||
$result = external_api::clean_returnvalue(mod_forum_external::get_discussion_posts_returns(), $result);
|
||||
$found = false;
|
||||
foreach ($result['posts'] as $post) {
|
||||
if ($post['id'] == $newpost->id) {
|
||||
|
||||
@@ -104,4 +104,72 @@ class mod_forum_vaults_post_attachment_testcase extends advanced_testcase {
|
||||
$this->assertEquals($attachment2->get_filename(), $results[$post2->get_id()][0]->get_filename());
|
||||
$this->assertEquals([], $results[$post3->get_id()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_inline_attachments_for_posts.
|
||||
*/
|
||||
public function test_get_inline_attachments_for_posts() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$filestorage = get_file_storage();
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$vault = $vaultfactory->get_post_attachment_vault();
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$coursemodule = get_coursemodule_from_instance('forum', $forum->id);
|
||||
$context = context_module::instance($coursemodule->id);
|
||||
[$discussion, $post1] = $this->helper_post_to_forum($forum, $user);
|
||||
$post2 = $this->helper_reply_to_post($post1, $user);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
$attachment1 = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'post',
|
||||
'itemid' => $post1->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
$attachment2 = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'post',
|
||||
'itemid' => $post2->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example2.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
$post1 = $entityfactory->get_post_from_stdclass($post1);
|
||||
$post2 = $entityfactory->get_post_from_stdclass($post2);
|
||||
$post3 = $entityfactory->get_post_from_stdclass($post3);
|
||||
|
||||
$results = $vault->get_inline_attachments_for_posts(context_system::instance(), [$post1, $post2, $post3]);
|
||||
$this->assertCount(3, $results);
|
||||
$this->assertEquals([], $results[$post1->get_id()]);
|
||||
$this->assertEquals([], $results[$post2->get_id()]);
|
||||
$this->assertEquals([], $results[$post3->get_id()]);
|
||||
|
||||
$results = $vault->get_inline_attachments_for_posts($context, [$post1]);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertEquals($attachment1->get_filename(), $results[$post1->get_id()][0]->get_filename());
|
||||
|
||||
$results = $vault->get_inline_attachments_for_posts($context, [$post1, $post2]);
|
||||
$this->assertCount(2, $results);
|
||||
$this->assertEquals($attachment1->get_filename(), $results[$post1->get_id()][0]->get_filename());
|
||||
$this->assertEquals($attachment2->get_filename(), $results[$post2->get_id()][0]->get_filename());
|
||||
|
||||
$results = $vault->get_inline_attachments_for_posts($context, [$post1, $post2, $post3]);
|
||||
$this->assertCount(3, $results);
|
||||
$this->assertEquals($attachment1->get_filename(), $results[$post1->get_id()][0]->get_filename());
|
||||
$this->assertEquals($attachment2->get_filename(), $results[$post2->get_id()][0]->get_filename());
|
||||
$this->assertEquals([], $results[$post3->get_id()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in /mod/forum/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.0 ===
|
||||
|
||||
* The forum_count_replies() function has been removed from core.
|
||||
* The mod_forum_get_forum_discussion_posts web service has been removed from core.
|
||||
|
||||
=== 3.11 ===
|
||||
|
||||
* The get_forum_discussions_paginated web service has been deprecated in favour of get_forum_discussions.
|
||||
|
||||
Reference in New Issue
Block a user