MDL-64820 forum: add new classes for rendering to local namespace
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Exported post builder class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\builders;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
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 core_tag_tag;
|
||||
use moodle_exception;
|
||||
use rating_manager;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Exported post builder class.
|
||||
*
|
||||
* This class is an implementation of the builder pattern (loosely). It is responsible
|
||||
* for taking a set of related forums, discussions, and posts and generate the exported
|
||||
* version of the posts.
|
||||
*
|
||||
* It encapsulates the complexity involved with exporting posts. All of the relevant
|
||||
* additional resources will be loaded by this class in order to ensure the exporting
|
||||
* process can happen.
|
||||
*
|
||||
* See this doc for more information on the builder pattern:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/Builder/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class exported_posts {
|
||||
/** @var renderer_base $renderer Core renderer */
|
||||
private $renderer;
|
||||
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
|
||||
/** @var exporter_factory $exporterfactory Exporter factory */
|
||||
private $exporterfactory;
|
||||
|
||||
/** @var vault_factory $vaultfactory Vault factory */
|
||||
private $vaultfactory;
|
||||
|
||||
/** @var rating_manager $ratingmanager Rating manager */
|
||||
private $ratingmanager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param renderer_base $renderer Core renderer
|
||||
* @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
|
||||
*/
|
||||
public function __construct(
|
||||
renderer_base $renderer,
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
rating_manager $ratingmanager
|
||||
) {
|
||||
$this->renderer = $renderer;
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->ratingmanager = $ratingmanager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the exported posts for a given set of forums, discussions, and posts.
|
||||
*
|
||||
* This will typically be used for a list of posts in the same discussion/forum however
|
||||
* it does support exporting any arbitrary list of posts as long as the caller also provides
|
||||
* a unique list of all discussions for the list of posts and all forums for the list of discussions.
|
||||
*
|
||||
* Increasing the number of different forums being processed will increase the processing time
|
||||
* due to processing multiple contexts (for things like capabilities, files, etc). The code attempts
|
||||
* to load the additional resources as efficiently as possible but there is no way around some of
|
||||
* the additional overhead.
|
||||
*
|
||||
* @param stdClass $user The user to export the posts for.
|
||||
* @param forum_entity[] $forums A list of all forums that each of the $discussions belong to
|
||||
* @param discussion_entity[] $discussions A list of all discussions that each of the $posts belong to
|
||||
* @param post_entity[] $posts The list of posts to export.
|
||||
* @return stdClass[] List of exported posts in the same order as the $posts array.
|
||||
*/
|
||||
public function build(
|
||||
stdClass $user,
|
||||
array $forums,
|
||||
array $discussions,
|
||||
array $posts
|
||||
) : array {
|
||||
// Format the forums and discussion to make them more easily accessed later.
|
||||
$forums = array_reduce($forums, function($carry, $forum) {
|
||||
$carry[$forum->get_id()] = $forum;
|
||||
return $carry;
|
||||
}, []);
|
||||
$discussions = array_reduce($discussions, function($carry, $discussion) {
|
||||
$carry[$discussion->get_id()] = $discussion;
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
// Group the posts by discussion and forum so that we can load the resources in
|
||||
// batches to improve performance.
|
||||
$groupedposts = $this->group_posts_by_discussion($forums, $discussions, $posts);
|
||||
// Load all of the resources we need in order to export the posts.
|
||||
$authorsbyid = $this->get_authors_for_posts($posts);
|
||||
$attachmentsbypostid = $this->get_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);
|
||||
$readreceiptcollectionbyforumid = $this->get_read_receipts_from_posts($user, $groupedposts);
|
||||
$exportedposts = [];
|
||||
|
||||
// Export each set of posts per discussion because it's the largest chunks we can
|
||||
// break them into due to constraints on capability checks.
|
||||
foreach ($groupedposts as $grouping) {
|
||||
[
|
||||
'forum' => $forum,
|
||||
'discussion' => $discussion,
|
||||
'posts' => $groupedposts
|
||||
] = $grouping;
|
||||
|
||||
$forumid = $forum->get_id();
|
||||
$courseid = $forum->get_course_record()->id;
|
||||
$postsexporter = $this->exporterfactory->get_posts_exporter(
|
||||
$user,
|
||||
$forum,
|
||||
$discussion,
|
||||
$groupedposts,
|
||||
$authorsbyid,
|
||||
$attachmentsbypostid,
|
||||
$groupsbycourseandauthorid[$courseid],
|
||||
$readreceiptcollectionbyforumid[$forumid] ?? null,
|
||||
$tagsbypostid,
|
||||
$ratingbypostid,
|
||||
true
|
||||
);
|
||||
['posts' => $exportedgroupedposts] = (array) $postsexporter->export($this->renderer);
|
||||
$exportedposts = array_merge($exportedposts, $exportedgroupedposts);
|
||||
}
|
||||
|
||||
if (count($forums) == 1 && count($discussions) == 1) {
|
||||
// All of the posts belong to a single discussion in a single forum so
|
||||
// the exported order will match the given $posts array.
|
||||
return $exportedposts;
|
||||
} else {
|
||||
// Since we grouped the posts by discussion and forum the ordering of the
|
||||
// exported posts may be different to the given $posts array so we should
|
||||
// sort it back into the correct order for the caller.
|
||||
return $this->sort_exported_posts($posts, $exportedposts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Group the posts by which discussion they belong to in order for them to be processed
|
||||
* in chunks by the exporting.
|
||||
*
|
||||
* Returns a list of groups where each group has a forum, discussion, and list of posts.
|
||||
* E.g.
|
||||
* [
|
||||
* [
|
||||
* 'forum' => <forum_entity>,
|
||||
* 'discussion' => <discussion_entity>,
|
||||
* 'posts' => [
|
||||
* <post_entity in discussion>,
|
||||
* <post_entity in discussion>,
|
||||
* <post_entity in discussion>
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @param forum_entity[] $forums A list of all forums that each of the $discussions belong to, indexed by id.
|
||||
* @param discussion_entity[] $discussions A list of all discussions that each of the $posts belong to, indexed by id.
|
||||
* @param post_entity[] $posts The list of posts to process.
|
||||
* @return array List of grouped posts. Each group has a discussion, forum, and posts.
|
||||
*/
|
||||
private function group_posts_by_discussion(array $forums, array $discussions, array $posts) : array {
|
||||
return array_reduce($posts, function($carry, $post) use ($forums, $discussions) {
|
||||
$discussionid = $post->get_discussion_id();
|
||||
if (!isset($discussions[$discussionid])) {
|
||||
throw new moodle_exception('Unable to find discussion with id ' . $discussionid);
|
||||
}
|
||||
|
||||
if (isset($carry[$discussionid])) {
|
||||
$carry[$discussionid]['posts'][] = $post;
|
||||
} else {
|
||||
$discussion = $discussions[$discussionid];
|
||||
$forumid = $discussion->get_forum_id();
|
||||
|
||||
if (!isset($forums[$forumid])) {
|
||||
throw new moodle_exception('Unable to find forum with id ' . $forumid);
|
||||
}
|
||||
|
||||
$carry[$discussionid] = [
|
||||
'forum' => $forums[$forumid],
|
||||
'discussion' => $discussions[$discussionid],
|
||||
'posts' => [$post]
|
||||
];
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the list of authors for the given posts.
|
||||
*
|
||||
* The list of authors will be indexed by the author id.
|
||||
*
|
||||
* @param post_entity[] $posts The list of posts to process.
|
||||
* @return author_entity[]
|
||||
*/
|
||||
private function get_authors_for_posts(array $posts) : array {
|
||||
$authorvault = $this->vaultfactory->get_author_vault();
|
||||
return $authorvault->get_authors_for_posts($posts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the list of all 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_attachments_for_posts(array $groupedposts) : array {
|
||||
$attachmentsbypostid = [];
|
||||
$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;
|
||||
$attachments = $postattachmentvault->get_attachments_for_posts($forum->get_context(), $posts);
|
||||
|
||||
// Have to loop in order to maintain the correct indexes since they are numeric.
|
||||
foreach ($attachments as $postid => $attachment) {
|
||||
$attachmentsbypostid[$postid] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
return $attachmentsbypostid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the groups for each author of the given posts.
|
||||
*
|
||||
* The results are grouped by course and then author id because the groups are
|
||||
* contextually related to the course, e.g. a single author can be part of two different
|
||||
* sets of groups in two different courses.
|
||||
*
|
||||
* @param array $groupedposts List of posts grouped by discussions.
|
||||
* @return array List of groups indexed by forum id and then author id.
|
||||
*/
|
||||
private function get_author_groups_from_posts(array $groupedposts) : array {
|
||||
$groupsbyauthorid = [];
|
||||
$authoridsbycourseid = [];
|
||||
|
||||
// Get the unique list of author ids for each course in the grouped
|
||||
// posts. Grouping by course is the largest grouping we can achieve.
|
||||
foreach ($groupedposts as $grouping) {
|
||||
['forum' => $forum, 'posts' => $posts] = $grouping;
|
||||
$course = $forum->get_course_record();
|
||||
$courseid = $course->id;
|
||||
|
||||
if (!isset($authoridsbycourseid[$courseid])) {
|
||||
$coursemodule = $forum->get_course_module_record();
|
||||
$authoridsbycourseid[$courseid] = [
|
||||
'groupingid' => $coursemodule->groupingid,
|
||||
'authorids' => []
|
||||
];
|
||||
}
|
||||
|
||||
$authorids = array_map(function($post) {
|
||||
return $post->get_author_id();
|
||||
}, $posts);
|
||||
|
||||
foreach ($authorids as $authorid) {
|
||||
$authoridsbycourseid[$courseid]['authorids'][$authorid] = $authorid;
|
||||
}
|
||||
}
|
||||
|
||||
// Load each set of groups per course.
|
||||
foreach ($authoridsbycourseid as $courseid => $values) {
|
||||
['groupingid' => $groupingid, 'authorids' => $authorids] = $values;
|
||||
$authorgroups = groups_get_all_groups(
|
||||
$courseid,
|
||||
array_keys($authorids),
|
||||
$groupingid,
|
||||
'g.*, gm.id, gm.groupid, gm.userid'
|
||||
);
|
||||
|
||||
if (!isset($groupsbyauthorid[$courseid])) {
|
||||
$groupsbyauthorid[$courseid] = [];
|
||||
}
|
||||
|
||||
foreach ($authorgroups as $group) {
|
||||
// Clean up data returned from groups_get_all_groups.
|
||||
$userid = $group->userid;
|
||||
$groupid = $group->groupid;
|
||||
|
||||
unset($group->userid);
|
||||
unset($group->groupid);
|
||||
$group->id = $groupid;
|
||||
|
||||
if (!isset($groupsbyauthorid[$courseid][$userid])) {
|
||||
$groupsbyauthorid[$courseid][$userid] = [];
|
||||
}
|
||||
|
||||
$groupsbyauthorid[$courseid][$userid][] = $group;
|
||||
}
|
||||
}
|
||||
|
||||
return $groupsbyauthorid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of tags for each of the posts. The tags will be returned in an
|
||||
* array indexed by the post id.
|
||||
*
|
||||
* @param post_entity[] $posts The list of posts to load tags for.
|
||||
* @return array Sets of tags indexed by post id.
|
||||
*/
|
||||
private function get_tags_from_posts(array $posts) : array {
|
||||
$postids = array_map(function($post) {
|
||||
return $post->get_id();
|
||||
}, $posts);
|
||||
return core_tag_tag::get_items_tags('mod_forum', 'forum_posts', $postids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of ratings for each post. The ratings are returned in an array
|
||||
* indexed by the post id.
|
||||
*
|
||||
* @param stdClass $user The user viewing the ratings.
|
||||
* @param array $groupedposts List of posts grouped by discussions.
|
||||
* @return array Sets of ratings indexed by post id.
|
||||
*/
|
||||
private function get_ratings_from_posts(stdClass $user, array $groupedposts) {
|
||||
$ratingsbypostid = [];
|
||||
$postsdatamapper = $this->legacydatamapperfactory->get_post_data_mapper();
|
||||
$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;
|
||||
|
||||
if (!$forum->has_rating_aggregate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$items = $postsdatamapper->to_legacy_objects($posts);
|
||||
$ratingoptions = (object) [
|
||||
'context' => $forum->get_context(),
|
||||
'component' => 'mod_forum',
|
||||
'ratingarea' => 'post',
|
||||
'items' => $items,
|
||||
'aggregate' => $forum->get_rating_aggregate(),
|
||||
'scaleid' => $forum->get_scale(),
|
||||
'userid' => $user->id,
|
||||
'assesstimestart' => $forum->get_assess_time_start(),
|
||||
'assesstimefinish' => $forum->get_assess_time_finish()
|
||||
];
|
||||
|
||||
$rm = $this->ratingmanager;
|
||||
$items = $rm->get_ratings($ratingoptions);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$ratingsbypostid[$item->id] = empty($item->rating) ? null : $item->rating;
|
||||
}
|
||||
}
|
||||
|
||||
return $ratingsbypostid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the read receipt collections for the given viewing user and each forum. The
|
||||
* receipt collections will only be loaded for posts in forums that the user is tracking.
|
||||
*
|
||||
* The receipt collections are returned in an array indexed by the forum ids.
|
||||
*
|
||||
* @param stdClass $user The user viewing the posts.
|
||||
* @param array $groupedposts List of posts grouped by discussions.
|
||||
*/
|
||||
private function get_read_receipts_from_posts(stdClass $user, array $groupedposts) {
|
||||
$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
|
||||
$trackedforums = [];
|
||||
$trackedpostids = [];
|
||||
|
||||
foreach ($groupedposts as $group) {
|
||||
['forum' => $forum, 'posts' => $posts] = $group;
|
||||
$forumid = $forum->get_id();
|
||||
|
||||
if (!isset($trackedforums[$forumid])) {
|
||||
$forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
$trackedforums[$forumid] = forum_tp_is_tracked($forumrecord, $user);
|
||||
}
|
||||
|
||||
if ($trackedforums[$forumid]) {
|
||||
foreach ($posts as $post) {
|
||||
$trackedpostids[] = $post->get_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($trackedpostids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// We can just load a single receipt collection for all tracked posts.
|
||||
$receiptvault = $this->vaultfactory->get_post_read_receipt_collection_vault();
|
||||
$readreceiptcollection = $receiptvault->get_from_user_id_and_post_ids($user->id, $trackedpostids);
|
||||
$receiptsbyforumid = [];
|
||||
|
||||
// Assign the collection to all forums that are tracked.
|
||||
foreach ($trackedforums as $forumid => $tracked) {
|
||||
if ($tracked) {
|
||||
$receiptsbyforumid[$forumid] = $readreceiptcollection;
|
||||
}
|
||||
}
|
||||
|
||||
return $receiptsbyforumid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the list of exported posts back into the same order as the given posts.
|
||||
* The ordering of the exported posts can often deviate from the given posts due
|
||||
* to the process of exporting them so we need to sort them back into the order
|
||||
* that the calling code expected.
|
||||
*
|
||||
* @param post_entity[] $posts The posts in the expected order.
|
||||
* @param stdClass[] $exportedposts The list of exported posts in any order.
|
||||
* @return stdClass[] Sorted exported posts.
|
||||
*/
|
||||
private function sort_exported_posts(array $posts, array $exportedposts) {
|
||||
$postindexes = [];
|
||||
foreach (array_values($posts) as $index => $post) {
|
||||
$postindexes[$post->get_id()] = $index;
|
||||
}
|
||||
|
||||
$sortedexportedposts = [];
|
||||
|
||||
foreach ($exportedposts as $exportedpost) {
|
||||
$index = $postindexes[$exportedpost->id];
|
||||
$sortedexportedposts[$index] = $exportedpost;
|
||||
}
|
||||
|
||||
return $sortedexportedposts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Container class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\factories\renderer as renderer_factory;
|
||||
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
||||
use mod_forum\local\factories\entity as entity_factory;
|
||||
use mod_forum\local\factories\exporter as exporter_factory;
|
||||
use mod_forum\local\factories\manager as manager_factory;
|
||||
use mod_forum\local\factories\vault as vault_factory;
|
||||
use mod_forum\local\factories\builder as builder_factory;
|
||||
use mod_forum\local\factories\url as url_factory;
|
||||
|
||||
/**
|
||||
* Container class.
|
||||
*
|
||||
* This class provides helper methods with static configurations to get any
|
||||
* of the factories from the "local" namespace.
|
||||
*
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class container {
|
||||
/**
|
||||
* Create the renderer factory.
|
||||
*
|
||||
* @return renderer_factory
|
||||
*/
|
||||
public static function get_renderer_factory() : renderer_factory {
|
||||
global $PAGE;
|
||||
|
||||
return new renderer_factory(
|
||||
self::get_legacy_data_mapper_factory(),
|
||||
self::get_exporter_factory(),
|
||||
self::get_vault_factory(),
|
||||
self::get_manager_factory(),
|
||||
self::get_entity_factory(),
|
||||
self::get_builder_factory(),
|
||||
self::get_url_factory(),
|
||||
$PAGE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the legacy data mapper factory.
|
||||
*
|
||||
* @return legacy_data_mapper_factory
|
||||
*/
|
||||
public static function get_legacy_data_mapper_factory() : legacy_data_mapper_factory {
|
||||
return new legacy_data_mapper_factory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the exporter factory.
|
||||
*
|
||||
* @return exporter_factory
|
||||
*/
|
||||
public static function get_exporter_factory() : exporter_factory {
|
||||
return new exporter_factory(
|
||||
self::get_legacy_data_mapper_factory(),
|
||||
self::get_manager_factory(),
|
||||
self::get_url_factory()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the vault factory.
|
||||
*
|
||||
* @return vault_factory
|
||||
*/
|
||||
public static function get_vault_factory() : vault_factory {
|
||||
global $DB;
|
||||
|
||||
return new vault_factory(
|
||||
$DB,
|
||||
self::get_entity_factory(),
|
||||
get_file_storage()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the manager factory.
|
||||
*
|
||||
* @return manager_factory
|
||||
*/
|
||||
public static function get_manager_factory() : manager_factory {
|
||||
return new manager_factory(
|
||||
self::get_legacy_data_mapper_factory()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the entity factory.
|
||||
*
|
||||
* @return entity_factory
|
||||
*/
|
||||
public static function get_entity_factory() : entity_factory {
|
||||
return new entity_factory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the builder factory.
|
||||
*
|
||||
* @return builder_factory
|
||||
*/
|
||||
public static function get_builder_factory() : builder_factory {
|
||||
global $PAGE;
|
||||
|
||||
return new builder_factory(
|
||||
self::get_legacy_data_mapper_factory(),
|
||||
self::get_exporter_factory(),
|
||||
self::get_vault_factory(),
|
||||
self::get_manager_factory(),
|
||||
$PAGE->get_renderer('mod_forum')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the URL factory.
|
||||
*
|
||||
* @return url_factory
|
||||
*/
|
||||
public static function get_url_factory() : url_factory {
|
||||
return new url_factory(
|
||||
self::get_legacy_data_mapper_factory()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Author data mapper.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\data_mappers\legacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Convert an author entity into an stdClass.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class author {
|
||||
/**
|
||||
* Convert a list of author entities into stdClasses.
|
||||
*
|
||||
* @param author_entity[] $authors The authors to convert.
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function to_legacy_objects(array $authors) : array {
|
||||
return array_map(function(author_entity $author) {
|
||||
return (object) [
|
||||
'id' => $author->get_id(),
|
||||
'picture' => $author->get_picture_item_id(),
|
||||
'firstname' => $author->get_first_name(),
|
||||
'lastname' => $author->get_last_name(),
|
||||
'fullname' => $author->get_full_name(),
|
||||
'email' => $author->get_email(),
|
||||
'middlename' => $author->get_middle_name(),
|
||||
'firstnamephonetic' => $author->get_first_name_phonetic(),
|
||||
'lastnamephonetic' => $author->get_last_name_phonetic(),
|
||||
'alternatename' => $author->get_alternate_name(),
|
||||
'imagealt' => $author->get_image_alt()
|
||||
];
|
||||
}, $authors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an author entity into an stdClass.
|
||||
*
|
||||
* @param author_entity $author The author to convert.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function to_legacy_object(author_entity $author) : stdClass {
|
||||
return $this->to_legacy_objects([$author])[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion data mapper.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\data_mappers\legacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Convert a discussion entity into an stdClass.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion {
|
||||
/**
|
||||
* Convert a list of discussion entities into stdClasses.
|
||||
*
|
||||
* @param discussion_entity[] $authors The authors to convert.
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function to_legacy_objects(array $discussions) : array {
|
||||
return array_map(function(discussion_entity $discussion) {
|
||||
return (object) [
|
||||
'id' => $discussion->get_id(),
|
||||
'course' => $discussion->get_course_id(),
|
||||
'forum' => $discussion->get_forum_id(),
|
||||
'name' => $discussion->get_name(),
|
||||
'firstpost' => $discussion->get_first_post_id(),
|
||||
'userid' => $discussion->get_user_id(),
|
||||
'groupid' => $discussion->get_group_id(),
|
||||
'assessed' => $discussion->is_assessed(),
|
||||
'timemodified' => $discussion->get_time_modified(),
|
||||
'usermodified' => $discussion->get_user_modified(),
|
||||
'timestart' => $discussion->get_time_start(),
|
||||
'timeend' => $discussion->get_time_end(),
|
||||
'pinned' => $discussion->is_pinned()
|
||||
];
|
||||
}, $discussions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a discussion entity into an stdClass.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion to convert.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function to_legacy_object(discussion_entity $discussion) : stdClass {
|
||||
return $this->to_legacy_objects([$discussion])[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Forum data mapper.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\data_mappers\legacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Convert a forum entity into an stdClass.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class forum {
|
||||
/**
|
||||
* Convert a list of forum entities into stdClasses.
|
||||
*
|
||||
* @param forum_entity[] $forums The forums to convert.
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function to_legacy_objects(array $forums) : array {
|
||||
return array_map(function(forum_entity $forum) {
|
||||
return (object) [
|
||||
'id' => $forum->get_id(),
|
||||
'course' => $forum->get_course_id(),
|
||||
'type' => $forum->get_type(),
|
||||
'name' => $forum->get_name(),
|
||||
'intro' => $forum->get_intro(),
|
||||
'introformat' => $forum->get_intro_format(),
|
||||
'assessed' => $forum->get_rating_aggregate(),
|
||||
'assesstimestart' => $forum->get_assess_time_start(),
|
||||
'assesstimefinish' => $forum->get_assess_time_finish(),
|
||||
'scale' => $forum->get_scale(),
|
||||
'maxbytes' => $forum->get_max_bytes(),
|
||||
'maxattachments' => $forum->get_max_attachments(),
|
||||
'forcesubscribe' => $forum->is_subscription_forced(),
|
||||
'trackingtype' => $forum->get_tracking_type(),
|
||||
'rsstype' => $forum->get_rss_type(),
|
||||
'rssarticles' => $forum->get_rss_articles(),
|
||||
'timemodified' => $forum->get_time_modified(),
|
||||
'warnafter' => $forum->get_warn_after(),
|
||||
'blockafter' => $forum->get_block_after(),
|
||||
'blockperiod' => $forum->get_block_period(),
|
||||
'completiondiscussions' => $forum->get_completion_discussions(),
|
||||
'completionreplies' => $forum->get_completion_replies(),
|
||||
'completionposts' => $forum->get_completion_posts(),
|
||||
'displaywordcount' => $forum->should_display_word_count(),
|
||||
'lockdiscussionafter' => $forum->get_lock_discussions_after()
|
||||
];
|
||||
}, $forums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a forum entity into an stdClass.
|
||||
*
|
||||
* @param forum_entity $forum The forum to convert.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function to_legacy_object(forum_entity $forum) : stdClass {
|
||||
return $this->to_legacy_objects([$forum])[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post data mapper.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\data_mappers\legacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Convert a post entity into an stdClass.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post {
|
||||
/**
|
||||
* Convert a list of post entities into stdClasses.
|
||||
*
|
||||
* @param post_entity[] $posts The posts to convert.
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function to_legacy_objects(array $posts) : array {
|
||||
return array_map(function(post_entity $post) {
|
||||
return (object) [
|
||||
'id' => $post->get_id(),
|
||||
'discussion' => $post->get_discussion_id(),
|
||||
'parent' => $post->get_parent_id(),
|
||||
'userid' => $post->get_author_id(),
|
||||
'created' => $post->get_time_created(),
|
||||
'modified' => $post->get_time_modified(),
|
||||
'mailed' => $post->has_been_mailed(),
|
||||
'subject' => $post->get_subject(),
|
||||
'message' => $post->get_message(),
|
||||
'messageformat' => $post->get_message_format(),
|
||||
'messagetrust' => $post->is_message_trusted(),
|
||||
'attachment' => $post->has_attachments(),
|
||||
'totalscore' => $post->get_total_score(),
|
||||
'mailnow' => $post->should_mail_now(),
|
||||
'deleted' => $post->is_deleted()
|
||||
];
|
||||
}, $posts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a post entity into an stdClass.
|
||||
*
|
||||
* @param post_entity $post The post to convert.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function to_legacy_object(post_entity $post) : stdClass {
|
||||
return $this->to_legacy_objects([$post])[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Author class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Author class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class author {
|
||||
/** @var int $id ID */
|
||||
private $id;
|
||||
/** @var int $pictureitemid Picture item id */
|
||||
private $pictureitemid;
|
||||
/** @var string $firstname First name */
|
||||
private $firstname;
|
||||
/** @var string $lastname Last name */
|
||||
private $lastname;
|
||||
/** @var string $fullname Full name */
|
||||
private $fullname;
|
||||
/** @var string $email Email */
|
||||
private $email;
|
||||
/** @var string $middlename Middle name */
|
||||
private $middlename;
|
||||
/** @var string $firstnamephonetic Phonetic spelling of first name */
|
||||
private $firstnamephonetic;
|
||||
/** @var string $lastnamephonetic Phonetic spelling of last name */
|
||||
private $lastnamephonetic;
|
||||
/** @var string $alternatename Altername name */
|
||||
private $alternatename;
|
||||
/** @var string $imagealt Image alt */
|
||||
private $imagealt;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $id ID
|
||||
* @param int $pictureitemid Picture item id
|
||||
* @param string $firstname First name
|
||||
* @param string $lastname Last name
|
||||
* @param string $fullname Full name
|
||||
* @param string $email Email
|
||||
* @param string|null $middlename Middle name
|
||||
* @param string|null $firstnamephonetic Phonetic spelling of first name
|
||||
* @param string|null $lastnamephonetic Phonetic spelling of last name
|
||||
* @param string|null $alternatename Altername name
|
||||
* @param string|null $imagealt Image alt
|
||||
*/
|
||||
public function __construct(
|
||||
int $id,
|
||||
int $pictureitemid,
|
||||
string $firstname,
|
||||
string $lastname,
|
||||
string $fullname,
|
||||
string $email,
|
||||
string $middlename = null,
|
||||
string $firstnamephonetic = null,
|
||||
string $lastnamephonetic = null,
|
||||
string $alternatename = null,
|
||||
string $imagealt = null
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->pictureitemid = $pictureitemid;
|
||||
$this->firstname = $firstname;
|
||||
$this->lastname = $lastname;
|
||||
$this->fullname = $fullname;
|
||||
$this->email = $email;
|
||||
$this->middlename = $middlename;
|
||||
$this->firstnamephonetic = $firstnamephonetic;
|
||||
$this->lastnamephonetic = $lastnamephonetic;
|
||||
$this->alternatename = $alternatename;
|
||||
$this->imagealt = $imagealt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() : int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the picture item id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_picture_item_id() : int {
|
||||
return $this->pictureitemid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_first_name() : string {
|
||||
return $this->firstname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_last_name() : string {
|
||||
return $this->lastname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_full_name() : string {
|
||||
return $this->fullname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the email.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_email() : string {
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the middle name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_middle_name() : ?string {
|
||||
return $this->middlename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first name phonetic.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_first_name_phonetic() : ?string {
|
||||
return $this->firstnamephonetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last name phonetic.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_last_name_phonetic() : ?string {
|
||||
return $this->lastnamephonetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the alternate name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_alternate_name() : ?string {
|
||||
return $this->alternatename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image alt.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_image_alt() : ?string {
|
||||
return $this->imagealt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
|
||||
/**
|
||||
* Discussion class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion {
|
||||
/** @var int $id ID */
|
||||
private $id;
|
||||
/** @var int $courseid Course id */
|
||||
private $courseid;
|
||||
/** @var int $forumid Forum id */
|
||||
private $forumid;
|
||||
/** @var string $name Discussion name */
|
||||
private $name;
|
||||
/** @var int $firstpostid Id of the first post in the discussion */
|
||||
private $firstpostid;
|
||||
/** @var int $userid Id of the user that created the discussion */
|
||||
private $userid;
|
||||
/** @var int $groupid Group id if it's a group dicussion */
|
||||
private $groupid;
|
||||
/** @var bool $assessed Is the discussion assessed? */
|
||||
private $assessed;
|
||||
/** @var int $timemodified Timestamp for last modification to the discussion */
|
||||
private $timemodified;
|
||||
/** @var int $usermodified Id of user that last modified the discussion */
|
||||
private $usermodified;
|
||||
/** @var int $timestart Start time for the discussion */
|
||||
private $timestart;
|
||||
/** @var int $timeend End time for the discussion */
|
||||
private $timeend;
|
||||
/** @var bool $pinned Is the discussion pinned? */
|
||||
private $pinned;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $id ID
|
||||
* @param int $courseid Course id
|
||||
* @param int $forumid Forum id
|
||||
* @param string $name Discussion name
|
||||
* @param int $firstpostid Id of the first post in the discussion
|
||||
* @param int $userid Id of the user that created the discussion
|
||||
* @param int $groupid Group id if it's a group dicussion
|
||||
* @param bool $assessed Is the discussion assessed?
|
||||
* @param int $timemodified Timestamp for last modification to the discussion
|
||||
* @param int $usermodified Id of user that last modified the discussion
|
||||
* @param int $timestart Start time for the discussion
|
||||
* @param int $timeend End time for the discussion
|
||||
* @param bool $pinned Is the discussion pinned?
|
||||
*/
|
||||
public function __construct(
|
||||
int $id,
|
||||
int $courseid,
|
||||
int $forumid,
|
||||
string $name,
|
||||
int $firstpostid,
|
||||
int $userid,
|
||||
int $groupid,
|
||||
bool $assessed,
|
||||
int $timemodified,
|
||||
int $usermodified,
|
||||
int $timestart,
|
||||
int $timeend,
|
||||
bool $pinned
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->courseid = $courseid;
|
||||
$this->forumid = $forumid;
|
||||
$this->name = $name;
|
||||
$this->firstpostid = $firstpostid;
|
||||
$this->userid = $userid;
|
||||
$this->groupid = $groupid;
|
||||
$this->assessed = $assessed;
|
||||
$this->timemodified = $timemodified;
|
||||
$this->usermodified = $usermodified;
|
||||
$this->timestart = $timestart;
|
||||
$this->timeend = $timeend;
|
||||
$this->pinned = $pinned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the discussion id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() : int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_course_id() : int {
|
||||
return $this->courseid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_forum_id() : int {
|
||||
return $this->forumid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the discussion.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() : string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the fist post in the discussion.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_first_post_id() : int {
|
||||
return $this->firstpostid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the user that created the discussion.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_user_id() : int {
|
||||
return $this->userid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the group that this discussion belongs to.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_group_id() : int {
|
||||
return $this->groupid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this discussion is assessed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_assessed() : bool {
|
||||
return $this->assessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when this discussion was last modified.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_modified() : int {
|
||||
return $this->timemodified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the user that last modified this discussion.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_user_modified() : int {
|
||||
return $this->usermodified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start time of this discussion. Returns zero if the discussion
|
||||
* has no designated start time.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_start() : int {
|
||||
return $this->timestart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end time of this discussion. Returns zero if the discussion
|
||||
* has no designated end time.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_end() : int {
|
||||
return $this->timeend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this discussion is pinned.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_pinned() : bool {
|
||||
return $this->pinned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given post is the first post in this discussion.
|
||||
*
|
||||
* @param post_entity $post The post to check
|
||||
* @return bool
|
||||
*/
|
||||
public function is_first_post(post_entity $post) : bool {
|
||||
return $this->get_first_post_id() === $post->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the discussion has started yet.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_started() : bool {
|
||||
$startime = $this->get_time_start();
|
||||
return empty($startime) || $startime < time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the discussion belongs to a group.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_group() : bool {
|
||||
return $this->get_group_id() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion summary class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
|
||||
/**
|
||||
* Discussion summary class.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion_summary {
|
||||
/** @var discussion_entity $discussion The discussion being summarised */
|
||||
private $discussion;
|
||||
/** @var author_entity $firstpostauthor Author of the first post in the discussion */
|
||||
private $firstpostauthor;
|
||||
/** @var post_entity $firstpost First post in the discussion */
|
||||
private $firstpost;
|
||||
/** @var author_entity $latestpostauthor Author of the last post in the discussion */
|
||||
private $latestpostauthor;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion being summarised
|
||||
* @param post_entity $firstpost First post in the discussion
|
||||
* @param author_entity $firstpostauthor Author of the first post in the discussion
|
||||
* @param author_entity $latestpostauthor Author of the last post in the discussion
|
||||
*/
|
||||
public function __construct(
|
||||
discussion_entity $discussion,
|
||||
post_entity $firstpost,
|
||||
author_entity $firstpostauthor,
|
||||
author_entity $latestpostauthor
|
||||
) {
|
||||
$this->discussion = $discussion;
|
||||
$this->firstpostauthor = $firstpostauthor;
|
||||
$this->firstpost = $firstpost;
|
||||
$this->latestpostauthor = $latestpostauthor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the discussion entity.
|
||||
*
|
||||
* @return discussion_entity
|
||||
*/
|
||||
public function get_discussion() : discussion_entity {
|
||||
return $this->discussion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author entity for the first post.
|
||||
*
|
||||
* @return author_entity
|
||||
*/
|
||||
public function get_first_post_author() : author_entity {
|
||||
return $this->firstpostauthor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author entity for the last post.
|
||||
*
|
||||
* @return author_entity
|
||||
*/
|
||||
public function get_latest_post_author() : author_entity {
|
||||
return $this->latestpostauthor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post entity for the first post.
|
||||
*
|
||||
* @return post_entity
|
||||
*/
|
||||
public function get_first_post() : post_entity {
|
||||
return $this->firstpost;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Forum class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use context;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Forum class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class forum {
|
||||
/** @var context $context The forum module context */
|
||||
private $context;
|
||||
/** @var stdClass $coursemodule The forum course module record */
|
||||
private $coursemodule;
|
||||
/** @var stdClass $course The forum course record */
|
||||
private $course;
|
||||
/** @var int $effectivegroupmode The effective group mode */
|
||||
private $effectivegroupmode;
|
||||
/** @var int $id ID */
|
||||
private $id;
|
||||
/** @var int $courseid Id of the course this forum is in */
|
||||
private $courseid;
|
||||
/** @var string $type The forum type, e.g. single, qanda, etc */
|
||||
private $type;
|
||||
/** @var string $name Name of the forum */
|
||||
private $name;
|
||||
/** @var string $intro Intro text */
|
||||
private $intro;
|
||||
/** @var int $introformat Format of the intro text */
|
||||
private $introformat;
|
||||
/** @var int $assessed The forum rating aggregate */
|
||||
private $assessed;
|
||||
/** @var int $assesstimestart Timestamp to begin assessment */
|
||||
private $assesstimestart;
|
||||
/** @var int $assesstimefinish Timestamp to end assessment */
|
||||
private $assesstimefinish;
|
||||
/** @var int $scale The rating scale */
|
||||
private $scale;
|
||||
/** @var int $maxbytes Maximum attachment size */
|
||||
private $maxbytes;
|
||||
/** @var int $maxattachments Maximum number of attachments */
|
||||
private $maxattachments;
|
||||
/** @var bool $forcesubscription Does the forum force users to subscribe? */
|
||||
private $forcesubscription;
|
||||
/** @var int $trackingtype Tracking type */
|
||||
private $trackingtype;
|
||||
/** @var int $rsstype RSS type */
|
||||
private $rsstype;
|
||||
/** @var int $rssarticles RSS articles */
|
||||
private $rssarticles;
|
||||
/** @var int $timemodified Timestamp when the forum was last modified */
|
||||
private $timemodified;
|
||||
/** @var int $warnafter Warn after */
|
||||
private $warnafter;
|
||||
/** @var int $blockafter Block after */
|
||||
private $blockafter;
|
||||
/** @var int $blockperiod Block period */
|
||||
private $blockperiod;
|
||||
/** @var int $completiondiscussions Completion discussions */
|
||||
private $completiondiscussions;
|
||||
/** @var int $completionreplies Completion replies */
|
||||
private $completionreplies;
|
||||
/** @var int $completionposts Completion posts */
|
||||
private $completionposts;
|
||||
/** @var bool $displaywordcounts Should display word counts in posts */
|
||||
private $displaywordcounts;
|
||||
/** @var bool $lockdiscussionafter Timestamp after which discussions should be locked */
|
||||
private $lockdiscussionafter;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context $context The forum module context
|
||||
* @param stdClass $coursemodule The forum course module record
|
||||
* @param stdClass $course The forum course record
|
||||
* @param int $effectivegroupmode The effective group mode
|
||||
* @param int $id ID
|
||||
* @param int $courseid Id of the course this forum is in
|
||||
* @param string $type The forum type, e.g. single, qanda, etc
|
||||
* @param string $name Name of the forum
|
||||
* @param string $intro Intro text
|
||||
* @param int $introformat Format of the intro text
|
||||
* @param int $assessed The forum rating aggregate
|
||||
* @param int $assesstimestart Timestamp to begin assessment
|
||||
* @param int $assesstimefinish Timestamp to end assessment
|
||||
* @param int $scale The rating scale
|
||||
* @param int $maxbytes Maximum attachment size
|
||||
* @param int $maxattachments Maximum number of attachments
|
||||
* @param bool $forcesubscribe Does the forum force users to subscribe?
|
||||
* @param int $trackingtype Tracking type
|
||||
* @param int $rsstype RSS type
|
||||
* @param int $rssarticles RSS articles
|
||||
* @param int $timemodified Timestamp when the forum was last modified
|
||||
* @param int $warnafter Warn after
|
||||
* @param int $blockafter Block after
|
||||
* @param int $blockperiod Block period
|
||||
* @param int $completiondiscussions Completion discussions
|
||||
* @param int $completionreplies Completion replies
|
||||
* @param int $completionposts Completion posts
|
||||
* @param bool $displaywordcount Should display word counts in posts
|
||||
* @param int $lockdiscussionafter Timestamp after which discussions should be locked
|
||||
*/
|
||||
public function __construct(
|
||||
context $context,
|
||||
stdClass $coursemodule,
|
||||
stdClass $course,
|
||||
int $effectivegroupmode,
|
||||
int $id,
|
||||
int $courseid,
|
||||
string $type,
|
||||
string $name,
|
||||
string $intro,
|
||||
int $introformat,
|
||||
int $assessed,
|
||||
int $assesstimestart,
|
||||
int $assesstimefinish,
|
||||
int $scale,
|
||||
int $maxbytes,
|
||||
int $maxattachments,
|
||||
bool $forcesubscribe,
|
||||
int $trackingtype,
|
||||
int $rsstype,
|
||||
int $rssarticles,
|
||||
int $timemodified,
|
||||
int $warnafter,
|
||||
int $blockafter,
|
||||
int $blockperiod,
|
||||
int $completiondiscussions,
|
||||
int $completionreplies,
|
||||
int $completionposts,
|
||||
bool $displaywordcount,
|
||||
int $lockdiscussionafter
|
||||
) {
|
||||
$this->context = $context;
|
||||
$this->coursemodule = $coursemodule;
|
||||
$this->course = $course;
|
||||
$this->effectivegroupmode = $effectivegroupmode;
|
||||
$this->id = $id;
|
||||
$this->courseid = $courseid;
|
||||
$this->type = $type;
|
||||
$this->name = $name;
|
||||
$this->intro = $intro;
|
||||
$this->introformat = $introformat;
|
||||
$this->assessed = $assessed;
|
||||
$this->assesstimestart = $assesstimestart;
|
||||
$this->assesstimefinish = $assesstimefinish;
|
||||
$this->scale = $scale;
|
||||
$this->maxbytes = $maxbytes;
|
||||
$this->maxattachments = $maxattachments;
|
||||
$this->forcesubscribe = $forcesubscribe;
|
||||
$this->trackingtype = $trackingtype;
|
||||
$this->rsstype = $rsstype;
|
||||
$this->rssarticles = $rssarticles;
|
||||
$this->timemodified = $timemodified;
|
||||
$this->warnafter = $warnafter;
|
||||
$this->blockafter = $blockafter;
|
||||
$this->blockperiod = $blockperiod;
|
||||
$this->completiondiscussions = $completiondiscussions;
|
||||
$this->completionreplies = $completionreplies;
|
||||
$this->completionposts = $completionposts;
|
||||
$this->displaywordcount = $displaywordcount;
|
||||
$this->lockdiscussionafter = $lockdiscussionafter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum module context.
|
||||
*
|
||||
* @return context
|
||||
*/
|
||||
public function get_context() : context {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum course module record
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function get_course_module_record() : stdClass {
|
||||
return $this->coursemodule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective group mode.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_effective_group_mode() : int {
|
||||
return $this->effectivegroupmode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the forum is set to group mode.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_in_group_mode() : bool {
|
||||
return $this->get_effective_group_mode() !== NOGROUPS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course record.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function get_course_record() : stdClass {
|
||||
return $this->course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() : int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the course that the forum belongs to.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_course_id() : int {
|
||||
return $this->courseid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type() : string {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() : string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum intro text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_intro() : string {
|
||||
return $this->intro;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum intro text format.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_intro_format() : int {
|
||||
return $this->introformat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rating aggregate.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_rating_aggregate() : int {
|
||||
return $this->assessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the forum have a rating aggregate?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_rating_aggregate() : bool {
|
||||
return $this->get_rating_aggregate() != RATING_AGGREGATE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when the assessment period begins.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_assess_time_start() : int {
|
||||
return $this->assesstimestart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when the assessment period ends.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_assess_time_finish() : int {
|
||||
return $this->assesstimefinish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rating scale.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_scale() : int {
|
||||
return $this->scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum bytes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_max_bytes() : int {
|
||||
return $this->maxbytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of attachments.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_max_attachments() : int {
|
||||
return $this->maxattachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the forum force subscription?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_subscription_forced() : bool {
|
||||
return $this->forcesubscribe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tracking type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_tracking_type() : int {
|
||||
return $this->trackingtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RSS type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_rss_type() : int {
|
||||
return $this->rsstype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RSS articles.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_rss_articles() : int {
|
||||
return $this->rssarticles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when the forum was last modified.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_modified() : int {
|
||||
return $this->timemodified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get warn after.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_warn_after() : int {
|
||||
return $this->warnafter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block after.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_block_after() : int {
|
||||
return $this->blockafter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block period.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_block_period() : int {
|
||||
return $this->blockperiod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the forum have blocking enabled?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_blocking_enabled() : bool {
|
||||
return !empty($this->get_block_after()) && !empty($this->get_block_period());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completion discussions.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_completion_discussions() : int {
|
||||
return $this->completiondiscussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completion replies.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_completion_replies() : int {
|
||||
return $this->completionreplies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completion posts.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_completion_posts() : int {
|
||||
return $this->completionposts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the word counts be shown in the posts?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function should_display_word_count() : bool {
|
||||
return $this->displaywordcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp after which the discussion should be locked.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_lock_discussions_after() : int {
|
||||
return $this->lockdiscussionafter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the forum have a discussion locking timestamp?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_lock_discussions_after() : bool {
|
||||
return !empty($this->get_lock_discussions_after());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the discussion locked?
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function is_discussion_locked(discussion_entity $discussion) : bool {
|
||||
if (!$this->has_lock_discussions_after()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->get_type() === 'single') {
|
||||
// It does not make sense to lock a single discussion forum.
|
||||
return false;
|
||||
}
|
||||
|
||||
return (($discussion->get_time_modified() + $this->get_lock_discussions_after()) < time());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Post class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post {
|
||||
/** @var int $id ID */
|
||||
private $id;
|
||||
/** @var int $discussionid The id of the discussion this post belongs to */
|
||||
private $discussionid;
|
||||
/** @var int $parentid The id of the post that this post is replying to. Zero if it isn't a reply. */
|
||||
private $parentid;
|
||||
/** @var int $authorid The id of user who authored the post */
|
||||
private $authorid;
|
||||
/** @var int $timecreated Timestamp for when the post was created */
|
||||
private $timecreated;
|
||||
/** @var int $timemodified Timestamp for when the post last modified */
|
||||
private $timemodified;
|
||||
/** @var bool $mailed If the post has been mailed */
|
||||
private $mailed;
|
||||
/** @var string $subject Post subject */
|
||||
private $subject;
|
||||
/** @var string $message Post message */
|
||||
private $message;
|
||||
/** @var int $messageformat Format of the post message */
|
||||
private $messageformat;
|
||||
/** @var bool $messagetrust Is this a trusted message, i.e. created by a trusted user. */
|
||||
private $messagetrust;
|
||||
/** @var bool $hasattachments Does the post have attachments */
|
||||
private $hasattachments;
|
||||
/** @var int $totalscore Total score */
|
||||
private $totalscore;
|
||||
/** @var bool $mailnow Should this post be mailed immediately */
|
||||
private $mailnow;
|
||||
/** @var bool $deleted Is the post deleted */
|
||||
private $deleted;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $id ID
|
||||
* @param int $discussionid The id of the discussion this post belongs to
|
||||
* @param int $parentid The id of the post that this post is replying to. Zero if it isn't a reply.
|
||||
* @param int $authorid The id of user who authored the post
|
||||
* @param int $timecreated Timestamp for when the post was created
|
||||
* @param int $timemodified Timestamp for when the post last modified
|
||||
* @param bool $mailed If the post has been mailed
|
||||
* @param string $subject Post subject
|
||||
* @param string $message Post message
|
||||
* @param int $messageformat Format of the post message
|
||||
* @param bool $messagetrust Is this a trusted message, i.e. created by a trusted user.
|
||||
* @param bool $hasattachments Does the post have attachments
|
||||
* @param int $totalscore Total score
|
||||
* @param bool $mailnow Should this post be mailed immediately
|
||||
* @param bool $deleted Is the post deleted
|
||||
*/
|
||||
public function __construct(
|
||||
int $id,
|
||||
int $discussionid,
|
||||
int $parentid,
|
||||
int $authorid,
|
||||
int $timecreated,
|
||||
int $timemodified,
|
||||
bool $mailed,
|
||||
string $subject,
|
||||
string $message,
|
||||
int $messageformat,
|
||||
bool $messagetrust,
|
||||
bool $hasattachments,
|
||||
int $totalscore,
|
||||
bool $mailnow,
|
||||
bool $deleted
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->discussionid = $discussionid;
|
||||
$this->parentid = $parentid;
|
||||
$this->authorid = $authorid;
|
||||
$this->timecreated = $timecreated;
|
||||
$this->timemodified = $timemodified;
|
||||
$this->mailed = $mailed;
|
||||
$this->subject = $subject;
|
||||
$this->message = $message;
|
||||
$this->messageformat = $messageformat;
|
||||
$this->messagetrust = $messagetrust;
|
||||
$this->hasattachments = $hasattachments;
|
||||
$this->totalscore = $totalscore;
|
||||
$this->mailnow = $mailnow;
|
||||
$this->deleted = $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() : int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the discussion id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_discussion_id() : int {
|
||||
return $this->discussionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the parent post. Returns zero if this post is not a reply.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_parent_id() : int {
|
||||
return $this->parentid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this post have a parent? I.e. is it a reply?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_parent() : bool {
|
||||
return $this->get_parent_id() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the user that authored the post.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_author_id() : int {
|
||||
return $this->authorid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when this post was created.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_created() : int {
|
||||
return $this->timecreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for when this post was last modified.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_time_modified() : int {
|
||||
return $this->timemodified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this post been mailed?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_been_mailed() : bool {
|
||||
return $this->mailed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post subject.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_subject() : string {
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_message() : string {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post message format.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_message_format() : int {
|
||||
return $this->messageformat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a trusted message? I.e. was it authored by a trusted user?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_message_trusted() : bool {
|
||||
return $this->messagetrust;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this post have attachments?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_attachments() : bool {
|
||||
return $this->hasattachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total score.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_score() : int {
|
||||
return $this->totalscore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should this post be mailed now?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function should_mail_now() : bool {
|
||||
return $this->mailnow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this post deleted?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_deleted() : bool {
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post's age in seconds.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_age() : int {
|
||||
return time() - $this->get_time_created();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given user authored this post.
|
||||
*
|
||||
* @param stdClass $user The user to check.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_owned_by_user(stdClass $user) : bool {
|
||||
return $this->get_author_id() == $user->id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post read receipt collection class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Post read receipt collection class.
|
||||
*
|
||||
* Contains the list of read receipts for posts.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post_read_receipt_collection {
|
||||
/** @var stdClass[] $receiptsbypostid Receipt records indexed by post id */
|
||||
private $receiptsbypostid = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $records The list of post read receipt records.
|
||||
*/
|
||||
public function __construct(array $records) {
|
||||
foreach ($records as $record) {
|
||||
$postid = $record->postid;
|
||||
|
||||
if (isset($this->receiptsbypostid[$postid])) {
|
||||
$this->receiptsbypostid[$postid][] = $record;
|
||||
} else {
|
||||
$this->receiptsbypostid[$postid] = [$record];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a user has read a post.
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param post_entity $post The post to check
|
||||
* @return bool
|
||||
*/
|
||||
public function has_user_read_post(stdClass $user, post_entity $post) : bool {
|
||||
global $CFG;
|
||||
$isoldpost = ($post->get_time_modified() < (time() - ($CFG->forum_oldpostdays * 24 * 3600)));
|
||||
|
||||
if ($isoldpost) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$receipts = isset($this->receiptsbypostid[$post->get_id()]) ? $this->receiptsbypostid[$post->get_id()] : [];
|
||||
|
||||
foreach ($receipts as $receipt) {
|
||||
if ($receipt->userid == $user->id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class to sort items.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\entities;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class to sort lists of items.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class sorter {
|
||||
/** @var callable $getid Function used to get the id from an item */
|
||||
private $getid;
|
||||
/** @var callable $getparentid Function used to get the parent id from an item */
|
||||
private $getparentid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Allows the calling code to provide 2 functions to get the id and parent id from
|
||||
* the list of items it is intended to process.
|
||||
*
|
||||
* This allows this class to be composed in numerous different ways to support various
|
||||
* types of items while keeping the underlying sorting algorithm consistent.
|
||||
*
|
||||
* @param callable $getid Function used to get the id from an item
|
||||
* @param callable $getparentid Function used to get the parent id from an item
|
||||
*/
|
||||
public function __construct(callable $getid, callable $getparentid) {
|
||||
$this->getid = $getid;
|
||||
$this->getparentid = $getparentid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort a list of items into a parent/child data structure. The resulting data structure
|
||||
* is a recursive array of arrays where the first element is the parent and the second is
|
||||
* an array of it's children.
|
||||
*
|
||||
* For example
|
||||
* If we have an array of items A, B, C, and D where D is a child of C, B and C are children
|
||||
* of A.
|
||||
*
|
||||
* This function would sort them into the following:
|
||||
* [
|
||||
* [
|
||||
* A,
|
||||
* [
|
||||
* [
|
||||
* B,
|
||||
* []
|
||||
* ],
|
||||
* [
|
||||
* C,
|
||||
* [
|
||||
* [
|
||||
* D,
|
||||
* []
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @param array $items The list of items to sort.
|
||||
* @return array
|
||||
*/
|
||||
public function sort_into_children(array $items) : array {
|
||||
$ids = array_reduce($items, function($carry, $item) {
|
||||
$carry[($this->getid)($item)] = true;
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
// Split out the items into "parents" and "replies" (children). These are unsorted
|
||||
// at this point.
|
||||
[$parents, $replies] = array_reduce($items, function($carry, $item) use ($ids) {
|
||||
$parentid = ($this->getparentid)($item);
|
||||
|
||||
if (!empty($ids[$parentid])) {
|
||||
// This is a child to another item in the list so add it to the children list.
|
||||
$carry[1][] = $item;
|
||||
} else {
|
||||
// This isn't a child to anything in our list so it's a parent.
|
||||
$carry[0][] = $item;
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, [[], []]);
|
||||
|
||||
if (empty($replies)) {
|
||||
return array_map(function($parent) {
|
||||
return [$parent, []];
|
||||
}, $parents);
|
||||
}
|
||||
|
||||
// Recurse to sort the replies into the correct nesting.
|
||||
$sortedreplies = $this->sort_into_children($replies);
|
||||
|
||||
// Sort the parents and sorted replies into their matching pairs.
|
||||
return array_map(function($parent) use ($sortedreplies) {
|
||||
$parentid = ($this->getid)($parent);
|
||||
return [
|
||||
$parent,
|
||||
array_values(array_filter($sortedreplies, function($replydata) use ($parentid) {
|
||||
return ($this->getparentid)($replydata[0]) == $parentid;
|
||||
}))
|
||||
];
|
||||
}, $parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the data structure returned from "sort_into_children" and flatten it back
|
||||
* into an array. It does a depth first flatten which maintains the reply ordering.
|
||||
*
|
||||
* @param array $items Items in the data structure returned by "sort_into_children"
|
||||
* @return array A flat array.
|
||||
*/
|
||||
public function flatten_children(array $items) : array {
|
||||
$result = [];
|
||||
|
||||
foreach ($items as [$item, $children]) {
|
||||
$result[] = $item;
|
||||
$result = array_merge($result, $this->flatten_children($children));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Author exporter.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* Author exporter.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class author extends exporter {
|
||||
/** @var author_entity $author Author entity */
|
||||
private $author;
|
||||
/** @var array $authorgroups List of groups that the author belongs to */
|
||||
private $authorgroups;
|
||||
/** @var bool $canview Should the author be anonymised? */
|
||||
private $canview;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param author_entity $author The author entity to export
|
||||
* @param stdClass[] $authorgroups The list of groups that the author belongs to
|
||||
* @param bool $canview Can the requesting user view this author or should it be anonymised?
|
||||
* @param array $related The related data for the export.
|
||||
*/
|
||||
public function __construct(author_entity $author, array $authorgroups = [], bool $canview = true, array $related = []) {
|
||||
$this->author = $author;
|
||||
$this->authorgroups = $authorgroups;
|
||||
$this->canview = $canview;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'id' => [
|
||||
'type' => PARAM_INT,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'fullname' => [
|
||||
'type' => PARAM_TEXT,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'groups' => [
|
||||
'multiple' => true,
|
||||
'optional' => true,
|
||||
'type' => [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'image' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'profile' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'profileimage' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$author = $this->author;
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
|
||||
if ($this->canview) {
|
||||
$groups = array_map(function($group) {
|
||||
$imageurl = get_group_picture_url($group, $group->courseid);
|
||||
return [
|
||||
'id' => $group->id,
|
||||
'urls' => [
|
||||
'image' => $imageurl ? $imageurl->out(false) : null
|
||||
]
|
||||
];
|
||||
}, $this->authorgroups);
|
||||
|
||||
return [
|
||||
'id' => $author->get_id(),
|
||||
'fullname' => $author->get_full_name(),
|
||||
'groups' => $groups,
|
||||
'urls' => [
|
||||
'profile' => ($urlfactory->get_author_profile_url($author))->out(false),
|
||||
'profileimage' => ($urlfactory->get_author_profile_image_url($author))->out(false)
|
||||
]
|
||||
];
|
||||
} else {
|
||||
// The author should be anonymised.
|
||||
return [
|
||||
'id' => null,
|
||||
'fullname' => get_string('forumauthorhidden', 'mod_forum'),
|
||||
'groups' => [],
|
||||
'urls' => [
|
||||
'profile' => null,
|
||||
'profileimage' => null
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'context' => 'context'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion exporter class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
use mod_forum\local\factories\exporter as exporter_factory;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Discussion exporter class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion extends exporter {
|
||||
/** @var discussion_entity $discussion Discussion to export */
|
||||
private $discussion;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param discussion_entity $discussion Discussion to export
|
||||
* @param array $related The related export data
|
||||
*/
|
||||
public function __construct(discussion_entity $discussion, array $related = []) {
|
||||
$this->discussion = $discussion;
|
||||
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'forumid' => ['type' => PARAM_INT],
|
||||
'pinned' => ['type' => PARAM_BOOL],
|
||||
'name' => ['type' => PARAM_TEXT],
|
||||
'group' => [
|
||||
'optional' => true,
|
||||
'type' => [
|
||||
'name' => ['type' => PARAM_TEXT],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'picture' => [
|
||||
'optional' => true,
|
||||
'type' => PARAM_URL,
|
||||
],
|
||||
'userlist' => [
|
||||
'optional' => true,
|
||||
'type' => PARAM_URL,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'times' => [
|
||||
'type' => [
|
||||
'modified' => ['type' => PARAM_INT],
|
||||
'start' => ['type' => PARAM_INT],
|
||||
'end' => ['type' => PARAM_INT],
|
||||
],
|
||||
],
|
||||
'userstate' => [
|
||||
'type' => [
|
||||
'subscribed' => ['type' => PARAM_BOOL],
|
||||
],
|
||||
],
|
||||
'capabilities' => [
|
||||
'type' => [
|
||||
'subscribe' => ['type' => PARAM_BOOL],
|
||||
'move' => ['type' => PARAM_BOOL],
|
||||
'pin' => ['type' => PARAM_BOOL],
|
||||
'post' => ['type' => PARAM_BOOL]
|
||||
]
|
||||
],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'view' => ['type' => PARAM_URL],
|
||||
'viewlatest' => [
|
||||
'optional' => true,
|
||||
'type' => PARAM_URL
|
||||
],
|
||||
'viewfirstunread' => [
|
||||
'optional' => true,
|
||||
'type' => PARAM_URL,
|
||||
],
|
||||
'markasread' => ['type' => PARAM_URL],
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$capabilitymanager = $this->related['capabilitymanager'];
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
|
||||
$forum = $this->related['forum'];
|
||||
$forumrecord = $this->get_forum_record();
|
||||
$user = $this->related['user'];
|
||||
$discussion = $this->discussion;
|
||||
|
||||
$groupdata = null;
|
||||
if ($discussion->has_group() && $group = $this->related['groupsbyid'][$discussion->get_group_id()]) {
|
||||
$groupdata = [
|
||||
'name' => $group->name,
|
||||
'urls' => [],
|
||||
];
|
||||
$canviewparticipants = $capabilitymanager->can_view_participants($user, $discussion);
|
||||
if (!$group->hidepicture) {
|
||||
$url = get_group_picture_url($group, $forum->get_course_id());
|
||||
if (!empty($url)) {
|
||||
$groupdata['urls']['picture'] = $url;
|
||||
}
|
||||
}
|
||||
if ($canviewparticipants) {
|
||||
$groupdata['urls']['userlist'] = (new \moodle_url('/user/index.php', [
|
||||
'id' => $forum->get_course_id(),
|
||||
'group' => $group->id,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$viewfirstunreadurl = $urlfactory->get_discussion_view_first_unread_post_url_from_discussion($discussion);
|
||||
$data = [
|
||||
'id' => $discussion->get_id(),
|
||||
'forumid' => $forum->get_id(),
|
||||
'pinned' => $discussion->is_pinned(),
|
||||
'name' => format_string($discussion->get_name(), true, [
|
||||
'context' => $this->related['context']
|
||||
]),
|
||||
'times' => [
|
||||
'modified' => $discussion->get_time_modified(),
|
||||
'start' => $discussion->get_time_start(),
|
||||
'end' => $discussion->get_time_end(),
|
||||
],
|
||||
'userstate' => [
|
||||
'subscribed' => \mod_forum\subscriptions::is_subscribed($user->id, $forumrecord, $discussion->get_id()),
|
||||
],
|
||||
'capabilities' => [
|
||||
'subscribe' => $capabilitymanager->can_subscribe_to_discussion($user, $discussion),
|
||||
'move' => $capabilitymanager->can_move_discussion($user, $discussion),
|
||||
'pin' => $capabilitymanager->can_pin_discussion($user, $discussion),
|
||||
'post' => $capabilitymanager->can_post_in_discussion($user, $discussion)
|
||||
],
|
||||
'urls' => [
|
||||
'view' => $urlfactory->get_discussion_view_url_from_discussion($discussion)->out(false),
|
||||
'viewfirstunread' => $viewfirstunreadurl->out(false),
|
||||
'markasread' => $urlfactory->get_mark_discussion_as_read_url_from_discussion($forum, $discussion)->out(false),
|
||||
]
|
||||
];
|
||||
|
||||
if (!empty($this->related['latestpostid'])) {
|
||||
$data['urls']['viewlatest'] = $urlfactory->get_discussion_view_latest_post_url_from_discussion(
|
||||
$discussion,
|
||||
$this->related['latestpostid']
|
||||
)->out(false);
|
||||
}
|
||||
|
||||
if ($groupdata) {
|
||||
$data['group'] = $groupdata;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy forum record from the forum entity.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_forum_record() {
|
||||
$forumdbdatamapper = $this->related['legacydatamapperfactory']->get_forum_data_mapper();
|
||||
return $forumdbdatamapper->to_legacy_object($this->related['forum']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'context' => 'context',
|
||||
'forum' => 'mod_forum\local\entities\forum',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'user' => 'stdClass',
|
||||
'groupsbyid' => 'stdClass[]',
|
||||
'latestpostid' => 'int?'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion summaries exporter.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Discussion summaries exporter.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion_summaries extends exporter {
|
||||
/** @var discussion_summary_entity[] The list of discussion summaries to export */
|
||||
private $discussions;
|
||||
|
||||
/** @var stdClass[] The group information for each author */
|
||||
private $groupsbyid;
|
||||
|
||||
/** @var stdClass[] The group information for each author */
|
||||
private $groupsbyauthorid;
|
||||
|
||||
/** @var int[] Discussion reply counts indexed by dicussion id */
|
||||
private $discussionreplycount;
|
||||
|
||||
/** @var int[] Discussion unread counts indexed by dicussion id */
|
||||
private $discussionunreadcount;
|
||||
|
||||
/** @var array The latest post in each discussion */
|
||||
private $latestpostids;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param discussion_summary_entity[] $discussion The list of discussion summaries to export
|
||||
* @param stdClass[] $groupsbyid The group information for each author
|
||||
* @param stdClass[] $groupsbyauthorid The group information for each author
|
||||
* @param int[] $discussionreplycount Discussion reply counts indexed by dicussion id
|
||||
* @param int[] $discussionunreadcount Discussion unread counts indexed by dicussion id
|
||||
* @param int[] $latestpostids List of latest post ids indexed by discussion id
|
||||
* @param array $related The related
|
||||
*/
|
||||
public function __construct(
|
||||
array $discussions,
|
||||
array $groupsbyid,
|
||||
array $groupsbyauthorid,
|
||||
array $discussionreplycount,
|
||||
array $discussionunreadcount,
|
||||
array $latestpostids,
|
||||
array $related = []
|
||||
) {
|
||||
$this->discussions = $discussions;
|
||||
$this->groupsbyid = $groupsbyid;
|
||||
$this->groupsbyauthorid = $groupsbyauthorid;
|
||||
$this->discussionreplycount = $discussionreplycount;
|
||||
$this->discussionunreadcount = $discussionunreadcount;
|
||||
$this->latestpostids = $latestpostids;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'summaries' => [
|
||||
'type' => discussion_summary::read_properties_definition(),
|
||||
'multiple' => true
|
||||
],
|
||||
'state' => [
|
||||
'type' => [
|
||||
'hasdiscussions' => ['type' => PARAM_BOOL],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$exporteddiscussions = [];
|
||||
$related = $this->related;
|
||||
|
||||
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;
|
||||
$exporter = new discussion_summary(
|
||||
$discussion,
|
||||
$this->groupsbyid,
|
||||
$this->groupsbyauthorid,
|
||||
$replycount,
|
||||
$unreadcount,
|
||||
$latestpostid,
|
||||
$related
|
||||
);
|
||||
$exporteddiscussions[] = $exporter->export($output);
|
||||
}
|
||||
|
||||
return [
|
||||
'summaries' => $exporteddiscussions,
|
||||
'state' => [
|
||||
'hasdiscussions' => !empty($exporteddiscussions),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'context' => 'context',
|
||||
'forum' => 'mod_forum\local\entities\forum',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'user' => 'stdClass',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion summary exporter class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion_summary as discussion_summary_entity;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Discussion summary exporter class.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion_summary extends exporter {
|
||||
/** @var discussion_summary_entity The discussion summary information */
|
||||
private $summary;
|
||||
|
||||
/** @var stdClass[] The group information for each author */
|
||||
private $groupsbyid;
|
||||
|
||||
/** @var stdClass[] The group information for each author */
|
||||
private $groupsbyauthorid;
|
||||
|
||||
/** @var int The number of replies to the discussion */
|
||||
private $replycount;
|
||||
|
||||
/** @var int number of unread posts if the user is tracking these */
|
||||
private $unreadcount;
|
||||
|
||||
/** @var int The latest post id in the discussion */
|
||||
private $latestpostid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param discussion_summary_entity $summary The discussion summary information
|
||||
* @param stdClass[] $groupsbyid The group information for each author
|
||||
* @param stdClass[] $groupsbyauthorid The group information for each author
|
||||
* @param int $replycount The number of replies to the discussion
|
||||
* @param int $unreadcount number of unread posts if the user is tracking these
|
||||
* @param int $latestpostid The latest post id in the discussion
|
||||
* @param array $related The related objects
|
||||
*/
|
||||
public function __construct(
|
||||
discussion_summary_entity $summary,
|
||||
array $groupsbyid,
|
||||
array $groupsbyauthorid,
|
||||
int $replycount,
|
||||
int $unreadcount,
|
||||
int $latestpostid,
|
||||
array $related = []
|
||||
) {
|
||||
$this->summary = $summary;
|
||||
$this->groupsbyid = $groupsbyid;
|
||||
$this->groupsbyauthorid = $groupsbyauthorid;
|
||||
$this->replycount = $replycount;
|
||||
$this->unreadcount = $unreadcount;
|
||||
$this->latestpostid = $latestpostid;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'discussion' => [
|
||||
'type' => discussion::read_properties_definition(),
|
||||
],
|
||||
'replies' => ['type' => PARAM_INT],
|
||||
'unread' => ['type' => PARAM_INT],
|
||||
'firstpostauthor' => [
|
||||
'type' => author::read_properties_definition(),
|
||||
],
|
||||
'latestpostauthor' => [
|
||||
'type' => author::read_properties_definition(),
|
||||
],
|
||||
'latestpostid' => ['type' => PARAM_INT],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$capabilitymanager = $this->related['capabilitymanager'];
|
||||
$forum = $this->related['forum'];
|
||||
$user = $this->related['user'];
|
||||
$discussion = $this->summary->get_discussion();
|
||||
|
||||
$related = (array) (object) $this->related;
|
||||
$related['latestpostid'] = $this->latestpostid;
|
||||
$related['groupsbyid'] = $this->groupsbyid;
|
||||
$discussionexporter = new discussion($discussion, $related);
|
||||
|
||||
$related = [
|
||||
'urlfactory' => $this->related['urlfactory'],
|
||||
'context' => $this->related['forum']->get_context(),
|
||||
];
|
||||
|
||||
$firstpostauthor = new author(
|
||||
$this->summary->get_first_post_author(),
|
||||
$this->groupsbyauthorid[$this->summary->get_first_post_author()->get_id()],
|
||||
$capabilitymanager->can_view_post(
|
||||
$user,
|
||||
$discussion,
|
||||
$this->summary->get_first_post()
|
||||
),
|
||||
$related
|
||||
);
|
||||
|
||||
$latestpostauthor = new author(
|
||||
$this->summary->get_latest_post_author(),
|
||||
[],
|
||||
$capabilitymanager->can_view_post(
|
||||
$user,
|
||||
$discussion,
|
||||
$this->summary->get_first_post()
|
||||
),
|
||||
$related
|
||||
);
|
||||
|
||||
return [
|
||||
'id' => $discussion->get_id(),
|
||||
'discussion' => $discussionexporter->export($output),
|
||||
'replies' => $this->replycount,
|
||||
'unread' => $this->unreadcount,
|
||||
'firstpostauthor' => $firstpostauthor->export($output),
|
||||
'latestpostauthor' => $latestpostauthor->export($output),
|
||||
'latestpostid' => $this->latestpostid,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'context' => 'context',
|
||||
'forum' => 'mod_forum\local\entities\forum',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'user' => 'stdClass',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Forum Exporter.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Forum class.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class forum extends exporter {
|
||||
/** @var forum_entity The entity relating to the forum being displayed */
|
||||
private $forum;
|
||||
|
||||
/**
|
||||
* Constructor for the forum exporter.
|
||||
*
|
||||
* @param forum_entity $forum The forum being displayed
|
||||
* @param array $related The related objects
|
||||
*/
|
||||
public function __construct(forum_entity $forum, $related = []) {
|
||||
$this->forum = $forum;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'state' => [
|
||||
'type' => [
|
||||
'groupmode' => ['type' => PARAM_INT],
|
||||
],
|
||||
],
|
||||
'userstate' => [
|
||||
'type' => [
|
||||
'tracked' => ['type' => PARAM_INT],
|
||||
],
|
||||
],
|
||||
'capabilities' => [
|
||||
'type' => [
|
||||
'viewdiscussions' => ['type' => PARAM_BOOL],
|
||||
'create' => ['type' => PARAM_BOOL],
|
||||
'subscribe' => ['type' => PARAM_BOOL],
|
||||
]
|
||||
],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'create' => ['type' => PARAM_URL],
|
||||
'markasread' => ['type' => PARAM_URL],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$capabilitymanager = $this->related['capabilitymanager'];
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
$user = $this->related['user'];
|
||||
$currentgroup = $this->related['currentgroup'];
|
||||
|
||||
return [
|
||||
'id' => $this->forum->get_id(),
|
||||
'state' => [
|
||||
'groupmode' => $this->forum->get_effective_group_mode(),
|
||||
],
|
||||
'userstate' => [
|
||||
'tracked' => forum_tp_is_tracked($this->get_forum_record(), $this->related['user']),
|
||||
],
|
||||
'capabilities' => [
|
||||
'viewdiscussions' => $capabilitymanager->can_view_discussions($user),
|
||||
'create' => $capabilitymanager->can_create_discussions($user, $currentgroup),
|
||||
'subscribe' => $capabilitymanager->can_subscribe_to_forum($user),
|
||||
],
|
||||
'urls' => [
|
||||
'create' => $urlfactory->get_discussion_create_url($this->forum)->out(false),
|
||||
'markasread' => $urlfactory->get_mark_all_discussions_as_read_url($this->forum)->out(false),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'user' => 'stdClass',
|
||||
'currentgroup' => 'int?',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy forum record for this forum.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_forum_record() : stdClass {
|
||||
$forumdbdatamapper = $this->related['legacydatamapperfactory']->get_forum_data_mapper();
|
||||
return $forumdbdatamapper->to_legacy_object($this->forum);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post exporter class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\exporters\author as author_exporter;
|
||||
use mod_forum\local\factories\exporter as exporter_factory;
|
||||
use core\external\exporter;
|
||||
use core_files\external\stored_file_exporter;
|
||||
use context;
|
||||
use core_tag_tag;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* Post exporter class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post extends exporter {
|
||||
/** @var post_entity $post The post to export */
|
||||
private $post;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param post_entity $post The post to export
|
||||
* @param array $related List of related data
|
||||
*/
|
||||
public function __construct(post_entity $post, array $related = []) {
|
||||
$this->post = $post;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
$attachmentdefinition = stored_file_exporter::read_properties_definition();
|
||||
$attachmentdefinition['urls'] = [
|
||||
'type' => [
|
||||
'export' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
]
|
||||
]
|
||||
];
|
||||
$attachmentdefinition['html'] = [
|
||||
'type' => [
|
||||
'plagiarism' => [
|
||||
'type' => PARAM_RAW,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
return [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'subject' => ['type' => PARAM_TEXT],
|
||||
'message' => ['type' => PARAM_RAW],
|
||||
'messageformat' => ['type' => PARAM_INT],
|
||||
'author' => ['type' => author_exporter::read_properties_definition()],
|
||||
'discussionid' => ['type' => PARAM_INT],
|
||||
'hasparent' => ['type' => PARAM_BOOL],
|
||||
'parentid' => [
|
||||
'type' => PARAM_INT,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'timecreated' => ['type' => PARAM_INT],
|
||||
'unread' => [
|
||||
'type' => PARAM_BOOL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'isdeleted' => ['type' => PARAM_BOOL],
|
||||
'haswordcount' => ['type' => PARAM_BOOL],
|
||||
'wordcount' => [
|
||||
'type' => PARAM_INT,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'capabilities' => [
|
||||
'type' => [
|
||||
'view' => ['type' => PARAM_BOOL],
|
||||
'edit' => ['type' => PARAM_BOOL],
|
||||
'delete' => ['type' => PARAM_BOOL],
|
||||
'split' => ['type' => PARAM_BOOL],
|
||||
'reply' => ['type' => PARAM_BOOL],
|
||||
'export' => ['type' => PARAM_BOOL],
|
||||
'controlreadstatus' => ['type' => PARAM_BOOL]
|
||||
]
|
||||
],
|
||||
'urls' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'type' => [
|
||||
'view' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'viewisolated' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'viewparent' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'edit' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'delete' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'split' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'reply' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'export' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'markasread' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'markasunread' => [
|
||||
'type' => PARAM_URL,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
]
|
||||
]
|
||||
],
|
||||
'attachments' => [
|
||||
'multiple' => true,
|
||||
'type' => $attachmentdefinition
|
||||
],
|
||||
'tags' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'multiple' => true,
|
||||
'type' => [
|
||||
'id' => ['type' => PARAM_INT],
|
||||
'tagid' => ['type' => PARAM_INT],
|
||||
'isstandard' => ['type' => PARAM_BOOL],
|
||||
'displayname' => ['type' => PARAM_TEXT],
|
||||
'flag' => ['type' => PARAM_BOOL],
|
||||
'urls' => [
|
||||
'type' => [
|
||||
'view' => ['type' => PARAM_URL]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'html' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'type' => [
|
||||
'rating' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'type' => PARAM_RAW
|
||||
],
|
||||
'taglist' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'type' => PARAM_RAW
|
||||
],
|
||||
'authorsubheading' => [
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED,
|
||||
'type' => PARAM_RAW
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
global $CFG;
|
||||
|
||||
$post = $this->post;
|
||||
$authorgroups = $this->related['authorgroups'];
|
||||
$forum = $this->related['forum'];
|
||||
$discussion = $this->related['discussion'];
|
||||
$author = $this->related['author'];
|
||||
$user = $this->related['user'];
|
||||
$context = $this->related['context'];
|
||||
$readreceiptcollection = $this->related['readreceiptcollection'];
|
||||
$rating = $this->related['rating'];
|
||||
$tags = $this->related['tags'];
|
||||
$attachments = $this->related['attachments'];
|
||||
$includehtml = $this->related['includehtml'];
|
||||
$forumrecord = $this->get_forum_record();
|
||||
$discussionrecord = $this->get_discussion_record();
|
||||
$postrecord = $this->get_post_record();
|
||||
$isdeleted = $post->is_deleted();
|
||||
$hasrating = $rating != null;
|
||||
$hastags = !empty($tags);
|
||||
$discussionid = $post->get_discussion_id();
|
||||
$parentid = $post->get_parent_id();
|
||||
|
||||
$capabilitymanager = $this->related['capabilitymanager'];
|
||||
$canview = $capabilitymanager->can_view_post($user, $discussion, $post);
|
||||
$canedit = $capabilitymanager->can_edit_post($user, $discussion, $post);
|
||||
$candelete = $capabilitymanager->can_delete_post($user, $discussion, $post);
|
||||
$cansplit = $capabilitymanager->can_split_post($user, $discussion, $post);
|
||||
$canreply = $capabilitymanager->can_reply_to_post($user, $discussion, $post);
|
||||
$canexport = $capabilitymanager->can_export_post($user, $post);
|
||||
$cancontrolreadstatus = $capabilitymanager->can_manually_control_post_read_status($user);
|
||||
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
$viewurl = $canview ? $urlfactory->get_view_post_url_from_post($post) : null;
|
||||
$viewisolatedurl = $canview ? $urlfactory->get_view_isolated_post_url_from_post($post) : null;
|
||||
$viewparenturl = $post->has_parent() ? $urlfactory->get_view_post_url_from_post_id($discussionid, $parentid) : null;
|
||||
$editurl = $canedit ? $urlfactory->get_edit_post_url_from_post($forum, $post) : null;
|
||||
$deleteurl = $candelete ? $urlfactory->get_delete_post_url_from_post($post) : null;
|
||||
$spliturl = $cansplit ? $urlfactory->get_split_discussion_at_post_url_from_post($post) : null;
|
||||
$replyurl = $canreply ? $urlfactory->get_reply_to_post_url_from_post($post) : null;
|
||||
$exporturl = $canexport ? $urlfactory->get_export_post_url_from_post($post) : null;
|
||||
$markasreadurl = $cancontrolreadstatus ? $urlfactory->get_mark_post_as_read_url_from_post($post) : null;
|
||||
$markasunreadurl = $cancontrolreadstatus ? $urlfactory->get_mark_post_as_unread_url_from_post($post) : null;
|
||||
|
||||
$authorexporter = new author_exporter($author, $authorgroups, ($canview && !$isdeleted), $this->related);
|
||||
$exportedauthor = $authorexporter->export($output);
|
||||
// Only bother loading the content if the user can see it.
|
||||
$loadcontent = $canview && !$isdeleted;
|
||||
$exportattachments = $loadcontent && !empty($attachments);
|
||||
|
||||
if ($loadcontent) {
|
||||
$subject = $post->get_subject();
|
||||
$timecreated = $post->get_time_created();
|
||||
$message = $this->get_message($post);
|
||||
} else {
|
||||
$subject = $isdeleted ? get_string('forumsubjectdeleted', 'forum') : get_string('forumsubjecthidden', 'forum');
|
||||
$message = $isdeleted ? get_string('forumbodydeleted', 'forum') : get_string('forumbodyhidden', 'forum');
|
||||
$timecreated = null;
|
||||
|
||||
if ($isdeleted) {
|
||||
$exportedauthor->fullname = null;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $post->get_id(),
|
||||
'subject' => $subject,
|
||||
'message' => $message,
|
||||
'messageformat' => $post->get_message_format(),
|
||||
'author' => $exportedauthor,
|
||||
'discussionid' => $post->get_discussion_id(),
|
||||
'hasparent' => $post->has_parent(),
|
||||
'parentid' => $post->has_parent() ? $post->get_parent_id() : null,
|
||||
'timecreated' => $timecreated,
|
||||
'unread' => ($loadcontent && $readreceiptcollection) ? !$readreceiptcollection->has_user_read_post($user, $post) : null,
|
||||
'isdeleted' => $isdeleted,
|
||||
'haswordcount' => $forum->should_display_word_count(),
|
||||
'wordcount' => $forum->should_display_word_count() ? count_words($message) : null,
|
||||
'capabilities' => [
|
||||
'view' => $canview,
|
||||
'edit' => $canedit,
|
||||
'delete' => $candelete,
|
||||
'split' => $cansplit,
|
||||
'reply' => $canreply,
|
||||
'export' => $canexport,
|
||||
'controlreadstatus' => $cancontrolreadstatus
|
||||
],
|
||||
'urls' => [
|
||||
'view' => $viewurl ? $viewurl->out(false) : null,
|
||||
'viewisolated' => $viewisolatedurl ? $viewisolatedurl->out(false) : null,
|
||||
'viewparent' => $viewparenturl ? $viewparenturl->out(false) : null,
|
||||
'edit' => $editurl ? $editurl->out(false) : null,
|
||||
'delete' => $deleteurl ? $deleteurl->out(false) : null,
|
||||
'split' => $spliturl ? $spliturl->out(false) : null,
|
||||
'reply' => $replyurl ? $replyurl->out(false) : null,
|
||||
'export' => $exporturl && $exporturl ? $exporturl->out(false) : null,
|
||||
'markasread' => $markasreadurl ? $markasreadurl->out(false) : null,
|
||||
'markasunread' => $markasunreadurl ? $markasunreadurl->out(false) : null,
|
||||
],
|
||||
'attachments' => ($exportattachments) ? $this->export_attachments($attachments, $post, $output, $canexport) : [],
|
||||
'tags' => ($loadcontent && $hastags) ? $this->export_tags($tags) : [],
|
||||
'html' => $includehtml ? [
|
||||
'rating' => ($loadcontent && $hasrating) ? $output->render($rating) : null,
|
||||
'taglist' => ($loadcontent && $hastags) ? $output->tag_list($tags) : null,
|
||||
'authorsubheading' => ($loadcontent) ? $this->get_author_subheading_html($exportedauthor, $timecreated) : null
|
||||
] : null
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'readreceiptcollection' => 'mod_forum\local\entities\post_read_receipt_collection?',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'forum' => 'mod_forum\local\entities\forum',
|
||||
'discussion' => 'mod_forum\local\entities\discussion',
|
||||
'author' => 'mod_forum\local\entities\author',
|
||||
'user' => 'stdClass',
|
||||
'context' => 'context',
|
||||
'authorgroups' => 'stdClass[]',
|
||||
'attachments' => '\stored_file[]?',
|
||||
'tags' => '\core_tag_tag[]?',
|
||||
'rating' => 'rating?',
|
||||
'includehtml' => 'bool'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message text from a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return string
|
||||
*/
|
||||
private function get_message(post_entity $post) : string {
|
||||
$context = $this->related['context'];
|
||||
$message = file_rewrite_pluginfile_urls(
|
||||
$post->get_message(),
|
||||
'pluginfile.php',
|
||||
$context->id,
|
||||
'mod_forum',
|
||||
'post',
|
||||
$post->get_id()
|
||||
);
|
||||
|
||||
if (!empty($CFG->enableplagiarism)) {
|
||||
require_once($CFG->libdir . '/plagiarismlib.php');
|
||||
$message .= plagiarism_get_links([
|
||||
'userid' => $post->get_author_id(),
|
||||
'content' => $message,
|
||||
'cmid' => $forum->get_course_module_record()->id,
|
||||
'course' => $forum->get_course_id(),
|
||||
'forum' => $forum->get_id()
|
||||
]);
|
||||
}
|
||||
|
||||
$message = format_text(
|
||||
$message,
|
||||
$post->get_message_format(),
|
||||
(object) [
|
||||
'para' => false,
|
||||
'trusted' => $post->is_message_trusted(),
|
||||
'context' => $context
|
||||
]
|
||||
);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exported attachments for a post.
|
||||
*
|
||||
* @param stored_file[] $attachments The list of attachments for the post
|
||||
* @param post_entity $post The post being exported
|
||||
* @param renderer_base $output Renderer base
|
||||
* @param bool $canexport If the user can export the post (relates to portfolios not exporters like this class)
|
||||
* @return array
|
||||
*/
|
||||
private function export_attachments(array $attachments, post_entity $post, renderer_base $output, bool $canexport) : array {
|
||||
global $CFG;
|
||||
|
||||
$urlfactory = $this->related['urlfactory'];
|
||||
$enableplagiarism = $CFG->enableplagiarism;
|
||||
$forum = $this->related['forum'];
|
||||
$context = $this->related['context'];
|
||||
|
||||
if ($enableplagiarism) {
|
||||
require_once($CFG->libdir . '/plagiarismlib.php' );
|
||||
}
|
||||
|
||||
return array_map(function($attachment) use (
|
||||
$output,
|
||||
$enableplagiarism,
|
||||
$canexport,
|
||||
$context,
|
||||
$forum,
|
||||
$post,
|
||||
$urlfactory
|
||||
) {
|
||||
$contextid = $attachment->get_contextid();
|
||||
$exporter = new stored_file_exporter($attachment, ['context' => $context]);
|
||||
$exportedattachment = $exporter->export($output);
|
||||
$exporturl = $canexport ? $urlfactory->get_export_attachment_url_from_post_and_attachment($post, $attachment) : null;
|
||||
|
||||
if ($enableplagiarism) {
|
||||
$plagiarismhtml = plagiarism_get_links([
|
||||
'userid' => $post->get_author_id(),
|
||||
'file' => $attachment,
|
||||
'cmid' => $forum->get_course_module_record()->id,
|
||||
'course' => $forum->get_course_id(),
|
||||
'forum' => $forum->get_id()
|
||||
]);
|
||||
} else {
|
||||
$plagiarismhtml = null;
|
||||
}
|
||||
|
||||
$exportedattachment->urls = [
|
||||
'export' => $exporturl ? $exporturl->out(false) : null
|
||||
];
|
||||
$exportedattachment->html = [
|
||||
'plagiarism' => $plagiarismhtml
|
||||
];
|
||||
|
||||
return $exportedattachment;
|
||||
}, $attachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the list of tags.
|
||||
*
|
||||
* @param core_tag_tag[] $tags List of tags to export
|
||||
* @return array
|
||||
*/
|
||||
private function export_tags(array $tags) : array {
|
||||
$user = $this->related['user'];
|
||||
$context = $this->related['context'];
|
||||
$capabilitymanager = $this->related['capabilitymanager'];
|
||||
$canmanagetags = $capabilitymanager->can_manage_tags($user);
|
||||
|
||||
return array_values(array_map(function($tag) use ($context, $canmanagetags) {
|
||||
$viewurl = core_tag_tag::make_url($tag->tagcollid, $tag->rawname, 0, $context->id);
|
||||
return [
|
||||
'id' => $tag->taginstanceid,
|
||||
'tagid' => $tag->id,
|
||||
'isstandard' => $tag->isstandard,
|
||||
'displayname' => $tag->get_display_name(),
|
||||
'flag' => $canmanagetags && !empty($tag->flag),
|
||||
'urls' => [
|
||||
'view' => $viewurl->out(false)
|
||||
]
|
||||
];
|
||||
}, $tags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to display as a subheading in a post.
|
||||
*
|
||||
* @param stdClass $exportedauthor The exported author object
|
||||
* @param int $timecreated The post time created timestamp if it's to be displayed
|
||||
*/
|
||||
private function get_author_subheading_html(stdClass $exportedauthor, int $timecreated) : string {
|
||||
$fullname = $exportedauthor->fullname;
|
||||
$profileurl = $exportedauthor->urls['profile'] ?? null;
|
||||
$formatteddate = userdate($timecreated, get_string('strftimedaydatetime', 'core_langconfig'));
|
||||
$name = $profileurl ? "<a href=\"{$profileurl}\">{$fullname}</a>" : $fullname;
|
||||
$date = "<time>{$formatteddate}</time>";
|
||||
return get_string('bynameondate', 'mod_forum', ['name' => $name, 'date' => $date]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy forum record.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_forum_record() : stdClass {
|
||||
$forumdbdatamapper = $this->related['legacydatamapperfactory']->get_forum_data_mapper();
|
||||
return $forumdbdatamapper->to_legacy_object($this->related['forum']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy discussion record.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_discussion_record() : stdClass {
|
||||
$discussiondbdatamapper = $this->related['legacydatamapperfactory']->get_discussion_data_mapper();
|
||||
return $discussiondbdatamapper->to_legacy_object($this->related['discussion']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy post record.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_post_record() : stdClass {
|
||||
$postdbdatamapper = $this->related['legacydatamapperfactory']->get_post_data_mapper();
|
||||
return $postdbdatamapper->to_legacy_object($this->post);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Posts exporter class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\exporters;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
use core\external\exporter;
|
||||
use renderer_base;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* Posts exporter class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class posts extends exporter {
|
||||
/** @var post_entity[] $posts List of posts to export */
|
||||
private $posts;
|
||||
/** @var author_entity[] $authorsbyid List of authors for the posts indexed by author id */
|
||||
private $authorsbyid;
|
||||
/** @var array $attachmentsbypostid List of attachments indexed by post id */
|
||||
private $attachmentsbypostid;
|
||||
/** @var array $groupsbyauthorid List of author's groups indexed by author id */
|
||||
private $groupsbyauthorid;
|
||||
/** @var array $tagsbypostid List of tags indexed by post id */
|
||||
private $tagsbypostid;
|
||||
/** @var array $ratingbypostid List of ratings indexed by post id */
|
||||
private $ratingbypostid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param post_entity[] $posts List of posts to export
|
||||
* @param author_entity[] $authorsbyid List of authors for the posts indexed by author id
|
||||
* @param array $attachmentsbypostid List of attachments indexed by post id
|
||||
* @param array $groupsbyauthorid List of author's groups indexed by author id
|
||||
* @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
|
||||
*/
|
||||
public function __construct(
|
||||
array $posts,
|
||||
array $authorsbyid = [],
|
||||
array $attachmentsbypostid = [],
|
||||
array $groupsbyauthorid = [],
|
||||
array $tagsbypostid = [],
|
||||
array $ratingbypostid = [],
|
||||
array $related = []
|
||||
) {
|
||||
$this->posts = $posts;
|
||||
$this->authorsbyid = $authorsbyid;
|
||||
$this->attachmentsbypostid = $attachmentsbypostid;
|
||||
$this->groupsbyauthorid = $groupsbyauthorid;
|
||||
$this->tagsbypostid = $tagsbypostid;
|
||||
$this->ratingbypostid = $ratingbypostid;
|
||||
return parent::__construct([], $related);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of additional properties.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_other_properties() {
|
||||
return [
|
||||
'posts' => [
|
||||
'type' => post_exporter::read_properties_definition(),
|
||||
'multiple' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional values to inject while exporting.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array Keys are the property names, values are their values.
|
||||
*/
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$related = $this->related;
|
||||
$authorsbyid = $this->authorsbyid;
|
||||
$attachmentsbypostid = $this->attachmentsbypostid;
|
||||
$groupsbyauthorid = $this->groupsbyauthorid;
|
||||
$tagsbypostid = $this->tagsbypostid;
|
||||
$ratingbypostid = $this->ratingbypostid;
|
||||
$exportedposts = array_map(
|
||||
function($post) use (
|
||||
$related,
|
||||
$authorsbyid,
|
||||
$attachmentsbypostid,
|
||||
$groupsbyauthorid,
|
||||
$tagsbypostid,
|
||||
$ratingbypostid,
|
||||
$output
|
||||
) {
|
||||
$authorid = $post->get_author_id();
|
||||
$postid = $post->get_id();
|
||||
$author = isset($authorsbyid[$authorid]) ? $authorsbyid[$authorid] : [];
|
||||
$attachments = isset($attachmentsbypostid[$postid]) ? $attachmentsbypostid[$postid] : [];
|
||||
$authorgroups = isset($groupsbyauthorid[$authorid]) ? $groupsbyauthorid[$authorid] : [];
|
||||
$tags = isset($tagsbypostid[$postid]) ? $tagsbypostid[$postid] : [];
|
||||
$rating = isset($ratingbypostid[$postid]) ? $ratingbypostid[$postid] : null;
|
||||
$exporter = new post_exporter($post, array_merge($related, [
|
||||
'author' => $author,
|
||||
'attachments' => $attachments,
|
||||
'authorgroups' => $authorgroups,
|
||||
'tags' => $tags,
|
||||
'rating' => $rating
|
||||
]));
|
||||
return $exporter->export($output);
|
||||
},
|
||||
$this->posts
|
||||
);
|
||||
|
||||
return [
|
||||
'posts' => $exportedposts
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects that are related.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_related() {
|
||||
return [
|
||||
'legacydatamapperfactory' => 'mod_forum\local\factories\legacy_data_mapper',
|
||||
'capabilitymanager' => 'mod_forum\local\managers\capability',
|
||||
'urlfactory' => 'mod_forum\local\factories\url',
|
||||
'forum' => 'mod_forum\local\entities\forum',
|
||||
'discussion' => 'mod_forum\local\entities\discussion',
|
||||
'readreceiptcollection' => 'mod_forum\local\entities\post_read_receipt_collection?',
|
||||
'user' => 'stdClass',
|
||||
'context' => 'context',
|
||||
'includehtml' => 'bool'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Builder factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\builders\exported_posts as exported_posts_builder;
|
||||
use mod_forum\local\factories\vault as vault_factory;
|
||||
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\manager as manager_factory;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Builder factory to construct any builders for forum.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class builder {
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
/** @var exporter_factory $exporterfactory Exporter factory */
|
||||
private $exporterfactory;
|
||||
/** @var vault_factory $vaultfactory Vault factory */
|
||||
private $vaultfactory;
|
||||
/** @var manager_factory $managerfactory Manager factory */
|
||||
private $managerfactory;
|
||||
/** @var renderer_base $rendererbase Renderer base */
|
||||
private $rendererbase;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
||||
* @param exporter_factory $exporterfactory Exporter factory
|
||||
* @param vault_factory $vaultfactory Vault factory
|
||||
* @param manager_factory $managerfactory Manager factory
|
||||
* @param renderer_base $rendererbase Renderer base
|
||||
*/
|
||||
public function __construct(
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
manager_factory $managerfactory,
|
||||
renderer_base $rendererbase
|
||||
) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->managerfactory = $managerfactory;
|
||||
$this->rendererbase = $rendererbase;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an instance of the exported posts builder.
|
||||
*
|
||||
* @return exported_posts_builder
|
||||
*/
|
||||
public function get_exported_posts_builder() : exported_posts_builder {
|
||||
return new exported_posts_builder(
|
||||
$this->rendererbase,
|
||||
$this->legacydatamapperfactory,
|
||||
$this->exporterfactory,
|
||||
$this->vaultfactory,
|
||||
$this->managerfactory->get_rating_manager()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Entity factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\discussion_summary as discussion_summary_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\entities\post_read_receipt_collection as post_read_receipt_collection_entity;
|
||||
use mod_forum\local\entities\sorter as sorter_entity;
|
||||
use stdClass;
|
||||
use context;
|
||||
use cm_info;
|
||||
use user_picture;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Entity factory to create the forum entities.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class entity {
|
||||
/**
|
||||
* Create a forum entity from a stdClass (legacy forum object).
|
||||
*
|
||||
* @param stdClass $record The forum record
|
||||
* @param context $context The forum module context
|
||||
* @param stdClass $coursemodule Course module record for the forum
|
||||
* @param stdClass $course Course the forum belongs to
|
||||
* @return forum_entity
|
||||
*/
|
||||
public function get_forum_from_stdclass(
|
||||
stdClass $record,
|
||||
context $context,
|
||||
stdClass $coursemodule,
|
||||
stdClass $course
|
||||
) : forum_entity {
|
||||
// Note: cm_info::create loads a cm_info in the context of the current user which
|
||||
// creates hidden dependency on the logged in user (very bad) however it's the best
|
||||
// option to load some data we need which doesn't require the logged in user.
|
||||
// Only use properties which do not require the logged in user.
|
||||
$cm = \cm_info::create($coursemodule);
|
||||
|
||||
return new forum_entity(
|
||||
$context,
|
||||
$coursemodule,
|
||||
$course,
|
||||
// This property is a general module property that isn't affected by the logged in user.
|
||||
$cm->effectivegroupmode,
|
||||
$record->id,
|
||||
$record->course,
|
||||
$record->type,
|
||||
$record->name,
|
||||
$record->intro,
|
||||
$record->introformat,
|
||||
$record->assessed,
|
||||
$record->assesstimestart,
|
||||
$record->assesstimefinish,
|
||||
$record->scale,
|
||||
$record->maxbytes,
|
||||
$record->maxattachments,
|
||||
$record->forcesubscribe,
|
||||
$record->trackingtype,
|
||||
$record->rsstype,
|
||||
$record->rssarticles,
|
||||
$record->timemodified,
|
||||
$record->warnafter,
|
||||
$record->blockafter,
|
||||
$record->blockperiod,
|
||||
$record->completiondiscussions,
|
||||
$record->completionreplies,
|
||||
$record->completionposts,
|
||||
$record->displaywordcount,
|
||||
$record->lockdiscussionafter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion entity from an stdClass (legacy dicussion object).
|
||||
*
|
||||
* @param stdClass $record Discussion record
|
||||
* @return discussion_entity
|
||||
*/
|
||||
public function get_discussion_from_stdclass(stdClass $record) : discussion_entity {
|
||||
return new discussion_entity(
|
||||
$record->id,
|
||||
$record->course,
|
||||
$record->forum,
|
||||
$record->name,
|
||||
$record->firstpost,
|
||||
$record->userid,
|
||||
$record->groupid,
|
||||
$record->assessed,
|
||||
$record->timemodified,
|
||||
$record->usermodified,
|
||||
$record->timestart,
|
||||
$record->timeend,
|
||||
$record->pinned
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post entity from an stdClass (legacy post object).
|
||||
*
|
||||
* @param stdClass $record The post record
|
||||
* @return post_entity
|
||||
*/
|
||||
public function get_post_from_stdclass(stdClass $record) : post_entity {
|
||||
return new post_entity(
|
||||
$record->id,
|
||||
$record->discussion,
|
||||
$record->parent,
|
||||
$record->userid,
|
||||
$record->created,
|
||||
$record->modified,
|
||||
$record->mailed,
|
||||
$record->subject,
|
||||
$record->message,
|
||||
$record->messageformat,
|
||||
$record->messagetrust,
|
||||
$record->attachment,
|
||||
$record->totalscore,
|
||||
$record->mailnow,
|
||||
$record->deleted
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an author entity from a user record.
|
||||
*
|
||||
* @param stdClass $record The user record
|
||||
* @return author_entity
|
||||
*/
|
||||
public function get_author_from_stdclass(stdClass $record) : author_entity {
|
||||
return new author_entity(
|
||||
$record->id,
|
||||
$record->picture,
|
||||
$record->firstname,
|
||||
$record->lastname,
|
||||
fullname($record),
|
||||
$record->email,
|
||||
$record->middlename,
|
||||
$record->firstnamephonetic,
|
||||
$record->lastnamephonetic,
|
||||
$record->alternatename,
|
||||
$record->imagealt
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion summary enttiy from stdClasses.
|
||||
*
|
||||
* @param stdClass $discussion The discussion record
|
||||
* @param stdClass $firstpost A post record for the first post in the discussion
|
||||
* @param stdClass $firstpostauthor A user record for the author of the first post
|
||||
* @param stdClass $latestpostauthor A user record for the author of the latest post in the discussion
|
||||
* @return discussion_summary_entity
|
||||
*/
|
||||
public function get_discussion_summary_from_stdclass(
|
||||
stdClass $discussion,
|
||||
stdClass $firstpost,
|
||||
stdClass $firstpostauthor,
|
||||
stdClass $latestpostauthor
|
||||
) : discussion_summary_entity {
|
||||
|
||||
$firstpostauthorentity = $this->get_author_from_stdclass($firstpostauthor);
|
||||
return new discussion_summary_entity(
|
||||
$this->get_discussion_from_stdclass($discussion),
|
||||
$this->get_post_from_stdclass($firstpost, $firstpostauthorentity),
|
||||
$firstpostauthorentity,
|
||||
$this->get_author_from_stdclass($latestpostauthor)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post read receipt collection entity from a list of read receipt records.
|
||||
*
|
||||
* @param array $records A list of read receipt records.
|
||||
* @return post_read_receipt_collection_entity
|
||||
*/
|
||||
public function get_post_read_receipt_collection_from_stdclasses(array $records) : post_read_receipt_collection_entity {
|
||||
return new post_read_receipt_collection_entity($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sorter entity to sort post entities.
|
||||
*
|
||||
* @return sorter_entity
|
||||
*/
|
||||
public function get_posts_sorter() : sorter_entity {
|
||||
return new sorter_entity(
|
||||
// Get id function for a post_entity.
|
||||
function(post_entity $post) {
|
||||
return $post->get_id();
|
||||
},
|
||||
// Get parent id function for a post_entity.
|
||||
function(post_entity $post) {
|
||||
return $post->get_parent_id();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sorter entity to sort exported posts.
|
||||
*
|
||||
* @return sorter_entity
|
||||
*/
|
||||
public function get_exported_posts_sorter() : sorter_entity {
|
||||
return new sorter_entity(
|
||||
// Get id function for an exported post.
|
||||
function(stdClass $post) {
|
||||
return $post->id;
|
||||
},
|
||||
// Get parent id function for an exported post.
|
||||
function(stdClass $post) {
|
||||
return $post->parentid;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Forum Exporter factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\entities\post_read_receipt_collection as post_read_receipt_collection_entity;
|
||||
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\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;
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
use mod_forum\local\exporters\posts as posts_exporter;
|
||||
use context;
|
||||
use rating;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* The exporter factory class used to fetch an instance of the different exporter types.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class exporter {
|
||||
/** @var legacy_data_mapper_factory The factory to fetch a legacy data mapper */
|
||||
private $legacydatamapperfactory;
|
||||
|
||||
/** @var manager_factory The factory to fetch a new manager */
|
||||
private $managerfactory;
|
||||
|
||||
/** @var url_factory The factory to create urls */
|
||||
private $urlfactory;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function __construct(
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
manager_factory $managerfactory,
|
||||
url_factory $urlfactory
|
||||
) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->managerfactory = $managerfactory;
|
||||
$this->urlfactory = $urlfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new forum exporter for the specified user and forum.
|
||||
*
|
||||
* @param stdClass $user The user viewing the forum
|
||||
* @param forum_entity $forum The forum being viewed
|
||||
* @param int $currentgroup The group currently being viewed
|
||||
* @return forum_exporter
|
||||
*/
|
||||
public function get_forum_exporter(
|
||||
stdClass $user,
|
||||
forum_entity $forum,
|
||||
?int $currentgroup
|
||||
) : forum_exporter {
|
||||
return new forum_exporter($forum, [
|
||||
'legacydatamapperfactory' => $this->legacydatamapperfactory,
|
||||
'capabilitymanager' => $this->managerfactory->get_capability_manager($forum),
|
||||
'urlfactory' => $this->urlfactory,
|
||||
'user' => $user,
|
||||
'currentgroup' => $currentgroup,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the structure of the forum exporter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_forum_export_structure() : array {
|
||||
return forum_exporter::read_properties_definition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new discussion exporter for the specified user and forum discussion.
|
||||
*
|
||||
* @param stdClass $user The user viewing the forum
|
||||
* @param forum_entity $forum The forum being viewed
|
||||
* @param discussion_entity $discussion The discussion being viewed
|
||||
* @param stdClass[] $groupsbyid The list of groups in the forum
|
||||
* @return discussion_exporter
|
||||
*/
|
||||
public function get_discussion_exporter(
|
||||
stdClass $user,
|
||||
forum_entity $forum,
|
||||
discussion_entity $discussion,
|
||||
array $groupsbyid = []
|
||||
) : discussion_exporter {
|
||||
return new discussion_exporter($discussion, [
|
||||
'context' => $forum->get_context(),
|
||||
'forum' => $forum,
|
||||
'capabilitymanager' => $this->managerfactory->get_capability_manager($forum),
|
||||
'urlfactory' => $this->urlfactory,
|
||||
'user' => $user,
|
||||
'legacydatamapperfactory' => $this->legacydatamapperfactory,
|
||||
'latestpostid' => null,
|
||||
'groupsbyid' => $groupsbyid
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the structure of the discussion exporter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_discussion_export_structure() {
|
||||
return discussion_exporter::read_properties_definition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new discussion summaries exporter for the specified user and set of discussions.
|
||||
*
|
||||
* @param stdClass $user The user viewing the forum
|
||||
* @param forum_entity $forum The forum being viewed
|
||||
* @param discussion_entity[] $discussions The set of discussions to be shown
|
||||
* @param stdClass[] $groupsbyauthorid The set of groups in an associative array for each author
|
||||
* @param stdClass[] $groupsbyid The set of groups in the forum in an associative array for each group
|
||||
* @param int[] $discussionreplycount The number of replies for each discussion
|
||||
* @param int[] $discussionunreadcount The number of unread posts for each discussion
|
||||
* @param int[] $latestpostids The latest post id for each discussion
|
||||
* @return discussion_summaries_exporter
|
||||
*/
|
||||
public function get_discussion_summaries_exporter(
|
||||
stdClass $user,
|
||||
forum_entity $forum,
|
||||
array $discussions,
|
||||
array $groupsbyid = [],
|
||||
array $groupsbyauthorid = [],
|
||||
array $discussionreplycount = [],
|
||||
array $discussionunreadcount = [],
|
||||
array $latestpostid = []
|
||||
) : discussion_summaries_exporter {
|
||||
return new discussion_summaries_exporter(
|
||||
$discussions,
|
||||
$groupsbyid,
|
||||
$groupsbyauthorid,
|
||||
$discussionreplycount,
|
||||
$discussionunreadcount,
|
||||
$latestpostid,
|
||||
[
|
||||
'legacydatamapperfactory' => $this->legacydatamapperfactory,
|
||||
'context' => $forum->get_context(),
|
||||
'forum' => $forum,
|
||||
'capabilitymanager' => $this->managerfactory->get_capability_manager($forum),
|
||||
'urlfactory' => $this->urlfactory,
|
||||
'user' => $user,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the structure of the discussion summaries exporter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_discussion_summaries_export_structure() {
|
||||
return discussion_summaries_exporter::read_properties_definition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new post exporter for the specified user and set of post.
|
||||
*
|
||||
* @param stdClass $user The user viewing the forum
|
||||
* @param forum_entity $forum The forum being viewed
|
||||
* @param discussion_entity $discussion The discussion that the post is in
|
||||
* @param post_entity[] $posts The set of posts to be exported
|
||||
* @param author_entity[] $authorsbyid List of authors indexed by author id
|
||||
* @param array $attachmentsbypostid List of attachments for each post indexed by post id
|
||||
* @param array $groupsbyauthorid List of groups for the post authors indexed by author id
|
||||
* @param post_read_receipt_collection_entity|null $readreceiptcollection Details of read receipts for each post
|
||||
* @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
|
||||
*/
|
||||
public function get_posts_exporter(
|
||||
stdClass $user,
|
||||
forum_entity $forum,
|
||||
discussion_entity $discussion,
|
||||
array $posts,
|
||||
array $authorsbyid = [],
|
||||
array $attachmentsbypostid = [],
|
||||
array $groupsbyauthorid = [],
|
||||
post_read_receipt_collection_entity $readreceiptcollection = null,
|
||||
array $tagsbypostid = [],
|
||||
array $ratingbypostid = [],
|
||||
bool $includehtml = false
|
||||
) : posts_exporter {
|
||||
return new posts_exporter($posts, $authorsbyid, $attachmentsbypostid, $groupsbyauthorid, $tagsbypostid, $ratingbypostid, [
|
||||
'legacydatamapperfactory' => $this->legacydatamapperfactory,
|
||||
'capabilitymanager' => $this->managerfactory->get_capability_manager($forum),
|
||||
'urlfactory' => $this->urlfactory,
|
||||
'forum' => $forum,
|
||||
'discussion' => $discussion,
|
||||
'user' => $user,
|
||||
'context' => $forum->get_context(),
|
||||
'readreceiptcollection' => $readreceiptcollection,
|
||||
'includehtml' => $includehtml
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the structure of the posts exporter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_posts_export_structure() {
|
||||
return posts_exporter::read_properties_definition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Legacy data mapper factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\data_mappers\legacy\author as author_data_mapper;
|
||||
use mod_forum\local\data_mappers\legacy\discussion as discussion_data_mapper;
|
||||
use mod_forum\local\data_mappers\legacy\forum as forum_data_mapper;
|
||||
use mod_forum\local\data_mappers\legacy\post as post_data_mapper;
|
||||
|
||||
/**
|
||||
* Legacy data mapper factory.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class legacy_data_mapper {
|
||||
/**
|
||||
* Create a legacy forum data mapper.
|
||||
*
|
||||
* @return forum_data_mapper
|
||||
*/
|
||||
public function get_forum_data_mapper() : forum_data_mapper {
|
||||
return new forum_data_mapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a legacy discussion data mapper.
|
||||
*
|
||||
* @return discussion_data_mapper
|
||||
*/
|
||||
public function get_discussion_data_mapper() : discussion_data_mapper {
|
||||
return new discussion_data_mapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a legacy post data mapper.
|
||||
*
|
||||
* @return post_data_mapper
|
||||
*/
|
||||
public function get_post_data_mapper() : post_data_mapper {
|
||||
return new post_data_mapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a legacy author data mapper.
|
||||
*
|
||||
* @return author_data_mapper
|
||||
*/
|
||||
public function get_author_data_mapper() : author_data_mapper {
|
||||
return new author_data_mapper();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Managers factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\managers\capability as capability_manager;
|
||||
use rating_manager;
|
||||
|
||||
/**
|
||||
* Managers factory.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manager {
|
||||
/** @var legacy_data_mapper $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param legacy_data_mapper $legacydatamapperfactory Legacy data mapper factory
|
||||
*/
|
||||
public function __construct(legacy_data_mapper $legacydatamapperfactory) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a capability manager for the given forum.
|
||||
*
|
||||
* @param forum_entity $forum The forum to manage capabilities for
|
||||
* @return capability_manager
|
||||
*/
|
||||
public function get_capability_manager(forum_entity $forum) {
|
||||
return new capability_manager(
|
||||
$forum,
|
||||
$this->legacydatamapperfactory->get_forum_data_mapper(),
|
||||
$this->legacydatamapperfactory->get_discussion_data_mapper(),
|
||||
$this->legacydatamapperfactory->get_post_data_mapper()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a rating manager.
|
||||
*
|
||||
* @return rating_manager
|
||||
*/
|
||||
public function get_rating_manager() : rating_manager {
|
||||
return new rating_manager();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderer factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\factories\vault as vault_factory;
|
||||
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
||||
use mod_forum\local\factories\entity as entity_factory;
|
||||
use mod_forum\local\factories\exporter as exporter_factory;
|
||||
use mod_forum\local\factories\manager as manager_factory;
|
||||
use mod_forum\local\factories\builder as builder_factory;
|
||||
use mod_forum\local\factories\url as url_factory;
|
||||
use mod_forum\local\renderers\discussion as discussion_renderer;
|
||||
use mod_forum\local\renderers\discussion_list as discussion_list_renderer;
|
||||
use mod_forum\local\renderers\posts as posts_renderer;
|
||||
use moodle_page;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Renderer factory.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer {
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
/** @var exporter_factory $exporterfactory Exporter factory */
|
||||
private $exporterfactory;
|
||||
/** @var vault_factory $vaultfactory Vault factory */
|
||||
private $vaultfactory;
|
||||
/** @var manager_factory $managerfactory Manager factory */
|
||||
private $managerfactory;
|
||||
/** @var entity_factory $entityfactory Entity factory */
|
||||
private $entityfactory;
|
||||
/** @var builder_factory $builderfactory Builder factory */
|
||||
private $builderfactory;
|
||||
/** @var url_factory $urlfactory URL factory */
|
||||
private $urlfactory;
|
||||
/** @var renderer_base $rendererbase Renderer base */
|
||||
private $rendererbase;
|
||||
/** @var moodle_page $page Moodle page */
|
||||
private $page;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
||||
* @param exporter_factory $exporterfactory Exporter factory
|
||||
* @param vault_factory $vaultfactory Vault factory
|
||||
* @param manager_factory $managerfactory Manager factory
|
||||
* @param entity_factory $entityfactory Entity factory
|
||||
* @param builder_factory $builderfactory Builder factory
|
||||
* @param url_factory $urlfactory URL factory
|
||||
* @param moodle_page $page Moodle page
|
||||
*/
|
||||
public function __construct(
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
manager_factory $managerfactory,
|
||||
entity_factory $entityfactory,
|
||||
builder_factory $builderfactory,
|
||||
url_factory $urlfactory,
|
||||
moodle_page $page
|
||||
) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->managerfactory = $managerfactory;
|
||||
$this->entityfactory = $entityfactory;
|
||||
$this->builderfactory = $builderfactory;
|
||||
$this->urlfactory = $urlfactory;
|
||||
$this->page = $page;
|
||||
$this->rendererbase = $page->get_renderer('mod_forum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion renderer for the given forum and discussion.
|
||||
*
|
||||
* @param forum_entity $forum Forum the discussion belongs to
|
||||
* @param discussion_entity $discussion Discussion to render
|
||||
* @param int $displaymode How should the posts be formatted?
|
||||
* @return discussion_renderer
|
||||
*/
|
||||
public function get_discussion_renderer(
|
||||
forum_entity $forum,
|
||||
discussion_entity $discussion,
|
||||
int $displaymode
|
||||
) : discussion_renderer {
|
||||
|
||||
$capabilitymanager = $this->managerfactory->get_capability_manager($forum);
|
||||
$ratingmanager = $this->managerfactory->get_rating_manager();
|
||||
$rendererbase = $this->rendererbase;
|
||||
$baseurl = $this->urlfactory->get_discussion_view_url_from_discussion($discussion);
|
||||
$notifications = [];
|
||||
|
||||
switch ($forum->get_type()) {
|
||||
case 'single':
|
||||
$baseurl = new moodle_url("/mod/forum/view.php", ['f' => $forum->get_id()]);
|
||||
break;
|
||||
case 'qanda':
|
||||
if ($capabilitymanager->must_post_before_viewing_discussion($user, $forum, $discussion)) {
|
||||
$notifications[] = $rendererbase->notification(get_string('qandanotify', 'forum'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return new discussion_renderer(
|
||||
$discussion,
|
||||
$forum,
|
||||
$displaymode,
|
||||
$rendererbase,
|
||||
$this->get_single_discussion_posts_renderer($displaymode, false),
|
||||
$this->page,
|
||||
$this->legacydatamapperfactory,
|
||||
$this->exporterfactory,
|
||||
$this->vaultfactory,
|
||||
$capabilitymanager,
|
||||
$ratingmanager,
|
||||
$this->entityfactory->get_exported_posts_sorter(),
|
||||
$baseurl,
|
||||
$notifications
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a posts renderer to render posts without defined parent/reply relationships.
|
||||
*
|
||||
* @return posts_renderer
|
||||
*/
|
||||
public function get_posts_renderer() : posts_renderer {
|
||||
return new posts_renderer(
|
||||
$this->rendererbase,
|
||||
$this->builderfactory->get_exported_posts_builder(),
|
||||
'mod_forum/forum_discussion_posts'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a posts renderer to render a list of posts in a single discussion.
|
||||
*
|
||||
* @param int|null $displaymode How should the posts be formatted?
|
||||
* @param bool $readonly Should the posts include the actions to reply, delete, etc?
|
||||
* @return posts_renderer
|
||||
*/
|
||||
public function get_single_discussion_posts_renderer(int $displaymode = null, bool $readonly = false) : posts_renderer {
|
||||
$exportedpostssorter = $this->entityfactory->get_exported_posts_sorter();
|
||||
|
||||
switch ($displaymode) {
|
||||
case FORUM_MODE_THREADED:
|
||||
$template = 'mod_forum/forum_discussion_threaded_posts';
|
||||
break;
|
||||
case FORUM_MODE_NESTED:
|
||||
$template = 'mod_forum/forum_discussion_nested_posts';
|
||||
break;
|
||||
default;
|
||||
$template = 'mod_forum/forum_discussion_posts';
|
||||
break;
|
||||
}
|
||||
|
||||
return new posts_renderer(
|
||||
$this->rendererbase,
|
||||
$this->builderfactory->get_exported_posts_builder(),
|
||||
$template,
|
||||
// Post process the exported posts for our template. This function will add the "replies"
|
||||
// and "hasreplies" properties to the exported posts. It will also sort them into the
|
||||
// reply tree structure if the display mode requires it.
|
||||
function($exportedposts, $forums) use ($displaymode, $readonly, $exportedpostssorter) {
|
||||
$forum = array_shift($forums);
|
||||
$seenfirstunread = false;
|
||||
$exportedposts = array_map(
|
||||
function($exportedpost) use ($forum, $readonly, $seenfirstunread) {
|
||||
if ($forum->get_type() == 'single' && !$exportedpost->hasparent) {
|
||||
// Remove the author from any posts that don't have a parent.
|
||||
unset($exportedpost->author);
|
||||
}
|
||||
|
||||
$exportedpost->readonly = $readonly;
|
||||
$exportedpost->hasreplies = false;
|
||||
$exportedpost->replies = [];
|
||||
|
||||
$exportedpost->isfirstunread = false;
|
||||
if (!$seenfirstunread && $exportedpost->unread) {
|
||||
$exportedpost->isfirstunread = true;
|
||||
$seenfirstunread = true;
|
||||
}
|
||||
|
||||
return $exportedpost;
|
||||
},
|
||||
$exportedposts
|
||||
);
|
||||
|
||||
if ($displaymode === FORUM_MODE_NESTED || $displaymode === FORUM_MODE_THREADED) {
|
||||
$sortedposts = $exportedpostssorter->sort_into_children($exportedposts);
|
||||
$sortintoreplies = function($nestedposts) use (&$sortintoreplies) {
|
||||
return array_map(function($postdata) use (&$sortintoreplies) {
|
||||
[$post, $replies] = $postdata;
|
||||
$post->replies = $sortintoreplies($replies);
|
||||
$post->hasreplies = !empty($post->replies);
|
||||
return $post;
|
||||
}, $nestedposts);
|
||||
};
|
||||
// Set the "replies" property on the exported posts.
|
||||
$exportedposts = $sortintoreplies($sortedposts);
|
||||
} else if ($displaymode === FORUM_MODE_FLATNEWEST || $displaymode === FORUM_MODE_FLATOLDEST) {
|
||||
$exportedfirstpost = array_shift($exportedposts);
|
||||
$exportedfirstpost->replies = $exportedposts;
|
||||
$exportedfirstpost->hasreplies = true;
|
||||
$exportedposts = [$exportedfirstpost];
|
||||
}
|
||||
|
||||
return $exportedposts;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a posts renderer to render posts in the forum search results.
|
||||
*
|
||||
* @param string[] $searchterms The search terms to be highlighted in the posts
|
||||
* @return posts_renderer
|
||||
*/
|
||||
public function get_posts_search_results_renderer(array $searchterms) : posts_renderer {
|
||||
$urlfactory = $this->urlfactory;
|
||||
|
||||
return new posts_renderer(
|
||||
$this->rendererbase,
|
||||
$this->builderfactory->get_exported_posts_builder(),
|
||||
'mod_forum/forum_posts_with_context_links',
|
||||
// Post process the exported posts to add the highlighting of the search terms to the post
|
||||
// and also the additional context links in the subject.
|
||||
function($exportedposts, $forumsbyid, $discussionsbyid) use ($searchterms, $urlfactory) {
|
||||
$highlightwords = implode(' ', $searchterms);
|
||||
|
||||
return array_map(
|
||||
function($exportedpost) use (
|
||||
$forumsbyid,
|
||||
$discussionsbyid,
|
||||
$searchterms,
|
||||
$highlightwords,
|
||||
$urlfactory
|
||||
) {
|
||||
$discussion = $discussionsbyid[$exportedpost->discussionid];
|
||||
$forum = $forumsbyid[$discussion->get_forum_id()];
|
||||
|
||||
$viewdiscussionurl = $urlfactory->get_discussion_view_url_from_discussion($discussion);
|
||||
$exportedpost->urls['viewforum'] = $urlfactory->get_forum_view_url_from_forum($forum)->out(false);
|
||||
$exportedpost->urls['viewdiscussion'] = $viewdiscussionurl->out(false);
|
||||
$exportedpost->subject = highlight($highlightwords, $exportedpost->subject);
|
||||
$exportedpost->forumname = format_string($forum->get_name(), true);
|
||||
$exportedpost->discussionname = highlight($highlightwords, format_string($discussion->get_name(), true));
|
||||
$exportedpost->showdiscussionname = $forum->get_type() != 'single';
|
||||
|
||||
// Identify search terms only found in HTML markup, and add a warning about them to
|
||||
// the start of the message text. This logic was copied exactly as is from the previous
|
||||
// implementation.
|
||||
$missingterms = '';
|
||||
$exportedpost->message = highlight(
|
||||
$highlightwords,
|
||||
$exportedpost->message,
|
||||
0,
|
||||
'<fgw9sdpq4>',
|
||||
'</fgw9sdpq4>'
|
||||
);
|
||||
|
||||
foreach ($searchterms as $searchterm) {
|
||||
if (
|
||||
preg_match("/$searchterm/i", $exportedpost->message) &&
|
||||
!preg_match('/<fgw9sdpq4>' . $searchterm . '<\/fgw9sdpq4>/i', $exportedpost->message)
|
||||
) {
|
||||
$missingterms .= " $searchterm";
|
||||
}
|
||||
}
|
||||
|
||||
$exportedpost->message = str_replace('<fgw9sdpq4>', '<span class="highlight">', $exportedpost->message);
|
||||
$exportedpost->message = str_replace('</fgw9sdpq4>', '</span>', $exportedpost->message);
|
||||
|
||||
if ($missingterms) {
|
||||
$strmissingsearchterms = get_string('missingsearchterms', 'forum');
|
||||
$exportedpost->message = '<p class="highlight2">' . $strmissingsearchterms . ' '
|
||||
. $missingterms . '</p>' . $exportedpost->message;
|
||||
}
|
||||
|
||||
return $exportedpost;
|
||||
},
|
||||
$exportedposts
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a posts renderer to render posts in mod/forum/user.php.
|
||||
*
|
||||
* @param bool $addlinkstocontext Should links to the course, forum, and discussion be included?
|
||||
* @return posts_renderer
|
||||
*/
|
||||
public function get_user_forum_posts_report_renderer(bool $addlinkstocontext) : posts_renderer {
|
||||
$urlfactory = $this->urlfactory;
|
||||
|
||||
return new posts_renderer(
|
||||
$this->rendererbase,
|
||||
$this->builderfactory->get_exported_posts_builder(),
|
||||
'mod_forum/forum_posts_with_context_links',
|
||||
function($exportedposts, $forumsbyid, $discussionsbyid) use ($urlfactory, $addlinkstocontext) {
|
||||
|
||||
return array_map(function($exportedpost) use ($forumsbyid, $discussionsbyid, $addlinkstocontext, $urlfactory) {
|
||||
$discussion = $discussionsbyid[$exportedpost->discussionid];
|
||||
$forum = $forumsbyid[$discussion->get_forum_id()];
|
||||
$courserecord = $forum->get_course_record();
|
||||
|
||||
if ($addlinkstocontext) {
|
||||
$viewdiscussionurl = $urlfactory->get_discussion_view_url_from_discussion($discussion);
|
||||
$exportedpost->urls['viewforum'] = $urlfactory->get_forum_view_url_from_forum($forum)->out(false);
|
||||
$exportedpost->urls['viewdiscussion'] = $viewdiscussionurl->out(false);
|
||||
$exportedpost->urls['viewcourse'] = $urlfactory->get_course_url_from_forum($forum)->out(false);
|
||||
}
|
||||
|
||||
$exportedpost->forumname = format_string($forum->get_name(), true);
|
||||
$exportedpost->discussionname = format_string($discussion->get_name(), true);
|
||||
$exportedpost->coursename = format_string($courserecord->shortname, true);
|
||||
$exportedpost->showdiscussionname = $forum->get_type() != 'single';
|
||||
|
||||
return $exportedpost;
|
||||
}, $exportedposts);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion list renderer.
|
||||
*
|
||||
* @param forum_entity $forum The forum that the discussions belong to
|
||||
* @return discussion_list_renderer
|
||||
*/
|
||||
public function get_discussion_list_renderer(
|
||||
forum_entity $forum
|
||||
) : discussion_list_renderer {
|
||||
|
||||
$capabilitymanager = $this->managerfactory->get_capability_manager($forum);
|
||||
$rendererbase = $this->rendererbase;
|
||||
$notifications = [];
|
||||
|
||||
return new discussion_list_renderer(
|
||||
$forum,
|
||||
$rendererbase,
|
||||
$this->legacydatamapperfactory,
|
||||
$this->exporterfactory,
|
||||
$this->vaultfactory,
|
||||
$capabilitymanager,
|
||||
$this->urlfactory,
|
||||
$notifications
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,446 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A URL factory for the forum.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
||||
use moodle_url;
|
||||
use stored_file;
|
||||
use user_picture;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* A URL factory for the forum.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class url {
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
||||
*/
|
||||
public function __construct(legacy_data_mapper_factory $legacydatamapperfactory) {
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course url from the given course id.
|
||||
*
|
||||
* @param int $courseid The course id
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_course_url_from_courseid(int $courseid) : moodle_url {
|
||||
return new moodle_url('/course/view.php', [
|
||||
'id' => $courseid,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course url from the given forum entity.
|
||||
*
|
||||
* @param forum_entity $forum The forum entity
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_course_url_from_forum(forum_entity $forum) : moodle_url {
|
||||
return $this->get_course_url_from_courseid($forum->get_course_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the create discussion url for the given forum.
|
||||
*
|
||||
* @param forum_entity $forum The forum entity
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_create_url(forum_entity $forum) : moodle_url {
|
||||
return new moodle_url('/mod/forum/post.php', [
|
||||
'forum' => $forum->get_id(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view forum url for the given forum and optionally a page number.
|
||||
*
|
||||
* @param forum_entity $forum The forum entity
|
||||
* @param int|null $pageno The page number
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view forum url for the given course module id and optionally a page number.
|
||||
*
|
||||
* @param int $coursemoduleid The course module id
|
||||
* @param int|null $pageno The page number
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_forum_view_url_from_course_module_id(int $coursemoduleid, ?int $pageno = null) : moodle_url {
|
||||
$url = new moodle_url('/mod/forum/discussions.php', [
|
||||
'id' => $coursemoduleid,
|
||||
]);
|
||||
|
||||
if (null !== $pageno) {
|
||||
$url->param('page', $pageno);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view discussion url from the given discussion id.
|
||||
*
|
||||
* @param int $discussionid The discussion id
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_view_url_from_discussion_id(int $discussionid) : moodle_url {
|
||||
return new moodle_url('/mod/forum/discuss.php', [
|
||||
'd' => $discussionid
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view discussion url from the given discussion.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_view_url_from_discussion(discussion_entity $discussion) : moodle_url {
|
||||
return $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view the first unread post in a discussion.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_view_first_unread_post_url_from_discussion(discussion_entity $discussion) {
|
||||
$viewurl = $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
|
||||
$viewurl->set_anchor('unread');
|
||||
|
||||
return $viewurl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view the latest post in a discussion.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param int|null $latestpost The id of the latest post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_view_latest_post_url_from_discussion(discussion_entity $discussion, ?int $latestpost) {
|
||||
$viewurl = $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
|
||||
if (null === $latestpost) {
|
||||
return $viewurl;
|
||||
} else {
|
||||
return new moodle_url($viewurl, ['parent' => $latestpost]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view a discussion from a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_discussion_view_url_from_post(post_entity $post) : moodle_url {
|
||||
return $this->get_discussion_view_url_from_discussion_id($post->get_discussion_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view a discussion from a discussion id and post id.
|
||||
*
|
||||
* @param int $discussionid The discussion id
|
||||
* @param int $postid The post id
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_view_post_url_from_post_id(int $discussionid, int $postid) : moodle_url {
|
||||
$url = $this->get_discussion_view_url_from_discussion_id($discussionid);
|
||||
$url->set_anchor('p' . $postid);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view a post in the context of the rest of the discussion.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_view_post_url_from_post(post_entity $post) : moodle_url {
|
||||
return $this->get_view_post_url_from_post_id($post->get_discussion_id(), $post->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view a post and it's replies in isolation without the rest of the
|
||||
* discussion.
|
||||
*
|
||||
* @param int $discussionid The discussion id
|
||||
* @param int $postid The post id
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_view_isolated_post_url_from_post_id(int $discussionid, int $postid) : moodle_url {
|
||||
$url = $this->get_discussion_view_url_from_discussion_id($discussionid);
|
||||
$url->params(['parent' => $postid]);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view a post and it's replies in isolation without the rest of the
|
||||
* discussion.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_view_isolated_post_url_from_post(post_entity $post) : moodle_url {
|
||||
return $this->get_view_isolated_post_url_from_post_id($post->get_discussion_id(), $post->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to edit a post.
|
||||
*
|
||||
* @param forum_entity $forum The forum the post belongs to
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_edit_post_url_from_post(forum_entity $forum, post_entity $post) : moodle_url {
|
||||
if ($forum->get_type() == 'single') {
|
||||
return new moodle_url('/course/modedit.php', [
|
||||
'update' => $forum->get_course_module_record()->id,
|
||||
'sesskey' => sesskey(),
|
||||
'return' => 1
|
||||
]);
|
||||
} else {
|
||||
return new moodle_url('/mod/forum/post.php', [
|
||||
'edit' => $post->get_id()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to split a discussion at a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_split_discussion_at_post_url_from_post(post_entity $post) : moodle_url {
|
||||
return new moodle_url('/mod/forum/post.php', [
|
||||
'prune' => $post->get_id()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to delete a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_delete_post_url_from_post(post_entity $post) : moodle_url {
|
||||
return new moodle_url('/mod/forum/post.php', [
|
||||
'delete' => $post->get_id()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to reply to a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_reply_to_post_url_from_post(post_entity $post) : moodle_url {
|
||||
return new moodle_url('/mod/forum/post.php#mformforum', [
|
||||
'reply' => $post->get_id()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to export (see portfolios) a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_export_post_url_from_post(post_entity $post) : ?moodle_url {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->libdir . '/portfoliolib.php');
|
||||
$button = new \portfolio_add_button();
|
||||
$button->set_callback_options('forum_portfolio_caller', ['postid' => $post->get_id()], 'mod_forum');
|
||||
if ($post->has_attachments()) {
|
||||
$button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
|
||||
} else {
|
||||
$button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
|
||||
}
|
||||
|
||||
$url = $button->to_html(PORTFOLIO_ADD_MOODLE_URL);
|
||||
return $url ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to mark a post as read.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @param int $displaymode The display mode to show the forum in after marking as read
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_mark_post_as_read_url_from_post(post_entity $post, int $displaymode = FORUM_MODE_THREADED) : moodle_url {
|
||||
$params = [
|
||||
'd' => $post->get_discussion_id(),
|
||||
'postid' => $post->get_id(),
|
||||
'mark' => 'read'
|
||||
];
|
||||
|
||||
$url = new moodle_url('/mod/forum/discuss.php', $params);
|
||||
|
||||
if ($displaymode == FORUM_MODE_THREADED) {
|
||||
$url->param('parent', $post->get_parent_id());
|
||||
} else {
|
||||
$url->set_anchor('p' . $post->get_id());
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to mark a post as unread.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @param int $displaymode The display mode to show the forum in after marking as unread
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_mark_post_as_unread_url_from_post(post_entity $post, int $displaymode = FORUM_MODE_THREADED) : moodle_url {
|
||||
$params = [
|
||||
'd' => $post->get_discussion_id(),
|
||||
'postid' => $post->get_id(),
|
||||
'mark' => 'unread'
|
||||
];
|
||||
|
||||
$url = new moodle_url('/mod/forum/discuss.php', $params);
|
||||
|
||||
if ($displaymode == FORUM_MODE_THREADED) {
|
||||
$url->param('parent', $post->get_parent_id());
|
||||
} else {
|
||||
$url->set_anchor('p' . $post->get_id());
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to export attachments for a post.
|
||||
*
|
||||
* @param post_entity $post The post
|
||||
* @param stored_file $attachment
|
||||
* @return moodle_url|null
|
||||
*/
|
||||
public function get_export_attachment_url_from_post_and_attachment(post_entity $post, stored_file $attachment) : ?moodle_url {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->libdir . '/portfoliolib.php');
|
||||
$button = new \portfolio_add_button();
|
||||
$button->set_callback_options(
|
||||
'forum_portfolio_caller',
|
||||
['postid' => $post->get_id(), 'attachment' => $attachment->get_id()],
|
||||
'mod_forum'
|
||||
);
|
||||
$button->set_format_by_file($attachment);
|
||||
$url = $button->to_html(PORTFOLIO_ADD_MOODLE_URL);
|
||||
return $url ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view an author's profile.
|
||||
*
|
||||
* @param author_entity $author The author
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_author_profile_url(author_entity $author) : moodle_url {
|
||||
return new moodle_url('/user/view.php', [
|
||||
'id' => $author->get_id()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to view the author's profile image.
|
||||
*
|
||||
* @param author_entity $author The author
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_author_profile_image_url(author_entity $author) : moodle_url {
|
||||
global $PAGE;
|
||||
|
||||
$datamapper = $this->legacydatamapperfactory->get_author_data_mapper();
|
||||
$record = $datamapper->to_legacy_object($author);
|
||||
$userpicture = new user_picture($record);
|
||||
$userpicture->size = 2;
|
||||
|
||||
return $userpicture->get_url($PAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to mark a discussion as read.
|
||||
*
|
||||
* @param forum_entity $forum The forum that the discussion belongs to
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_mark_discussion_as_read_url_from_discussion(
|
||||
forum_entity $forum,
|
||||
discussion_entity $discussion
|
||||
) : moodle_url {
|
||||
return new moodle_url('/mod/forum/markposts.php', [
|
||||
'f' => $discussion->get_forum_id(),
|
||||
'd' => $discussion->get_id(),
|
||||
'mark' => 'read',
|
||||
'sesskey' => sesskey(),
|
||||
'return' => $this->get_forum_view_url_from_forum($forum)->out(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to mark all discussions as read.
|
||||
*
|
||||
* @param forum_entity $forum The forum that the discussions belong to
|
||||
* @return moodle_url
|
||||
*/
|
||||
public function get_mark_all_discussions_as_read_url(forum_entity $forum) : moodle_url {
|
||||
return new moodle_url('/mod/forum/markposts.php', [
|
||||
'f' => $forum->get_id(),
|
||||
'mark' => 'read',
|
||||
'sesskey' => sesskey(),
|
||||
'return' => $this->get_forum_view_url_from_forum($forum)->out(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Vault factory.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\factories;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\factories\entity as entity_factory;
|
||||
use mod_forum\local\vaults\author as author_vault;
|
||||
use mod_forum\local\vaults\discussion as discussion_vault;
|
||||
use mod_forum\local\vaults\discussion_list as discussion_list_vault;
|
||||
use mod_forum\local\vaults\forum as forum_vault;
|
||||
use mod_forum\local\vaults\post as post_vault;
|
||||
use mod_forum\local\vaults\post_attachment as post_attachment_vault;
|
||||
use mod_forum\local\vaults\post_read_receipt_collection as post_read_receipt_collection_vault;
|
||||
use file_storage;
|
||||
use moodle_database;
|
||||
|
||||
/**
|
||||
* Vault factory.
|
||||
*
|
||||
* See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class vault {
|
||||
/** @var entity_factory $entityfactory Entity factory */
|
||||
private $entityfactory;
|
||||
/** @var moodle_database $db A moodle database */
|
||||
private $db;
|
||||
/** @var file_storage $filestorage A file storage instance */
|
||||
private $filestorage;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moodle_database $db A moodle database
|
||||
* @param entity_factory $entityfactory Entity factory
|
||||
* @param file_storage $filestorage A file storage instance
|
||||
*/
|
||||
public function __construct(moodle_database $db, entity_factory $entityfactory, file_storage $filestorage) {
|
||||
$this->db = $db;
|
||||
$this->entityfactory = $entityfactory;
|
||||
$this->filestorage = $filestorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a forum vault.
|
||||
*
|
||||
* @return forum_vault
|
||||
*/
|
||||
public function get_forum_vault() : forum_vault {
|
||||
return new forum_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion vault.
|
||||
*
|
||||
* @return discussion_vault
|
||||
*/
|
||||
public function get_discussion_vault() : discussion_vault {
|
||||
return new discussion_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discussion list vault.
|
||||
*
|
||||
* @return discussion_list_vault
|
||||
*/
|
||||
public function get_discussions_in_forum_vault() : discussion_list_vault {
|
||||
return new discussion_list_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post vault.
|
||||
*
|
||||
* @return post_vault
|
||||
*/
|
||||
public function get_post_vault() : post_vault {
|
||||
return new post_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an author vault.
|
||||
*
|
||||
* @return author_vault
|
||||
*/
|
||||
public function get_author_vault() : author_vault {
|
||||
return new author_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post read receipt collection vault.
|
||||
*
|
||||
* @return post_read_receipt_collection_vault
|
||||
*/
|
||||
public function get_post_read_receipt_collection_vault() : post_read_receipt_collection_vault {
|
||||
return new post_read_receipt_collection_vault(
|
||||
$this->db,
|
||||
$this->entityfactory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post attachment vault.
|
||||
*
|
||||
* @return post_attachment_vault
|
||||
*/
|
||||
public function get_post_attachment_vault() : post_attachment_vault {
|
||||
return new post_attachment_vault(
|
||||
$this->filestorage
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Capability manager for the forum.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\managers;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\data_mappers\legacy\forum as legacy_forum_data_mapper;
|
||||
use mod_forum\local\data_mappers\legacy\discussion as legacy_discussion_data_mapper;
|
||||
use mod_forum\local\data_mappers\legacy\post as legacy_post_data_mapper;
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\subscriptions;
|
||||
use context;
|
||||
use context_system;
|
||||
use stdClass;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* Capability manager for the forum.
|
||||
*
|
||||
* Defines all the business rules for what a user can and can't do in the forum.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class capability {
|
||||
/** @var legacy_forum_data_mapper $forumdatamapper Legacy forum data mapper */
|
||||
private $forumdatamapper;
|
||||
/** @var legacy_discussion_data_mapper $discussiondatamapper Legacy discussion data mapper */
|
||||
private $discussiondatamapper;
|
||||
/** @var legacy_post_data_mapper $postdatamapper Legacy post data mapper */
|
||||
private $postdatamapper;
|
||||
/** @var forum_entity $forum Forum entity */
|
||||
private $forum;
|
||||
/** @var stdClass $forumrecord Legacy forum record */
|
||||
private $forumrecord;
|
||||
/** @var context $context Module context for the forum */
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param forum_entity $forum The forum entity to manage capabilities for.
|
||||
* @param legacy_forum_data_mapper $forumdatamapper Legacy forum data mapper
|
||||
* @param legacy_discussion_data_mapper $discussiondatamapper Legacy discussion data mapper
|
||||
* @param legacy_post_data_mapper $postdatamapper Legacy post data mapper
|
||||
*/
|
||||
public function __construct(
|
||||
forum_entity $forum,
|
||||
legacy_forum_data_mapper $forumdatamapper,
|
||||
legacy_discussion_data_mapper $discussiondatamapper,
|
||||
legacy_post_data_mapper $postdatamapper
|
||||
) {
|
||||
$this->forumdatamapper = $forumdatamapper;
|
||||
$this->discussiondatamapper = $discussiondatamapper;
|
||||
$this->postdatamapper = $postdatamapper;
|
||||
$this->forum = $forum;
|
||||
$this->forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
$this->context = $forum->get_context();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user subscribe to this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_subscribe_to_forum(stdClass $user) : bool {
|
||||
return !is_guest($this->get_context(), $user) &&
|
||||
subscriptions::is_subscribable($this->get_forum_record());
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user create discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param int|null $groupid The current activity group id
|
||||
* @return bool
|
||||
*/
|
||||
public function can_create_discussions(stdClass $user, int $groupid = null) : bool {
|
||||
if (isguestuser($user) or !isloggedin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($this->forum->get_type()) {
|
||||
case 'news':
|
||||
$capability = 'mod/forum:addnews';
|
||||
break;
|
||||
case 'qanda':
|
||||
$capability = 'mod/forum:addquestion';
|
||||
break;
|
||||
default:
|
||||
$capability = 'mod/forum:startdiscussion';
|
||||
}
|
||||
|
||||
if (!has_capability($capability, $this->forum->get_context(), $user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->forum->is_in_group_mode()) {
|
||||
return $groupid ? $this->can_access_group($user, $groupid) : $this->can_access_all_groups($user);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user access all groups?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_access_all_groups(stdClass $user) {
|
||||
return has_capability('moodle/site:accessallgroups', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user access the given group?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param int $groupid The id of the group that the forum is set to
|
||||
* @return bool
|
||||
*/
|
||||
public function can_access_group(stdClass $user, int $groupid) {
|
||||
if ($this->can_access_all_groups($user)) {
|
||||
// This user has access to all groups.
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a group discussion for a forum in separate groups mode.
|
||||
// Check if the user is a member.
|
||||
// This is the most expensive check.
|
||||
return groups_is_member($groupid, $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_discussions(stdClass $user) : bool {
|
||||
return has_capability('mod/forum:viewdiscussion', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user move discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_move_discussions(stdClass $user) : bool {
|
||||
$forum = $this->get_forum();
|
||||
return $forum->get_type() !== 'single' && has_capability('mod/forum:movediscussions', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user pin discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_pin_discussions(stdClass $user) : bool {
|
||||
return has_capability('mod/forum:pindiscussions', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user split discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_split_discussions(stdClass $user) : bool {
|
||||
$forum = $this->get_forum();
|
||||
return $forum->get_type() !== 'single' && has_capability('mod/forum:splitdiscussions', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user export (see portfolios) discussions in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_export_discussions(stdClass $user) : bool {
|
||||
global $CFG;
|
||||
return $CFG->enableportfolios && has_capability('mod/forum:exportdiscussion', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user manually mark posts as read/unread in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_manually_control_post_read_status(stdClass $user) : bool {
|
||||
global $CFG;
|
||||
return $CFG->forum_usermarksread && isloggedin() && forum_tp_is_tracked($this->get_forum_record(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the user required to post in the discussion before they can view it?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function must_post_before_viewing_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
$forum = $this->get_forum();
|
||||
|
||||
if ($forum->get_type() === 'qanda') {
|
||||
// If it's a Q and A forum then the user must either have the capability to view without
|
||||
// posting or the user must have posted before they can view the discussion.
|
||||
return !has_capability('mod/forum:viewqandawithoutposting', $this->get_context(), $user) &&
|
||||
!forum_user_has_posted($forum->get_id(), $discussion->get_id(), $user->id);
|
||||
} else {
|
||||
// No other forum types require posting before viewing.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user subscribe to the give discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_subscribe_to_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
return $this->can_subscribe_to_forum($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user move the discussion in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_move_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
return $this->can_move_discussions($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the user pin the discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_pin_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
return $this->can_pin_discussions($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_post_in_discussion(stdClass $user, discussion_entity $discussion) : bool {
|
||||
$forum = $this->get_forum();
|
||||
$forumrecord = $this->get_forum_record();
|
||||
$discussionrecord = $this->get_discussion_record($discussion);
|
||||
$context = $this->get_context();
|
||||
$coursemodule = $forum->get_course_module_record();
|
||||
$course = $forum->get_course_record();
|
||||
|
||||
return forum_user_can_post($forumrecord, $discussionrecord, $user, $coursemodule, $course, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @param post_entity $post The post the user wants to view
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
$forum = $this->get_forum();
|
||||
$forumrecord = $this->get_forum_record();
|
||||
$discussionrecord = $this->get_discussion_record($discussion);
|
||||
$postrecord = $this->get_post_record($post);
|
||||
$coursemodule = $forum->get_course_module_record();
|
||||
return forum_user_can_see_post($forumrecord, $discussionrecord, $postrecord, $user, $coursemodule, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user edit the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @param post_entity $post The post the user wants to edit
|
||||
* @return bool
|
||||
*/
|
||||
public function can_edit_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
global $CFG;
|
||||
|
||||
$context = $this->get_context();
|
||||
$ownpost = $post->is_owned_by_user($user);
|
||||
$ineditingtime = $post->get_age() < $CFG->maxeditingtime;
|
||||
|
||||
switch ($this->forum->get_type()) {
|
||||
case 'news':
|
||||
// Allow editing of news posts once the discussion has started.
|
||||
$ineditingtime = !$post->has_parent() && $discussion->has_started();
|
||||
break;
|
||||
case 'single':
|
||||
return $discussion->is_first_post($post) && has_capability('moodle/course:manageactivities', $context, $user);
|
||||
}
|
||||
|
||||
return ($ownpost && $ineditingtime) || has_capability('mod/forum:editanypost', $context, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user delete the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @param post_entity $post The post the user wants to delete
|
||||
* @return bool
|
||||
*/
|
||||
public function can_delete_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
global $CFG;
|
||||
|
||||
$forum = $this->get_forum();
|
||||
|
||||
if ($forum->get_type() == 'single' && $discussion->is_first_post($post)) {
|
||||
// Do not allow deleting of first post in single simple type.
|
||||
return false;
|
||||
} else {
|
||||
$context = $this->get_context();
|
||||
$ownpost = $post->is_owned_by_user($user);
|
||||
$ineditingtime = $post->get_age() < $CFG->maxeditingtime;
|
||||
|
||||
return ($ownpost && $ineditingtime && has_capability('mod/forum:deleteownpost', $context, $user)) ||
|
||||
has_capability('mod/forum:deleteanypost', $context, $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user split the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @param post_entity $post The post the user wants to split
|
||||
* @return bool
|
||||
*/
|
||||
public function can_split_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->can_split_discussions($user) && $post->has_parent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user reply to the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @param post_entity $post The post the user wants to reply to
|
||||
* @return bool
|
||||
*/
|
||||
public function can_reply_to_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->can_post_in_discussion($user, $discussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user export (see portfolios) the post in this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param post_entity $post The post the user wants to export
|
||||
* @return bool
|
||||
*/
|
||||
public function can_export_post(stdClass $user, post_entity $post) : bool {
|
||||
global $CFG;
|
||||
$context = $this->get_context();
|
||||
return $CFG->enableportfolios && (has_capability('mod/forum:exportpost', $context, $user) ||
|
||||
($post->is_owned_by_user($user) && has_capability('mod/forum:exportownpost', $context, $user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum entity for this capability manager.
|
||||
*
|
||||
* @return forum_entity
|
||||
*/
|
||||
protected function get_forum() : forum_entity {
|
||||
return $this->forum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy forum record for this forum.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_forum_record() : stdClass {
|
||||
return $this->forumrecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context for this capability manager.
|
||||
*
|
||||
* @return context
|
||||
*/
|
||||
protected function get_context() : context {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy discussion record for the given discussion entity.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion to convert
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_discussion_record(discussion_entity $discussion) : stdClass {
|
||||
return $this->discussiondatamapper->to_legacy_object($discussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy post record for the given post entity.
|
||||
*
|
||||
* @param post_entity $post The post to convert
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_post_record(post_entity $post) : stdClass {
|
||||
return $this->postdatamapper->to_legacy_object($post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view the participants of this discussion?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @param discussion_entity $discussion The discussion to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_participants(stdClass $user, discussion_entity $discussion) : bool {
|
||||
return course_can_view_participants($this->get_context()) &&
|
||||
!$this->must_post_before_viewing_discussion($user, $discussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user view hidden posts in this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_hidden_posts(stdClass $user) : bool {
|
||||
return has_capability('mod/forum:viewhiddentimedposts', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user manage this forum?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_manage_forum(stdClass $user) {
|
||||
return has_capability('moodle/course:manageactivities', $this->get_context(), $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user manage tags on the site?
|
||||
*
|
||||
* @param stdClass $user The user to check
|
||||
* @return bool
|
||||
*/
|
||||
public function can_manage_tags(stdClass $user) : bool {
|
||||
return has_capability('moodle/tag:manage', context_system::instance(), $user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion renderer.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\renderers;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\entities\sorter as sorter_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 mod_forum\local\managers\capability as capability_manager;
|
||||
use mod_forum\local\renderers\posts as posts_renderer;
|
||||
use core\output\notification;
|
||||
use context;
|
||||
use context_module;
|
||||
use html_writer;
|
||||
use moodle_exception;
|
||||
use moodle_page;
|
||||
use moodle_url;
|
||||
use rating_manager;
|
||||
use renderer_base;
|
||||
use single_button;
|
||||
use single_select;
|
||||
use stdClass;
|
||||
use url_select;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* Discussion renderer class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion {
|
||||
/** @var discussion_entity $discussion The discussion to render */
|
||||
private $discussion;
|
||||
/** @var stdClass $discussionrecord Legacy discussion record */
|
||||
private $discussionrecord;
|
||||
/** @var forum_entity $forum The forum that the discussion belongs to */
|
||||
private $forum;
|
||||
/** @var stdClass $forumrecord Legacy forum record */
|
||||
private $forumrecord;
|
||||
/** @var int $displaymode The display mode to render the discussion in */
|
||||
private $displaymode;
|
||||
/** @var renderer_base $renderer Renderer base */
|
||||
private $renderer;
|
||||
/** @var posts_renderer $postsrenderer A posts renderer */
|
||||
private $postsrenderer;
|
||||
/** @var moodle_page $page The page this discussion is being rendered for */
|
||||
private $page;
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
/** @var exporter_factory $exporterfactory Exporter factory */
|
||||
private $exporterfactory;
|
||||
/** @var vault_factory $vaultfactory Vault factory */
|
||||
private $vaultfactory;
|
||||
/** @var capability_manager $capabilitymanager Capability manager */
|
||||
private $capabilitymanager;
|
||||
/** @var rating_manager $ratingmanager Rating manager */
|
||||
private $ratingmanager;
|
||||
/** @var moodle_url $baseurl The base URL for the discussion */
|
||||
private $baseurl;
|
||||
/** @var array $notifications List of HTML notifications to display */
|
||||
private $notifications;
|
||||
/** @var sorter_entity $exportedpostsorter Sorter for the exported posts */
|
||||
private $exportedpostsorter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param discussion_entity $discussion The discussion to render
|
||||
* @param forum_entity $forum The forum that the discussion belongs to
|
||||
* @param int $displaymode The display mode to render the discussion in
|
||||
* @param renderer_base $renderer Renderer base
|
||||
* @param posts_renderer $postsrenderer A posts renderer
|
||||
* @param moodle_page $page The page this discussion is being rendered for
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
||||
* @param exporter_factory $exporterfactory Exporter factory
|
||||
* @param vault_factory $vaultfactory Vault factory
|
||||
* @param capability_manager $capabilitymanager Capability manager
|
||||
* @param rating_manager $ratingmanager Rating manager
|
||||
* @param sorter_entity $exportedpostsorter Sorter for the exported posts
|
||||
* @param moodle_url $baseurl The base URL for the discussion
|
||||
* @param array $notifications List of HTML notifications to display
|
||||
*/
|
||||
public function __construct(
|
||||
discussion_entity $discussion,
|
||||
forum_entity $forum,
|
||||
int $displaymode,
|
||||
renderer_base $renderer,
|
||||
posts_renderer $postsrenderer,
|
||||
moodle_page $page,
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
capability_manager $capabilitymanager,
|
||||
rating_manager $ratingmanager,
|
||||
sorter_entity $exportedpostsorter,
|
||||
moodle_url $baseurl,
|
||||
array $notifications = []
|
||||
) {
|
||||
$this->discussion = $discussion;
|
||||
$this->forum = $forum;
|
||||
$this->displaymode = $displaymode;
|
||||
$this->renderer = $renderer;
|
||||
$this->postsrenderer = $postsrenderer;
|
||||
$this->page = $page;
|
||||
$this->baseurl = $baseurl;
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->capabilitymanager = $capabilitymanager;
|
||||
$this->ratingmanager = $ratingmanager;
|
||||
$this->notifications = $notifications;
|
||||
$this->exportedpostsorter = $exportedpostsorter;
|
||||
|
||||
$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
|
||||
$this->forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
|
||||
$discussiondatamapper = $this->legacydatamapperfactory->get_discussion_data_mapper();
|
||||
$this->discussionrecord = $discussiondatamapper->to_legacy_object($discussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the discussion for the given user in the specified display mode.
|
||||
*
|
||||
* @param stdClass $user The user viewing the discussion
|
||||
* @param post_entity $firstpost The first post in the discussion
|
||||
* @param array $replies List of replies to the first post
|
||||
* @return string HTML for the discussion
|
||||
*/
|
||||
public function render(
|
||||
stdClass $user,
|
||||
post_entity $firstpost,
|
||||
array $replies
|
||||
) : string {
|
||||
global $CFG;
|
||||
|
||||
$displaymode = $this->displaymode;
|
||||
$capabilitymanager = $this->capabilitymanager;
|
||||
$forum = $this->forum;
|
||||
|
||||
// Make sure we can render.
|
||||
if (!$capabilitymanager->can_view_discussions($user)) {
|
||||
throw new moodle_exception('noviewdiscussionspermission', 'mod_forum');
|
||||
}
|
||||
|
||||
$posts = array_merge([$firstpost], array_values($replies));
|
||||
|
||||
$exporteddiscussion = $this->get_exported_discussion($user);
|
||||
$exporteddiscussion = array_merge($exporteddiscussion, [
|
||||
'notifications' => $this->get_notifications(),
|
||||
'html' => [
|
||||
'posts' => $this->postsrenderer->render($user, [$this->forum], [$this->discussion], $posts),
|
||||
'modeselectorform' => $this->get_display_mode_selector_html($displaymode),
|
||||
'subscribe' => null,
|
||||
'movediscussion' => null,
|
||||
'pindiscussion' => null,
|
||||
'neighbourlinks' => $this->get_neighbour_links_html(),
|
||||
'exportdiscussion' => !empty($CFG->enableportfolios) ? $this->get_export_discussion_html() : null
|
||||
]
|
||||
]);
|
||||
|
||||
$capabilities = (array) $exporteddiscussion['capabilities'];
|
||||
|
||||
if ($capabilities['subscribe']) {
|
||||
$exporteddiscussion['html']['subscribe'] = $this->get_subscription_button_html();
|
||||
}
|
||||
|
||||
if ($capabilities['move']) {
|
||||
$exporteddiscussion['html']['movediscussion'] = $this->get_move_discussion_html();
|
||||
}
|
||||
|
||||
if ($capabilities['pin']) {
|
||||
$exporteddiscussion['html']['pindiscussion'] = $this->get_pin_discussion_html();
|
||||
}
|
||||
|
||||
return $this->renderer->render_from_template('mod_forum/forum_discussion', $exporteddiscussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the groups details for all groups available to the forum.
|
||||
*
|
||||
* @return stdClass[]
|
||||
*/
|
||||
private function get_groups_available_in_forum() : array {
|
||||
$course = $this->forum->get_course_record();
|
||||
$coursemodule = $this->forum->get_course_module_record();
|
||||
|
||||
return groups_get_all_groups($course->id, 0, $coursemodule->groupingid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exported discussion.
|
||||
*
|
||||
* @param stdClass $user The user viewing the discussion
|
||||
* @return array
|
||||
*/
|
||||
private function get_exported_discussion(stdClass $user) : array {
|
||||
$discussionexporter = $this->exporterfactory->get_discussion_exporter(
|
||||
$user,
|
||||
$this->forum,
|
||||
$this->discussion,
|
||||
$this->get_groups_available_in_forum()
|
||||
);
|
||||
|
||||
return (array) $discussionexporter->export($this->renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML for the display mode selector.
|
||||
*
|
||||
* @param int $displaymode The current display mode
|
||||
* @return string
|
||||
*/
|
||||
private function get_display_mode_selector_html(int $displaymode) : string {
|
||||
$baseurl = $this->baseurl;
|
||||
$select = new single_select(
|
||||
$baseurl,
|
||||
'mode',
|
||||
forum_get_layout_modes(),
|
||||
$displaymode,
|
||||
null,
|
||||
'mode'
|
||||
);
|
||||
$select->set_label(get_string('displaymode', 'forum'), ['class' => 'accesshide']);
|
||||
|
||||
return $this->renderer->render($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to render the subscription button.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_subscription_button_html() : string {
|
||||
global $PAGE;
|
||||
|
||||
$forumrecord = $this->forumrecord;
|
||||
$discussion = $this->discussion;
|
||||
$html = html_writer::div(
|
||||
forum_get_discussion_subscription_icon($forumrecord, $discussion->get_id(), null, true),
|
||||
'discussionsubscription'
|
||||
);
|
||||
$html .= forum_get_discussion_subscription_icon_preloaders();
|
||||
// Add the subscription toggle JS.
|
||||
$PAGE->requires->yui_module('moodle-mod_forum-subscriptiontoggle', 'Y.M.mod_forum.subscriptiontoggle.init');
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to render the move discussion selector and button.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_move_discussion_html() : string {
|
||||
global $DB;
|
||||
|
||||
$forum = $this->forum;
|
||||
$discussion = $this->discussion;
|
||||
$courseid = $forum->get_course_id();
|
||||
|
||||
// Popup menu to move discussions to other forums. The discussion in a
|
||||
// single discussion forum can't be moved.
|
||||
$modinfo = get_fast_modinfo($courseid);
|
||||
if (isset($modinfo->instances['forum'])) {
|
||||
$forummenu = [];
|
||||
// Check forum types and eliminate simple discussions.
|
||||
$forumcheck = $DB->get_records('forum', ['course' => $courseid], '', 'id, type');
|
||||
foreach ($modinfo->instances['forum'] as $forumcm) {
|
||||
if (!$forumcm->uservisible || !has_capability('mod/forum:startdiscussion',
|
||||
context_module::instance($forumcm->id))) {
|
||||
continue;
|
||||
}
|
||||
$section = $forumcm->sectionnum;
|
||||
$sectionname = get_section_name($courseid, $section);
|
||||
if (empty($forummenu[$section])) {
|
||||
$forummenu[$section] = [$sectionname => []];
|
||||
}
|
||||
$forumidcompare = $forumcm->instance != $forum->get_id();
|
||||
$forumtypecheck = $forumcheck[$forumcm->instance]->type !== 'single';
|
||||
|
||||
if ($forumidcompare and $forumtypecheck) {
|
||||
$url = "/mod/forum/discuss.php?d={$discussion->get_id()}&move=$forumcm->instance&sesskey=".sesskey();
|
||||
$forummenu[$section][$sectionname][$url] = format_string($forumcm->name);
|
||||
}
|
||||
}
|
||||
if (!empty($forummenu)) {
|
||||
$html = '<div class="movediscussionoption">';
|
||||
$select = new url_select($forummenu, '',
|
||||
['/mod/forum/discuss.php?d=' . $discussion->get_id() => get_string("movethisdiscussionto", "forum")],
|
||||
'forummenu', get_string('move'));
|
||||
$html .= $this->renderer->render($select);
|
||||
$html .= "</div>";
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to render the pin discussion button.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_pin_discussion_html() : string {
|
||||
$discussion = $this->discussion;
|
||||
|
||||
if ($discussion->is_pinned()) {
|
||||
$pinlink = FORUM_DISCUSSION_UNPINNED;
|
||||
$pintext = get_string('discussionunpin', 'forum');
|
||||
} else {
|
||||
$pinlink = FORUM_DISCUSSION_PINNED;
|
||||
$pintext = get_string('discussionpin', 'forum');
|
||||
}
|
||||
|
||||
$button = new single_button(
|
||||
new moodle_url('discuss.php', ['pin' => $pinlink, 'd' => $discussion->get_id()]),
|
||||
$pintext,
|
||||
'post'
|
||||
);
|
||||
return $this->renderer->render($button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to render the export discussion button.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_export_discussion_html() : ?string {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->libdir . '/portfoliolib.php');
|
||||
$discussion = $this->discussion;
|
||||
$button = new \portfolio_add_button();
|
||||
$button->set_callback_options('forum_portfolio_caller', ['discussionid' => $discussion->get_id()], 'mod_forum');
|
||||
$button = $button->to_html(PORTFOLIO_ADD_FULL_FORM, get_string('exportdiscussion', 'mod_forum'));
|
||||
return $button ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of notification HTML to render in the page.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_notifications() : array {
|
||||
$notifications = $this->notifications;
|
||||
$discussion = $this->discussion;
|
||||
$forum = $this->forum;
|
||||
$renderer = $this->renderer;
|
||||
|
||||
if ($forum->is_discussion_locked($discussion)) {
|
||||
$notifications[] = (new notification(
|
||||
get_string('discussionlocked', 'forum'),
|
||||
notification::NOTIFY_INFO
|
||||
))
|
||||
->set_extra_classes(['discussionlocked'])
|
||||
->set_show_closebutton();
|
||||
}
|
||||
|
||||
if ($forum->has_blocking_enabled()) {
|
||||
$notifications[] = (new notification(
|
||||
get_string('thisforumisthrottled', 'forum', [
|
||||
'blockafter' => $forum->get_block_after(),
|
||||
'blockperiod' => get_string('secondstotime' . $forum->get_block_period())
|
||||
])
|
||||
))->set_show_closebutton();
|
||||
}
|
||||
|
||||
return array_map(function($notification) {
|
||||
return $notification->export_for_template($this->renderer);
|
||||
}, $notifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML to display the neighbour links.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_neighbour_links_html() : string {
|
||||
$forum = $this->forum;
|
||||
$coursemodule = $forum->get_course_module_record();
|
||||
$neighbours = forum_get_discussion_neighbours($coursemodule, $this->discussionrecord, $this->forumrecord);
|
||||
return $this->renderer->neighbouring_discussion_navigation($neighbours['prev'], $neighbours['next']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion list renderer.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\renderers;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_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 mod_forum\local\factories\url as url_factory;
|
||||
use mod_forum\local\managers\capability as capability_manager;
|
||||
use mod_forum\local\vaults\discussion_list as discussion_list_vault;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use core\output\notification;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
/**
|
||||
* The discussion list renderer.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion_list {
|
||||
/** @var forum_entity The forum being rendered */
|
||||
private $forum;
|
||||
|
||||
/** @var stdClass The DB record for the forum being rendered */
|
||||
private $forumrecord;
|
||||
|
||||
/** @var renderer_base The renderer used to render the view */
|
||||
private $renderer;
|
||||
|
||||
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
|
||||
private $legacydatamapperfactory;
|
||||
|
||||
/** @var exporter_factory $exporterfactory Exporter factory */
|
||||
private $exporterfactory;
|
||||
|
||||
/** @var vault_factory $vaultfactory Vault factory */
|
||||
private $vaultfactory;
|
||||
|
||||
/** @var capability_manager $capabilitymanager Capability manager */
|
||||
private $capabilitymanager;
|
||||
|
||||
/** @var url_factory $urlfactory URL factory */
|
||||
private $urlfactory;
|
||||
|
||||
/** @var array $notifications List of notification HTML */
|
||||
private $notifications;
|
||||
|
||||
/**
|
||||
* Constructor for a new discussion list renderer.
|
||||
*
|
||||
* @param forum_entity $forum The forum entity to be rendered
|
||||
* @param renderer_base $renderer The renderer used to render the view
|
||||
* @param legacy_data_mapper_factory $legacydatamapperfactory The factory used to fetch a legacy record
|
||||
* @param exporter_factory $exporterfactory The factory used to fetch exporter instances
|
||||
* @param vault_factory $vaultfactory The factory used to fetch the vault instances
|
||||
* @param capability_manager $capabilitymanager The managed used to check capabilities on the forum
|
||||
* @param url_factory $urlfactory The factory used to create URLs in the forum
|
||||
* @param notification[] $notifications A list of any notifications to be displayed within the page
|
||||
*/
|
||||
public function __construct(
|
||||
forum_entity $forum,
|
||||
renderer_base $renderer,
|
||||
legacy_data_mapper_factory $legacydatamapperfactory,
|
||||
exporter_factory $exporterfactory,
|
||||
vault_factory $vaultfactory,
|
||||
capability_manager $capabilitymanager,
|
||||
url_factory $urlfactory,
|
||||
array $notifications = []
|
||||
) {
|
||||
$this->forum = $forum;
|
||||
$this->renderer = $renderer;
|
||||
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
||||
$this->exporterfactory = $exporterfactory;
|
||||
$this->vaultfactory = $vaultfactory;
|
||||
$this->capabilitymanager = $capabilitymanager;
|
||||
$this->urlfactory = $urlfactory;
|
||||
$this->notifications = $notifications;
|
||||
|
||||
$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
|
||||
$this->forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render for the specified user.
|
||||
*
|
||||
* @param stdClass $user The user to render for
|
||||
* @param cm_info $cm The course module info for this discussion list
|
||||
* @param int $groupid The group to render
|
||||
* @param int $sortorder The sort order to use when selecting the discussions in the list
|
||||
* @param int $pageno The zero-indexed page number to use
|
||||
* @param int $pagesize The number of discussions to show on the page
|
||||
* @return string The rendered content for display
|
||||
*/
|
||||
public function render(stdClass $user, \cm_info $cm, ?int $groupid, ?int $sortorder, ?int $pageno, ?int $pagesize) : string {
|
||||
$capabilitymanager = $this->capabilitymanager;
|
||||
$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
|
||||
);
|
||||
|
||||
$forumview = array_merge(
|
||||
[
|
||||
'notifications' => $this->get_notifications($user, $groupid),
|
||||
'forum' => (array) $forumexporter->export($this->renderer),
|
||||
'groupchangemenu' => groups_print_activity_menu(
|
||||
$cm,
|
||||
$this->urlfactory->get_forum_view_url_from_forum($forum),
|
||||
true
|
||||
),
|
||||
],
|
||||
(array) $this->get_exported_discussions($user, $groupids, $sortorder, $pageno, $pagesize)
|
||||
);
|
||||
|
||||
return $this->renderer->render_from_template($this->get_template(), $forumview);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_exported_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) {
|
||||
$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));
|
||||
} else {
|
||||
$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));
|
||||
}
|
||||
|
||||
$discussionids = array_keys($discussions);
|
||||
|
||||
$discussioncount = count($discussionids);
|
||||
if ($discussioncount >= $pagesize) {
|
||||
if (null === $groupids) {
|
||||
$discussioncount = $discussionvault->get_total_discussion_count_from_forum_id(
|
||||
$forum->get_id(),
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
} else {
|
||||
$discussioncount = $discussionvault->get_total_discussion_count_from_forum_id_and_group_id(
|
||||
$forum->get_id(),
|
||||
$groupids,
|
||||
$this->capabilitymanager->can_view_hidden_posts($user),
|
||||
$user->id);
|
||||
}
|
||||
}
|
||||
|
||||
$pagedcontent = new \core\external\paged_content_exporter(
|
||||
$pagesize,
|
||||
$pageno,
|
||||
$discussioncount,
|
||||
function ($pageno, $pagelimit) : \moodle_url {
|
||||
return $this->urlfactory->get_forum_view_url_from_forum($this->forum, $pageno);
|
||||
}
|
||||
);
|
||||
|
||||
$postvault = $this->vaultfactory->get_post_vault();
|
||||
$posts = $postvault->get_from_discussion_ids($discussionids);
|
||||
$groupsbyid = $this->get_groups_available_in_forum();
|
||||
$groupsbyauthorid = $this->get_author_groups_from_posts($posts);
|
||||
|
||||
$replycounts = $postvault->get_reply_count_for_discussion_ids($discussionids);
|
||||
$latestposts = $postvault->get_latest_post_id_for_discussion_ids($discussionids);
|
||||
|
||||
$unreadcounts = [];
|
||||
if (forum_tp_can_track_forums($this->forumrecord)) {
|
||||
$unreadcounts = $postvault->get_unread_count_for_discussion_ids($user, $discussionids);
|
||||
}
|
||||
|
||||
$summaryexporter = $this->exporterfactory->get_discussion_summaries_exporter(
|
||||
$user,
|
||||
$forum,
|
||||
$discussions,
|
||||
$groupsbyid,
|
||||
$groupsbyauthorid,
|
||||
$replycounts,
|
||||
$unreadcounts,
|
||||
$latestposts
|
||||
);
|
||||
|
||||
return $summaryexporter->export($this->renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the page size to use when displaying the page.
|
||||
*
|
||||
* @param int $pagesize The number of discussions to show on the page
|
||||
* @return int The normalised page size
|
||||
*/
|
||||
private function get_page_size(?int $pagesize) : int {
|
||||
if (null === $pagesize || $pagesize <= 0) {
|
||||
$pagesize = discussion_list_vault::PAGESIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return $pagesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the current page number (zero-indexed).
|
||||
*
|
||||
* @param int $pageno The zero-indexed page number to use
|
||||
* @return int The normalised page number
|
||||
*/
|
||||
private function get_page_number(?int $pageno) : int {
|
||||
if (null === $pageno || $pageno < 0) {
|
||||
$pageno = 0;
|
||||
}
|
||||
|
||||
return $pageno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the name of the template to use for the current forum and view modes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_template() : string {
|
||||
switch ($this->forum->get_type()) {
|
||||
case 'news':
|
||||
return 'mod_forum/news_discussion_list';
|
||||
break;
|
||||
case 'blog':
|
||||
return 'mod_forum/blog_discussion_list';
|
||||
break;
|
||||
case 'qanda':
|
||||
return 'mod_forum/qanda_discussion_list';
|
||||
break;
|
||||
default:
|
||||
return 'mod_forum/discussion_list';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the groups details for all groups available to the forum.
|
||||
*
|
||||
* @return stdClass[]
|
||||
*/
|
||||
private function get_groups_available_in_forum() : array {
|
||||
$course = $this->forum->get_course_record();
|
||||
$coursemodule = $this->forum->get_course_module_record();
|
||||
|
||||
return groups_get_all_groups($course->id, 0, $coursemodule->groupingid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author's groups for a list of posts.
|
||||
*
|
||||
* @param post_entity[] $posts The list of posts
|
||||
* @return array Author groups indexed by author id
|
||||
*/
|
||||
private function get_author_groups_from_posts(array $posts) : array {
|
||||
$course = $this->forum->get_course_record();
|
||||
$coursemodule = $this->forum->get_course_module_record();
|
||||
$authorids = array_reduce($posts, function($carry, $post) {
|
||||
$carry[$post->get_author_id()] = true;
|
||||
return $carry;
|
||||
}, []);
|
||||
$authorgroups = groups_get_all_groups(
|
||||
$course->id,
|
||||
array_keys($authorids),
|
||||
$coursemodule->groupingid,
|
||||
'g.*, gm.id, gm.groupid, gm.userid'
|
||||
);
|
||||
|
||||
$authorgroups = array_reduce($authorgroups, function($carry, $group) {
|
||||
// Clean up data returned from groups_get_all_groups.
|
||||
$userid = $group->userid;
|
||||
$groupid = $group->groupid;
|
||||
|
||||
unset($group->userid);
|
||||
unset($group->groupid);
|
||||
$group->id = $groupid;
|
||||
|
||||
if (!isset($carry[$userid])) {
|
||||
$carry[$userid] = [$group];
|
||||
} else {
|
||||
$carry[$userid][] = $group;
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
foreach (array_diff(array_keys($authorids), array_keys($authorgroups)) as $authorid) {
|
||||
$authorgroups[$authorid] = [];
|
||||
}
|
||||
|
||||
return $authorgroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of notification for display.
|
||||
*
|
||||
* @param stdClass $user The viewing user
|
||||
* @param int|null $groupid The forum's group id
|
||||
* @return array
|
||||
*/
|
||||
private function get_notifications(stdClass $user, ?int $groupid) : array {
|
||||
$notifications = $this->notifications;
|
||||
$forum = $this->forum;
|
||||
$renderer = $this->renderer;
|
||||
$capabilitymanager = $this->capabilitymanager;
|
||||
|
||||
if ($forum->has_blocking_enabled()) {
|
||||
$notifications[] = (new notification(
|
||||
get_string('thisforumisthrottled', 'forum', [
|
||||
'blockafter' => $forum->get_block_after(),
|
||||
'blockperiod' => get_string('secondstotime' . $forum->get_block_period())
|
||||
])
|
||||
))->set_show_closebutton();
|
||||
}
|
||||
|
||||
if ($forum->is_in_group_mode()) {
|
||||
if (
|
||||
($groupid === null && !$capabilitymanager->can_access_all_groups($user)) ||
|
||||
($groupid !== null && !$capabilitymanager->can_access_group($user, $groupid))
|
||||
) {
|
||||
// Cannot post to the current group.
|
||||
$notifications[] = (new notification(
|
||||
get_string('cannotadddiscussion', 'mod_forum'),
|
||||
\core\output\notification::NOTIFY_WARNING
|
||||
))->set_show_closebutton();
|
||||
}
|
||||
}
|
||||
|
||||
if ('qanda' === $forum->get_type() && !$capabilitymanager->can_manage_forum($user)) {
|
||||
$notifications[] = (new notification(
|
||||
get_string('qandanotify', 'forum'),
|
||||
notification::NOTIFY_INFO
|
||||
))->set_show_closebutton();
|
||||
}
|
||||
|
||||
if ('eachuser' === $forum->get_type()) {
|
||||
$notifications[] = (new notification(
|
||||
get_string('allowsdiscussions', 'forum'),
|
||||
notification::NOTIFY_INFO)
|
||||
)->set_show_closebutton();
|
||||
}
|
||||
|
||||
return array_map(function($notification) {
|
||||
return $notification->export_for_template($this->renderer);
|
||||
}, $notifications);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Posts renderer.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\renderers;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\builders\exported_posts as exported_posts_builder;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Posts renderer class.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class posts {
|
||||
/** @var renderer_base $renderer Renderer base */
|
||||
private $renderer;
|
||||
/** @var exported_posts_builder $exportedpostsbuilder Builder for building exported posts */
|
||||
private $exportedpostsbuilder;
|
||||
/** @var string $template The template to render */
|
||||
private $template;
|
||||
/** @var callable $postprocessfortemplate Function to process exported posts before template rendering */
|
||||
private $postprocessfortemplate;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param renderer_base $renderer Renderer base
|
||||
* @param exported_posts_builder $exportedpostsbuilder Builder for building exported posts
|
||||
* @param string $template The template to render
|
||||
* @param callable $postprocessfortemplate Function to process exported posts before template rendering
|
||||
*/
|
||||
public function __construct(
|
||||
renderer_base $renderer,
|
||||
exported_posts_builder $exportedpostsbuilder,
|
||||
string $template,
|
||||
callable $postprocessfortemplate = null
|
||||
) {
|
||||
$this->renderer = $renderer;
|
||||
$this->exportedpostsbuilder = $exportedpostsbuilder;
|
||||
$this->template = $template;
|
||||
$this->postprocessfortemplate = $postprocessfortemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the given posts for the forums and discussions.
|
||||
*
|
||||
* @param stdClass $user The user viewing the posts
|
||||
* @param forum_entity[] $forums A list of all forums for these posts
|
||||
* @param discussion_entity[] $discussions A list of all discussions for these posts
|
||||
* @param post_entity[] $posts The posts to render
|
||||
* @return string
|
||||
*/
|
||||
public function render(
|
||||
stdClass $user,
|
||||
array $forums,
|
||||
array $discussions,
|
||||
array $posts
|
||||
) : string {
|
||||
// Format the forums and discussion to make them more easily accessed later.
|
||||
$forums = array_reduce($forums, function($carry, $forum) {
|
||||
$carry[$forum->get_id()] = $forum;
|
||||
return $carry;
|
||||
}, []);
|
||||
$discussions = array_reduce($discussions, function($carry, $discussion) {
|
||||
$carry[$discussion->get_id()] = $discussion;
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$exportedposts = $this->exportedpostsbuilder->build(
|
||||
$user,
|
||||
$forums,
|
||||
$discussions,
|
||||
$posts
|
||||
);
|
||||
|
||||
if ($this->postprocessfortemplate !== null) {
|
||||
// We've got some post processing to do!
|
||||
$exportedposts = ($this->postprocessfortemplate)($exportedposts, $forums, $discussions, $user);
|
||||
}
|
||||
|
||||
return $this->renderer->render_from_template(
|
||||
$this->template,
|
||||
['posts' => array_values($exportedposts)]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Author vault class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Author vault class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class author extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'user';
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'a';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string {
|
||||
$selectsql = 'SELECT * FROM {' . self::TABLE . '} ' . $this->get_table_alias();
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into author entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return author_entity[]
|
||||
*/
|
||||
protected function from_db_records(array $results) {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
|
||||
return array_map(function(array $result) use ($entityfactory) {
|
||||
[
|
||||
'record' => $record,
|
||||
] = $result;
|
||||
return $entityfactory->get_author_from_stdclass($record);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authors for the given posts.
|
||||
*
|
||||
* Returns a distinct list of authors indexed by author id.
|
||||
*
|
||||
* @param post_entity[] $posts The list of posts
|
||||
* @return author_entity[]
|
||||
*/
|
||||
public function get_authors_for_posts(array $posts) : array {
|
||||
$authorids = array_reduce($posts, function($carry, $post) {
|
||||
$carry[$post->get_author_id()] = true;
|
||||
return $carry;
|
||||
}, []);
|
||||
$authorids = array_keys($authorids);
|
||||
return $this->get_from_ids($authorids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Abstract class for loading records from the DB.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\factories\entity as entity_factory;
|
||||
use moodle_database;
|
||||
|
||||
/**
|
||||
* Abstract class for loading records from the DB.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class db_table_vault {
|
||||
/** @var moodle_database $db A moodle database */
|
||||
private $db;
|
||||
/** @var entity_factory $entityfactory Entity factory */
|
||||
private $entityfactory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moodle_database $db A moodle database
|
||||
* @param entity_factory $entityfactory Entity factory
|
||||
*/
|
||||
public function __construct(
|
||||
moodle_database $db,
|
||||
entity_factory $entityfactory
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->entityfactory = $entityfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_table_alias() : string;
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string;
|
||||
|
||||
/**
|
||||
* Convert the DB records into entities. The list of records will have been
|
||||
* passed through any preprocessors that may be defined before being given to
|
||||
* this function.
|
||||
*
|
||||
* Each result will from the list will be an associative array where the key
|
||||
* is set to the identifier given to the preprocessor and the result is the value
|
||||
* generated by the preprocessor.
|
||||
*
|
||||
* All results will have a 'record' key who's value is the original DB record.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
*/
|
||||
abstract protected function from_db_records(array $results);
|
||||
|
||||
/**
|
||||
* Get the list of preprocessors to run on the DB record results. The preprocessors
|
||||
* should be defined using an associative array. The key used to identify the
|
||||
* preprocessor in this list will be used to identify the value of that preprocessor
|
||||
* in the list of results when passed to the from_db_records function.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_preprocessors() : array {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the moodle database.
|
||||
*
|
||||
* @return moodle_database
|
||||
*/
|
||||
protected function get_db() : moodle_database {
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity factory.
|
||||
*
|
||||
* @return entity_factory
|
||||
*/
|
||||
protected function get_entity_factory() : entity_factory {
|
||||
return $this->entityfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the defined preprocessors on the DB record results and then convert
|
||||
* them into entities.
|
||||
*
|
||||
* @param stdClass[] $records List of DB results
|
||||
* @return array
|
||||
*/
|
||||
protected function transform_db_records_to_entities(array $records) {
|
||||
$preprocessors = $this->get_preprocessors();
|
||||
$result = array_map(function($record) {
|
||||
return ['record' => $record];
|
||||
}, $records);
|
||||
|
||||
$result = array_reduce(array_keys($preprocessors), function($carry, $preprocessor) use ($records, $preprocessors) {
|
||||
$step = $preprocessors[$preprocessor];
|
||||
$dependencies = $step->execute($records);
|
||||
|
||||
foreach ($dependencies as $index => $dependency) {
|
||||
// Add the new dependency to the list.
|
||||
$carry[$index] = array_merge($carry[$index], [$preprocessor => $dependency]);
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, $result);
|
||||
|
||||
return $this->from_db_records($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity for the given id.
|
||||
*
|
||||
* @param int $id Identifier for the entity
|
||||
* @return object|null
|
||||
*/
|
||||
public function get_from_id(int $id) {
|
||||
$records = $this->get_from_ids([$id]);
|
||||
return count($records) ? array_shift($records) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of entities for the given ids.
|
||||
*
|
||||
* @param int[] $ids Identifiers
|
||||
* @return array
|
||||
*/
|
||||
public function get_from_ids(array $ids) {
|
||||
$alias = $this->get_table_alias();
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($ids);
|
||||
$wheresql = $alias . '.id ' . $insql;
|
||||
$sql = $this->generate_get_records_sql($wheresql);
|
||||
$records = $this->get_db()->get_records_sql($sql, $params);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Discussion vault class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
|
||||
/**
|
||||
* Discussion vault class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'forum_discussions';
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'd';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string {
|
||||
$selectsql = 'SELECT * FROM {' . self::TABLE . '} ' . $this->get_table_alias();
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into discussion entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return discussion_entity[]
|
||||
*/
|
||||
protected function from_db_records(array $results) {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
|
||||
return array_map(function(array $result) use ($entityfactory) {
|
||||
[
|
||||
'record' => $record,
|
||||
] = $result;
|
||||
return $entityfactory->get_discussion_from_stdclass($record);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first discussion in the specified forum.
|
||||
*
|
||||
* @param forum_entity $forum
|
||||
* @return discussion_entity|null
|
||||
*/
|
||||
public function get_first_discussion_in_forum(forum_entity $forum) : ?discussion_entity {
|
||||
$records = $this->get_db()->get_records(self::TABLE, [
|
||||
'forum' => $forum->get_id(),
|
||||
], 'timemodified ASC', '*', 0, 1);
|
||||
|
||||
$records = $this->transform_db_records_to_entities($records);
|
||||
return count($records) ? array_shift($records) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Vault class for a discussion list.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\vaults\preprocessors\extract_record as extract_record_preprocessor;
|
||||
use mod_forum\local\vaults\preprocessors\extract_user as extract_user_preprocessor;
|
||||
use mod_forum\local\renderers\discussion_list as discussion_list_renderer;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Discussion list vault.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class discussion_list extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'forum_discussions';
|
||||
/** Alias for first author id */
|
||||
private const FIRST_AUTHOR_ID_ALIAS = 'userpictureid';
|
||||
/** Alias for author fields */
|
||||
private const FIRST_AUTHOR_ALIAS = 'userrecord';
|
||||
/** Alias for last author id */
|
||||
private const LATEST_AUTHOR_ID_ALIAS = 'userpictureid';
|
||||
/** Alias for last author fields */
|
||||
private const LATEST_AUTHOR_ALIAS = 'userrecord';
|
||||
/** Default limit */
|
||||
public const PAGESIZE_DEFAULT = 100;
|
||||
|
||||
/** Sort by newest first */
|
||||
public const SORTORDER_NEWEST_FIRST = 1;
|
||||
/** Sort by oldest first */
|
||||
public const SORTORDER_OLDEST_FIRST = 2;
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'd';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, ?string $sortsql = null) : string {
|
||||
$alias = $this->get_table_alias();
|
||||
$db = $this->get_db();
|
||||
|
||||
// Fetch:
|
||||
// - Discussion
|
||||
// - First post
|
||||
// - Author
|
||||
// - Most recent editor.
|
||||
$tablefields = $db->get_preload_columns(self::TABLE, $alias);
|
||||
$postfields = $db->get_preload_columns('forum_posts', 'p_');
|
||||
$firstauthorfields = \user_picture::fields('fa', null, self::FIRST_AUTHOR_ID_ALIAS, self::FIRST_AUTHOR_ALIAS);
|
||||
$latestuserfields = \user_picture::fields('la', null, self::LATEST_AUTHOR_ID_ALIAS, self::LATEST_AUTHOR_ALIAS);
|
||||
|
||||
$fields = implode(', ', [
|
||||
$db->get_preload_columns_sql($tablefields, $alias),
|
||||
$db->get_preload_columns_sql($postfields, 'fp'),
|
||||
$firstauthorfields,
|
||||
$latestuserfields,
|
||||
]);
|
||||
|
||||
$tables = '{' . self::TABLE . '} ' . $alias;
|
||||
$tables .= ' JOIN {user} fa ON fa.id = ' . $alias . '.userid';
|
||||
$tables .= ' JOIN {user} la ON la.id = ' . $alias . '.usermodified';
|
||||
$tables .= ' JOIN {forum_posts} fp ON fp.id = ' . $alias . '.firstpost';
|
||||
|
||||
$selectsql = 'SELECT ' . $fields . ' FROM ' . $tables;
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in count_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_count_records_sql(string $wheresql = null) : string {
|
||||
$alias = $this->get_table_alias();
|
||||
$db = $this->get_db();
|
||||
|
||||
$selectsql = "SELECT COUNT(1) FROM {" . self::TABLE . "} {$alias}";
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of preprocessors to execute on the DB results before being converted
|
||||
* into entities.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_preprocessors() : array {
|
||||
return array_merge(
|
||||
parent::get_preprocessors(),
|
||||
[
|
||||
'discussion' => new extract_record_preprocessor($this->get_db(), self::TABLE, $this->get_table_alias()),
|
||||
'firstpost' => new extract_record_preprocessor($this->get_db(), 'forum_posts', 'p_'),
|
||||
'firstpostauthor' => new extract_user_preprocessor(self::FIRST_AUTHOR_ID_ALIAS, self::FIRST_AUTHOR_ALIAS),
|
||||
'latestpostauthor' => new extract_user_preprocessor(self::LATEST_AUTHOR_ID_ALIAS, self::LATEST_AUTHOR_ALIAS),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into discussion list entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return discussion_list[]
|
||||
*/
|
||||
protected function from_db_records(array $results) {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
|
||||
return array_map(function(array $result) use ($entityfactory) {
|
||||
[
|
||||
'discussion' => $discussion,
|
||||
'firstpost' => $firstpost,
|
||||
'firstpostauthor' => $firstpostauthor,
|
||||
'latestpostauthor' => $latestpostauthor,
|
||||
] = $result;
|
||||
return $entityfactory->get_discussion_summary_from_stdclass(
|
||||
$discussion,
|
||||
$firstpost,
|
||||
$firstpostauthor,
|
||||
$latestpostauthor
|
||||
);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sort order SQL for a sort method.
|
||||
*
|
||||
* @param int|null $sortmethod
|
||||
*/
|
||||
public function get_sort_order(?int $sortmethod) : string {
|
||||
global $CFG;
|
||||
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
// TODO consider user favourites...
|
||||
$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";
|
||||
}
|
||||
|
||||
return "{$alias}.pinned DESC, {$keyfield} {$direction}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch any required SQL to respect timed posts.
|
||||
*
|
||||
* @param bool $includehiddendiscussions Whether to include hidden discussions or not
|
||||
* @param int $includepostsforuser Which user to include posts for, if any
|
||||
* @return array The SQL and parameters to include
|
||||
*/
|
||||
protected function get_hidden_post_sql(bool $includehiddendiscussions, ?int $includepostsforuser) {
|
||||
$wheresql = '';
|
||||
$params = [];
|
||||
if (!$includehiddendiscussions) {
|
||||
$now = time();
|
||||
$wheresql = " AND ((d.timestart <= :timestart AND (d.timeend = 0 OR d.timeend > :timeend))";
|
||||
$params['timestart'] = $now;
|
||||
$params['timeend'] = $now;
|
||||
if (null !== $includepostsforuser) {
|
||||
$wheresql .= " OR d.userid = :byuser";
|
||||
$params['byuser'] = $includepostsforuser;
|
||||
}
|
||||
$wheresql .= ")";
|
||||
}
|
||||
|
||||
return [
|
||||
'wheresql' => $wheresql,
|
||||
'params' => $params,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get each discussion, first post, first and last post author for the given forum, considering timed posts, and
|
||||
* pagination.
|
||||
*
|
||||
* @param int $forumid The forum to fetch the discussion set for
|
||||
* @param bool $includehiddendiscussions Whether to include hidden discussions or not
|
||||
* @param int|null $includepostsforuser Which user to include posts for, if any
|
||||
* @param int $sortorder The sort order to use
|
||||
* @param int $limit The number of discussions to fetch
|
||||
* @param int $offset The record offset
|
||||
* @return array The set of data fetched
|
||||
*/
|
||||
public function get_from_forum_id(
|
||||
int $forumid,
|
||||
bool $includehiddendiscussions,
|
||||
?int $includepostsforuser,
|
||||
?int $sortorder,
|
||||
int $limit,
|
||||
int $offset
|
||||
) {
|
||||
$alias = $this->get_table_alias();
|
||||
$wheresql = "{$alias}.forum = :forumid";
|
||||
[
|
||||
'wheresql' => $hiddensql,
|
||||
'params' => $hiddenparams
|
||||
] = $this->get_hidden_post_sql($includehiddendiscussions, $includepostsforuser);
|
||||
$wheresql .= $hiddensql;
|
||||
|
||||
$params = array_merge($hiddenparams, [
|
||||
'forumid' => $forumid,
|
||||
]);
|
||||
|
||||
$sql = $this->generate_get_records_sql($wheresql, $this->get_sort_order($sortorder));
|
||||
$records = $this->get_db()->get_records_sql($sql, $params, $offset, $limit);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get each discussion, first post, first and last post author for the given forum, and the set of groups to display
|
||||
* considering timed posts, and pagination.
|
||||
*
|
||||
* @param int $forumid The forum to fetch the discussion set for
|
||||
* @param int[] $groupids The list of real groups to filter on
|
||||
* @param bool $includehiddendiscussions Whether to include hidden discussions or not
|
||||
* @param int|null $includepostsforuser Which user to include posts for, if any
|
||||
* @param int $sortorder The sort order to use
|
||||
* @param int $limit The number of discussions to fetch
|
||||
* @param int $offset The record offset
|
||||
* @return array The set of data fetched
|
||||
*/
|
||||
public function get_from_forum_id_and_group_id(
|
||||
int $forumid,
|
||||
array $groupids,
|
||||
bool $includehiddendiscussions,
|
||||
?int $includepostsforuser,
|
||||
?int $sortorder,
|
||||
int $limit,
|
||||
int $offset
|
||||
) {
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
$wheresql = "{$alias}.forum = :forumid AND ";
|
||||
$groupparams = [];
|
||||
if (empty($groupids)) {
|
||||
$wheresql .= "{$alias}.groupid = :allgroupsid";
|
||||
} else {
|
||||
list($insql, $groupparams) = $this->get_db()->get_in_or_equal($groupids, SQL_PARAMS_NAMED, 'gid');
|
||||
$wheresql .= "({$alias}.groupid = :allgroupsid OR {$alias}.groupid {$insql})";
|
||||
}
|
||||
|
||||
[
|
||||
'wheresql' => $hiddensql,
|
||||
'params' => $hiddenparams
|
||||
] = $this->get_hidden_post_sql($includehiddendiscussions, $includepostsforuser);
|
||||
$wheresql .= $hiddensql;
|
||||
|
||||
$params = array_merge($hiddenparams, $groupparams, [
|
||||
'forumid' => $forumid,
|
||||
'allgroupsid' => -1,
|
||||
]);
|
||||
|
||||
$sql = $this->generate_get_records_sql($wheresql, $this->get_sort_order($sortorder));
|
||||
$records = $this->get_db()->get_records_sql($sql, $params, $offset, $limit);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of discussions in the forum.
|
||||
*
|
||||
* @param int $forumid Id of the forum to count discussions in
|
||||
* @param bool $includehiddendiscussions Include hidden dicussions in the count?
|
||||
* @param int|null $includepostsforuser Include discussions created by this user in the count
|
||||
* (only works if not including hidden discussions).
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_discussion_count_from_forum_id(
|
||||
int $forumid,
|
||||
bool $includehiddendiscussions,
|
||||
?int $includepostsforuser
|
||||
) {
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
$wheresql = "{$alias}.forum = :forumid";
|
||||
|
||||
[
|
||||
'wheresql' => $hiddensql,
|
||||
'params' => $hiddenparams
|
||||
] = $this->get_hidden_post_sql($includehiddendiscussions, $includepostsforuser);
|
||||
$wheresql .= $hiddensql;
|
||||
|
||||
$params = array_merge($hiddenparams, [
|
||||
'forumid' => $forumid,
|
||||
]);
|
||||
|
||||
return $this->get_db()->count_records_sql($this->generate_count_records_sql($wheresql), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of discussions in all groups and the list of groups provided.
|
||||
*
|
||||
* @param int $forumid Id of the forum to count discussions in
|
||||
* @param int[] $groupids List of group ids to include in the count (discussions in all groups will always be counted)
|
||||
* @param bool $includehiddendiscussions Include hidden dicussions in the count?
|
||||
* @param int|null $includepostsforuser Include discussions created by this user in the count
|
||||
* (only works if not including hidden discussions).
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_discussion_count_from_forum_id_and_group_id(
|
||||
int $forumid,
|
||||
array $groupids,
|
||||
bool $includehiddendiscussions,
|
||||
?int $includepostsforuser
|
||||
) {
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
$wheresql = "{$alias}.forum = :forumid AND ";
|
||||
$groupparams = [];
|
||||
if (empty($groupids)) {
|
||||
$wheresql .= "{$alias}.groupid = :allgroupsid";
|
||||
} else {
|
||||
list($insql, $groupparams) = $this->get_db()->get_in_or_equal($groupids, SQL_PARAMS_NAMED, 'gid');
|
||||
$wheresql .= "({$alias}.groupid = :allgroupsid OR {$alias}.groupid {$insql})";
|
||||
}
|
||||
|
||||
[
|
||||
'wheresql' => $hiddensql,
|
||||
'params' => $hiddenparams
|
||||
] = $this->get_hidden_post_sql($includehiddendiscussions, $includepostsforuser);
|
||||
$wheresql .= $hiddensql;
|
||||
|
||||
$params = array_merge($hiddenparams, $groupparams, [
|
||||
'forumid' => $forumid,
|
||||
'allgroupsid' => -1,
|
||||
]);
|
||||
|
||||
return $this->get_db()->count_records_sql($this->generate_count_records_sql($wheresql), $params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Forum vault class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\vaults\preprocessors\extract_context as extract_context_preprocessor;
|
||||
use mod_forum\local\vaults\preprocessors\extract_record as extract_record_preprocessor;
|
||||
use context_helper;
|
||||
|
||||
/**
|
||||
* Forum vault class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class forum extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'forum';
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'f';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string {
|
||||
$db = $this->get_db();
|
||||
$alias = $this->get_table_alias();
|
||||
$tablefields = $db->get_preload_columns(self::TABLE, $alias);
|
||||
$coursemodulefields = $db->get_preload_columns('course_modules', 'cm_');
|
||||
$coursefields = $db->get_preload_columns('course', 'c_');
|
||||
|
||||
$fields = implode(', ', [
|
||||
$db->get_preload_columns_sql($tablefields, $alias),
|
||||
context_helper::get_preload_record_columns_sql('ctx'),
|
||||
$db->get_preload_columns_sql($coursemodulefields, 'cm'),
|
||||
$db->get_preload_columns_sql($coursefields, 'c'),
|
||||
]);
|
||||
|
||||
$tables = '{' . self::TABLE . '} ' . $alias;
|
||||
$tables .= " JOIN {modules} m ON m.name = 'forum'";
|
||||
$tables .= " JOIN {course_modules} cm ON cm.module = m.id AND cm.instance = {$alias}.id";
|
||||
$tables .= ' JOIN {context} ctx ON ctx.contextlevel = ' . CONTEXT_MODULE . ' AND ctx.instanceid = cm.id';
|
||||
$tables .= " JOIN {course} c ON c.id = {$alias}.course";
|
||||
|
||||
$selectsql = 'SELECT ' . $fields . ' FROM ' . $tables;
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of preprocessors to execute on the DB results before being converted
|
||||
* into entities.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_preprocessors() : array {
|
||||
return array_merge(
|
||||
parent::get_preprocessors(),
|
||||
[
|
||||
'forum' => new extract_record_preprocessor($this->get_db(), self::TABLE, $this->get_table_alias()),
|
||||
'course_module' => new extract_record_preprocessor($this->get_db(), 'course_modules', 'cm_'),
|
||||
'course' => new extract_record_preprocessor($this->get_db(), 'course', 'c_'),
|
||||
'context' => new extract_context_preprocessor(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into forum entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return forum_entity[]
|
||||
*/
|
||||
protected function from_db_records(array $results) : array {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
|
||||
return array_map(function(array $result) use ($entityfactory) {
|
||||
[
|
||||
'forum' => $forumrecord,
|
||||
'course_module' => $coursemodule,
|
||||
'course' => $course,
|
||||
'context' => $context,
|
||||
] = $result;
|
||||
return $entityfactory->get_forum_from_stdclass($forumrecord, $context, $coursemodule, $course);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forum for the given course module id.
|
||||
*
|
||||
* @param int $id The course module id
|
||||
* @return forum_entity|null
|
||||
*/
|
||||
public function get_from_course_module_id(int $id) : ?forum_entity {
|
||||
$records = $this->get_from_course_module_ids([$id]);
|
||||
return count($records) ? array_shift($records) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forums for the given course module ids
|
||||
*
|
||||
* @param int[] $ids The course module ids
|
||||
* @return forum_entity[]
|
||||
*/
|
||||
public function get_from_course_module_ids(array $ids) : array {
|
||||
$alias = $this->get_table_alias();
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($ids);
|
||||
$wheresql = 'cm.id ' . $insql;
|
||||
$sql = $this->generate_get_records_sql($wheresql);
|
||||
$records = $this->get_db()->get_records_sql($sql, $params);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post vault class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use mod_forum\local\factories\entity as entity_factory;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Post vault class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'forum_posts';
|
||||
/** Alias for user id */
|
||||
private const USER_ID_ALIAS = 'userpictureid';
|
||||
/** Alias for user fields */
|
||||
private const USER_ALIAS = 'userrecord';
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'p';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string {
|
||||
$table = self::TABLE;
|
||||
$alias = $this->get_table_alias();
|
||||
$fields = $alias . '.*';
|
||||
$tables = "{{$table}} {$alias}";
|
||||
|
||||
$selectsql = "SELECT {$fields} FROM {$tables}";
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into post entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return post_entity[]
|
||||
*/
|
||||
protected function from_db_records(array $results) {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
|
||||
return array_map(function(array $result) use ($entityfactory) {
|
||||
['record' => $record] = $result;
|
||||
return $entityfactory->get_post_from_stdclass($record);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post ids for the given discussion.
|
||||
*
|
||||
* @param int $discussionid The discussion to load posts for
|
||||
* @param string $orderby Order the results
|
||||
* @return post_entity[]
|
||||
*/
|
||||
public function get_from_discussion_id(int $discussionid, string $orderby = 'created ASC') : array {
|
||||
$alias = $this->get_table_alias();
|
||||
$wheresql = $alias . '.discussion = ?';
|
||||
$orderbysql = $alias . '.' . $orderby;
|
||||
$sql = $this->generate_get_records_sql($wheresql, $orderbysql);
|
||||
$records = $this->get_db()->get_records_sql($sql, [$discussionid]);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of posts for the given discussions.
|
||||
*
|
||||
* @param int[] $discussionids The list of discussion ids to load posts for
|
||||
* @return post_entity[]
|
||||
*/
|
||||
public function get_from_discussion_ids(array $discussionids) : array {
|
||||
if (empty($discussionids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$alias = $this->get_table_alias();
|
||||
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids);
|
||||
|
||||
$wheresql = "{$alias}.discussion {$insql}";
|
||||
|
||||
$sql = $this->generate_get_records_sql($wheresql, '');
|
||||
$records = $this->get_db()->get_records_sql($sql, $params);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of replies to the given post. This will load all descendants of the post.
|
||||
* That is, all direct replies and replies to those replies etc.
|
||||
*
|
||||
* The return value will be a flat array of posts in the requested order.
|
||||
*
|
||||
* @param post_entity $post The post to load replies for
|
||||
* @param string $orderby How to order the replies
|
||||
* @return post_entity[]
|
||||
*/
|
||||
public function get_replies_to_post(post_entity $post, string $orderby = 'created ASC') : array {
|
||||
$alias = $this->get_table_alias();
|
||||
$params = [$post->get_discussion_id(), $post->get_time_created()];
|
||||
// Unfortunately the best we can do to filter down the query is ignore all posts
|
||||
// that were created before the given post (since they can't be replies).
|
||||
$wheresql = "{$alias}.discussion = ? and {$alias}.created > ?";
|
||||
$orderbysql = $alias . '.' . $orderby;
|
||||
$sql = $this->generate_get_records_sql($wheresql, $orderbysql);
|
||||
$records = $this->get_db()->get_records_sql($sql, $params);
|
||||
$posts = $this->transform_db_records_to_entities($records);
|
||||
$sorter = $this->get_entity_factory()->get_posts_sorter();
|
||||
// We need to sort all of the values into the replies tree in order to capture
|
||||
// the full list of descendants.
|
||||
$sortedposts = $sorter->sort_into_children($posts);
|
||||
$replies = [];
|
||||
|
||||
// From the sorted list we can grab the first elements and check if they are replies
|
||||
// to the post we care about. If so we keep them.
|
||||
foreach ($sortedposts as $candidate) {
|
||||
[$candidatepost, $candidatereplies] = $candidate;
|
||||
if ($candidatepost->has_parent() && $candidatepost->get_parent_id() == $post->get_id()) {
|
||||
$replies[] = $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($replies)) {
|
||||
return $replies;
|
||||
}
|
||||
|
||||
$getreplypostids = function($candidates) use (&$getreplypostids) {
|
||||
$ids = [];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
[$reply, $replies] = $candidate;
|
||||
$ids = array_merge($ids, [$reply->get_id()], $getreplypostids($replies));
|
||||
}
|
||||
|
||||
return $ids;
|
||||
};
|
||||
// Recursively build a list of the ids of all posts in the full reply tree.
|
||||
$replypostids = $getreplypostids($replies);
|
||||
|
||||
// Now go back and filter the original result set down to just the posts that
|
||||
// we've flagged as in the reply tree. We need to filter the original set of values
|
||||
// so that we can maintain the requested sort order.
|
||||
return array_values(array_filter($posts, function($post) use ($replypostids) {
|
||||
return in_array($post->get_id(), $replypostids);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mapping of replies to the specified discussions.
|
||||
*
|
||||
* @param int[] $discussionids The list of discussions to fetch counts for
|
||||
* @return int[] The number of replies for each discussion returned in an associative array
|
||||
*/
|
||||
public function get_reply_count_for_discussion_ids(array $discussionids) : array {
|
||||
if (empty($discussionids)) {
|
||||
return [];
|
||||
}
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids);
|
||||
$sql = "SELECT discussion, COUNT(1) FROM {" . self::TABLE . "} p " .
|
||||
"WHERE p.discussion {$insql} AND p.parent > 0 GROUP BY discussion";
|
||||
|
||||
return $this->get_db()->get_records_sql_menu($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mapping of unread post counts for the specified discussions.
|
||||
*
|
||||
* @param stdClass $user The user to fetch counts for
|
||||
* @param int[] $discussionids The list of discussions to fetch counts for
|
||||
* @return int[] The count of unread posts for each discussion returned in an associative array
|
||||
*/
|
||||
public function get_unread_count_for_discussion_ids(stdClass $user, array $discussionids) : array {
|
||||
global $CFG;
|
||||
|
||||
if (empty($discussionids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$alias = $this->get_table_alias();
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids, SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT p.discussion, COUNT(p.id) FROM {" . self::TABLE . "} p
|
||||
LEFT JOIN {forum_read} r ON r.postid = p.id AND r.userid = :userid
|
||||
WHERE p.discussion {$insql} AND p.modified > :cutofftime AND r.id IS NULL
|
||||
GROUP BY p.discussion";
|
||||
|
||||
$params['userid'] = $user->id;
|
||||
$params['cutofftime'] = floor((new \DateTime())
|
||||
->sub(new \DateInterval("P{$CFG->forum_oldpostdays}D"))
|
||||
->format('U') / 60) * 60;
|
||||
|
||||
return $this->get_db()->get_records_sql_menu($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mapping of the most recent post in each discussion based on post creation time.
|
||||
*
|
||||
* @param int[] $discussionids The list of discussions to fetch counts for
|
||||
* @return int[] The post id of the most recent post for each discussions returned in an associative array
|
||||
*/
|
||||
public function get_latest_post_id_for_discussion_ids(array $discussionids) : array {
|
||||
global $CFG;
|
||||
|
||||
if (empty($discussionids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$alias = $this->get_table_alias();
|
||||
list($insql, $params) = $this->get_db()->get_in_or_equal($discussionids, SQL_PARAMS_NAMED);
|
||||
|
||||
$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
|
||||
GROUP BY p.discussion";
|
||||
|
||||
return $this->get_db()->get_records_sql_menu($sql, $params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post attachment vault class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
use context;
|
||||
use file_storage;
|
||||
|
||||
/**
|
||||
* Post attachment vault class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
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 */
|
||||
private const INCLUDE_DIRECTORIES = false;
|
||||
/** @var file_storage $filestorage File storage */
|
||||
private $filestorage;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param file_storage $filestorage File storage
|
||||
*/
|
||||
public function __construct(file_storage $filestorage) {
|
||||
$this->filestorage = $filestorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the given posts. The results are indexed by
|
||||
* post id.
|
||||
*
|
||||
* @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) {
|
||||
$itemids = array_map(function($post) {
|
||||
return $post->get_id();
|
||||
}, $posts);
|
||||
|
||||
$files = $this->filestorage->get_area_files(
|
||||
$context->id,
|
||||
self::COMPONENT,
|
||||
self::FILE_AREA,
|
||||
$itemids,
|
||||
self::SORT,
|
||||
self::INCLUDE_DIRECTORIES
|
||||
);
|
||||
|
||||
$filesbyid = array_reduce($posts, function($carry, $post) {
|
||||
$carry[$post->get_id()] = [];
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
return array_reduce($files, function($carry, $file) {
|
||||
$itemid = $file->get_itemid();
|
||||
$carry[$itemid] = array_merge($carry[$itemid], [$file]);
|
||||
return $carry;
|
||||
}, $filesbyid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Post read receipt collection class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Post read receipt collection class.
|
||||
*
|
||||
* This should be the only place that accessed the database.
|
||||
*
|
||||
* This uses the repository pattern. See:
|
||||
* https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
|
||||
*
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class post_read_receipt_collection extends db_table_vault {
|
||||
/** The table for this vault */
|
||||
private const TABLE = 'forum_read';
|
||||
|
||||
/**
|
||||
* Get the table alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_alias() : string {
|
||||
return 'fr';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL to be used in get_records_sql.
|
||||
*
|
||||
* @param string|null $wheresql Where conditions for the SQL
|
||||
* @param string|null $sortsql Order by conditions for the SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_get_records_sql(string $wheresql = null, string $sortsql = null) : string {
|
||||
$selectsql = 'SELECT * FROM {' . self::TABLE . '} ' . $this->get_table_alias();
|
||||
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
|
||||
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
|
||||
|
||||
return $selectsql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB records into post_read_receipt_collection entities.
|
||||
*
|
||||
* @param array $results The DB records
|
||||
* @return post_read_receipt_collection
|
||||
*/
|
||||
protected function from_db_records(array $results) {
|
||||
$entityfactory = $this->get_entity_factory();
|
||||
$records = array_map(function($result) {
|
||||
return $result['record'];
|
||||
}, $results);
|
||||
|
||||
return $entityfactory->get_post_read_receipt_collection_from_stdclasses($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the post_read_receipt_collection for the given user and set
|
||||
* of posts.
|
||||
*
|
||||
* @param int $userid Id of the user to load receipts for
|
||||
* @param int[] $postids List of post ids to load receipts for
|
||||
* @return post_read_receipt_collection
|
||||
*/
|
||||
public function get_from_user_id_and_post_ids(int $userid, array $postids) {
|
||||
$alias = $this->get_table_alias();
|
||||
[$postidinsql, $params] = $this->get_db()->get_in_or_equal($postids);
|
||||
$params[] = $userid;
|
||||
|
||||
$wheresql = "{$alias}.postid {$postidinsql}";
|
||||
$wheresql .= " AND {$alias}.userid = ?";
|
||||
$sql = $this->generate_get_records_sql($wheresql);
|
||||
$records = $this->get_db()->get_records_sql($sql, $params);
|
||||
|
||||
return $this->transform_db_records_to_entities($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the post_read_receipt_collection for the given user and set
|
||||
* of posts.
|
||||
*
|
||||
* @param stdClass $user The user to load receipts for
|
||||
* @param post_entity[] $posts List of posts to load receipts for
|
||||
* @return post_read_receipt_collection
|
||||
*/
|
||||
public function get_from_user_and_posts(stdClass $user, array $posts) {
|
||||
$postids = array_map(function($post) {
|
||||
return $post->get_id();
|
||||
}, $posts);
|
||||
return $this->get_from_user_id_and_post_ids($user->id, $postids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Extract context vault preprocessor.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults\preprocessors;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use context;
|
||||
use context_helper;
|
||||
|
||||
/**
|
||||
* Extract context vault preprocessor.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class extract_context {
|
||||
/**
|
||||
* Extract the contexts from a list of records.
|
||||
*
|
||||
* @param stdClass[] $records The list of records which have context properties
|
||||
* @return context[] List of contexts matching the records.
|
||||
*/
|
||||
public function execute(array $records) : array {
|
||||
return array_map(function($record) {
|
||||
$contextid = $record->ctxid;
|
||||
context_helper::preload_from_record($record);
|
||||
$context = context::instance_by_id($contextid);
|
||||
return $context;
|
||||
}, $records);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Extract record vault preprocessor.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults\preprocessors;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use moodle_database;
|
||||
|
||||
/**
|
||||
* Extract record vault preprocessor.
|
||||
*
|
||||
* Extract record vault preprocessor. Typically used to separate out records
|
||||
* when two tables have been joined together in a query.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class extract_record {
|
||||
/** @var moodle_database $db A moodle database */
|
||||
private $db;
|
||||
/** @var string $table The table name where the records were loaded from */
|
||||
private $table;
|
||||
/** @var string $alias The table alias used as the record property prefix */
|
||||
private $alias;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moodle_database $db A moodle database
|
||||
* @param string $table The table name where the records were loaded from
|
||||
* @param string $alias The table alias used as the record property prefix
|
||||
*/
|
||||
public function __construct(moodle_database $db, string $table, string $alias) {
|
||||
$this->db = $db;
|
||||
$this->table = $table;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a record embedded in the properties of another record out into a
|
||||
* separate record.
|
||||
*
|
||||
* @param stdClass[] $records The list of records to process
|
||||
* @return stdClass[] The extracted records
|
||||
*/
|
||||
public function execute(array $records) : array {
|
||||
$db = $this->db;
|
||||
$fields = $this->db->get_preload_columns($this->table, $this->alias);
|
||||
|
||||
return array_map(function($record) use ($db, $fields) {
|
||||
return $db->extract_fields_from_object($fields, $record);
|
||||
}, $records);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Extract user vault preprocessor.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_forum\local\vaults\preprocessors;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use user_picture;
|
||||
|
||||
/**
|
||||
* Extract user vault preprocessor.
|
||||
*
|
||||
* Used to separate out the user record
|
||||
* from a list of DB records that have been joined on the user table.
|
||||
*
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class extract_user {
|
||||
/** @var string $idalias The alias for the id property of the user */
|
||||
private $idalias;
|
||||
/** @var string $alias The prefix used for each of the user properties */
|
||||
private $alias;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $idalias The alias for the id property of the user
|
||||
* @param string $alias The prefix used for each of the user properties
|
||||
*/
|
||||
public function __construct(string $idalias, string $alias) {
|
||||
$this->idalias = $idalias;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the user records from a list of DB records.
|
||||
*
|
||||
* @param stdClass[] $records The DB records
|
||||
* @return stdClass[] The list of extracted users
|
||||
*/
|
||||
public function execute(array $records) : array {
|
||||
$idalias = $this->idalias;
|
||||
$alias = $this->alias;
|
||||
|
||||
return array_map(function($record) use ($idalias, $alias) {
|
||||
return user_picture::unalias($record, null, $idalias, $alias);
|
||||
}, $records);
|
||||
}
|
||||
}
|
||||
+13
-15
@@ -3111,7 +3111,7 @@ function forum_print_discussion_header(&$post, $forum, $group = -1, $datestring
|
||||
echo $post->unread;
|
||||
echo '</a>';
|
||||
echo '<a title="'.$strmarkalldread.'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
|
||||
$forum->id.'&d='.$post->discussion.'&mark=read&returnpage=view.php&sesskey=' . sesskey() . '">' .
|
||||
$forum->id.'&d='.$post->discussion.'&mark=read&return=/mod/forum/view.php&sesskey=' . sesskey() . '">' .
|
||||
$OUTPUT->pix_icon('t/markasread', $strmarkalldread) . '</a>';
|
||||
echo '</span>';
|
||||
} else {
|
||||
@@ -4819,7 +4819,7 @@ function forum_print_latest_discussions($course, $forum, $maxdiscussions = -1, $
|
||||
if ($forumtracked) {
|
||||
echo '<a title="'.get_string('markallread', 'forum').
|
||||
'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
|
||||
$forum->id.'&mark=read&returnpage=view.php&sesskey=' . sesskey() . '">'.
|
||||
$forum->id.'&mark=read&return=/mod/forum/view.php&sesskey=' . sesskey() . '">'.
|
||||
$OUTPUT->pix_icon('t/markasread', get_string('markallread', 'forum')) . '</a>';
|
||||
}
|
||||
echo '</th>';
|
||||
@@ -7471,20 +7471,18 @@ function mod_forum_inplace_editable($itemtype, $itemid, $newvalue) {
|
||||
* @return bool
|
||||
*/
|
||||
function forum_discussion_is_locked($forum, $discussion) {
|
||||
if (empty($forum->lockdiscussionafter)) {
|
||||
return false;
|
||||
}
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$coursemoduleinfo = get_fast_modinfo($forum->course);
|
||||
$cminfo = $coursemoduleinfo->instances['forum'][$forum->id];
|
||||
$forumentity = $entityfactory->get_forum_from_stdclass(
|
||||
$forum,
|
||||
context_module::instance($cminfo->id),
|
||||
$cminfo->get_course_module_record(),
|
||||
$cminfo->get_course()
|
||||
);
|
||||
$discussionentity = $entityfactory->get_discussion_from_stdclass($discussion);
|
||||
|
||||
if ($forum->type === 'single') {
|
||||
// It does not make sense to lock a single discussion forum.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($discussion->timemodified + $forum->lockdiscussionafter) < time()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $forumentity->is_discussion_locked($discussionentity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-14
@@ -29,14 +29,14 @@ require_once("lib.php");
|
||||
$f = required_param('f',PARAM_INT); // The forum to mark
|
||||
$mark = required_param('mark',PARAM_ALPHA); // Read or unread?
|
||||
$d = optional_param('d',0,PARAM_INT); // Discussion to mark.
|
||||
$returnpage = optional_param('returnpage', 'index.php', PARAM_FILE); // Page to return to.
|
||||
$return = optional_param('return', null, PARAM_LOCALURL); // Page to return to.
|
||||
|
||||
$url = new moodle_url('/mod/forum/markposts.php', array('f'=>$f, 'mark'=>$mark));
|
||||
if ($d !== 0) {
|
||||
$url->param('d', $d);
|
||||
}
|
||||
if ($returnpage !== 'index.php') {
|
||||
$url->param('returnpage', $returnpage);
|
||||
if (null !== $return) {
|
||||
$url->param('return', $return);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
|
||||
@@ -57,10 +57,10 @@ $user = $USER;
|
||||
require_login($course, false, $cm);
|
||||
require_sesskey();
|
||||
|
||||
if ($returnpage == 'index.php') {
|
||||
$returnto = new moodle_url("/mod/forum/$returnpage", array('id' => $course->id));
|
||||
if (null === $return) {
|
||||
$returnto = new moodle_url("/mod/forum/index.php", ['id' => $course->id]);
|
||||
} else {
|
||||
$returnto = new moodle_url("/mod/forum/$returnpage", array('f' => $forum->id));
|
||||
$returnto = new moodle_url($return);
|
||||
}
|
||||
|
||||
if (isguestuser()) { // Guests can't change forum
|
||||
@@ -93,14 +93,6 @@ if ($mark == 'read') {
|
||||
}
|
||||
forum_tp_mark_forum_read($user, $forum->id, $currentgroup);
|
||||
}
|
||||
|
||||
/// FUTURE - Add ability to mark them as unread.
|
||||
// } else { // subscribe
|
||||
// if (forum_tp_start_tracking($forum->id, $user->id)) {
|
||||
// redirect($returnto, get_string("nowtracking", "forum", $info), 1);
|
||||
// } else {
|
||||
// print_error("Could not start tracking that forum", get_local_referer());
|
||||
// }
|
||||
}
|
||||
|
||||
redirect($returnto);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/qanda_discussion_list
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{< mod_forum/discussion_list }}
|
||||
{{$discussion_create_text}}
|
||||
{{#str}}addanewtopic, forum{{/str}}
|
||||
{{/discussion_create_text}}
|
||||
{{/ mod_forum/discussion_list }}
|
||||
@@ -0,0 +1,205 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/discussion_list
|
||||
|
||||
Template to display the list of forum discussions.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* TODO
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<span id="{{uniqid}}">
|
||||
{{{groupchangemenu}}}
|
||||
|
||||
{{#notifications}}
|
||||
{{> core/notification}}
|
||||
{{/notifications}}
|
||||
|
||||
{{#forum.capabilities.create}}
|
||||
<div class="p-t-1 p-b-1">
|
||||
<a href="{{forum.urls.create}}" class="btn btn-primary">
|
||||
{{$discussion_create_text}}
|
||||
{{#str}}addanewdiscussion, forum{{/str}}
|
||||
{{/discussion_create_text}}
|
||||
</a>
|
||||
</div>
|
||||
{{/forum.capabilities.create}}
|
||||
|
||||
{{#state.hasdiscussions}}
|
||||
<table class="table table-hover table-striped">
|
||||
{{$discussion_list_header}}
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"> </th>
|
||||
<th scope="col" class="p-l-0">{{#str}}discussion, mod_forum{{/str}}</th>
|
||||
<th scope="col" class="author">{{#str}}startedby, mod_forum{{/str}}</th>
|
||||
{{#forum.state.groupmode}}
|
||||
<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>
|
||||
{{#forum.userstate.tracked}}
|
||||
<th scope="col" class="text-center">
|
||||
{{#str}}unread, mod_forum{{/str}}
|
||||
<a href="{{{forum.urls.markasread}}}">{{#pix}}t/markasread, core, {{#str}}markallread, mod_forum{{/str}}{{/pix}}</a>
|
||||
</th>
|
||||
{{/forum.userstate.tracked}}
|
||||
{{/forum.capabilities.viewdiscussions}}
|
||||
<th scope="col" class="lastpost">{{#str}}lastpost, mod_forum{{/str}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{/discussion_list_header}}
|
||||
{{$discussion_list_body}}
|
||||
<tbody>
|
||||
{{#summaries}}
|
||||
<tr>
|
||||
<td scope="col" class="pinned p-0 text-center align-middle">
|
||||
{{#discussion.pinned}}
|
||||
{{#pix}}i/pinned, mod_forum, {{#str}}discussionpinned, mod_forum{{/str}}{{/pix}}
|
||||
{{/discussion.pinned}}
|
||||
</td>
|
||||
<td scope="col" class="topic p-0">
|
||||
<a class="p-3 p-l-0 w-100 h-100 d-block" href="{{discussion.urls.view}}">{{discussion.name}}</a>
|
||||
</td>
|
||||
<td scope="col" class="author">
|
||||
{{#firstpostauthor}}
|
||||
<a href="{{urls.profile}}">
|
||||
<div class="d-flex flex-row">
|
||||
<div class="align-middle p-0">
|
||||
<a href="{{urls.profile}}">
|
||||
<img {{!
|
||||
}} class="h-auto rounded-circle userpicture" {{!
|
||||
}} src="{{urls.profileimage}}" {{!
|
||||
}} alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}" {{!
|
||||
}}>
|
||||
</a>
|
||||
</div>
|
||||
<div class="align-middle p-2">
|
||||
<a href="{{urls.profile}}">{{fullname}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{{/firstpostauthor}}
|
||||
</td>
|
||||
{{#forum.state.groupmode}}
|
||||
<td scope="col" class="group">
|
||||
{{#discussion.group}}
|
||||
{{#urls.picture}}
|
||||
{{#urls.userlist}}
|
||||
<a href="{{{urls.userlist}}}">
|
||||
<img class="border rounded h-auto rounded-circle" src="{{{urls.picture}}}">
|
||||
</a>
|
||||
{{/urls.userlist}}
|
||||
{{^urls.userlist}}
|
||||
<img class="border rounded h-auto rounded-circle" src="{{{urls.picture}}}">
|
||||
{{/urls.userlist}}
|
||||
{{/urls.picture}}
|
||||
{{^urls.picture}}
|
||||
{{#urls.userlist}}
|
||||
<a href="{{{urls.userlist}}}">{{name}}</a>
|
||||
{{/urls.userlist}}
|
||||
{{^urls.userlist}}
|
||||
{{name}}
|
||||
{{/urls.userlist}}
|
||||
{{/urls.picture}}
|
||||
{{/discussion.group}}
|
||||
</td>
|
||||
{{/forum.state.groupmode}}
|
||||
{{#forum.capabilities.viewdiscussions}}
|
||||
<td scope="col" class="p-0 text-center">
|
||||
<a href="{{discussion.urls.view}}" class="p-3 w-100 h-100 d-block">
|
||||
{{replies}}
|
||||
</a>
|
||||
</td>
|
||||
{{#forum.userstate.tracked}}
|
||||
<td scope="col" class="p-0 text-center p-3 w-100 h-100 d-block">
|
||||
{{#unread}}
|
||||
{{! TODO Rewrite as AJAX}}
|
||||
<a href="{{{discussion.urls.viewfirstunread}}}">{{unread}}</a>
|
||||
<a href="{{{discussion.urls.markasread}}}">{{#pix}}t/markasread, core, {{#str}}markalldread, mod_forum{{/str}}{{/pix}}</a>
|
||||
{{/unread}}
|
||||
{{^unread}}
|
||||
<span class="p-3 w-100 h-100 d-block">
|
||||
0
|
||||
</span>
|
||||
{{/unread}}
|
||||
</td>
|
||||
{{/forum.userstate.tracked}}
|
||||
{{/forum.capabilities.viewdiscussions}}
|
||||
<td scope="col" class="text-left">
|
||||
{{! TODO Check q&a, eachuser }}
|
||||
{{#latestpostid}}
|
||||
<div class="d-flex flex-row">
|
||||
<div class="align-middle p-0">
|
||||
<a href="{{latestpostauthor.urls.profile}}">
|
||||
<img {{!
|
||||
}} class="h-auto rounded-circle userpicture" {{!
|
||||
}} src="{{latestpostauthor.urls.profileimage}}" {{!
|
||||
}} alt="{{#str}}pictureof, moodle, {{latestpostauthor.fullname}}{{/str}}" {{!
|
||||
}}>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-2 p-t-0 p-b-0 d-inline-flex flex-column">
|
||||
<div>
|
||||
<a href="{{latestpostauthor.urls.profile}}">{{latestpostauthor.fullname}}</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{{discussion.urls.viewlatest}}}">{{#userdate}}
|
||||
{{discussion.times.modified}}, {{#str}}strftimerecentfull{{/str}}
|
||||
{{/userdate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/latestpostid}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/summaries}}
|
||||
</tbody>
|
||||
{{/discussion_list_body}}
|
||||
</table>
|
||||
{{#pageno}}
|
||||
<a href="{{{prev_page_link}}}">Previous</a>
|
||||
{{/pageno}}
|
||||
{{#more_pages}}
|
||||
<a href="{{{next_page_link}}}">Next</a>
|
||||
{{/more_pages}}
|
||||
{{#can_create_discussion}}
|
||||
<div class="forumaddnew">
|
||||
<a href="{{create_discussion_link}}" class="btn btn-primary">{{create_discussion_link_text}}</a>
|
||||
</div>
|
||||
{{/can_create_discussion}}
|
||||
{{/state.hasdiscussions}}
|
||||
{{^state.hasdiscussions}}
|
||||
<div class="forumnodiscuss">
|
||||
{{$no_discussions_text}}
|
||||
({{#str}}nodiscussions, forum{{/str}})
|
||||
{{/no_discussions_text}}
|
||||
</div>
|
||||
{{/state.hasdiscussions}}
|
||||
|
||||
</span>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
|
||||
{{#html}}
|
||||
{{{subscribe}}}
|
||||
{{{neighbourlinks}}}
|
||||
|
||||
<div class="d-flex flex-wrap m-b-1">
|
||||
<div>{{{exportdiscussion}}}</div>
|
||||
<div class="{{#exportdiscussion}}ml-2{{/exportdiscussion}}">{{{modeselectorform}}}</div>
|
||||
<div class="ml-2">{{{movediscussion}}}</div>
|
||||
<div class="ml-2">{{{pindiscussion}}}</div>
|
||||
</div>
|
||||
{{/html}}
|
||||
|
||||
{{#notifications}}
|
||||
{{> core/notification}}
|
||||
{{/notifications}}
|
||||
|
||||
{{{html.posts}}}
|
||||
|
||||
{{#html.neighbourlinks}}{{{.}}}{{/html.neighbourlinks}}
|
||||
@@ -0,0 +1,40 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{< mod_forum/forum_discussion_post }}
|
||||
{{$replies}}
|
||||
<div class="indent">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_nested_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
{{/replies}}
|
||||
{{/ mod_forum/forum_discussion_post }}
|
||||
@@ -0,0 +1,34 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{#posts}}
|
||||
{{> mod_forum/forum_discussion_nested_post }}
|
||||
{{/posts}}
|
||||
@@ -0,0 +1,175 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<article id="p{{id}}" class="relativelink mb-2" tabindex="-1" data-post-id="{{id}}">
|
||||
|
||||
<div class="d-flex border p-2 mb-2 forumpost {{#unread}}unread{{/unread}}">
|
||||
{{#isfirstunread}}<a id="unread"></a>{{/isfirstunread}}
|
||||
<div style="width: 45px;">
|
||||
{{^isdeleted}}
|
||||
{{#author}}
|
||||
{{#urls.profileimage}}
|
||||
<img class="rounded-circle w-100" src="{{{.}}}">
|
||||
{{/urls.profileimage}}
|
||||
{{#groups}}
|
||||
<img class="rounded-circle w-100" src="{{{urls.image}}}">
|
||||
{{/groups}}
|
||||
{{/author}}
|
||||
{{/isdeleted}}
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column ml-2 w-100">
|
||||
<header class="mb-2 header row">
|
||||
<h3 class="h6 font-weight-bold mb-0">{{$subject}}{{{subject}}}{{/subject}}</h3>
|
||||
{{^isdeleted}}
|
||||
<address>
|
||||
{{{html.authorsubheading}}}
|
||||
</address>
|
||||
{{/isdeleted}}
|
||||
</header>
|
||||
<div>
|
||||
{{{message}}}
|
||||
</div>
|
||||
|
||||
{{^isdeleted}}
|
||||
{{#haswordcount}}
|
||||
<p class="font-italic mb-0"><small>{{#str}} numwords, core, {{wordcount}} {{/str}}</small></p>
|
||||
{{/haswordcount}}
|
||||
|
||||
{{#attachments}}
|
||||
{{#isimage}}
|
||||
<div>
|
||||
<img src="{{{url}}}" alt="{{filename}}" style="max-width: 100%">
|
||||
{{#urls.export}}
|
||||
<a href="{{{.}}}" title="{{#str}} addtoportfolio, core_portfolio {{/str}}">
|
||||
{{#pix}} t/portfolioadd, core {{/pix}}
|
||||
</a>
|
||||
{{/urls.export}}
|
||||
{{#html.plagiarism}}
|
||||
<div>{{{.}}}</div>
|
||||
{{/html.plagiarism}}
|
||||
</div>
|
||||
{{/isimage}}
|
||||
{{/attachments}}
|
||||
|
||||
{{{html.taglist}}}
|
||||
|
||||
{{#attachments}}
|
||||
{{^isimage}}
|
||||
<div>
|
||||
<a href="{{{url}}}">{{#pix}} {{icon}}, core {{/pix}} {{filename}}</a>
|
||||
{{#urls.export}}
|
||||
<a href="{{{.}}}" title="{{#str}} addtoportfolio, core_portfolio {{/str}}">
|
||||
{{#pix}} t/portfolioadd, core {{/pix}}
|
||||
</a>
|
||||
{{/urls.export}}
|
||||
{{#html.plagiarism}}
|
||||
<div>{{{.}}}</div>
|
||||
{{/html.plagiarism}}
|
||||
</div>
|
||||
{{/isimage}}
|
||||
{{/attachments}}
|
||||
|
||||
{{#html.rating}}
|
||||
<div class="mt-2">{{{.}}}</div>
|
||||
{{/html.rating}}
|
||||
|
||||
{{$actions}}
|
||||
{{^readonly}}
|
||||
<div class="d-flex justify-content-end">
|
||||
{{#capabilities}}
|
||||
{{#view}}
|
||||
<a href="{{{urls.view}}}" class="btn btn-link">
|
||||
{{#str}} permalink, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/view}}
|
||||
{{#controlreadstatus}}
|
||||
{{#unread}}
|
||||
<a href="{{{urls.markasread}}}" class="btn btn-link">
|
||||
{{#str}} markread, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/unread}}
|
||||
{{^unread}}
|
||||
<a href="{{{urls.markasunread}}}" class="btn btn-link">
|
||||
{{#str}} markunread, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/unread}}
|
||||
{{/controlreadstatus}}
|
||||
{{#urls.viewparent}}
|
||||
<a href="{{{.}}}" class="btn btn-link">
|
||||
{{#str}} parent, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/urls.viewparent}}
|
||||
{{#edit}}
|
||||
<a href="{{{urls.edit}}}" class="btn btn-link">
|
||||
{{#str}} edit, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/edit}}
|
||||
{{#split}}
|
||||
<a href="{{{urls.split}}}" class="btn btn-link">
|
||||
{{#str}} prune, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/split}}
|
||||
{{#delete}}
|
||||
<a href="{{{urls.delete}}}" class="btn btn-link">
|
||||
{{#str}} delete, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/delete}}
|
||||
{{#reply}}
|
||||
<a href="{{{urls.reply}}}" class="btn btn-link">
|
||||
{{#str}} reply, mod_forum {{/str}}
|
||||
</a>
|
||||
{{/reply}}
|
||||
{{#export}}
|
||||
<a href="{{{urls.export}}}" class="btn btn-link">
|
||||
{{#str}} addtoportfolio, core_portfolio {{/str}}
|
||||
</a>
|
||||
{{/export}}
|
||||
{{/capabilities}}
|
||||
</div>
|
||||
{{/readonly}}
|
||||
{{/actions}}
|
||||
|
||||
{{$footer}}{{/footer}}
|
||||
{{/isdeleted}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{$replies}}
|
||||
{{#hasreplies}}
|
||||
<div>
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
{{/hasreplies}}
|
||||
{{/replies}}
|
||||
</article>
|
||||
@@ -0,0 +1,34 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{#posts}}
|
||||
{{> mod_forum/forum_discussion_post }}
|
||||
{{/posts}}
|
||||
@@ -0,0 +1,45 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div class="mb-2" data-post-id="{{id}}">
|
||||
<a href="{{{urls.viewisolated}}}">{{subject}}</a>
|
||||
{{^isdeleted}}
|
||||
<address class="d-inline-block mb-0">
|
||||
{{{html.authorsubheading}}}
|
||||
</address>
|
||||
{{/isdeleted}}
|
||||
|
||||
<div class="indent">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_threaded_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
|
||||
{{#posts}}
|
||||
{{< mod_forum/forum_discussion_post }}
|
||||
{{$replies}}
|
||||
<div class="indent">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_threaded_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
{{/replies}}
|
||||
{{/ mod_forum/forum_discussion_post }}
|
||||
{{/posts}}
|
||||
@@ -0,0 +1,71 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{#posts}}
|
||||
{{< mod_forum/forum_discussion_post }}
|
||||
{{$subject}}
|
||||
{{#coursename}}
|
||||
{{#urls.viewcourse}}
|
||||
<a href="{{{urls.viewcourse}}}">{{{coursename}}}</a> ->
|
||||
{{/urls.viewcourse}}
|
||||
{{^urls.viewcourse}}
|
||||
{{coursename}} ->
|
||||
{{/urls.viewcourse}}
|
||||
{{/coursename}}
|
||||
{{#urls.viewforum}}
|
||||
<a href="{{{urls.viewforum}}}">{{{forumname}}}</a>
|
||||
{{/urls.viewforum}}
|
||||
{{^urls.viewforum}}
|
||||
{{{forumname}}}
|
||||
{{/urls.viewforum}}
|
||||
{{#showdiscussionname}}
|
||||
{{#urls.viewdiscussion}}
|
||||
-> <a href="{{{urls.viewdiscussion}}}">{{{discussionname}}}</a>
|
||||
{{/urls.viewdiscussion}}
|
||||
{{^urls.viewdiscussion}}
|
||||
{{{discussionname}}}
|
||||
{{/urls.viewdiscussion}}
|
||||
{{#hasparent}}
|
||||
{{#urls.viewparent}}
|
||||
-> <a href="{{{urls.viewparent}}}">{{{subject}}}</a>
|
||||
{{/urls.viewparent}}
|
||||
{{^urls.viewparent}}
|
||||
{{{subject}}}
|
||||
{{/urls.viewparent}}
|
||||
{{/hasparent}}
|
||||
{{/showdiscussionname}}
|
||||
{{/subject}}
|
||||
{{$replies}}{{/replies}}
|
||||
{{$footer}}
|
||||
<div><a href="{{{urls.view}}}">{{#str}} postincontext, mod_forum {{/str}}</a></div>
|
||||
{{/footer}}
|
||||
{{/ mod_forum/forum_discussion_post }}
|
||||
{{/posts}}
|
||||
@@ -0,0 +1,39 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/qanda_discussion_list
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{< mod_forum/discussion_list }}
|
||||
{{$discussion_create_text}}
|
||||
{{#str}}addanewtopic, forum{{/str}}
|
||||
{{/discussion_create_text}}
|
||||
{{$no_discussions_text}}
|
||||
({{#str}}nonews, forum{{/str}})
|
||||
{{/no_discussions_text}}
|
||||
{{/ mod_forum/discussion_list }}
|
||||
@@ -0,0 +1,39 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_forum/qanda_discussion_list
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{< mod_forum/discussion_list }}
|
||||
{{$discussion_create_text}}
|
||||
{{#str}}addanewquestion, forum{{/str}}
|
||||
{{/discussion_create_text}}
|
||||
{{$no_discussions_text}}
|
||||
({{#str}}noquestions, forum{{/str}})
|
||||
{{/no_discussions_text}}
|
||||
{{/ mod_forum/discussion_list }}
|
||||
@@ -0,0 +1,524 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The exported_posts builder tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The exported_posts builder tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_builders_exported_posts_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/** @var \mod_forum\local\builders\exported_posts */
|
||||
private $builder;
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||||
// tests using these functions.
|
||||
\mod_forum\subscriptions::reset_forum_cache();
|
||||
|
||||
$builderfactory = \mod_forum\local\container::get_builder_factory();
|
||||
$this->builder = $builderfactory->get_exported_posts_builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down function for tests.
|
||||
*/
|
||||
public function tearDown() {
|
||||
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||||
// tests using these functions.
|
||||
\mod_forum\subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the stdClass values into their proper entity classes.
|
||||
*
|
||||
* @param stdClass[] $forums List of forums
|
||||
* @param stdClass[] $discussions List of discussions
|
||||
* @param stdClass[] $posts List of posts
|
||||
* @return array
|
||||
*/
|
||||
private function convert_to_entities(array $forums, array $discussions, array $posts) {
|
||||
global $DB;
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
|
||||
return [
|
||||
// Forums.
|
||||
array_map(function($forum) use ($entityfactory, $DB) {
|
||||
$course = $DB->get_record('course', ['id' => $forum->course]);
|
||||
$coursemodule = get_coursemodule_from_instance('forum', $forum->id);
|
||||
$context = context_module::instance($coursemodule->id);
|
||||
return $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
}, $forums),
|
||||
// Discussions.
|
||||
array_map(function($discussion) use ($entityfactory) {
|
||||
return $entityfactory->get_discussion_from_stdclass($discussion);
|
||||
}, $discussions),
|
||||
// Posts.
|
||||
array_map(function($post) use ($entityfactory) {
|
||||
return $entityfactory->get_post_from_stdclass($post);
|
||||
}, $posts)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function throws exception if not given all of the forums for
|
||||
* the list of posts.
|
||||
*/
|
||||
public function test_build_throws_exception_on_missing_forums() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_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, $user);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum2, $user);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2],
|
||||
[$post1, $post2]
|
||||
);
|
||||
|
||||
$this->expectException('moodle_exception');
|
||||
$this->builder->build($user, [$forums[0]], $discussions, $posts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function throws exception if not given all of the discussions for
|
||||
* the list of posts.
|
||||
*/
|
||||
public function test_build_throws_exception_on_missing_discussions() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_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, $user);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum2, $user);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2],
|
||||
[$post1, $post2]
|
||||
);
|
||||
|
||||
$this->expectException('moodle_exception');
|
||||
$this->builder->build($user, $forums, [$discussions[0]], $posts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function returns the exported posts in the order that the posts are
|
||||
* given.
|
||||
*/
|
||||
public function test_build_returns_posts_in_order() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_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);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
$post7 = $this->helper_reply_to_post($post2, $user1);
|
||||
$post8 = $this->helper_reply_to_post($post2, $user2);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8]
|
||||
);
|
||||
|
||||
// Randomly order the posts.
|
||||
shuffle($posts);
|
||||
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
$expectedpostids = array_map(function($post) {
|
||||
return $post->get_id();
|
||||
}, $posts);
|
||||
$actualpostids = array_map(function($exportedpost) {
|
||||
return (int) $exportedpost->id;
|
||||
}, $exportedposts);
|
||||
|
||||
$this->assertEquals($expectedpostids, $actualpostids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function loads authors.
|
||||
*/
|
||||
public function test_build_loads_authors() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$user3 = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_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);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
// These 2 replies from user 3 won't be inlcuded in the export.
|
||||
$post7 = $this->helper_reply_to_post($post2, $user3);
|
||||
$post8 = $this->helper_reply_to_post($post2, $user3);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6]
|
||||
);
|
||||
|
||||
$datagenerator->enrol_user($user1->id, $course->id);
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
// We didn't include any posts from user 3 so we shouldn't see the authors
|
||||
// that match that user.
|
||||
$expectedids = [$user1->id, $user2->id];
|
||||
$actualids = array_unique(array_map(function($exportedpost) {
|
||||
return (int) $exportedpost->author->id;
|
||||
}, $exportedposts));
|
||||
|
||||
sort($expectedids);
|
||||
sort($actualids);
|
||||
|
||||
$this->assertEquals($expectedids, $actualids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function loads attachments.
|
||||
*/
|
||||
public function test_build_loads_attachments() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$user3 = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_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);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
$post7 = $this->helper_reply_to_post($post5, $user3);
|
||||
$post8 = $this->helper_reply_to_post($post5, $user3);
|
||||
$filestorage = get_file_storage();
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8]
|
||||
);
|
||||
|
||||
// Add an attachment to a post in forum 1.
|
||||
$attachment1 = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $forums[0]->get_context()->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'itemid' => $post1->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
// Add an attachment to a post in forum 2.
|
||||
$attachment2 = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $forums[1]->get_context()->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'itemid' => $post7->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example2.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
// Enrol the user so that they can see the posts.
|
||||
$datagenerator->enrol_user($user1->id, $course->id);
|
||||
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
$expected = ['example1.jpg', 'example2.jpg'];
|
||||
$actual = array_reduce($exportedposts, function($carry, $exportedpost) {
|
||||
if (!empty($exportedpost->attachments)) {
|
||||
foreach ($exportedpost->attachments as $attachment) {
|
||||
$carry[] = $attachment->filename;
|
||||
}
|
||||
}
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
sort($expected);
|
||||
sort($actual);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function loads author groups.
|
||||
*/
|
||||
public function test_build_loads_author_groups() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$user3 = $datagenerator->create_user();
|
||||
$course1 = $datagenerator->create_course();
|
||||
$course2 = $datagenerator->create_course();
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course1->id]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course1->id]);
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
$post7 = $this->helper_reply_to_post($post5, $user3);
|
||||
$post8 = $this->helper_reply_to_post($post5, $user3);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8]
|
||||
);
|
||||
|
||||
// Enrol the user so that they can see the posts.
|
||||
$datagenerator->enrol_user($user1->id, $course1->id);
|
||||
$datagenerator->enrol_user($user1->id, $course2->id);
|
||||
$datagenerator->enrol_user($user2->id, $course1->id);
|
||||
$datagenerator->enrol_user($user2->id, $course2->id);
|
||||
$datagenerator->enrol_user($user3->id, $course1->id);
|
||||
$datagenerator->enrol_user($user3->id, $course2->id);
|
||||
|
||||
$group1 = $datagenerator->create_group(['courseid' => $course1->id]);
|
||||
$group2 = $datagenerator->create_group(['courseid' => $course1->id]);
|
||||
// This group shouldn't be included in the results since it's in a different course.
|
||||
$group3 = $datagenerator->create_group(['courseid' => $course2->id]);
|
||||
|
||||
$datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group1->id]);
|
||||
$datagenerator->create_group_member(['userid' => $user2->id, 'groupid' => $group1->id]);
|
||||
$datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group2->id]);
|
||||
$datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group3->id]);
|
||||
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
$expected = [
|
||||
$user1->id => [$group1->id, $group2->id],
|
||||
$user2->id => [$group1->id],
|
||||
$user3->id => []
|
||||
];
|
||||
$actual = array_reduce($exportedposts, function($carry, $exportedpost) {
|
||||
$author = $exportedpost->author;
|
||||
$authorid = $author->id;
|
||||
|
||||
if (!isset($carry[$authorid])) {
|
||||
$carry[$authorid] = array_map(function($group) {
|
||||
return $group['id'];
|
||||
}, $author->groups);
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function loads tags.
|
||||
*/
|
||||
public function test_build_loads_tags() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user();
|
||||
$user2 = $datagenerator->create_user();
|
||||
$user3 = $datagenerator->create_user();
|
||||
$course1 = $datagenerator->create_course();
|
||||
$course2 = $datagenerator->create_course();
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course1->id]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course1->id]);
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
$post7 = $this->helper_reply_to_post($post5, $user3);
|
||||
$post8 = $this->helper_reply_to_post($post5, $user3);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8]
|
||||
);
|
||||
|
||||
// Enrol the user so that they can see the posts.
|
||||
$datagenerator->enrol_user($user1->id, $course1->id);
|
||||
$datagenerator->enrol_user($user1->id, $course2->id);
|
||||
$datagenerator->enrol_user($user2->id, $course1->id);
|
||||
$datagenerator->enrol_user($user2->id, $course2->id);
|
||||
$datagenerator->enrol_user($user3->id, $course1->id);
|
||||
$datagenerator->enrol_user($user3->id, $course2->id);
|
||||
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post1->id, $forums[0]->get_context(), ['foo', 'bar']);
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post4->id, $forums[0]->get_context(), ['foo', 'baz']);
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post7->id, $forums[1]->get_context(), ['bip']);
|
||||
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
$expected = [
|
||||
$post1->id => ['foo', 'bar'],
|
||||
$post4->id => ['foo', 'baz'],
|
||||
$post7->id => ['bip']
|
||||
];
|
||||
$actual = array_reduce($exportedposts, function($carry, $exportedpost) {
|
||||
if (!empty($exportedpost->tags)) {
|
||||
$carry[$exportedpost->id] = array_map(function($tag) {
|
||||
return $tag['displayname'];
|
||||
}, $exportedpost->tags);
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the build function loads read_receipts.
|
||||
*/
|
||||
public function test_build_loads_read_receipts() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user1 = $datagenerator->create_user(['trackforums' => 1]);
|
||||
$user2 = $datagenerator->create_user(['trackforums' => 0]);
|
||||
$course1 = $datagenerator->create_course();
|
||||
$course2 = $datagenerator->create_course();
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course1->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course1->id, 'trackingtype' => FORUM_TRACKING_OFF]);
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user1);
|
||||
$post4 = $this->helper_reply_to_post($post1, $user2);
|
||||
[$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1);
|
||||
[$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2);
|
||||
$post7 = $this->helper_reply_to_post($post5, $user1);
|
||||
$post8 = $this->helper_reply_to_post($post5, $user1);
|
||||
|
||||
[$forums, $discussions, $posts] = $this->convert_to_entities(
|
||||
[$forum1, $forum2],
|
||||
[$discussion1, $discussion2, $discussion3, $discussion4],
|
||||
[$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8]
|
||||
);
|
||||
|
||||
// Enrol the user so that they can see the posts.
|
||||
$datagenerator->enrol_user($user1->id, $course1->id);
|
||||
$datagenerator->enrol_user($user1->id, $course2->id);
|
||||
$datagenerator->enrol_user($user2->id, $course1->id);
|
||||
$datagenerator->enrol_user($user2->id, $course2->id);
|
||||
|
||||
forum_tp_add_read_record($user1->id, $post1->id);
|
||||
forum_tp_add_read_record($user1->id, $post4->id);
|
||||
forum_tp_add_read_record($user1->id, $post7->id);
|
||||
forum_tp_add_read_record($user2->id, $post1->id);
|
||||
forum_tp_add_read_record($user2->id, $post4->id);
|
||||
forum_tp_add_read_record($user2->id, $post7->id);
|
||||
|
||||
// User 1 has tracking enabled.
|
||||
$exportedposts = $this->builder->build($user1, $forums, $discussions, $posts);
|
||||
|
||||
$expected = [
|
||||
// Tracking set for forum 1 for user 1.
|
||||
$post1->id => false,
|
||||
$post2->id => true,
|
||||
$post3->id => true,
|
||||
$post4->id => false,
|
||||
// Tracking is off for forum 2 so everything should be null.
|
||||
$post5->id => null,
|
||||
$post6->id => null,
|
||||
$post7->id => null,
|
||||
$post8->id => null
|
||||
];
|
||||
$actual = array_reduce($exportedposts, function($carry, $exportedpost) {
|
||||
$carry[$exportedpost->id] = $exportedpost->unread;
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
// User 2 has tracking disabled.
|
||||
$exportedposts = $this->builder->build($user2, $forums, $discussions, $posts);
|
||||
|
||||
// Tracking is off for user 2 so everything should be null.
|
||||
$expected = [
|
||||
$post1->id => null,
|
||||
$post2->id => null,
|
||||
$post3->id => null,
|
||||
$post4->id => null,
|
||||
$post5->id => null,
|
||||
$post6->id => null,
|
||||
$post7->id => null,
|
||||
$post8->id => null
|
||||
];
|
||||
$actual = array_reduce($exportedposts, function($carry, $exportedpost) {
|
||||
$carry[$exportedpost->id] = $exportedpost->unread;
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Coverage information for the mod_forum component.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @category phpunit
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Coverage information for the core subsystem.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
return new class extends phpunit_coverage_info {
|
||||
/** @var array The list of folders relative to the plugin root to whitelist in coverage generation. */
|
||||
protected $whitelistfolders = [
|
||||
'classes/local',
|
||||
];
|
||||
|
||||
/** @var array The list of files relative to the plugin root to whitelist in coverage generation. */
|
||||
protected $whitelistfiles = [];
|
||||
|
||||
/** @var array The list of folders relative to the plugin root to excludelist in coverage generation. */
|
||||
protected $excludelistfolders = [];
|
||||
|
||||
/** @var array The list of files relative to the plugin root to excludelist in coverage generation. */
|
||||
protected $excludelistfiles = [];
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The author entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
|
||||
/**
|
||||
* The author entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_author_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$author = new author_entity(
|
||||
1,
|
||||
2,
|
||||
'test',
|
||||
'person',
|
||||
'test person',
|
||||
'[email protected]',
|
||||
'middle',
|
||||
'tteeeeest',
|
||||
'ppppeeerssson',
|
||||
'maverick',
|
||||
'image alt'
|
||||
);
|
||||
|
||||
$this->assertEquals(1, $author->get_id());
|
||||
$this->assertEquals(2, $author->get_picture_item_id());
|
||||
$this->assertEquals('test', $author->get_first_name());
|
||||
$this->assertEquals('person', $author->get_last_name());
|
||||
$this->assertEquals('test person', $author->get_full_name());
|
||||
$this->assertEquals('[email protected]', $author->get_email());
|
||||
$this->assertEquals('middle', $author->get_middle_name());
|
||||
$this->assertEquals('tteeeeest', $author->get_first_name_phonetic());
|
||||
$this->assertEquals('ppppeeerssson', $author->get_last_name_phonetic());
|
||||
$this->assertEquals('maverick', $author->get_alternate_name());
|
||||
$this->assertEquals('image alt', $author->get_image_alt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion_summary entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\discussion_summary as discussion_summary_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
|
||||
/**
|
||||
* The discussion_summary entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_discussion_summary_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$firstauthor = new author_entity(
|
||||
1,
|
||||
2,
|
||||
'test',
|
||||
'person',
|
||||
'test person',
|
||||
'[email protected]'
|
||||
);
|
||||
$lastauthor = new author_entity(
|
||||
2,
|
||||
3,
|
||||
'test 2',
|
||||
'person 2',
|
||||
'test 2 person 2',
|
||||
'[email protected]'
|
||||
);
|
||||
$discussion = new discussion_entity(
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
'test discussion',
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
false,
|
||||
time(),
|
||||
time(),
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
$firstpost = new post_entity(
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
time(),
|
||||
time(),
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
$discussionsummary = new discussion_summary_entity($discussion, $firstpost, $firstauthor, $lastauthor);
|
||||
|
||||
$this->assertEquals($discussion, $discussionsummary->get_discussion());
|
||||
$this->assertEquals($firstauthor, $discussionsummary->get_first_post_author());
|
||||
$this->assertEquals($lastauthor, $discussionsummary->get_latest_post_author());
|
||||
$this->assertEquals($firstpost, $discussionsummary->get_first_post());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
|
||||
/**
|
||||
* The discussion entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_discussion_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// In the past to ensure the time started is true.
|
||||
$time = time() + 10;
|
||||
$discussion = new discussion_entity(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
'test discussion',
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
false,
|
||||
$time,
|
||||
$time,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
$firstpost = new post_entity(
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
time(),
|
||||
time(),
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
$notfirstpost = new post_entity(
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
time(),
|
||||
time(),
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
$this->assertEquals(1, $discussion->get_id());
|
||||
$this->assertEquals(2, $discussion->get_course_id());
|
||||
$this->assertEquals(3, $discussion->get_forum_id());
|
||||
$this->assertEquals('test discussion', $discussion->get_name());
|
||||
$this->assertEquals(4, $discussion->get_first_post_id());
|
||||
$this->assertEquals(5, $discussion->get_user_id());
|
||||
$this->assertEquals(6, $discussion->get_group_id());
|
||||
$this->assertEquals(false, $discussion->is_assessed());
|
||||
$this->assertEquals($time, $discussion->get_time_modified());
|
||||
$this->assertEquals($time, $discussion->get_user_modified());
|
||||
$this->assertEquals(0, $discussion->get_time_start());
|
||||
$this->assertEquals(0, $discussion->get_time_end());
|
||||
$this->assertEquals(false, $discussion->is_pinned());
|
||||
$this->assertEquals(true, $discussion->is_first_post($firstpost));
|
||||
$this->assertEquals(false, $discussion->is_first_post($notfirstpost));
|
||||
$this->assertEquals(true, $discussion->has_started());
|
||||
$this->assertEquals(true, $discussion->has_group());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The forum entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
|
||||
/**
|
||||
* The forum entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_forum_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$time = time() - 10;
|
||||
$discussion = new discussion_entity(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
'test discussion',
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
false,
|
||||
$time,
|
||||
$time,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
$past = time() - 100;
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
|
||||
$coursemodule = get_coursemodule_from_instance('forum', $forum->id);
|
||||
$context = context_module::instance($coursemodule->id);
|
||||
$effectivegroupmode = NOGROUPS;
|
||||
$id = 1;
|
||||
$courseid = 2;
|
||||
$type = 'standard';
|
||||
$name = 'test forum';
|
||||
$intro = 'this is the intro';
|
||||
$introformat = FORMAT_MOODLE;
|
||||
$assessed = RATING_AGGREGATE_NONE;
|
||||
$assesstimestart = 0;
|
||||
$assesstimefinish = 0;
|
||||
$scale = 0;
|
||||
$maxbytes = 200;
|
||||
$maxattachments = 5;
|
||||
$forcesubscribe = false;
|
||||
$trackingtype = 1;
|
||||
$rsstype = 0;
|
||||
$rssarticles = 0;
|
||||
$timemodified = $past;
|
||||
$warnafter = 0;
|
||||
$blockafter = 0;
|
||||
$blockperiod = 0;
|
||||
$completiondiscussions = 0;
|
||||
$completionreplies = 0;
|
||||
$completionposts = 0;
|
||||
$displaywordcount = false;
|
||||
$lockdiscussionafter = 0;
|
||||
|
||||
$forum = new forum_entity(
|
||||
$context,
|
||||
$coursemodule,
|
||||
$course,
|
||||
$effectivegroupmode,
|
||||
$id,
|
||||
$courseid,
|
||||
$type,
|
||||
$name,
|
||||
$intro,
|
||||
$introformat,
|
||||
$assessed,
|
||||
$assesstimestart,
|
||||
$assesstimefinish,
|
||||
$scale,
|
||||
$maxbytes,
|
||||
$maxattachments,
|
||||
$forcesubscribe,
|
||||
$trackingtype,
|
||||
$rsstype,
|
||||
$rssarticles,
|
||||
$timemodified,
|
||||
$warnafter,
|
||||
$blockafter,
|
||||
$blockperiod,
|
||||
$completiondiscussions,
|
||||
$completionreplies,
|
||||
$completionposts,
|
||||
$displaywordcount,
|
||||
$lockdiscussionafter
|
||||
);
|
||||
|
||||
$this->assertEquals($context, $forum->get_context());
|
||||
$this->assertEquals($coursemodule, $forum->get_course_module_record());
|
||||
$this->assertEquals($coursemodule, $forum->get_course_module_record());
|
||||
$this->assertEquals($effectivegroupmode, $forum->get_effective_group_mode());
|
||||
$this->assertEquals(false, $forum->is_in_group_mode());
|
||||
$this->assertEquals($course, $forum->get_course_record());
|
||||
$this->assertEquals($id, $forum->get_id());
|
||||
$this->assertEquals($courseid, $forum->get_course_id());
|
||||
$this->assertEquals($name, $forum->get_name());
|
||||
$this->assertEquals($intro, $forum->get_intro());
|
||||
$this->assertEquals($introformat, $forum->get_intro_format());
|
||||
$this->assertEquals($assessed, $forum->get_rating_aggregate());
|
||||
// Rating aggregate is set to none.
|
||||
$this->assertEquals(false, $forum->has_rating_aggregate());
|
||||
$this->assertEquals($assesstimestart, $forum->get_assess_time_start());
|
||||
$this->assertEquals($assesstimefinish, $forum->get_assess_time_finish());
|
||||
$this->assertEquals($scale, $forum->get_scale());
|
||||
$this->assertEquals($maxbytes, $forum->get_max_bytes());
|
||||
$this->assertEquals($maxattachments, $forum->get_max_attachments());
|
||||
$this->assertEquals($forcesubscribe, $forum->is_subscription_forced());
|
||||
$this->assertEquals($trackingtype, $forum->get_tracking_type());
|
||||
$this->assertEquals($rsstype, $forum->get_rss_type());
|
||||
$this->assertEquals($rssarticles, $forum->get_rss_articles());
|
||||
$this->assertEquals($timemodified, $forum->get_time_modified());
|
||||
$this->assertEquals($warnafter, $forum->get_warn_after());
|
||||
$this->assertEquals($blockafter, $forum->get_block_after());
|
||||
$this->assertEquals($blockperiod, $forum->get_block_period());
|
||||
$this->assertEquals(false, $forum->has_blocking_enabled());
|
||||
$this->assertEquals($completiondiscussions, $forum->get_completion_discussions());
|
||||
$this->assertEquals($completionreplies, $forum->get_completion_replies());
|
||||
$this->assertEquals($completionposts, $forum->get_completion_posts());
|
||||
$this->assertEquals($displaywordcount, $forum->should_display_word_count());
|
||||
$this->assertEquals($lockdiscussionafter, $forum->get_lock_discussions_after());
|
||||
$this->assertEquals(false, $forum->has_lock_discussions_after());
|
||||
$this->assertEquals(false, $forum->is_discussion_locked($discussion));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post_read_receipt_collection entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post_read_receipt_collection as collection_entity;
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
|
||||
/**
|
||||
* The post_read_receipt_collection entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_post_read_receipt_collection_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$missingpost = new post_entity(
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
time(),
|
||||
time(),
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
$post = new post_entity(
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
time(),
|
||||
time(),
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
$collection = new collection_entity([
|
||||
(object) [
|
||||
'postid' => 1,
|
||||
'userid' => $user->id + 1
|
||||
],
|
||||
(object) [
|
||||
'postid' => 1,
|
||||
'userid' => $user->id
|
||||
],
|
||||
(object) [
|
||||
'postid' => 4,
|
||||
'userid' => $user->id + 1
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(true, $collection->has_user_read_post($user, $post));
|
||||
$this->assertEquals(false, $collection->has_user_read_post($user, $missingpost));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\post as post_entity;
|
||||
|
||||
/**
|
||||
* The post entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_post_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$owner = $this->getDataGenerator()->create_user();
|
||||
$notowner = $this->getDataGenerator()->create_user();
|
||||
$past = time() - 10;
|
||||
$post = new post_entity(
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
$owner->id,
|
||||
$past,
|
||||
$past,
|
||||
true,
|
||||
'post subject',
|
||||
'post message',
|
||||
FORMAT_MOODLE,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
$this->assertEquals(4, $post->get_id());
|
||||
$this->assertEquals(1, $post->get_discussion_id());
|
||||
$this->assertEquals(0, $post->get_parent_id());
|
||||
$this->assertEquals(false, $post->has_parent());
|
||||
$this->assertEquals($owner->id, $post->get_author_id());
|
||||
$this->assertEquals($past, $post->get_time_created());
|
||||
$this->assertEquals($past, $post->get_time_modified());
|
||||
$this->assertEquals(true, $post->has_been_mailed());
|
||||
$this->assertEquals('post subject', $post->get_subject());
|
||||
$this->assertEquals('post message', $post->get_message());
|
||||
$this->assertEquals(FORMAT_MOODLE, $post->get_message_format());
|
||||
$this->assertEquals(true, $post->is_message_trusted());
|
||||
$this->assertEquals(false, $post->has_attachments());
|
||||
$this->assertEquals(0, $post->get_total_score());
|
||||
$this->assertEquals(false, $post->should_mail_now());
|
||||
$this->assertEquals(false, $post->is_deleted());
|
||||
$this->assertTrue($post->get_age() >= 10);
|
||||
$this->assertEquals(true, $post->is_owned_by_user($owner));
|
||||
$this->assertEquals(false, $post->is_owned_by_user($notowner));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\sorter as sorter_entity;
|
||||
|
||||
/**
|
||||
* The discussion entity tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_entities_sorter_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity_sort_into_children() {
|
||||
$this->resetAfterTest();
|
||||
$sorter = new sorter_entity(
|
||||
function($entity) {
|
||||
return $entity['id'];
|
||||
},
|
||||
function($entity) {
|
||||
return $entity['parent'];
|
||||
}
|
||||
);
|
||||
|
||||
$a = ['id' => 1, 'parent' => 0];
|
||||
$b = ['id' => 2, 'parent' => 1];
|
||||
$c = ['id' => 3, 'parent' => 1];
|
||||
$d = ['id' => 4, 'parent' => 2];
|
||||
|
||||
$expected = [
|
||||
[$a, [[$b, [[$d, []]]], [$c, []]]]
|
||||
];
|
||||
|
||||
$actual = $sorter->sort_into_children([$d, $b, $a, $c]);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the entity returns expected values.
|
||||
*/
|
||||
public function test_entity_flatten_children() {
|
||||
$this->resetAfterTest();
|
||||
$sorter = new sorter_entity(
|
||||
function($entity) {
|
||||
return $entity['id'];
|
||||
},
|
||||
function($entity) {
|
||||
return $entity['parent'];
|
||||
}
|
||||
);
|
||||
|
||||
$a = ['id' => 1, 'parent' => 0];
|
||||
$b = ['id' => 2, 'parent' => 1];
|
||||
$c = ['id' => 3, 'parent' => 1];
|
||||
$d = ['id' => 4, 'parent' => 3];
|
||||
|
||||
$sorted = [
|
||||
[$a, [[$b, [[$d, []]]], [$c, []]]]
|
||||
];
|
||||
|
||||
$expected = [$a, $b, $d, $c];
|
||||
$actual = $sorter->flatten_children($sorted);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The author exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\author as author_entity;
|
||||
use mod_forum\local\exporters\author as author_exporter;
|
||||
global $CFG;
|
||||
|
||||
/**
|
||||
* The author exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_exporters_author_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the export function returns expected values.
|
||||
*/
|
||||
public function test_export_author() {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$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);
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$author = new author_entity(
|
||||
1,
|
||||
1,
|
||||
'test',
|
||||
'user',
|
||||
'test user',
|
||||
'[email protected]'
|
||||
);
|
||||
|
||||
$exporter = new author_exporter($author, [], true, [
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'context' => $context
|
||||
]);
|
||||
|
||||
$exportedauthor = $exporter->export($renderer);
|
||||
|
||||
$this->assertEquals(1, $exportedauthor->id);
|
||||
$this->assertEquals('test user', $exportedauthor->fullname);
|
||||
$this->assertEquals([], $exportedauthor->groups);
|
||||
$this->assertNotEquals(null, $exportedauthor->urls['profile']);
|
||||
$this->assertNotEquals(null, $exportedauthor->urls['profileimage']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export function with groups.
|
||||
*/
|
||||
public function test_export_author_with_groups() {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$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);
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$author = new author_entity(
|
||||
1,
|
||||
1,
|
||||
'test',
|
||||
'user',
|
||||
'test user',
|
||||
'[email protected]'
|
||||
);
|
||||
|
||||
$group = $datagenerator->create_group(['courseid' => $course->id]);
|
||||
|
||||
$exporter = new author_exporter($author, [$group], true, [
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'context' => $context
|
||||
]);
|
||||
|
||||
$exportedauthor = $exporter->export($renderer);
|
||||
|
||||
$this->assertCount(1, $exportedauthor->groups);
|
||||
$this->assertEquals($group->id, $exportedauthor->groups[0]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export function with no view capability.
|
||||
*/
|
||||
public function test_export_author_no_view_capability() {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$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);
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$author = new author_entity(
|
||||
1,
|
||||
1,
|
||||
'test',
|
||||
'user',
|
||||
'test user',
|
||||
'[email protected]'
|
||||
);
|
||||
|
||||
$group = $datagenerator->create_group(['courseid' => $course->id]);
|
||||
|
||||
$exporter = new author_exporter($author, [$group], false, [
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'context' => $context
|
||||
]);
|
||||
|
||||
$exportedauthor = $exporter->export($renderer);
|
||||
|
||||
$this->assertEquals(null, $exportedauthor->id);
|
||||
$this->assertNotEquals('test user', $exportedauthor->fullname);
|
||||
$this->assertEquals([], $exportedauthor->groups);
|
||||
$this->assertEquals(null, $exportedauthor->urls['profile']);
|
||||
$this->assertEquals(null, $exportedauthor->urls['profileimage']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\discussion as discussion_entity;
|
||||
use mod_forum\local\exporters\discussion as discussion_exporter;
|
||||
|
||||
/**
|
||||
* The discussion exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_exporters_discussion_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test set up function.
|
||||
*/
|
||||
public function setUp() {
|
||||
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||||
// tests using these functions.
|
||||
\mod_forum\subscriptions::reset_forum_cache();
|
||||
|
||||
$builderfactory = \mod_forum\local\container::get_builder_factory();
|
||||
$this->builder = $builderfactory->get_exported_posts_builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tear down function.
|
||||
*/
|
||||
public function tearDown() {
|
||||
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||||
// tests using these functions.
|
||||
\mod_forum\subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export function returns expected values.
|
||||
*/
|
||||
public function test_export() {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$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);
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$group = $datagenerator->create_group(['courseid' => $course->id]);
|
||||
$now = time();
|
||||
$discussion = new discussion_entity(
|
||||
1,
|
||||
$course->id,
|
||||
$forum->get_id(),
|
||||
'test discussion',
|
||||
1,
|
||||
$user->id,
|
||||
$group->id,
|
||||
false,
|
||||
$now,
|
||||
$now,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
$exporter = new discussion_exporter($discussion, [
|
||||
'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(),
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'capabilitymanager' => (\mod_forum\local\container::get_manager_factory())->get_capability_manager($forum),
|
||||
'context' => $context,
|
||||
'forum' => $forum,
|
||||
'user' => $user,
|
||||
'groupsbyid' => [$group->id => $group],
|
||||
'latestpostid' => 7
|
||||
]);
|
||||
|
||||
$exporteddiscussion = $exporter->export($renderer);
|
||||
|
||||
$this->assertEquals(1, $exporteddiscussion->id);
|
||||
$this->assertEquals($forum->get_id(), $exporteddiscussion->forumid);
|
||||
$this->assertEquals(false, $exporteddiscussion->pinned);
|
||||
$this->assertEquals('test discussion', $exporteddiscussion->name);
|
||||
$this->assertEquals($now, $exporteddiscussion->times['modified']);
|
||||
$this->assertEquals(0, $exporteddiscussion->times['start']);
|
||||
$this->assertEquals(0, $exporteddiscussion->times['end']);
|
||||
$this->assertEquals($group->name, $exporteddiscussion->group['name']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion forum tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
use mod_forum\local\exporters\forum as forum_exporter;
|
||||
|
||||
/**
|
||||
* The discussion forum tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_exporters_forum_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test the export function returns expected values.
|
||||
*/
|
||||
public function test_export() {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', [
|
||||
'course' => $course->id,
|
||||
'groupmode' => VISIBLEGROUPS
|
||||
]);
|
||||
$coursemodule = get_coursemodule_from_instance('forum', $forum->id);
|
||||
$context = context_module::instance($coursemodule->id);
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
|
||||
$exporter = new forum_exporter($forum, [
|
||||
'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(),
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'capabilitymanager' => (\mod_forum\local\container::get_manager_factory())->get_capability_manager($forum),
|
||||
'user' => $user,
|
||||
'currentgroup' => null
|
||||
]);
|
||||
|
||||
$exportedforum = $exporter->export($renderer);
|
||||
|
||||
$this->assertEquals($forum->get_id(), $exportedforum->id);
|
||||
$this->assertEquals(VISIBLEGROUPS, $exportedforum->state['groupmode']);
|
||||
$this->assertEquals(false, $exportedforum->userstate['tracked']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['viewdiscussions']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['create']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['subscribe']);
|
||||
$this->assertNotEquals(null, $exportedforum->urls['create']);
|
||||
$this->assertNotEquals(null, $exportedforum->urls['markasread']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,519 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use \mod_forum\local\entities\discussion as discussion_entity;
|
||||
use \mod_forum\local\entities\post as post_entity;
|
||||
use \mod_forum\local\exporters\post as post_exporter;
|
||||
use \mod_forum\local\managers\capability as capability_manager;
|
||||
|
||||
global $CFG;
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
/**
|
||||
* The post exporter tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_exporters_post_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/**
|
||||
* Test the export function returns expected values.
|
||||
*/
|
||||
public function test_export_post() {
|
||||
global $CFG, $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$CFG->enableportfolios = true;
|
||||
$filestorage = get_file_storage();
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
|
||||
$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 = $forumgenerator->create_discussion((object) [
|
||||
'course' => $forum->course,
|
||||
'userid' => $user->id,
|
||||
'forum' => $forum->id
|
||||
]);
|
||||
$now = time();
|
||||
$post = $forumgenerator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => 0,
|
||||
'userid' => $user->id,
|
||||
'created' => $now,
|
||||
'modified' => $now,
|
||||
'subject' => 'This is the subject',
|
||||
'message' => 'This is the message',
|
||||
'messagetrust' => 1,
|
||||
'attachment' => 0,
|
||||
'totalscore' => 0,
|
||||
'mailnow' => 1,
|
||||
'deleted' => 0
|
||||
]);
|
||||
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']);
|
||||
$tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id);
|
||||
$attachment = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'itemid' => $post->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
$canview = true;
|
||||
$canedit = true;
|
||||
$candelete = true;
|
||||
$cansplit = true;
|
||||
$canreply = true;
|
||||
$canexport = true;
|
||||
$cancontrolreadstatus = true;
|
||||
$capabilitymanager = new test_capability_manager(
|
||||
$canview,
|
||||
$canedit,
|
||||
$candelete,
|
||||
$cansplit,
|
||||
$canreply,
|
||||
$canexport,
|
||||
$cancontrolreadstatus
|
||||
);
|
||||
$managerfactory = \mod_forum\local\container::get_manager_factory();
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$discussion = $entityfactory->get_discussion_from_stdclass($discussion);
|
||||
$post = $entityfactory->get_post_from_stdclass($post);
|
||||
$author = $entityfactory->get_author_from_stdclass($user);
|
||||
|
||||
$exporter = new post_exporter($post, [
|
||||
'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(),
|
||||
'capabilitymanager' => $capabilitymanager,
|
||||
'readreceiptcollection' => null,
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'forum' => $forum,
|
||||
'discussion' => $discussion,
|
||||
'author' => $author,
|
||||
'user' => $user,
|
||||
'context' => $context,
|
||||
'authorgroups' => [],
|
||||
'attachments' => [$attachment],
|
||||
'tags' => $tags,
|
||||
'rating' => null,
|
||||
'includehtml' => true
|
||||
]);
|
||||
|
||||
$exportedpost = $exporter->export($renderer);
|
||||
|
||||
$this->assertEquals('This is the subject', $exportedpost->subject);
|
||||
$this->assertEquals('This is the message', $exportedpost->message);
|
||||
$this->assertEquals($user->id, $exportedpost->author->id);
|
||||
$this->assertEquals($discussion->get_id(), $exportedpost->discussionid);
|
||||
$this->assertEquals(false, $exportedpost->hasparent);
|
||||
$this->assertEquals(null, $exportedpost->parentid);
|
||||
$this->assertEquals($now, $exportedpost->timecreated);
|
||||
$this->assertEquals(null, $exportedpost->unread);
|
||||
$this->assertEquals(false, $exportedpost->isdeleted);
|
||||
$this->assertEquals($canview, $exportedpost->capabilities['view']);
|
||||
$this->assertEquals($canedit, $exportedpost->capabilities['edit']);
|
||||
$this->assertEquals($candelete, $exportedpost->capabilities['delete']);
|
||||
$this->assertEquals($cansplit, $exportedpost->capabilities['split']);
|
||||
$this->assertEquals($canreply, $exportedpost->capabilities['reply']);
|
||||
$this->assertEquals($canexport, $exportedpost->capabilities['export']);
|
||||
$this->assertEquals($cancontrolreadstatus, $exportedpost->capabilities['controlreadstatus']);
|
||||
$this->assertNotEmpty($exportedpost->urls['view']);
|
||||
$this->assertNotEmpty($exportedpost->urls['viewisolated']);
|
||||
$this->assertNotEmpty($exportedpost->urls['edit']);
|
||||
$this->assertNotEmpty($exportedpost->urls['delete']);
|
||||
$this->assertNotEmpty($exportedpost->urls['split']);
|
||||
$this->assertNotEmpty($exportedpost->urls['reply']);
|
||||
$this->assertNotEmpty($exportedpost->urls['markasread']);
|
||||
$this->assertNotEmpty($exportedpost->urls['markasunread']);
|
||||
$this->assertCount(1, $exportedpost->attachments);
|
||||
$this->assertEquals('example1.jpg', $exportedpost->attachments[0]->filename);
|
||||
$this->assertCount(2, $exportedpost->tags);
|
||||
$this->assertEquals('foo', $exportedpost->tags[0]['displayname']);
|
||||
$this->assertEquals('bar', $exportedpost->tags[1]['displayname']);
|
||||
$this->assertEquals(null, $exportedpost->html['rating']);
|
||||
$this->assertNotEquals(null, $exportedpost->html['taglist']);
|
||||
$this->assertNotEmpty($exportedpost->html['authorsubheading']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exporting of a deleted post.
|
||||
*/
|
||||
public function test_export_deleted_post() {
|
||||
global $CFG, $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$CFG->enableportfolios = true;
|
||||
$filestorage = get_file_storage();
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
|
||||
$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 = $forumgenerator->create_discussion((object) [
|
||||
'course' => $forum->course,
|
||||
'userid' => $user->id,
|
||||
'forum' => $forum->id
|
||||
]);
|
||||
$now = time();
|
||||
$post = $forumgenerator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => 0,
|
||||
'userid' => $user->id,
|
||||
'created' => $now,
|
||||
'modified' => $now,
|
||||
'subject' => 'This is the subject',
|
||||
'message' => 'This is the message',
|
||||
'messagetrust' => 1,
|
||||
'attachment' => 0,
|
||||
'totalscore' => 0,
|
||||
'mailnow' => 1,
|
||||
'deleted' => 1
|
||||
]);
|
||||
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']);
|
||||
$tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id);
|
||||
$attachment = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'itemid' => $post->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
$canview = true;
|
||||
$canedit = true;
|
||||
$candelete = true;
|
||||
$cansplit = true;
|
||||
$canreply = true;
|
||||
$canexport = true;
|
||||
$cancontrolreadstatus = true;
|
||||
$capabilitymanager = new test_capability_manager(
|
||||
$canview,
|
||||
$canedit,
|
||||
$candelete,
|
||||
$cansplit,
|
||||
$canreply,
|
||||
$canexport,
|
||||
$cancontrolreadstatus
|
||||
);
|
||||
$managerfactory = \mod_forum\local\container::get_manager_factory();
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$discussion = $entityfactory->get_discussion_from_stdclass($discussion);
|
||||
$post = $entityfactory->get_post_from_stdclass($post);
|
||||
$author = $entityfactory->get_author_from_stdclass($user);
|
||||
|
||||
$exporter = new post_exporter($post, [
|
||||
'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(),
|
||||
'capabilitymanager' => $capabilitymanager,
|
||||
'readreceiptcollection' => null,
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'forum' => $forum,
|
||||
'discussion' => $discussion,
|
||||
'author' => $author,
|
||||
'user' => $user,
|
||||
'context' => $context,
|
||||
'authorgroups' => [],
|
||||
'attachments' => [$attachment],
|
||||
'tags' => $tags,
|
||||
'rating' => null,
|
||||
'includehtml' => true
|
||||
]);
|
||||
|
||||
$exportedpost = $exporter->export($renderer);
|
||||
|
||||
$this->assertNotEquals('This is the subject', $exportedpost->subject);
|
||||
$this->assertNotEquals('This is the message', $exportedpost->message);
|
||||
$this->assertEquals(null, $exportedpost->timecreated);
|
||||
$this->assertEquals(null, $exportedpost->unread);
|
||||
$this->assertEquals(true, $exportedpost->isdeleted);
|
||||
$this->assertEquals([], $exportedpost->attachments);
|
||||
$this->assertEquals([], $exportedpost->tags);
|
||||
$this->assertEquals(null, $exportedpost->html['rating']);
|
||||
$this->assertEquals(null, $exportedpost->html['taglist']);
|
||||
$this->assertEquals(null, $exportedpost->html['authorsubheading']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exporting of a post the user can't view.
|
||||
*/
|
||||
public function test_export_post_no_view_capability() {
|
||||
global $CFG, $PAGE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$CFG->enableportfolios = true;
|
||||
$filestorage = get_file_storage();
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
|
||||
$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 = $forumgenerator->create_discussion((object) [
|
||||
'course' => $forum->course,
|
||||
'userid' => $user->id,
|
||||
'forum' => $forum->id
|
||||
]);
|
||||
$now = time();
|
||||
$post = $forumgenerator->create_post((object) [
|
||||
'discussion' => $discussion->id,
|
||||
'parent' => 0,
|
||||
'userid' => $user->id,
|
||||
'created' => $now,
|
||||
'modified' => $now,
|
||||
'subject' => 'This is the subject',
|
||||
'message' => 'This is the message',
|
||||
'messagetrust' => 1,
|
||||
'attachment' => 0,
|
||||
'totalscore' => 0,
|
||||
'mailnow' => 1,
|
||||
'deleted' => 0
|
||||
]);
|
||||
|
||||
\core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']);
|
||||
$tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id);
|
||||
$attachment = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'itemid' => $post->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
|
||||
$canview = false;
|
||||
$canedit = true;
|
||||
$candelete = true;
|
||||
$cansplit = true;
|
||||
$canreply = true;
|
||||
$canexport = true;
|
||||
$cancontrolreadstatus = true;
|
||||
$capabilitymanager = new test_capability_manager(
|
||||
$canview,
|
||||
$canedit,
|
||||
$candelete,
|
||||
$cansplit,
|
||||
$canreply,
|
||||
$canexport,
|
||||
$cancontrolreadstatus
|
||||
);
|
||||
$managerfactory = \mod_forum\local\container::get_manager_factory();
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$forum = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
$discussion = $entityfactory->get_discussion_from_stdclass($discussion);
|
||||
$post = $entityfactory->get_post_from_stdclass($post);
|
||||
$author = $entityfactory->get_author_from_stdclass($user);
|
||||
|
||||
$exporter = new post_exporter($post, [
|
||||
'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(),
|
||||
'capabilitymanager' => $capabilitymanager,
|
||||
'readreceiptcollection' => null,
|
||||
'urlfactory' => \mod_forum\local\container::get_url_factory(),
|
||||
'forum' => $forum,
|
||||
'discussion' => $discussion,
|
||||
'author' => $author,
|
||||
'user' => $user,
|
||||
'context' => $context,
|
||||
'authorgroups' => [],
|
||||
'attachments' => [$attachment],
|
||||
'tags' => $tags,
|
||||
'rating' => null,
|
||||
'includehtml' => true
|
||||
]);
|
||||
|
||||
$exportedpost = $exporter->export($renderer);
|
||||
|
||||
$this->assertNotEquals('This is the subject', $exportedpost->subject);
|
||||
$this->assertNotEquals('This is the message', $exportedpost->message);
|
||||
$this->assertEquals(null, $exportedpost->timecreated);
|
||||
$this->assertEquals(null, $exportedpost->unread);
|
||||
$this->assertEquals(false, $exportedpost->isdeleted);
|
||||
$this->assertEquals([], $exportedpost->attachments);
|
||||
$this->assertEquals([], $exportedpost->tags);
|
||||
$this->assertEquals(null, $exportedpost->html['rating']);
|
||||
$this->assertEquals(null, $exportedpost->html['taglist']);
|
||||
$this->assertEquals(null, $exportedpost->html['authorsubheading']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test implementation of the capability manager.
|
||||
*
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_capability_manager extends capability_manager {
|
||||
/** @var bool $view Value for can_view_post */
|
||||
private $view;
|
||||
/** @var bool $edit Value for can_edit_post */
|
||||
private $edit;
|
||||
/** @var bool $delete Value for can_delete_post */
|
||||
private $delete;
|
||||
/** @var bool $split Value for can_split_post */
|
||||
private $split;
|
||||
/** @var bool $reply Value for can_reply_to_post */
|
||||
private $reply;
|
||||
/** @var bool $export Value for can_export_post */
|
||||
private $export;
|
||||
/** @var bool $controlreadstatus Value for can_manually_control_post_read_status */
|
||||
private $controlreadstatus;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param bool $view Value for can_view_post
|
||||
* @param bool $edit Value for can_edit_post
|
||||
* @param bool $delete Value for can_delete_post
|
||||
* @param bool $split Value for can_split_post
|
||||
* @param bool $reply Value for can_reply_to_post
|
||||
* @param bool $export Value for can_export_post
|
||||
* @param bool $controlreadstatus Value for can_manually_control_post_read_status
|
||||
*/
|
||||
public function __construct(
|
||||
bool $view = true,
|
||||
bool $edit = true,
|
||||
bool $delete = true,
|
||||
bool $split = true,
|
||||
bool $reply = true,
|
||||
bool $export = true,
|
||||
bool $controlreadstatus = true
|
||||
) {
|
||||
$this->view = $view;
|
||||
$this->edit = $edit;
|
||||
$this->delete = $delete;
|
||||
$this->split = $split;
|
||||
$this->reply = $reply;
|
||||
$this->export = $export;
|
||||
$this->controlreadstatus = $controlreadstatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_view_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_view_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_edit_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_edit_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->edit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_delete_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_delete_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_split_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_split_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->split;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_reply_to_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param discussion_entity $discussion The discussion
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_reply_to_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
|
||||
return $this->reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_export_post
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @param post_entity $post The post
|
||||
* @return bool
|
||||
*/
|
||||
public function can_export_post(stdClass $user, post_entity $post) : bool {
|
||||
return $this->export;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can_manually_control_post_read_status
|
||||
*
|
||||
* @param stdClass $user The user
|
||||
* @return bool
|
||||
*/
|
||||
public function can_manually_control_post_read_status(stdClass $user) : bool {
|
||||
return $this->controlreadstatus;
|
||||
}
|
||||
}
|
||||
@@ -300,6 +300,10 @@ class mod_forum_generator extends testing_module_generator {
|
||||
$record['mailnow'] = 0;
|
||||
}
|
||||
|
||||
if (!isset($record['deleted'])) {
|
||||
$record['deleted'] = 0;
|
||||
}
|
||||
|
||||
$record = (object) $record;
|
||||
|
||||
// Add the post.
|
||||
|
||||
@@ -3009,6 +3009,22 @@ class mod_forum_lib_testcase extends advanced_testcase {
|
||||
* @param bool $expect
|
||||
*/
|
||||
public function test_forum_discussion_is_locked($forum, $discussion, $expect) {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$plugingenerator = $datagenerator->get_plugin_generator('mod_forum');
|
||||
|
||||
$course = $datagenerator->create_course();
|
||||
$user = $datagenerator->create_user();
|
||||
$forum = $datagenerator->create_module('forum', (object) array_merge([
|
||||
'course' => $course->id
|
||||
], $forum));
|
||||
$discussion = $plugingenerator->create_discussion((object) array_merge([
|
||||
'course' => $course->id,
|
||||
'userid' => $user->id,
|
||||
'forum' => $forum->id,
|
||||
], $discussion));
|
||||
|
||||
$this->assertEquals($expect, forum_discussion_is_locked($forum, $discussion));
|
||||
}
|
||||
|
||||
@@ -3019,39 +3035,29 @@ class mod_forum_lib_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function forum_discussion_is_locked_provider() {
|
||||
return [
|
||||
'Unlocked: lockdiscussionafter is unset' => [
|
||||
(object) [],
|
||||
(object) [],
|
||||
false
|
||||
],
|
||||
'Unlocked: lockdiscussionafter is false' => [
|
||||
(object) ['lockdiscussionafter' => false],
|
||||
(object) [],
|
||||
false
|
||||
],
|
||||
'Unlocked: lockdiscussionafter is null' => [
|
||||
(object) ['lockdiscussionafter' => null],
|
||||
(object) [],
|
||||
['lockdiscussionafter' => false],
|
||||
[],
|
||||
false
|
||||
],
|
||||
'Unlocked: lockdiscussionafter is set; forum is of type single; post is recent' => [
|
||||
(object) ['lockdiscussionafter' => DAYSECS, 'type' => 'single'],
|
||||
(object) ['timemodified' => time()],
|
||||
['lockdiscussionafter' => DAYSECS, 'type' => 'single'],
|
||||
['timemodified' => time()],
|
||||
false
|
||||
],
|
||||
'Unlocked: lockdiscussionafter is set; forum is of type single; post is old' => [
|
||||
(object) ['lockdiscussionafter' => MINSECS, 'type' => 'single'],
|
||||
(object) ['timemodified' => time() - DAYSECS],
|
||||
['lockdiscussionafter' => MINSECS, 'type' => 'single'],
|
||||
['timemodified' => time() - DAYSECS],
|
||||
false
|
||||
],
|
||||
'Unlocked: lockdiscussionafter is set; forum is of type eachuser; post is recent' => [
|
||||
(object) ['lockdiscussionafter' => DAYSECS, 'type' => 'eachuser'],
|
||||
(object) ['timemodified' => time()],
|
||||
['lockdiscussionafter' => DAYSECS, 'type' => 'eachuser'],
|
||||
['timemodified' => time()],
|
||||
false
|
||||
],
|
||||
'Locked: lockdiscussionafter is set; forum is of type eachuser; post is old' => [
|
||||
(object) ['lockdiscussionafter' => MINSECS, 'type' => 'eachuser'],
|
||||
(object) ['timemodified' => time() - DAYSECS],
|
||||
['lockdiscussionafter' => MINSECS, 'type' => 'eachuser'],
|
||||
['timemodified' => time() - DAYSECS],
|
||||
true
|
||||
],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for the local\container class.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Tests for the local\container class.
|
||||
*
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \mod_forum\local\container
|
||||
*/
|
||||
class mod_forum_local_container_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Ensure that a renderer factory is returned.
|
||||
*
|
||||
* @covers ::get_renderer_factory
|
||||
*/
|
||||
public function test_get_renderer_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\renderer::class, \mod_forum\local\container::get_renderer_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a legacy_data_mapper_factory factory is returned.
|
||||
*
|
||||
* @covers ::get_legacy_data_mapper_factory
|
||||
*/
|
||||
public function test_get_legacy_data_mapper_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\legacy_data_mapper::class, \mod_forum\local\container::get_legacy_data_mapper_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a exporter factory is returned.
|
||||
*
|
||||
* @covers ::get_exporter_factory
|
||||
*/
|
||||
public function test_get_exporter_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\exporter::class, \mod_forum\local\container::get_exporter_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a vault factory is returned.
|
||||
*
|
||||
* @covers ::get_vault_factory
|
||||
*/
|
||||
public function test_get_vault_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\vault::class, \mod_forum\local\container::get_vault_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a manager factory is returned.
|
||||
*
|
||||
* @covers ::get_manager_factory
|
||||
*/
|
||||
public function test_get_manager_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\manager::class, \mod_forum\local\container::get_manager_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a entity factory is returned.
|
||||
*
|
||||
* @covers ::get_entity_factory
|
||||
*/
|
||||
public function test_get_entity_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\entity::class, \mod_forum\local\container::get_entity_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a builder factory is returned.
|
||||
*
|
||||
* @covers ::get_builder_factory
|
||||
*/
|
||||
public function test_get_builder_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\builder::class, \mod_forum\local\container::get_builder_factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a url factory is returned.
|
||||
*
|
||||
* @covers ::get_url_factory
|
||||
*/
|
||||
public function test_get_url_factory() {
|
||||
$this->assertInstanceOf(\mod_forum\local\factories\url::class, \mod_forum\local\container::get_url_factory());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The author vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The author vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_author_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Test get_from_id.
|
||||
*/
|
||||
public function test_get_from_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$authorvault = $vaultfactory->get_author_vault();
|
||||
|
||||
$author = $authorvault->get_from_id($user->id);
|
||||
|
||||
$this->assertEquals($user->id, $author->get_id());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion_list vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The discussion_list vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_discussion_list_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/** @var \mod_forum\local\vaults\discussion_list */
|
||||
private $vault;
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$this->vault = $vaultfactory->get_discussions_in_forum_vault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_id.
|
||||
*/
|
||||
public function test_get_from_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$vault = $this->vault;
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
[$discussion, $post] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$discussionlist = $vault->get_from_id($discussion->id);
|
||||
|
||||
$this->assertEquals($discussion->id, $discussionlist->get_discussion()->get_id());
|
||||
$this->assertEquals($post->id, $discussionlist->get_first_post()->get_id());
|
||||
$this->assertEquals($user->id, $discussionlist->get_first_post_author()->get_id());
|
||||
$this->assertEquals($user->id, $discussionlist->get_latest_post_author()->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_forum_id.
|
||||
*/
|
||||
public function test_get_from_forum_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$vault = $this->vault;
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $vault->get_from_forum_id($forum->id, true, $user->id, null, 0, 0));
|
||||
|
||||
$now = time();
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 10, 'timemodified' => 1]);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 9, 'timemodified' => 2]);
|
||||
[$hiddendiscussion, $post3] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now + 10, 'timemodified' => 3]);
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, false, null, null, 0, 0));
|
||||
$this->assertCount(2, $summaries);
|
||||
$this->assertEquals($discussion2->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[1]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, true, null, null, 0, 0));
|
||||
$this->assertCount(3, $summaries);
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[2]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, false, $user->id, null, 0, 0));
|
||||
$this->assertCount(3, $summaries);
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[2]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, true, null, null, 1, 0));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, true, null, null, 1, 1));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($discussion2->id, $summaries[0]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id($forum->id, true, null, null, 1, 2));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($discussion1->id, $summaries[0]->get_discussion()->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_forum_id_and_group_id.
|
||||
*/
|
||||
public function test_get_from_forum_id_and_group_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$vault = $this->vault;
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $vault->get_from_forum_id($forum->id, true, true, null, 0, 0));
|
||||
|
||||
$now = time();
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 10, 'timemodified' => 1]);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 9, 'timemodified' => 2]);
|
||||
[$hiddendiscussion, $post3] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now + 10, 'timemodified' => 3]);
|
||||
[$groupdiscussion1, $post4] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now - 8, 'timemodified' => 4, 'groupid' => 1]
|
||||
);
|
||||
[$groupdiscussion2, $post5] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now - 7, 'timemodified' => 5, 'groupid' => 2]
|
||||
);
|
||||
[$hiddengroupdiscussion, $post6] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now + 11, 'timemodified' => 6, 'groupid' => 3]
|
||||
);
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], true, null, null, 0, 0));
|
||||
$this->assertCount(6, $summaries);
|
||||
$this->assertEquals($hiddengroupdiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($groupdiscussion2->id, $summaries[2]->get_discussion()->get_id());
|
||||
$this->assertEquals($groupdiscussion1->id, $summaries[3]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[4]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[5]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], false, $user->id, null, 0, 0));
|
||||
$this->assertCount(6, $summaries);
|
||||
$this->assertEquals($hiddengroupdiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($groupdiscussion2->id, $summaries[2]->get_discussion()->get_id());
|
||||
$this->assertEquals($groupdiscussion1->id, $summaries[3]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[4]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[5]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], true, null, null, 1, 0));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($hiddengroupdiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], true, null, null, 1, 1));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], true, null, null, 1, 2));
|
||||
$this->assertCount(1, $summaries);
|
||||
$this->assertEquals($groupdiscussion2->id, $summaries[0]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [1, 2, 3], false, null, null, 0, 0));
|
||||
$this->assertCount(4, $summaries);
|
||||
$this->assertEquals($groupdiscussion2->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($groupdiscussion1->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[2]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[3]->get_discussion()->get_id());
|
||||
|
||||
$summaries = array_values($vault->get_from_forum_id_and_group_id($forum->id, [], true, null, null, 0, 0));
|
||||
$this->assertCount(3, $summaries);
|
||||
$this->assertEquals($hiddendiscussion->id, $summaries[0]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion2->id, $summaries[1]->get_discussion()->get_id());
|
||||
$this->assertEquals($discussion1->id, $summaries[2]->get_discussion()->get_id());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test get_total_discussion_count_from_forum_id.
|
||||
*/
|
||||
public function test_get_total_discussion_count_from_forum_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$vault = $this->vault;
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals(0, $vault->get_total_discussion_count_from_forum_id($forum->id, true, null));
|
||||
|
||||
$now = time();
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 10, 'timemodified' => 1]);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 9, 'timemodified' => 2]);
|
||||
[$hiddendiscussion, $post3] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now + 10, 'timemodified' => 3]);
|
||||
|
||||
$this->assertEquals(2, $vault->get_total_discussion_count_from_forum_id($forum->id, false, null));
|
||||
$this->assertEquals(3, $vault->get_total_discussion_count_from_forum_id($forum->id, true, null));
|
||||
$this->assertEquals(3, $vault->get_total_discussion_count_from_forum_id($forum->id, false, $user->id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test get_total_discussion_count_from_forum_id_and_group_id.
|
||||
*/
|
||||
public function test_get_total_discussion_count_from_forum_id_and_group_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$vault = $this->vault;
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $vault->get_from_forum_id($forum->id, true, true, null, 0, 0));
|
||||
|
||||
$now = time();
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 10, 'timemodified' => 1]);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now - 9, 'timemodified' => 2]);
|
||||
[$hiddendiscussion, $post3] = $this->helper_post_to_forum($forum, $user, ['timestart' => $now + 10, 'timemodified' => 3]);
|
||||
[$groupdiscussion1, $post4] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now - 8, 'timemodified' => 4, 'groupid' => 1]
|
||||
);
|
||||
[$groupdiscussion2, $post5] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now - 7, 'timemodified' => 5, 'groupid' => 2]
|
||||
);
|
||||
[$hiddengroupdiscussion, $post6] = $this->helper_post_to_forum(
|
||||
$forum,
|
||||
$user,
|
||||
['timestart' => $now + 11, 'timemodified' => 6, 'groupid' => 3]
|
||||
);
|
||||
|
||||
$this->assertEquals(6, $vault->get_total_discussion_count_from_forum_id_and_group_id($forum->id, [1, 2, 3], true, null));
|
||||
$this->assertEquals(6, $vault->get_total_discussion_count_from_forum_id_and_group_id(
|
||||
$forum->id,
|
||||
[1, 2, 3],
|
||||
false,
|
||||
$user->id
|
||||
));
|
||||
$this->assertEquals(4, $vault->get_total_discussion_count_from_forum_id_and_group_id($forum->id, [1, 2, 3], false, null));
|
||||
$this->assertEquals(3, $vault->get_total_discussion_count_from_forum_id_and_group_id($forum->id, [], true, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The discussion vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The discussion vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_discussion_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/** @var \mod_forum\local\vaults\discussion */
|
||||
private $vault;
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$this->vault = $vaultfactory->get_discussion_vault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_id.
|
||||
*/
|
||||
public function test_get_from_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$vault = $this->vault;
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
[$discussionrecord, $post] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$discussion = $vault->get_from_id($discussionrecord->id);
|
||||
|
||||
$this->assertEquals($discussionrecord->id, $discussion->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_first_discussion_in_forum.
|
||||
*/
|
||||
public function test_get_first_discussion_in_forum() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$vault = $this->vault;
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$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);
|
||||
$forumentity = $entityfactory->get_forum_from_stdclass($forum, $context, $coursemodule, $course);
|
||||
|
||||
$this->assertEquals(null, $vault->get_first_discussion_in_forum($forumentity));
|
||||
|
||||
[$discussion1, $post] = $this->helper_post_to_forum($forum, $user, ['timemodified' => 2]);
|
||||
[$discussion2, $post] = $this->helper_post_to_forum($forum, $user, ['timemodified' => 1]);
|
||||
[$discussion3, $post] = $this->helper_post_to_forum($forum, $user, ['timemodified' => 3]);
|
||||
|
||||
$discussionentity = $vault->get_first_discussion_in_forum($forumentity);
|
||||
$this->assertEquals($discussion2->id, $discussionentity->get_id());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The forum vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The forum vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_forum_testcase extends advanced_testcase {
|
||||
/** @var \mod_forum\local\vaults\discussion */
|
||||
private $vault;
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$this->vault = $vaultfactory->get_forum_vault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_id.
|
||||
*/
|
||||
public function test_get_from_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$vault = $this->vault;
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$entity = $vault->get_from_id($forum->id);
|
||||
|
||||
$this->assertEquals($forum->id, $entity->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_course_module_id.
|
||||
*/
|
||||
public function test_get_from_course_module_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$vault = $this->vault;
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$coursemodule1 = get_coursemodule_from_instance('forum', $forum1->id);
|
||||
$coursemodule2 = get_coursemodule_from_instance('forum', $forum2->id);
|
||||
|
||||
// Don't exist.
|
||||
$entity = $vault->get_from_course_module_id($coursemodule1->id + 100);
|
||||
$this->assertEquals(null, $entity);
|
||||
|
||||
$entity = $vault->get_from_course_module_id($coursemodule1->id);
|
||||
$this->assertEquals($forum1->id, $entity->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_course_module_ids.
|
||||
*/
|
||||
public function test_get_from_course_module_ids() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$vault = $this->vault;
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum1 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$forum2 = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
$coursemodule1 = get_coursemodule_from_instance('forum', $forum1->id);
|
||||
$coursemodule2 = get_coursemodule_from_instance('forum', $forum2->id);
|
||||
|
||||
// Don't exist.
|
||||
$entities = array_values($vault->get_from_course_module_ids([$coursemodule1->id + 100, $coursemodule1->id + 200]));
|
||||
$this->assertEquals([], $entities);
|
||||
|
||||
$entities = array_values($vault->get_from_course_module_ids([$coursemodule1->id, $coursemodule2->id]));
|
||||
$this->assertCount(2, $entities);
|
||||
$this->assertEquals($forum2->id, $entities[0]->get_id());
|
||||
$this->assertEquals($forum1->id, $entities[1]->get_id());
|
||||
|
||||
$entities = array_values($vault->get_from_course_module_ids([$coursemodule1->id]));
|
||||
$this->assertCount(1, $entities);
|
||||
$this->assertEquals($forum1->id, $entities[0]->get_id());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post_attachment vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The post_attachment vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_post_attachment_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/**
|
||||
* Test get_attachments_for_posts.
|
||||
*/
|
||||
public function test_get_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' => 'attachment',
|
||||
'itemid' => $post1->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'example1.jpg',
|
||||
],
|
||||
'image contents'
|
||||
);
|
||||
$attachment2 = $filestorage->create_file_from_string(
|
||||
[
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_forum',
|
||||
'filearea' => 'attachment',
|
||||
'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_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_attachments_for_posts($context, [$post1]);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertEquals($attachment1->get_filename(), $results[$post1->get_id()][0]->get_filename());
|
||||
|
||||
$results = $vault->get_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_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()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post read receipt collection vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The post read receipt collection vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_forum_vaults_post_read_receipt_collection_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/**
|
||||
* Test get_from_user_id_and_post_ids.
|
||||
*/
|
||||
public function test_get_from_user_id_and_post_ids() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$vault = $vaultfactory->get_post_read_receipt_collection_vault();
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$otheruser = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
[$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
|
||||
[$discussion2, $post2] = $this->helper_post_to_forum($forum, $user);
|
||||
$post3 = $this->helper_reply_to_post($post2, $user);
|
||||
|
||||
$DB->insert_record('forum_read', [
|
||||
'userid' => $user->id,
|
||||
'forumid' => $forum->id,
|
||||
'discussionid' => $discussion1->id,
|
||||
'postid' => $post1->id,
|
||||
'firstread' => time(),
|
||||
'lastread' => time()
|
||||
]);
|
||||
// Receipt for other user.
|
||||
$DB->insert_record('forum_read', [
|
||||
'userid' => $otheruser->id,
|
||||
'forumid' => $forum->id,
|
||||
'discussionid' => $discussion1->id,
|
||||
'postid' => $post1->id,
|
||||
'firstread' => time(),
|
||||
'lastread' => time()
|
||||
]);
|
||||
$DB->insert_record('forum_read', [
|
||||
'userid' => $user->id,
|
||||
'forumid' => $forum->id,
|
||||
'discussionid' => $discussion2->id,
|
||||
'postid' => $post3->id,
|
||||
'firstread' => time(),
|
||||
'lastread' => time()
|
||||
]);
|
||||
|
||||
$post1 = $entityfactory->get_post_from_stdclass($post1);
|
||||
$post2 = $entityfactory->get_post_from_stdclass($post2);
|
||||
$post3 = $entityfactory->get_post_from_stdclass($post3);
|
||||
$collection = $vault->get_from_user_id_and_post_ids($user->id, [$post1->get_id(), $post2->get_id()]);
|
||||
|
||||
// True because there is a read receipt for this user.
|
||||
$this->assertTrue($collection->has_user_read_post($user, $post1));
|
||||
// False because other user wasn't included in the fetch.
|
||||
$this->assertFalse($collection->has_user_read_post($otheruser, $post1));
|
||||
// No read receipt.
|
||||
$this->assertFalse($collection->has_user_read_post($user, $post2));
|
||||
// Wasn't included in fetch.
|
||||
$this->assertFalse($collection->has_user_read_post($user, $post3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The post vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/generator_trait.php');
|
||||
|
||||
/**
|
||||
* The post vault tests.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \mod_forum\local\vaults\post
|
||||
*/
|
||||
class mod_forum_vaults_post_testcase extends advanced_testcase {
|
||||
// Make use of the test generator trait.
|
||||
use mod_forum_tests_generator_trait;
|
||||
|
||||
/** @var \mod_forum\local\vaults\post */
|
||||
private $vault;
|
||||
|
||||
/**
|
||||
* Set up function for tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$this->vault = $vaultfactory->get_post_vault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Teardown for all tests.
|
||||
*/
|
||||
public function tearDown() {
|
||||
unset($this->vault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_id.
|
||||
*/
|
||||
public function test_get_from_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
[$discussion, $post] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$postentity = $this->vault->get_from_id($post->id);
|
||||
|
||||
$this->assertEquals($post->id, $postentity->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_discussion_id.
|
||||
*
|
||||
* @covers ::get_from_discussion_id
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_from_discussion_id() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
[$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$entities = array_values($this->vault->get_from_discussion_id($discussion1->id));
|
||||
|
||||
$this->assertCount(3, $entities);
|
||||
$this->assertEquals($post1->id, $entities[0]->get_id());
|
||||
$this->assertEquals($post2->id, $entities[1]->get_id());
|
||||
$this->assertEquals($post3->id, $entities[2]->get_id());
|
||||
|
||||
$entities = array_values($this->vault->get_from_discussion_id($discussion1->id + 1000));
|
||||
$this->assertCount(0, $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_discussion_ids when no discussion ids were provided.
|
||||
*
|
||||
* @covers ::get_from_discussion_ids
|
||||
*/
|
||||
public function test_get_from_discussion_ids_empty() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $this->vault->get_from_discussion_ids([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_from_discussion_ids.
|
||||
*
|
||||
* @covers ::get_from_discussion_ids
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_from_discussion_ids() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
[$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$entities = array_values($this->vault->get_from_discussion_ids([$discussion1->id]));
|
||||
usort($entities, function($a, $b) {
|
||||
return $a <=> $b;
|
||||
});
|
||||
$this->assertCount(3, $entities);
|
||||
$this->assertEquals($post1->id, $entities[0]->get_id());
|
||||
$this->assertEquals($post2->id, $entities[1]->get_id());
|
||||
$this->assertEquals($post3->id, $entities[2]->get_id());
|
||||
|
||||
$entities = array_values($this->vault->get_from_discussion_ids([$discussion1->id, $discussion2->id]));
|
||||
usort($entities, function($a, $b) {
|
||||
return $a <=> $b;
|
||||
});
|
||||
$this->assertCount(4, $entities);
|
||||
$this->assertEquals($post1->id, $entities[0]->get_id());
|
||||
$this->assertEquals($post2->id, $entities[1]->get_id());
|
||||
$this->assertEquals($post3->id, $entities[2]->get_id());
|
||||
$this->assertEquals($post4->id, $entities[3]->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_replies_to_post.
|
||||
*
|
||||
* @covers ::get_replies_to_post
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_replies_to_post() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
$post4 = $this->helper_reply_to_post($post2, $user);
|
||||
[$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
|
||||
|
||||
$entityfactory = \mod_forum\local\container::get_entity_factory();
|
||||
$post1 = $entityfactory->get_post_from_stdclass($post1);
|
||||
$post2 = $entityfactory->get_post_from_stdclass($post2);
|
||||
$post3 = $entityfactory->get_post_from_stdclass($post3);
|
||||
$post4 = $entityfactory->get_post_from_stdclass($post4);
|
||||
|
||||
$entities = $this->vault->get_replies_to_post($post1);
|
||||
$this->assertCount(3, $entities);
|
||||
$this->assertEquals($post2->get_id(), $entities[0]->get_id());
|
||||
$this->assertEquals($post3->get_id(), $entities[1]->get_id());
|
||||
$this->assertEquals($post4->get_id(), $entities[2]->get_id());
|
||||
|
||||
$entities = $this->vault->get_replies_to_post($post2);
|
||||
$this->assertCount(1, $entities);
|
||||
$this->assertEquals($post4->get_id(), $entities[0]->get_id());
|
||||
|
||||
$entities = $this->vault->get_replies_to_post($post3);
|
||||
$this->assertCount(0, $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_reply_count_for_discussion_ids when no discussion ids were provided.
|
||||
*
|
||||
* @covers ::get_reply_count_for_discussion_ids
|
||||
*/
|
||||
public function test_get_reply_count_for_discussion_ids_empty() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$counts = $this->vault->get_reply_count_for_discussion_ids([]);
|
||||
$this->assertCount(0, $counts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_reply_count_for_discussion_ids.
|
||||
*
|
||||
* @covers ::get_reply_count_for_discussion_ids
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_reply_count_for_discussion_ids() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
$post4 = $this->helper_reply_to_post($post2, $user);
|
||||
[$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);
|
||||
|
||||
$counts = $this->vault->get_reply_count_for_discussion_ids([$discussion1->id]);
|
||||
$this->assertCount(1, $counts);
|
||||
$this->assertEquals(3, $counts[$discussion1->id]);
|
||||
|
||||
$counts = $this->vault->get_reply_count_for_discussion_ids([$discussion1->id, $discussion2->id]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(3, $counts[$discussion1->id]);
|
||||
$this->assertEquals(1, $counts[$discussion2->id]);
|
||||
|
||||
$counts = $this->vault->get_reply_count_for_discussion_ids([$discussion1->id, $discussion2->id, $discussion3->id]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(3, $counts[$discussion1->id]);
|
||||
$this->assertEquals(1, $counts[$discussion2->id]);
|
||||
|
||||
$counts = $this->vault->get_reply_count_for_discussion_ids([
|
||||
$discussion1->id,
|
||||
$discussion2->id,
|
||||
$discussion3->id,
|
||||
$discussion3->id + 1000
|
||||
]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(3, $counts[$discussion1->id]);
|
||||
$this->assertEquals(1, $counts[$discussion2->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_unread_count_for_discussion_ids.
|
||||
*
|
||||
* @covers ::get_unread_count_for_discussion_ids
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_unread_count_for_discussion_ids() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$otheruser = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
$post4 = $this->helper_reply_to_post($post2, $user);
|
||||
[$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
|
||||
$post6 = $this->helper_reply_to_post($post5, $user);
|
||||
|
||||
$modgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
|
||||
$post7 = $modgenerator->create_post((object) [
|
||||
'discussion' => $post5->discussion,
|
||||
'parent' => $post5->id,
|
||||
'userid' => $user->id,
|
||||
'mailnow' => 1,
|
||||
'subject' => 'old post',
|
||||
// Two days ago which makes it an "old post".
|
||||
'modified' => time() - 172800
|
||||
]);
|
||||
|
||||
forum_tp_add_read_record($user->id, $post1->id);
|
||||
forum_tp_add_read_record($user->id, $post4->id);
|
||||
$CFG->forum_oldpostdays = 1;
|
||||
|
||||
$counts = $this->vault->get_unread_count_for_discussion_ids($user, [$discussion1->id]);
|
||||
$this->assertCount(1, $counts);
|
||||
$this->assertEquals(2, $counts[$discussion1->id]);
|
||||
|
||||
$counts = $this->vault->get_unread_count_for_discussion_ids($user, [$discussion1->id, $discussion2->id]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(2, $counts[$discussion1->id]);
|
||||
$this->assertEquals(2, $counts[$discussion2->id]);
|
||||
|
||||
$counts = $this->vault->get_unread_count_for_discussion_ids($user, [
|
||||
$discussion1->id,
|
||||
$discussion2->id,
|
||||
$discussion2->id + 1000
|
||||
]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(2, $counts[$discussion1->id]);
|
||||
$this->assertEquals(2, $counts[$discussion2->id]);
|
||||
|
||||
$counts = $this->vault->get_unread_count_for_discussion_ids($otheruser, [$discussion1->id, $discussion2->id]);
|
||||
$this->assertCount(2, $counts);
|
||||
$this->assertEquals(4, $counts[$discussion1->id]);
|
||||
$this->assertEquals(2, $counts[$discussion2->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_unread_count_for_discussion_ids when no discussion ids were provided.
|
||||
*
|
||||
* @covers ::get_unread_count_for_discussion_ids
|
||||
*/
|
||||
public function test_get_unread_count_for_discussion_ids_empty() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $this->vault->get_unread_count_for_discussion_ids($user, [], false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_latest_post_id_for_discussion_ids.
|
||||
*
|
||||
* @covers ::get_latest_post_id_for_discussion_ids
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_latest_post_id_for_discussion_ids() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$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);
|
||||
$post3 = $this->helper_reply_to_post($post1, $user);
|
||||
$post4 = $this->helper_reply_to_post($post2, $user);
|
||||
[$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);
|
||||
|
||||
$ids = $this->vault->get_latest_post_id_for_discussion_ids([$discussion1->id]);
|
||||
$this->assertCount(1, $ids);
|
||||
$this->assertEquals($post4->id, $ids[$discussion1->id]);
|
||||
|
||||
$ids = $this->vault->get_latest_post_id_for_discussion_ids([$discussion1->id, $discussion2->id]);
|
||||
$this->assertCount(2, $ids);
|
||||
$this->assertEquals($post4->id, $ids[$discussion1->id]);
|
||||
$this->assertEquals($post6->id, $ids[$discussion2->id]);
|
||||
|
||||
$ids = $this->vault->get_latest_post_id_for_discussion_ids([$discussion1->id, $discussion2->id, $discussion3->id]);
|
||||
$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]);
|
||||
|
||||
$ids = $this->vault->get_latest_post_id_for_discussion_ids([
|
||||
$discussion1->id,
|
||||
$discussion2->id,
|
||||
$discussion3->id,
|
||||
$discussion3->id + 1000
|
||||
]);
|
||||
$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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_latest_post_id_for_discussion_ids when no discussion ids were provided.
|
||||
*
|
||||
* @covers ::get_latest_post_id_for_discussion_ids
|
||||
* @covers ::<!public>
|
||||
*/
|
||||
public function test_get_latest_post_id_for_discussion_ids_empty() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$datagenerator = $this->getDataGenerator();
|
||||
$user = $datagenerator->create_user();
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->assertEquals([], $this->vault->get_latest_post_id_for_discussion_ids([]));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user