mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
MDL-65071 forum: Add sorting in discussion list
This commit is contained in:
parent
3f9ed16e56
commit
1a9c60e931
@ -349,6 +349,7 @@ class icon_system_fontawesome extends icon_system_font {
|
||||
'core:t/dock_to_block' => 'fa-chevron-left',
|
||||
'core:t/download' => 'fa-download',
|
||||
'core:t/down' => 'fa-arrow-down',
|
||||
'core:t/downlong' => 'fa-long-arrow-down',
|
||||
'core:t/dropdown' => 'fa-cog',
|
||||
'core:t/editinline' => 'fa-pencil',
|
||||
'core:t/edit_menu' => 'fa-cog',
|
||||
@ -402,6 +403,7 @@ class icon_system_fontawesome extends icon_system_font {
|
||||
'core:t/unlocked' => 'fa-unlock-alt',
|
||||
'core:t/unlock' => 'fa-lock',
|
||||
'core:t/up' => 'fa-arrow-up',
|
||||
'core:t/uplong' => 'fa-long-arrow-up',
|
||||
'core:t/user' => 'fa-user',
|
||||
'core:t/viewdetails' => 'fa-list',
|
||||
];
|
||||
|
@ -147,7 +147,30 @@ class exported_discussion_summaries {
|
||||
$favourites
|
||||
);
|
||||
|
||||
return (array) $summaryexporter->export($this->renderer);
|
||||
$exportedposts = (array) $summaryexporter->export($this->renderer);
|
||||
$firstposts = $postvault->get_first_post_for_discussion_ids($discussionids);
|
||||
|
||||
array_walk($exportedposts['summaries'], function($summary) use ($firstposts) {
|
||||
$summary->discussion->times['created'] = (int) $firstposts[$summary->discussion->firstpostid]->created;
|
||||
});
|
||||
|
||||
// Pass the current, preferred sort order for the discussions list.
|
||||
$discussionlistvault = $this->vaultfactory->get_discussions_in_forum_vault();
|
||||
$sortorder = get_user_preferences('forum_discussionlistsortorder',
|
||||
$discussionlistvault::SORTORDER_LASTPOST_DESC);
|
||||
|
||||
$sortoptions = array(
|
||||
'islastpostdesc' => $sortorder == $discussionlistvault::SORTORDER_LASTPOST_DESC,
|
||||
'islastpostasc' => $sortorder == $discussionlistvault::SORTORDER_LASTPOST_ASC,
|
||||
'isrepliesdesc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_DESC,
|
||||
'isrepliesasc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_ASC,
|
||||
'iscreateddesc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_DESC,
|
||||
'iscreatedasc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_ASC
|
||||
);
|
||||
|
||||
$exportedposts['state']['sortorder'] = $sortoptions;
|
||||
|
||||
return $exportedposts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,7 +83,8 @@ class container {
|
||||
return new exporter_factory(
|
||||
self::get_legacy_data_mapper_factory(),
|
||||
self::get_manager_factory(),
|
||||
self::get_url_factory()
|
||||
self::get_url_factory(),
|
||||
self::get_vault_factory()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ class discussion extends exporter {
|
||||
'locked' => ['type' => PARAM_BOOL],
|
||||
'istimelocked' => ['type' => PARAM_BOOL],
|
||||
'name' => ['type' => PARAM_TEXT],
|
||||
'firstpostid' => ['type' => PARAM_INT],
|
||||
'group' => [
|
||||
'optional' => true,
|
||||
'type' => [
|
||||
@ -195,6 +196,7 @@ class discussion extends exporter {
|
||||
'name' => format_string($discussion->get_name(), true, [
|
||||
'context' => $this->related['context']
|
||||
]),
|
||||
'firstpostid' => $discussion->get_first_post_id(),
|
||||
'times' => [
|
||||
'modified' => $discussion->get_time_modified(),
|
||||
'start' => $discussion->get_time_start(),
|
||||
|
@ -83,6 +83,12 @@ class forum extends exporter {
|
||||
'create' => ['type' => PARAM_URL],
|
||||
'markasread' => ['type' => PARAM_URL],
|
||||
'view' => ['type' => PARAM_URL],
|
||||
'sortrepliesasc' => ['type' => PARAM_URL],
|
||||
'sortrepliesdesc' => ['type' => PARAM_URL],
|
||||
'sortlastpostasc' => ['type' => PARAM_URL],
|
||||
'sortlastpostdesc' => ['type' => PARAM_URL],
|
||||
'sortcreatedasc' => ['type' => PARAM_URL],
|
||||
'sortcreateddesc' => ['type' => PARAM_URL],
|
||||
],
|
||||
],
|
||||
];
|
||||
@ -99,6 +105,8 @@ class forum extends exporter {
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
$user = $this->related['user'];
|
||||
$currentgroup = $this->related['currentgroup'];
|
||||
$vaultfactory = $this->related['vaultfactory'];
|
||||
$discussionvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
|
||||
return [
|
||||
'id' => $this->forum->get_id(),
|
||||
@ -117,6 +125,18 @@ class forum extends exporter {
|
||||
'create' => $urlfactory->get_discussion_create_url($this->forum)->out(false),
|
||||
'markasread' => $urlfactory->get_mark_all_discussions_as_read_url($this->forum)->out(false),
|
||||
'view' => $urlfactory->get_forum_view_url_from_forum($this->forum)->out(false),
|
||||
'sortrepliesasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_REPLIES_ASC)->out(false),
|
||||
'sortrepliesdesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_REPLIES_DESC)->out(false),
|
||||
'sortlastpostasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_LASTPOST_ASC)->out(false),
|
||||
'sortlastpostdesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_LASTPOST_DESC)->out(false),
|
||||
'sortcreatedasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_CREATED_ASC)->out(false),
|
||||
'sortcreateddesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
|
||||
$discussionvault::SORTORDER_CREATED_DESC)->out(false)
|
||||
],
|
||||
];
|
||||
}
|
||||
@ -133,6 +153,7 @@ class forum extends exporter {
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'user' => 'stdClass',
|
||||
'currentgroup' => 'int?',
|
||||
'vaultfactory' => 'mod_forum\local\factories\vault'
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ use mod_forum\local\entities\post_read_receipt_collection as post_read_receipt_c
|
||||
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
||||
use mod_forum\local\factories\manager as manager_factory;
|
||||
use mod_forum\local\factories\url as url_factory;
|
||||
use mod_forum\local\factories\vault as vault_factory;
|
||||
use mod_forum\local\exporters\forum as forum_exporter;
|
||||
use mod_forum\local\exporters\discussion as discussion_exporter;
|
||||
use mod_forum\local\exporters\discussion_summaries as discussion_summaries_exporter;
|
||||
@ -61,21 +62,23 @@ class exporter {
|
||||
/** @var url_factory The factory to create urls */
|
||||
private $urlfactory;
|
||||
|
||||
/** @var vault_factory The vault factory */
|
||||
private $vaultfactory;
|
||||
|
||||
/**
|
||||
* Constructor for the exporter factory.
|
||||
*
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory The factory to fetch a legacy data mapper instance
|
||||
* @param manager_factory $managerfactory The factory fo fetch a manager instance
|
||||
* @param url_factory $urlfactory The factory to create urls
|
||||
* @param vault_factory $vaultfactory The vault factory
|
||||
*/
|
||||
public function __construct(
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
manager_factory $managerfactory,
|
||||
url_factory $urlfactory
|
||||
) {
|
||||
public function __construct(legacy_data_mapper_factory $legacydatamapperfactory, manager_factory $managerfactory,
|
||||
url_factory $urlfactory, vault_factory $vaultfactory) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->managerfactory = $managerfactory;
|
||||
$this->urlfactory = $urlfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,6 +100,7 @@ class exporter {
|
||||
'urlfactory' => $this->urlfactory,
|
||||
'user' => $user,
|
||||
'currentgroup' => $currentgroup,
|
||||
'vaultfactory' => $this->vaultfactory,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -95,10 +95,13 @@ class url {
|
||||
*
|
||||
* @param forum_entity $forum The forum entity
|
||||
* @param int|null $pageno The page number
|
||||
* @param int|null $sortorder The sorting order
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_forum_view_url_from_forum(forum_entity $forum, ?int $pageno = null) : moodle_url {
|
||||
return $this->get_forum_view_url_from_course_module_id($forum->get_course_module_record()->id, $pageno);
|
||||
public function get_forum_view_url_from_forum(forum_entity $forum, ?int $pageno = null,
|
||||
?int $sortorder = null) : moodle_url {
|
||||
|
||||
return $this->get_forum_view_url_from_course_module_id($forum->get_course_module_record()->id, $pageno, $sortorder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,15 +109,22 @@ class url {
|
||||
*
|
||||
* @param int $coursemoduleid The course module id
|
||||
* @param int|null $pageno The page number
|
||||
* @param int|null $sortorder The sorting order
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_forum_view_url_from_course_module_id(int $coursemoduleid, ?int $pageno = null) : moodle_url {
|
||||
public function get_forum_view_url_from_course_module_id(int $coursemoduleid, ?int $pageno = null,
|
||||
?int $sortorder = null) : moodle_url {
|
||||
|
||||
$url = new moodle_url('/mod/forum/view.php', [
|
||||
'id' => $coursemoduleid,
|
||||
]);
|
||||
|
||||
if (null !== $pageno) {
|
||||
$url->param('page', $pageno);
|
||||
$url->param('p', $pageno);
|
||||
}
|
||||
|
||||
if (null !== $sortorder) {
|
||||
$url->param('o', $sortorder);
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
@ -328,11 +328,27 @@ class capability {
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_favourite_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
public function can_favourite_discussion(stdClass $user, discussion_entity $discussion) : bool
|
||||
{
|
||||
$context = $this->get_context();
|
||||
return has_capability('mod/forum:cantogglefavourite', $context, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view the content of a discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
$forumrecord = $this->get_forum_record();
|
||||
$discussionrecord = $this->get_discussion_record($discussion);
|
||||
$context = $this->get_context();
|
||||
|
||||
return forum_user_can_see_discussion($forumrecord, $discussionrecord, $context, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view the content of the post in this discussion?
|
||||
*
|
||||
|
@ -145,21 +145,20 @@ class discussion_list {
|
||||
|
||||
$forum = $this->forum;
|
||||
|
||||
$pagesize = $this->get_page_size($pagesize);
|
||||
$pageno = $this->get_page_number($pageno);
|
||||
|
||||
$groupids = $this->get_groups_from_groupid($user, $groupid);
|
||||
$forumexporter = $this->exporterfactory->get_forum_exporter(
|
||||
$user,
|
||||
$this->forum,
|
||||
$groupid
|
||||
);
|
||||
|
||||
$pagesize = $this->get_page_size($pagesize);
|
||||
$pageno = $this->get_page_number($pageno);
|
||||
|
||||
// Count all forum discussion posts.
|
||||
$alldiscussionscount = $this->get_count_all_discussions($user, $groupids);
|
||||
$alldiscussionscount = get_count_all_discussions($forum, $user, $groupid);
|
||||
|
||||
// Get all forum discussions posts.
|
||||
$discussions = $this->get_discussions($user, $groupids, $sortorder, $pageno, $pagesize);
|
||||
$discussions = get_discussions($forum, $user, $groupid, $sortorder, $pageno, $pagesize);
|
||||
|
||||
$forumview = [
|
||||
'forum' => (array) $forumexporter->export($this->renderer),
|
||||
@ -186,10 +185,12 @@ class discussion_list {
|
||||
$exportedposts = ($this->postprocessfortemplate) ($discussions, $user, $forum);
|
||||
}
|
||||
|
||||
$baseurl = new \moodle_url($PAGE->url, array('o' => $sortorder));
|
||||
|
||||
$forumview = array_merge(
|
||||
$forumview,
|
||||
[
|
||||
'pagination' => $this->renderer->render(new \paging_bar($alldiscussionscount, $pageno, $pagesize, $PAGE->url, 'p')),
|
||||
'pagination' => $this->renderer->render(new \paging_bar($alldiscussionscount, $pageno, $pagesize, $baseurl, 'p')),
|
||||
],
|
||||
$exportedposts
|
||||
);
|
||||
@ -256,102 +257,6 @@ class discussion_list {
|
||||
return $mformpost->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of groups to show based on the current user and requested groupid.
|
||||
*
|
||||
* @param stdClass $user The user viewing
|
||||
* @param int $groupid The groupid requested
|
||||
* @return array The list of groups to show
|
||||
*/
|
||||
private function get_groups_from_groupid(stdClass $user, ?int $groupid) : ?array {
|
||||
$forum = $this->forum;
|
||||
$effectivegroupmode = $forum->get_effective_group_mode();
|
||||
if (empty($effectivegroupmode)) {
|
||||
// This forum is not in a group mode. Show all posts always.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null == $groupid) {
|
||||
// No group was specified.
|
||||
$showallgroups = (VISIBLEGROUPS == $effectivegroupmode);
|
||||
$showallgroups = $showallgroups || $this->capabilitymanager->can_access_all_groups($user);
|
||||
if ($showallgroups) {
|
||||
// Return null to show all groups.
|
||||
return null;
|
||||
} else {
|
||||
// No group was specified. Only show the users current groups.
|
||||
return array_keys(
|
||||
groups_get_all_groups(
|
||||
$forum->get_course_id(),
|
||||
$user->id,
|
||||
$forum->get_course_module_record()->groupingid
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// A group was specified. Just show that group.
|
||||
return [$groupid];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the data used to display the discussions on the current page.
|
||||
*
|
||||
* @param stdClass $user The user to render for
|
||||
* @param int[]|null $groupids The group ids for this list of discussions
|
||||
* @param int|null $sortorder The sort order to use when selecting the discussions in the list
|
||||
* @param int|null $pageno The zero-indexed page number to use
|
||||
* @param int|null $pagesize The number of discussions to show on the page
|
||||
* @return stdClass The data to use for display
|
||||
*/
|
||||
private function get_discussions(stdClass $user, ?array $groupids, ?int $sortorder, ?int $pageno, ?int $pagesize) {
|
||||
$forum = $this->forum;
|
||||
$discussionvault = $this->vaultfactory->get_discussions_in_forum_vault();
|
||||
if (null === $groupids) {
|
||||
return $discussions = $discussionvault->get_from_forum_id(
|
||||
$forum->get_id(),
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id,
|
||||
$sortorder,
|
||||
$this->get_page_size($pagesize),
|
||||
$this->get_page_number($pageno) * $this->get_page_size($pagesize),
|
||||
$user);
|
||||
} else {
|
||||
return $discussions = $discussionvault->get_from_forum_id_and_group_id(
|
||||
$forum->get_id(),
|
||||
$groupids,
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id,
|
||||
$sortorder,
|
||||
$this->get_page_size($pagesize),
|
||||
$this->get_page_number($pageno) * $this->get_page_size($pagesize),
|
||||
$user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all discussions in a forum.
|
||||
*
|
||||
* @param stdClass $user The user to render for
|
||||
* @param array $groupids The array of groups to render
|
||||
* @return int The number of discussions in a forum
|
||||
*/
|
||||
public function get_count_all_discussions(stdClass $user, ?array $groupids) {
|
||||
$discussionvault = $this->vaultfactory->get_discussions_in_forum_vault();
|
||||
if (null === $groupids) {
|
||||
return $discussionvault->get_total_discussion_count_from_forum_id(
|
||||
$this->forum->get_id(),
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
} else {
|
||||
return $discussionvault->get_total_discussion_count_from_forum_id_and_group_id(
|
||||
$this->forum->get_id(),
|
||||
$groupids,
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the page size to use when displaying the page.
|
||||
*
|
||||
|
@ -59,11 +59,17 @@ class discussion_list extends db_table_vault {
|
||||
public const PAGESIZE_DEFAULT = 100;
|
||||
|
||||
/** Sort by newest first */
|
||||
public const SORTORDER_NEWEST_FIRST = 1;
|
||||
public const SORTORDER_LASTPOST_DESC = 1;
|
||||
/** Sort by oldest first */
|
||||
public const SORTORDER_OLDEST_FIRST = 2;
|
||||
public const SORTORDER_LASTPOST_ASC = 2;
|
||||
/** Sort by created desc */
|
||||
public const SORTORDER_CREATED_DESC = 3;
|
||||
/** Sort by created asc */
|
||||
public const SORTORDER_CREATED_ASC = 4;
|
||||
/** Sort by number of replies desc */
|
||||
public const SORTORDER_REPLIES_DESC = 5;
|
||||
/** Sort by number of replies desc */
|
||||
public const SORTORDER_REPLIES_ASC = 6;
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
@ -119,12 +125,29 @@ class discussion_list extends db_table_vault {
|
||||
$latestuserfields,
|
||||
]);
|
||||
|
||||
$sortkeys = [
|
||||
$this->get_sort_order(self::SORTORDER_REPLIES_DESC),
|
||||
$this->get_sort_order(self::SORTORDER_REPLIES_ASC)
|
||||
];
|
||||
$issortbyreplies = in_array($sortsql, $sortkeys);
|
||||
|
||||
$tables = $thistable->get_from_sql();
|
||||
$tables .= ' JOIN {user} fa ON fa.id = ' . $alias . '.userid';
|
||||
$tables .= ' JOIN {user} la ON la.id = ' . $alias . '.usermodified';
|
||||
$tables .= ' JOIN ' . $posttable->get_from_sql() . ' ON fp.id = ' . $alias . '.firstpost';
|
||||
$tables .= isset($favsql) ? $favsql : '';
|
||||
|
||||
if ($issortbyreplies) {
|
||||
// Join the discussion replies.
|
||||
$tables .= ' JOIN (
|
||||
SELECT rd.id, COUNT(rp.id) as replycount
|
||||
FROM {forum_discussions} rd
|
||||
LEFT JOIN {forum_posts} rp
|
||||
ON rp.discussion = rd.id AND rp.id != rd.firstpost
|
||||
GROUP BY rd.id
|
||||
) r ON d.id = r.id';
|
||||
}
|
||||
|
||||
$selectsql = 'SELECT ' . $fields . ' FROM ' . $tables;
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
@ -191,31 +214,64 @@ class discussion_list extends db_table_vault {
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field to sort by.
|
||||
*
|
||||
* @param int|null $sortmethod
|
||||
* @return string
|
||||
*/
|
||||
protected function get_keyfield(?int $sortmethod) : string {
|
||||
switch ($sortmethod) {
|
||||
case self::SORTORDER_CREATED_DESC:
|
||||
case self::SORTORDER_CREATED_ASC:
|
||||
return 'fp.created';
|
||||
case self::SORTORDER_REPLIES_DESC:
|
||||
case self::SORTORDER_REPLIES_ASC:
|
||||
return 'replycount';
|
||||
default:
|
||||
global $CFG;
|
||||
$alias = $this->get_table_alias();
|
||||
$field = "{$alias}.timemodified";
|
||||
if (!empty($CFG->forum_enabletimedposts)) {
|
||||
return "CASE WHEN {$field} < {$alias}.timestart THEN {$alias}.timestart ELSE {$field} END";
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sort direction.
|
||||
*
|
||||
* @param int|null $sortmethod
|
||||
* @return string
|
||||
*/
|
||||
protected function get_sort_direction(?int $sortmethod) : string {
|
||||
switch ($sortmethod) {
|
||||
case self::SORTORDER_LASTPOST_ASC:
|
||||
case self::SORTORDER_CREATED_ASC:
|
||||
case self::SORTORDER_REPLIES_ASC:
|
||||
return "ASC";
|
||||
case self::SORTORDER_LASTPOST_DESC:
|
||||
case self::SORTORDER_CREATED_DESC:
|
||||
case self::SORTORDER_REPLIES_DESC:
|
||||
return "DESC";
|
||||
default:
|
||||
return "DESC";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sort order SQL for a sort method.
|
||||
*
|
||||
* @param int|null $sortmethod
|
||||
* @return string
|
||||
*/
|
||||
public function get_sort_order(?int $sortmethod, $includefavourites = true) : string {
|
||||
global $CFG;
|
||||
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
if ($sortmethod == self::SORTORDER_CREATED_DESC) {
|
||||
$keyfield = "fp.created";
|
||||
$direction = "DESC";
|
||||
} else {
|
||||
$keyfield = "{$alias}.timemodified";
|
||||
$direction = "DESC";
|
||||
|
||||
if ($sortmethod == self::SORTORDER_OLDEST_FIRST) {
|
||||
$direction = "ASC";
|
||||
}
|
||||
|
||||
if (!empty($CFG->forum_enabletimedposts)) {
|
||||
$keyfield = "CASE WHEN {$keyfield} < {$alias}.timestart THEN {$alias}.timestart ELSE {$keyfield} END";
|
||||
}
|
||||
}
|
||||
// TODO consider user favourites...
|
||||
$keyfield = $this->get_keyfield($sortmethod);
|
||||
$direction = $this->get_sort_direction($sortmethod);
|
||||
|
||||
$favouritesort = '';
|
||||
if ($includefavourites) {
|
||||
|
@ -414,4 +414,31 @@ class post extends db_table_vault {
|
||||
'params' => $params,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mapping of the first post in each discussion based on post creation time.
|
||||
*
|
||||
* @param int[] $discussionids The list of discussions to fetch counts for
|
||||
* @return stdClass[] The post object of the first post for each discussions returned in an associative array
|
||||
*/
|
||||
public function get_first_post_for_discussion_ids(array $discussionids) : array {
|
||||
|
||||
if (empty($discussionids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids, SQL_PARAMS_NAMED);
|
||||
|
||||
$sql = "
|
||||
SELECT p.*
|
||||
FROM {" . self::TABLE . "} p
|
||||
JOIN (
|
||||
SELECT mp.discussion, MIN(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";
|
||||
|
||||
return $this->get_db()->get_records_sql($sql, $params);
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +140,8 @@ class provider implements
|
||||
$items->add_user_preference('autosubscribe', 'privacy:metadata:preference:autosubscribe');
|
||||
$items->add_user_preference('trackforums', 'privacy:metadata:preference:trackforums');
|
||||
$items->add_user_preference('markasreadonnotification', 'privacy:metadata:preference:markasreadonnotification');
|
||||
$items->add_user_preference('forum_discussionlistsortorder',
|
||||
'privacy:metadata:preference:forum_discussionlistsortorder');
|
||||
|
||||
return $items;
|
||||
}
|
||||
@ -407,8 +409,42 @@ class provider implements
|
||||
writer::export_user_preference('mod_forum', 'markasreadonnotification', $markasreadonnotification,
|
||||
$markasreadonnotificationdescription);
|
||||
}
|
||||
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$discussionlistvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
$discussionlistsortorder = get_user_preferences('forum_discussionlistsortorder',
|
||||
$discussionlistvault::SORTORDER_LASTPOST_DESC);
|
||||
switch ($discussionlistsortorder) {
|
||||
case $discussionlistvault::SORTORDER_LASTPOST_DESC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbylastpostdesc',
|
||||
'mod_forum');
|
||||
break;
|
||||
case $discussionlistvault::SORTORDER_LASTPOST_ASC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbylastpostasc',
|
||||
'mod_forum');
|
||||
break;
|
||||
case $discussionlistvault::SORTORDER_CREATED_DESC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbycreateddesc',
|
||||
'mod_forum');
|
||||
break;
|
||||
case $discussionlistvault::SORTORDER_CREATED_ASC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbycreatedasc',
|
||||
'mod_forum');
|
||||
break;
|
||||
case $discussionlistvault::SORTORDER_REPLIES_DESC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbyrepliesdesc',
|
||||
'mod_forum');
|
||||
break;
|
||||
case $discussionlistvault::SORTORDER_REPLIES_ASC:
|
||||
$discussionlistsortorderdescription = get_string('discussionlistsortbyrepliesasc',
|
||||
'mod_forum');
|
||||
break;
|
||||
}
|
||||
writer::export_user_preference('mod_forum', 'forum_discussionlistsortorder',
|
||||
$discussionlistsortorder, $discussionlistsortorderdescription);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
|
@ -61,6 +61,17 @@ $functions = array(
|
||||
'classname' => 'mod_forum_external',
|
||||
'methodname' => 'get_forum_discussions_paginated',
|
||||
'classpath' => 'mod/forum/externallib.php',
|
||||
'description' => '** DEPRECATED ** Please do not call this function any more.
|
||||
Returns a list of forum discussions optionally sorted and paginated.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/forum:viewdiscussion, mod/forum:viewqandawithoutposting',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
|
||||
'mod_forum_get_forum_discussions' => array(
|
||||
'classname' => 'mod_forum_external',
|
||||
'methodname' => 'get_forum_discussions',
|
||||
'classpath' => 'mod/forum/externallib.php',
|
||||
'description' => 'Returns a list of forum discussions optionally sorted and paginated.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/forum:viewdiscussion, mod/forum:viewqandawithoutposting',
|
||||
|
@ -496,6 +496,7 @@ class mod_forum_external extends external_api {
|
||||
/**
|
||||
* Describes the parameters for get_forum_discussions_paginated.
|
||||
*
|
||||
* @deprecated since 3.7
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
@ -515,6 +516,7 @@ class mod_forum_external extends external_api {
|
||||
/**
|
||||
* Returns a list of forum discussions optionally sorted and paginated.
|
||||
*
|
||||
* @deprecated since 3.7
|
||||
* @param int $forumid the forum instance id
|
||||
* @param string $sortby sort by this element (id, timemodified, timestart or timeend)
|
||||
* @param string $sortdirection sort direction: ASC or DESC
|
||||
@ -525,7 +527,7 @@ class mod_forum_external extends external_api {
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
public static function get_forum_discussions_paginated($forumid, $sortby = 'timemodified', $sortdirection = 'DESC',
|
||||
$page = -1, $perpage = 0) {
|
||||
$page = -1, $perpage = 0) {
|
||||
global $CFG, $DB, $USER, $PAGE;
|
||||
|
||||
require_once($CFG->dirroot . "/mod/forum/lib.php");
|
||||
@ -699,6 +701,7 @@ class mod_forum_external extends external_api {
|
||||
/**
|
||||
* Describes the get_forum_discussions_paginated return value.
|
||||
*
|
||||
* @deprecated since 3.7
|
||||
* @return external_single_structure
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
@ -750,6 +753,274 @@ class mod_forum_external extends external_api {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for get_forum_discussions.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 3.7
|
||||
*/
|
||||
public static function get_forum_discussions_parameters() {
|
||||
return new external_function_parameters (
|
||||
array(
|
||||
'forumid' => new external_value(PARAM_INT, 'forum instance id', VALUE_REQUIRED),
|
||||
'sortorder' => new external_value(PARAM_INT,
|
||||
'sort by this element: numreplies, , created or timemodified', VALUE_DEFAULT, -1),
|
||||
'page' => new external_value(PARAM_INT, 'current page', VALUE_DEFAULT, -1),
|
||||
'perpage' => new external_value(PARAM_INT, 'items per page', VALUE_DEFAULT, 0),
|
||||
'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of forum discussions optionally sorted and paginated.
|
||||
*
|
||||
* @param int $forumid the forum instance id
|
||||
* @param int $sortorder The sort order
|
||||
* @param int $page page number
|
||||
* @param int $perpage items per page
|
||||
* @param int $groupid the user course group
|
||||
*
|
||||
*
|
||||
* @return array the forum discussion details including warnings
|
||||
* @since Moodle 3.7
|
||||
*/
|
||||
public static function get_forum_discussions(int $forumid, ?int $sortorder = -1, ?int $page = -1,
|
||||
?int $perpage = 0, ?int $groupid = 0) {
|
||||
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
require_once($CFG->dirroot . "/mod/forum/lib.php");
|
||||
|
||||
$warnings = array();
|
||||
$discussions = array();
|
||||
|
||||
$params = self::validate_parameters(self::get_forum_discussions_parameters(),
|
||||
array(
|
||||
'forumid' => $forumid,
|
||||
'sortorder' => $sortorder,
|
||||
'page' => $page,
|
||||
'perpage' => $perpage,
|
||||
'groupid' => $groupid
|
||||
)
|
||||
);
|
||||
|
||||
// Compact/extract functions are not recommended.
|
||||
$forumid = $params['forumid'];
|
||||
$sortorder = $params['sortorder'];
|
||||
$page = $params['page'];
|
||||
$perpage = $params['perpage'];
|
||||
$groupid = $params['groupid'];
|
||||
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$discussionlistvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
|
||||
$sortallowedvalues = array(
|
||||
$discussionlistvault::SORTORDER_LASTPOST_DESC,
|
||||
$discussionlistvault::SORTORDER_LASTPOST_ASC,
|
||||
$discussionlistvault::SORTORDER_CREATED_DESC,
|
||||
$discussionlistvault::SORTORDER_CREATED_ASC,
|
||||
$discussionlistvault::SORTORDER_REPLIES_DESC,
|
||||
$discussionlistvault::SORTORDER_REPLIES_ASC
|
||||
);
|
||||
|
||||
// If sortorder not defined set a default one.
|
||||
if ($sortorder == -1) {
|
||||
$sortorder = $discussionlistvault::SORTORDER_LASTPOST_DESC;
|
||||
}
|
||||
|
||||
if (!in_array($sortorder, $sortallowedvalues)) {
|
||||
throw new invalid_parameter_exception('Invalid value for sortorder parameter (value: ' . $sortorder . '),' .
|
||||
' allowed values are: ' . implode(',', $sortallowedvalues));
|
||||
}
|
||||
|
||||
$managerfactory = \mod_forum\local\container::get_manager_factory();
|
||||
$urlfactory = \mod_forum\local\container::get_url_factory();
|
||||
$legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
|
||||
|
||||
$forumvault = $vaultfactory->get_forum_vault();
|
||||
$forum = $forumvault->get_from_id($forumid);
|
||||
$forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper();
|
||||
$forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
|
||||
$capabilitymanager = $managerfactory->get_capability_manager($forum);
|
||||
|
||||
$course = $DB->get_record('course', array('id' => $forum->get_course_id()), '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_instance('forum', $forum->get_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);
|
||||
|
||||
$canseeanyprivatereply = $capabilitymanager->can_view_any_private_reply($USER);
|
||||
|
||||
// Check they have the view forum capability.
|
||||
if (!$capabilitymanager->can_view_discussions($USER)) {
|
||||
throw new moodle_exception('noviewdiscussionspermission', 'forum');
|
||||
}
|
||||
|
||||
$alldiscussions = get_discussions($forum, $USER, $groupid, $sortorder, $page, $perpage);
|
||||
|
||||
if ($alldiscussions) {
|
||||
$discussionids = array_keys($alldiscussions);
|
||||
|
||||
$postvault = $vaultfactory->get_post_vault();
|
||||
// Return the reply count for each discussion in a given forum.
|
||||
$replies = $postvault->get_reply_count_for_discussion_ids($USER, $discussionids, $canseeanyprivatereply);
|
||||
// Return the first post for each discussion in a given forum.
|
||||
$firstposts = $postvault->get_first_post_for_discussion_ids($discussionids);
|
||||
|
||||
// Get the unreads array, this takes a forum id and returns data for all discussions.
|
||||
$unreads = array();
|
||||
if ($cantrack = forum_tp_can_track_forums($forumrecord)) {
|
||||
if ($forumtracked = forum_tp_is_tracked($forumrecord)) {
|
||||
$unreads = $postvault->get_unread_count_for_discussion_ids($USER, $discussionids, $canseeanyprivatereply);
|
||||
}
|
||||
}
|
||||
|
||||
$canlock = $capabilitymanager->can_manage_forum($USER);
|
||||
|
||||
foreach ($alldiscussions as $discussionsummary) {
|
||||
$discussion = $discussionsummary->get_discussion();
|
||||
$firstpostauthor = $discussionsummary->get_first_post_author();
|
||||
$latestpostauthor = $discussionsummary->get_latest_post_author();
|
||||
|
||||
// This function checks for qanda forums.
|
||||
$canviewdiscussion = $capabilitymanager->can_view_discussion($USER, $discussion);
|
||||
if (!$canviewdiscussion) {
|
||||
$warning = array();
|
||||
// Function forum_get_discussions returns forum_posts ids not forum_discussions ones.
|
||||
$warning['item'] = 'post';
|
||||
$warning['itemid'] = $discussion->get_id();
|
||||
$warning['warningcode'] = '1';
|
||||
$warning['message'] = 'You can\'t see this discussion';
|
||||
$warnings[] = $warning;
|
||||
continue;
|
||||
}
|
||||
|
||||
$discussionobject = $firstposts[$discussion->get_first_post_id()];
|
||||
$discussionobject->groupid = $discussion->get_group_id();
|
||||
$discussionobject->timemodified = $discussion->get_time_modified();
|
||||
$discussionobject->usermodified = $discussion->get_user_modified();
|
||||
$discussionobject->timestart = $discussion->get_time_start();
|
||||
$discussionobject->timeend = $discussion->get_time_end();
|
||||
$discussionobject->pinned = $discussion->is_pinned();
|
||||
|
||||
$discussionobject->numunread = 0;
|
||||
if ($cantrack && $forumtracked) {
|
||||
if (isset($unreads[$discussion->get_id()])) {
|
||||
$discussionobject->numunread = (int) $unreads[$discussion->get_id()];
|
||||
}
|
||||
}
|
||||
|
||||
$discussionobject->numreplies = 0;
|
||||
if (!empty($replies[$discussion->get_id()])) {
|
||||
$discussionobject->numreplies = (int) $replies[$discussion->get_id()];
|
||||
}
|
||||
|
||||
$discussionobject->name = external_format_string($discussion->get_name(), $modcontext->id);
|
||||
$discussionobject->subject = external_format_string($discussionobject->subject, $modcontext->id);
|
||||
// Rewrite embedded images URLs.
|
||||
list($discussionobject->message, $discussionobject->messageformat) =
|
||||
external_format_text($discussionobject->message, $discussionobject->messageformat,
|
||||
$modcontext->id, 'mod_forum', 'post', $discussionobject->id);
|
||||
|
||||
// List attachments.
|
||||
if (!empty($discussionobject->attachment)) {
|
||||
$discussionobject->attachments = external_util::get_area_files($modcontext->id, 'mod_forum',
|
||||
'attachment', $discussionobject->id);
|
||||
}
|
||||
$messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post',
|
||||
$discussionobject->id);
|
||||
if (!empty($messageinlinefiles)) {
|
||||
$discussionobject->messageinlinefiles = $messageinlinefiles;
|
||||
}
|
||||
|
||||
$discussionobject->locked = $forum->is_discussion_locked($discussion);
|
||||
$discussionobject->canlock = $canlock;
|
||||
$discussionobject->canreply = $capabilitymanager->can_post_in_discussion($USER, $discussion);
|
||||
|
||||
if (forum_is_author_hidden($discussionobject, $forumrecord)) {
|
||||
$discussionobject->userid = null;
|
||||
$discussionobject->userfullname = null;
|
||||
$discussionobject->userpictureurl = null;
|
||||
|
||||
$discussionobject->usermodified = null;
|
||||
$discussionobject->usermodifiedfullname = null;
|
||||
$discussionobject->usermodifiedpictureurl = null;
|
||||
|
||||
} else {
|
||||
$discussionobject->userfullname = $firstpostauthor->get_full_name();
|
||||
$discussionobject->userpictureurl = $urlfactory->get_author_profile_image_url($firstpostauthor)
|
||||
->out(false);
|
||||
|
||||
$discussionobject->usermodifiedfullname = $latestpostauthor->get_full_name();
|
||||
$discussionobject->usermodifiedpictureurl = $urlfactory->get_author_profile_image_url($latestpostauthor)
|
||||
->out(false);
|
||||
}
|
||||
|
||||
$discussions[] = (array) $discussionobject;
|
||||
}
|
||||
}
|
||||
$result = array();
|
||||
$result['discussions'] = $discussions;
|
||||
$result['warnings'] = $warnings;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the get_forum_discussions return value.
|
||||
*
|
||||
* @return external_single_structure
|
||||
* @since Moodle 3.7
|
||||
*/
|
||||
public static function get_forum_discussions_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'discussions' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'Post id'),
|
||||
'name' => new external_value(PARAM_TEXT, 'Discussion name'),
|
||||
'groupid' => new external_value(PARAM_INT, 'Group id'),
|
||||
'timemodified' => new external_value(PARAM_INT, 'Time modified'),
|
||||
'usermodified' => new external_value(PARAM_INT, 'The id of the user who last modified'),
|
||||
'timestart' => new external_value(PARAM_INT, 'Time discussion can start'),
|
||||
'timeend' => new external_value(PARAM_INT, 'Time discussion ends'),
|
||||
'discussion' => new external_value(PARAM_INT, 'Discussion id'),
|
||||
'parent' => new external_value(PARAM_INT, 'Parent id'),
|
||||
'userid' => new external_value(PARAM_INT, 'User who started the discussion 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_TEXT, '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?'),
|
||||
'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'),
|
||||
'usermodifiedfullname' => new external_value(PARAM_TEXT, 'Post modifier full name'),
|
||||
'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.'),
|
||||
'usermodifiedpictureurl' => new external_value(PARAM_URL, 'Post modifier picture.'),
|
||||
'numreplies' => new external_value(PARAM_INT, 'The number of replies in the discussion'),
|
||||
'numunread' => new external_value(PARAM_INT, 'The number of unread discussions.'),
|
||||
'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned'),
|
||||
'locked' => new external_value(PARAM_BOOL, 'Is the discussion locked'),
|
||||
'canreply' => new external_value(PARAM_BOOL, 'Can the user reply to the discussion'),
|
||||
'canlock' => new external_value(PARAM_BOOL, 'Can the user lock the discussion'),
|
||||
), 'post'
|
||||
)
|
||||
),
|
||||
'warnings' => new external_warnings()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
|
@ -131,6 +131,7 @@ $string['confirmunsubscribe'] = 'Do you really want to unsubscribe from forum \'
|
||||
$string['couldnotadd'] = 'Could not add your post due to an unknown error';
|
||||
$string['couldnotdeletereplies'] = 'Sorry, that cannot be deleted as people have already responded to it';
|
||||
$string['couldnotupdate'] = 'Could not update your post due to an unknown error';
|
||||
$string['created'] = 'Created';
|
||||
$string['crontask'] = 'Forum mailings and maintenance jobs';
|
||||
$string['cutoffdate'] = 'Cut-off date';
|
||||
$string['cutoffdate_help'] = 'If set, the forum will not accept posts after this date.';
|
||||
@ -154,6 +155,12 @@ $string['disallowsubscription'] = 'Subscription';
|
||||
$string['disallowsubscription_help'] = 'This forum has been configured so that you cannot subscribe to discussions.';
|
||||
$string['disallowsubscribeteacher'] = 'Subscriptions not allowed (except for teachers)';
|
||||
$string['discussion'] = 'Discussion';
|
||||
$string['discussionlistsortbycreatedasc'] = 'Sort the discussions list by the creation date in ascending order';
|
||||
$string['discussionlistsortbycreateddesc'] = 'Sort the discussions list by the creation date in descending order';
|
||||
$string['discussionlistsortbylastpostdesc'] = 'Sort the discussions list by the creation date of the last post in descending order';
|
||||
$string['discussionlistsortbylastpostasc'] = 'Sort the discussions list by the creation date of the last post in ascending order';
|
||||
$string['discussionlistsortbyrepliesasc'] = 'Sort the discussions list by the number of replies in ascending order';
|
||||
$string['discussionlistsortbyrepliesdesc'] = 'Sort the discussions list by the number of replies in descending order';
|
||||
$string['discussionlocked'] = 'This discussion has been locked so you can no longer reply to it.';
|
||||
$string['discussionlockingheader'] = 'Discussion locking';
|
||||
$string['discussionlockingdisabled'] = 'Do not lock discussions';
|
||||
@ -517,6 +524,7 @@ $string['privacy:metadata:forum_track_prefs'] = 'Information about which forums
|
||||
$string['privacy:metadata:forum_track_prefs:forumid'] = 'The forum that has read tracking enabled.';
|
||||
$string['privacy:metadata:forum_track_prefs:userid'] = 'The ID of the user that this forum tracking preference relates to.';
|
||||
$string['privacy:metadata:preference:autosubscribe'] = 'Whether to subscribe to discussions when replying to posts within them.';
|
||||
$string['privacy:metadata:preference:forum_discussionlistsortorder'] = 'The preferred sorting order of the discussions list';
|
||||
$string['privacy:metadata:preference:maildigest'] = 'The site-wide mail digest preference';
|
||||
$string['privacy:metadata:preference:markasreadonnotification'] = 'Whether to mark forum posts as read when receiving them as messages.';
|
||||
$string['privacy:metadata:preference:trackforums'] = 'Whether to enable read tracking.';
|
||||
|
@ -6746,3 +6746,143 @@ function mod_forum_core_calendar_event_timestart_updated(\calendar_event $event,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the data used to display the discussions on the current page.
|
||||
*
|
||||
* @param \mod_forum\local\entities\forum $forum The forum entity
|
||||
* @param stdClass $user The user to render for
|
||||
* @param int[]|null $groupid The group to render
|
||||
* @param int|null $sortorder The sort order to use when selecting the discussions in the list
|
||||
* @param int|null $pageno The zero-indexed page number to use
|
||||
* @param int|null $pagesize The number of discussions to show on the page
|
||||
* @return stdClass The data to use for display
|
||||
*/
|
||||
function get_discussions(\mod_forum\local\entities\forum $forum, stdClass $user, ?int $groupid, ?int $sortorder,
|
||||
?int $pageno = 0, ?int $pagesize = 0) {
|
||||
|
||||
$vaultfactory = mod_forum\local\container::get_vault_factory();
|
||||
$discussionvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
$managerfactory = mod_forum\local\container::get_manager_factory();
|
||||
$capabilitymanager = $managerfactory->get_capability_manager($forum);
|
||||
|
||||
$groupids = get_groups_from_groupid($forum, $user, $groupid);
|
||||
|
||||
if (null === $groupids) {
|
||||
return $discussions = $discussionvault->get_from_forum_id(
|
||||
$forum->get_id(),
|
||||
$capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id,
|
||||
$sortorder,
|
||||
$pagesize,
|
||||
$pageno * $pagesize);
|
||||
} else {
|
||||
return $discussions = $discussionvault->get_from_forum_id_and_group_id(
|
||||
$forum->get_id(),
|
||||
$groupids,
|
||||
$capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id,
|
||||
$sortorder,
|
||||
$pagesize,
|
||||
$pageno * $pagesize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all discussions in a forum.
|
||||
*
|
||||
* @param \mod_forum\local\entities\forum $forum The forum entity
|
||||
* @param stdClass $user The user to render for
|
||||
* @param int $groupid The group to render
|
||||
* @return int The number of discussions in a forum
|
||||
*/
|
||||
function get_count_all_discussions(\mod_forum\local\entities\forum $forum, stdClass $user, ?int $groupid) {
|
||||
|
||||
$managerfactory = mod_forum\local\container::get_manager_factory();
|
||||
$capabilitymanager = $managerfactory->get_capability_manager($forum);
|
||||
$vaultfactory = mod_forum\local\container::get_vault_factory();
|
||||
$discussionvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
|
||||
$groupids = get_groups_from_groupid($forum, $user, $groupid);
|
||||
|
||||
if (null === $groupids) {
|
||||
return $discussionvault->get_total_discussion_count_from_forum_id(
|
||||
$forum->get_id(),
|
||||
$capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
} else {
|
||||
return $discussionvault->get_total_discussion_count_from_forum_id_and_group_id(
|
||||
$forum->get_id(),
|
||||
$groupids,
|
||||
$capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of groups to show based on the current user and requested groupid.
|
||||
*
|
||||
* @param \mod_forum\local\entities\forum $forum The forum entity
|
||||
* @param stdClass $user The user viewing
|
||||
* @param int $groupid The groupid requested
|
||||
* @return array The list of groups to show
|
||||
*/
|
||||
function get_groups_from_groupid(\mod_forum\local\entities\forum $forum, stdClass $user, ?int $groupid) : ?array {
|
||||
|
||||
$effectivegroupmode = $forum->get_effective_group_mode();
|
||||
if (empty($effectivegroupmode)) {
|
||||
// This forum is not in a group mode. Show all posts always.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null == $groupid) {
|
||||
$managerfactory = mod_forum\local\container::get_manager_factory();
|
||||
$capabilitymanager = $managerfactory->get_capability_manager($forum);
|
||||
// No group was specified.
|
||||
$showallgroups = (VISIBLEGROUPS == $effectivegroupmode);
|
||||
$showallgroups = $showallgroups || $capabilitymanager->can_access_all_groups($user);
|
||||
if ($showallgroups) {
|
||||
// Return null to show all groups.
|
||||
return null;
|
||||
} else {
|
||||
// No group was specified. Only show the users current groups.
|
||||
return array_keys(
|
||||
groups_get_all_groups(
|
||||
$forum->get_course_id(),
|
||||
$user->id,
|
||||
$forum->get_course_module_record()->groupingid
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// A group was specified. Just show that group.
|
||||
return [$groupid];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all the user preferences used by mod_forum.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function mod_forum_user_preferences() {
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$discussionlistvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
|
||||
$preferences = array();
|
||||
$preferences['forum_discussionlistsortorder'] = array(
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => $discussionlistvault::SORTORDER_LASTPOST_DESC,
|
||||
'type' => PARAM_INT,
|
||||
'choices' => array(
|
||||
$discussionlistvault::SORTORDER_LASTPOST_DESC,
|
||||
$discussionlistvault::SORTORDER_LASTPOST_ASC,
|
||||
$discussionlistvault::SORTORDER_CREATED_DESC,
|
||||
$discussionlistvault::SORTORDER_CREATED_ASC,
|
||||
$discussionlistvault::SORTORDER_REPLIES_DESC,
|
||||
$discussionlistvault::SORTORDER_REPLIES_ASC
|
||||
)
|
||||
);
|
||||
|
||||
return $preferences;
|
||||
}
|
||||
|
@ -68,7 +68,20 @@
|
||||
<th scope="col" class="group">{{#str}}group{{/str}}</th>
|
||||
{{/forum.state.groupmode}}
|
||||
{{#forum.capabilities.viewdiscussions}}
|
||||
<th scope="col" class="text-center">{{#str}}replies, mod_forum{{/str}}</th>
|
||||
<th scope="col" class="text-center">
|
||||
{{#state.sortorder.isrepliesdesc}}
|
||||
<a href="{{{forum.urls.sortrepliesasc}}}" aria-label="{{#str}}discussionlistsortbyrepliesasc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.isrepliesdesc}}
|
||||
{{#state.sortorder.isrepliesasc}}
|
||||
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.isrepliesasc}}
|
||||
{{^state.sortorder.isrepliesdesc}}
|
||||
{{^state.sortorder.isrepliesasc}}
|
||||
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a>
|
||||
{{/state.sortorder.isrepliesasc}}
|
||||
{{/state.sortorder.isrepliesdesc}}
|
||||
</th>
|
||||
|
||||
{{#forum.userstate.tracked}}
|
||||
<th scope="col" class="text-center">
|
||||
{{#str}}unread, mod_forum{{/str}}
|
||||
@ -76,7 +89,32 @@
|
||||
</th>
|
||||
{{/forum.userstate.tracked}}
|
||||
{{/forum.capabilities.viewdiscussions}}
|
||||
<th scope="col" class="lastpost">{{#str}}lastpost, mod_forum{{/str}}</th>
|
||||
<th scope="col" class="lastpost">
|
||||
{{#state.sortorder.islastpostdesc}}
|
||||
<a href="{{{forum.urls.sortlastpostasc}}}" aria-label="{{#str}}discussionlistsortbylastpostasc, mod_forum{{/str}}">{{#str}}lastpost, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.islastpostdesc}}
|
||||
{{#state.sortorder.islastpostasc}}
|
||||
<a href="{{{forum.urls.sortlastpostdesc}}}" aria-label="{{#str}}discussionlistsortbylastpostdesc, mod_forum{{/str}}">{{#str}}lastpost, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.islastpostasc}}
|
||||
{{^state.sortorder.islastpostdesc}}
|
||||
{{^state.sortorder.islastpostasc}}
|
||||
<a href="{{{forum.urls.sortlastpostdesc}}}" aria-label="{{#str}}discussionlistsortbylastpostdesc, mod_forum{{/str}}">{{#str}}lastpost, mod_forum{{/str}}</a>
|
||||
{{/state.sortorder.islastpostasc}}
|
||||
{{/state.sortorder.islastpostdesc}}
|
||||
</th>
|
||||
<th scope="col" class="created">
|
||||
{{#state.sortorder.iscreateddesc}}
|
||||
<a href="{{{forum.urls.sortcreatedasc}}}" aria-label="{{#str}}discussionlistsortbycreatedasc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.iscreateddesc}}
|
||||
{{#state.sortorder.iscreatedasc}}
|
||||
<a href="{{{forum.urls.sortcreateddesc}}}" aria-label="{{#str}}discussionlistsortbycreateddesc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
|
||||
{{/state.sortorder.iscreatedasc}}
|
||||
{{^state.sortorder.iscreateddesc}}
|
||||
{{^state.sortorder.iscreatedasc}}
|
||||
<a href="{{{forum.urls.sortcreateddesc}}}" aria-label="{{#str}}discussionlistsortbycreateddesc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a>
|
||||
{{/state.sortorder.iscreatedasc}}
|
||||
{{/state.sortorder.iscreateddesc}}
|
||||
</th>
|
||||
<th scope="col"> </th>
|
||||
{{#forum.capabilities.subscribe}}
|
||||
<th scope="col" class="discussionsubscription"></th>
|
||||
@ -195,6 +233,9 @@
|
||||
</div>
|
||||
{{/latestpostid}}
|
||||
</td>
|
||||
<td scope="col" class="text-left align-middle">
|
||||
{{#userdate}}{{discussion.times.created}}, {{#str}}strftimerecentfull{{/str}}{{/userdate}}
|
||||
</td>
|
||||
<td scope="col" class="timed p-0 text-center align-middle">
|
||||
{{#discussion.timed.istimed}}
|
||||
<div class="timedpost">
|
||||
|
@ -11,6 +11,9 @@ information provided here is intended especially for developers.
|
||||
the Post vault.
|
||||
* External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date for posting to the forums respectively.
|
||||
* External function get_forum_discussion_posts now returns an additional field "tags" returning the post tags.
|
||||
* New external function mod_forum_external::get_forum_discussions returns a list of forum discussions optionally sorted and paginated.
|
||||
* External function mod_forum_external::get_forum_discussions_paginated has been deprecated.
|
||||
Use mod_forum_external::get_forum_discussions instead.
|
||||
|
||||
=== 3.6 ===
|
||||
|
||||
|
@ -30,6 +30,7 @@ $vaultfactory = mod_forum\local\container::get_vault_factory();
|
||||
$forumvault = $vaultfactory->get_forum_vault();
|
||||
$discussionvault = $vaultfactory->get_discussion_vault();
|
||||
$postvault = $vaultfactory->get_post_vault();
|
||||
$discussionlistvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
|
||||
$cmid = optional_param('id', 0, PARAM_INT);
|
||||
$forumid = optional_param('f', 0, PARAM_INT);
|
||||
@ -134,6 +135,12 @@ if ($mode) {
|
||||
|
||||
$displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
|
||||
|
||||
if ($sortorder) {
|
||||
set_user_preference('forum_discussionlistsortorder', $sortorder);
|
||||
}
|
||||
|
||||
$sortorder = get_user_preferences('forum_discussionlistsortorder', $discussionlistvault::SORTORDER_LASTPOST_DESC);
|
||||
|
||||
// Fetch the current groupid.
|
||||
$groupid = groups_get_activity_group($cm, true) ?: null;
|
||||
$rendererfactory = mod_forum\local\container::get_renderer_factory();
|
||||
@ -141,7 +148,7 @@ switch ($forum->get_type()) {
|
||||
case 'single':
|
||||
$discussion = $discussionvault->get_last_discussion_in_forum($forum);
|
||||
$discussioncount = $discussionvault->get_count_discussions_in_forum($forum);
|
||||
$hasmultiplediscussions = $discussioncount > 1 ? true : false;
|
||||
$hasmultiplediscussions = $discussioncount > 1;
|
||||
$discussionsrenderer = $rendererfactory->get_single_discussion_list_renderer($forum, $discussion,
|
||||
$hasmultiplediscussions, $displaymode);
|
||||
$post = $postvault->get_from_id($discussion->get_first_post_id());
|
||||
@ -156,9 +163,9 @@ switch ($forum->get_type()) {
|
||||
break;
|
||||
case 'blog':
|
||||
$discussionsrenderer = $rendererfactory->get_blog_discussion_list_renderer($forum);
|
||||
$discussionlistvault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
// Blog forums always show discussions newest first.
|
||||
echo $discussionsrenderer->render($USER, $cm, $groupid, $discussionlistvault::SORTORDER_CREATED_DESC, $pageno, $pagesize);
|
||||
echo $discussionsrenderer->render($USER, $cm, $groupid, $discussionlistvault::SORTORDER_CREATED_DESC,
|
||||
$pageno, $pagesize);
|
||||
break;
|
||||
default:
|
||||
$discussionsrenderer = $rendererfactory->get_discussion_list_renderer($forum);
|
||||
|
Loading…
x
Reference in New Issue
Block a user