Merge branch 'MDL-65457-master' of git://github.com/peterRd/moodle

This commit is contained in:
Adrian Greeve 2019-05-10 10:42:34 +08:00
commit cdc5c34030
6 changed files with 112 additions and 56 deletions

View File

@ -124,10 +124,16 @@ class exported_discussion_summaries {
$groupsbyauthorid = $this->get_author_groups_from_posts($posts, $forum);
$replycounts = $postvault->get_reply_count_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
$latestposts = $postvault->get_latest_post_id_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
$postauthorids = array_unique(array_reduce($discussions, function($carry, $summary) {
$latestposts = $postvault->get_latest_posts_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
$latestauthors = $this->get_latest_posts_authors($latestposts);
$latestpostsids = array_map(function($post) {
return $post->get_id();
}, $latestposts);
$postauthorids = array_unique(array_reduce($discussions, function($carry, $summary) use ($latestposts){
$firstpostauthorid = $summary->get_first_post_author()->get_id();
$lastpostauthorid = $summary->get_latest_post_author()->get_id();
$discussion = $summary->get_discussion();
$lastpostauthorid = $latestposts[$discussion->get_id()]->get_author_id();
return array_merge($carry, [$firstpostauthorid, $lastpostauthorid]);
}, []));
$postauthorcontextids = $this->get_author_context_ids($postauthorids);
@ -149,16 +155,18 @@ class exported_discussion_summaries {
$groupsbyauthorid,
$replycounts,
$unreadcounts,
$latestposts,
$latestpostsids,
$postauthorcontextids,
$favourites
$favourites,
$latestauthors
);
$exportedposts = (array) $summaryexporter->export($this->renderer);
$firstposts = $postvault->get_first_post_for_discussion_ids($discussionids);
array_walk($exportedposts['summaries'], function($summary) use ($firstposts) {
array_walk($exportedposts['summaries'], function($summary) use ($firstposts, $latestposts) {
$summary->discussion->times['created'] = (int) $firstposts[$summary->discussion->firstpostid]->created;
$summary->discussion->times['modified'] = (int) $latestposts[$summary->discussion->id]->get_time_created();
});
// Pass the current, preferred sort order for the discussions list.
@ -201,6 +209,23 @@ class exported_discussion_summaries {
return $ids;
}
/**
* Returns a mapped array of discussionid to the authors of the latest post
*
* @param array $latestposts Mapped array of discussion to latest posts.
* @return array Array of authors mapped to the discussion
*/
private function get_latest_posts_authors($latestposts) {
$authors = $this->vaultfactory->get_author_vault()->get_authors_for_posts($latestposts);
$mappedauthors = array_reduce($latestposts, function($carry, $item) use ($authors) {
$carry[$item->get_discussion_id()] = $authors[$item->get_author_id()];
return $carry;
}, []);
return $mappedauthors;
}
/**
* Get the groups details for all groups available to the forum.
* @param forum_entity $forum The forum entity

View File

@ -119,12 +119,15 @@ class discussion_summaries extends exporter {
protected function get_other_values(renderer_base $output) {
$exporteddiscussions = [];
$related = $this->related;
$latestauthors = $this->related['latestauthors'];
foreach ($this->discussions as $discussion) {
$discussionid = $discussion->get_discussion()->get_id();
$replycount = isset($this->discussionreplycount[$discussionid]) ? $this->discussionreplycount[$discussionid] : 0;
$unreadcount = isset($this->discussionunreadcount[$discussionid]) ? $this->discussionunreadcount[$discussionid] : 0;
$latestpostid = isset($this->latestpostids[$discussionid]) ? $this->latestpostids[$discussionid] : 0;
$latestauthor = $latestauthors[$discussionid] ?? null;
$related['latestauthor'] = $latestauthor;
$exporter = new discussion_summary(
$discussion,
$this->groupsbyid,
@ -133,7 +136,7 @@ class discussion_summaries extends exporter {
$unreadcount,
$latestpostid,
$this->postauthorcontextids[$discussion->get_first_post_author()->get_id()],
$this->postauthorcontextids[$discussion->get_latest_post_author()->get_id()],
$this->postauthorcontextids[$latestauthor->get_id()],
$related
);
$exporteddiscussions[] = $exporter->export($output);
@ -160,7 +163,8 @@ class discussion_summaries extends exporter {
'capabilitymanager' => 'mod_forum\local\managers\capability',
'urlfactory' => 'mod_forum\local\factories\url',
'user' => 'stdClass',
'favouriteids' => 'int[]?'
'favouriteids' => 'int[]?',
'latestauthors' => 'mod_forum\local\entities\author[]?'
];
}
}

View File

@ -129,6 +129,7 @@ class discussion_summary extends exporter {
$capabilitymanager = $this->related['capabilitymanager'];
$forum = $this->related['forum'];
$user = $this->related['user'];
$latestpostauthor = $this->related['latestauthor'];
$discussion = $this->summary->get_discussion();
$related = (array) (object) $this->related;
@ -154,7 +155,7 @@ class discussion_summary extends exporter {
);
$latestpostauthor = new author(
$this->summary->get_latest_post_author(),
$latestpostauthor ?? $this->summary->get_latest_post_author(),
$this->latestpostauthorcontextid,
[],
$capabilitymanager->can_view_post(
@ -189,7 +190,8 @@ class discussion_summary extends exporter {
'capabilitymanager' => 'mod_forum\local\managers\capability',
'urlfactory' => 'mod_forum\local\factories\url',
'user' => 'stdClass',
'favouriteids' => 'int[]?'
'favouriteids' => 'int[]?',
'latestauthor' => 'mod_forum\local\entities\author?'
];
}
}

View File

@ -176,7 +176,8 @@ class exporter {
array $discussionunreadcount = [],
array $latestpostids = [],
array $postauthorcontextids = [],
array $favourites = []
array $favourites = [],
array $latestauthors = []
) : discussion_summaries_exporter {
return new discussion_summaries_exporter(
$discussions,
@ -193,7 +194,8 @@ class exporter {
'capabilitymanager' => $this->managerfactory->get_capability_manager($forum),
'urlfactory' => $this->urlfactory,
'user' => $user,
'favouriteids' => $favourites
'favouriteids' => $favourites,
'latestauthors' => $latestauthors
]
);
}

View File

@ -355,42 +355,51 @@ class post extends db_table_vault {
}
/**
* Get a mapping of the most recent post in each discussion based on post creation time.
* Get a mapping of the most recent post record in each discussion based on post creation time.
*
* @param stdClass $user The user to fetch counts for
* @param int[] $discussionids The list of discussions to fetch counts for
* @param bool $canseeprivatereplies Whether this user can see all private replies or not
* @return int[] The post id of the most recent post for each discussions returned in an associative array
* @param stdClass $user
* @param array $discussionids
* @param bool $canseeprivatereplies
* @return array
* @throws \coding_exception
* @throws \dml_exception
*/
public function get_latest_post_id_for_discussion_ids(
stdClass $user, array $discussionids, bool $canseeprivatereplies) : array {
global $CFG;
public function get_latest_posts_for_discussion_ids(
stdClass $user, array $discussionids, bool $canseeprivatereplies) : array {
if (empty($discussionids)) {
return [];
}
$alias = $this->get_table_alias();
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids, SQL_PARAMS_NAMED);
[
'where' => $privatewhere,
'params' => $privateparams,
] = $this->get_private_reply_sql($user, $canseeprivatereplies);
] = $this->get_private_reply_sql($user, $canseeprivatereplies, "mp");
$sql = "
SELECT p.discussion, MAX(p.id)
FROM {" . self::TABLE . "} p
JOIN (
SELECT mp.discussion, MAX(mp.created) AS created
FROM {" . self::TABLE . "} mp
WHERE mp.discussion {$insql}
GROUP BY mp.discussion
) lp ON lp.discussion = p.discussion AND lp.created = p.created
WHERE 1 = 1 {$privatewhere}
GROUP BY p.discussion";
SELECT posts.*
FROM {" . self::TABLE . "} posts
JOIN (
SELECT p.discussion, MAX(p.id) as latestpostid
FROM {" . self::TABLE . "} p
JOIN (
SELECT mp.discussion, MAX(mp.created) AS created
FROM {" . self::TABLE . "} mp
WHERE mp.discussion {$insql} {$privatewhere}
GROUP BY mp.discussion
) lp ON lp.discussion = p.discussion AND lp.created = p.created
GROUP BY p.discussion
) plp on plp.discussion = posts.discussion AND plp.latestpostid = posts.id";
return $this->get_db()->get_records_sql_menu($sql, array_merge($params, $privateparams));
$records = $this->get_db()->get_records_sql($sql, array_merge($params, $privateparams));
$entities = $this->transform_db_records_to_entities($records);
return array_reduce($entities, function($carry, $entity) {
$carry[$entity->get_discussion_id()] = $entity;
return $carry;
}, []);
}
/**
@ -400,11 +409,12 @@ class post extends db_table_vault {
* @param bool $canseeprivatereplies Whether this user can see all private replies or not
* @return array The SQL WHERE clause, and parameters to use in the SQL.
*/
private function get_private_reply_sql(stdClass $user, bool $canseeprivatereplies) {
private function get_private_reply_sql(stdClass $user, bool $canseeprivatereplies, $posttablealias = "p") {
$params = [];
$privatewhere = '';
if (!$canseeprivatereplies) {
$privatewhere = ' AND (p.privatereplyto = :privatereplyto OR p.userid = :privatereplyfrom OR p.privatereplyto = 0)';
$privatewhere = " AND ({$posttablealias}.privatereplyto = :privatereplyto OR " .
"{$posttablealias}.userid = :privatereplyfrom OR {$posttablealias}.privatereplyto = 0)";
$params['privatereplyto'] = $user->id;
$params['privatereplyfrom'] = $user->id;
}

View File

@ -734,17 +734,18 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
}
/**
* Test get_latest_post_id_for_discussion_ids.
* Test get_latest_posts_for_discussion_ids.
*
* @covers ::get_latest_post_id_for_discussion_ids
* @covers ::get_latest_posts_for_discussion_ids
* @covers ::<!public>
*/
public function test_get_latest_post_id_for_discussion_ids() {
public function test_get_latest_posts_for_discussion_ids() {
$this->resetAfterTest();
$datagenerator = $this->getDataGenerator();
$user = $datagenerator->create_user();
$course = $datagenerator->create_course();
[$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
[$user, $user2] = $this->helper_create_users($course, 2, 'student');
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
$post2 = $this->helper_reply_to_post($post1, $user);
@ -753,43 +754,55 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
[$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
$post6 = $this->helper_reply_to_post($post5, $user);
[$discussion3, $post7] = $this->helper_post_to_forum($forum, $user);
$post8 = $this->helper_post_to_discussion($forum, $discussion3, $teacher, [
'privatereplyto' => $user->id,
]);
$ids = $this->vault->get_latest_post_id_for_discussion_ids($user, [$discussion1->id], false);
$ids = $this->vault->get_latest_posts_for_discussion_ids($user, [$discussion1->id], false);
$this->assertCount(1, $ids);
$this->assertEquals($post4->id, $ids[$discussion1->id]);
$this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
$ids = $this->vault->get_latest_post_id_for_discussion_ids($user,
$ids = $this->vault->get_latest_posts_for_discussion_ids($user,
[$discussion1->id, $discussion2->id], false);
$this->assertCount(2, $ids);
$this->assertEquals($post4->id, $ids[$discussion1->id]);
$this->assertEquals($post6->id, $ids[$discussion2->id]);
$this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
$this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
$ids = $this->vault->get_latest_post_id_for_discussion_ids($user,
$ids = $this->vault->get_latest_posts_for_discussion_ids($user,
[$discussion1->id, $discussion2->id, $discussion3->id], false);
$this->assertCount(3, $ids);
$this->assertEquals($post4->id, $ids[$discussion1->id]);
$this->assertEquals($post6->id, $ids[$discussion2->id]);
$this->assertEquals($post7->id, $ids[$discussion3->id]);
$this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
$this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
$this->assertEquals($post8->id, $ids[$discussion3->id]->get_id());
$ids = $this->vault->get_latest_post_id_for_discussion_ids($user, [
// Checks the user who doesn't have access to the private reply.
$ids = $this->vault->get_latest_posts_for_discussion_ids($user2,
[$discussion1->id, $discussion2->id, $discussion3->id], false);
$this->assertCount(3, $ids);
$this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
$this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
$this->assertEquals($post7->id, $ids[$discussion3->id]->get_id());
// Checks the user with the private reply to.
$ids = $this->vault->get_latest_posts_for_discussion_ids($user, [
$discussion1->id,
$discussion2->id,
$discussion3->id,
$discussion3->id + 1000
], false);
$this->assertCount(3, $ids);
$this->assertEquals($post4->id, $ids[$discussion1->id]);
$this->assertEquals($post6->id, $ids[$discussion2->id]);
$this->assertEquals($post7->id, $ids[$discussion3->id]);
$this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
$this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
$this->assertEquals($post8->id, $ids[$discussion3->id]->get_id());
}
/**
* Test get_latest_post_id_for_discussion_ids when no discussion ids were provided.
* Test get_latest_posts_for_discussion_ids when no discussion ids were provided.
*
* @covers ::get_latest_post_id_for_discussion_ids
* @covers ::get_latest_posts_for_discussion_ids
* @covers ::<!public>
*/
public function test_get_latest_post_id_for_discussion_ids_empty() {
public function test_get_latest_posts_for_discussion_ids_empty() {
$this->resetAfterTest();
$datagenerator = $this->getDataGenerator();
@ -797,7 +810,7 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
$course = $datagenerator->create_course();
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
$this->assertEquals([], $this->vault->get_latest_post_id_for_discussion_ids($user, [], false));
$this->assertEquals([], $this->vault->get_latest_posts_for_discussion_ids($user, [], false));
}
/**