Skip to content

Commit

Permalink
MDL-22077 forum: Add forum private replies
Browse files Browse the repository at this point in the history
This patch adds new capabilities:
'mod/forum:postprivatereply'   - whether a user is able to post private replies; and
'mod/forum:readprivatereplies' - whether a user is able to read private replies.

Private replies are only visible to the intended recipient (the author of
the parent post), the author of the private reply, and those with the
ability to read private replies.

If a post is private then it cannot be replied to further.
  • Loading branch information
andrewnicols authored and Peter committed Apr 4, 2019
1 parent 12a1f9c commit bc4c733
Show file tree
Hide file tree
Showing 47 changed files with 1,805 additions and 141 deletions.
16 changes: 12 additions & 4 deletions mod/forum/classes/local/builders/exported_discussion_summaries.php
Expand Up @@ -32,6 +32,7 @@
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\manager as manager_factory;
use rating_manager;
use renderer_base;
use stdClass;
Expand Down Expand Up @@ -67,6 +68,9 @@ class exported_discussion_summaries {
/** @var vault_factory $vaultfactory Vault factory */
private $vaultfactory;

/** @var manager_factory $managerfactory Manager factory */
private $managerfactory;

/** @var rating_manager $ratingmanager Rating manager */
private $ratingmanager;

Expand All @@ -84,12 +88,14 @@ public function __construct(
legacy_data_mapper_factory $legacydatamapperfactory,
exporter_factory $exporterfactory,
vault_factory $vaultfactory,
manager_factory $managerfactory,
rating_manager $ratingmanager
) {
$this->renderer = $renderer;
$this->legacydatamapperfactory = $legacydatamapperfactory;
$this->exporterfactory = $exporterfactory;
$this->vaultfactory = $vaultfactory;
$this->managerfactory = $managerfactory;
$this->ratingmanager = $ratingmanager;
}

Expand All @@ -108,24 +114,26 @@ public function build(
forum_entity $forum,
array $discussions
) : array {
$capabilitymanager = $this->managerfactory->get_capability_manager($forum);
$canseeanyprivatereply = $capabilitymanager->can_view_any_private_reply($user);

$discussionids = array_keys($discussions);

$postvault = $this->vaultfactory->get_post_vault();
$posts = $postvault->get_from_discussion_ids($discussionids);
$posts = $postvault->get_from_discussion_ids($user, $discussionids, $canseeanyprivatereply);
$groupsbyid = $this->get_groups_available_in_forum($forum);
$groupsbyauthorid = $this->get_author_groups_from_posts($posts, $forum);

$replycounts = $postvault->get_reply_count_for_discussion_ids($discussionids);
$latestposts = $postvault->get_latest_post_id_for_discussion_ids($discussionids);
$replycounts = $postvault->get_reply_count_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
$latestposts = $postvault->get_latest_post_id_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);

$unreadcounts = [];

$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
$forumrecord = $forumdatamapper->to_legacy_object($forum);

if (forum_tp_can_track_forums($forumrecord)) {
$unreadcounts = $postvault->get_unread_count_for_discussion_ids($user, $discussionids);
$unreadcounts = $postvault->get_unread_count_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
}

$summaryexporter = $this->exporterfactory->get_discussion_summaries_exporter(
Expand Down
3 changes: 3 additions & 0 deletions mod/forum/classes/local/builders/exported_posts.php
Expand Up @@ -107,6 +107,9 @@ public function __construct(
* to load the additional resources as efficiently as possible but there is no way around some of
* the additional overhead.
*
* Note: Some posts will be removed as part of the build process according to capabilities.
* A one-to-one mapping should not be expected.
*
* @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
Expand Down
3 changes: 2 additions & 1 deletion mod/forum/classes/local/data_mappers/legacy/post.php
Expand Up @@ -59,7 +59,8 @@ public function to_legacy_objects(array $posts) : array {
'attachment' => $post->has_attachments(),
'totalscore' => $post->get_total_score(),
'mailnow' => $post->should_mail_now(),
'deleted' => $post->is_deleted()
'deleted' => $post->is_deleted(),
'privatereplyto' => $post->get_private_reply_recipient_id(),
];
}, $posts);
}
Expand Down
36 changes: 35 additions & 1 deletion mod/forum/classes/local/entities/post.php
Expand Up @@ -65,6 +65,8 @@ class post {
private $mailnow;
/** @var bool $deleted Is the post deleted */
private $deleted;
/** @var int $privatereplyto The user being privately replied to */
private $privatereplyto;

/**
* Constructor.
Expand All @@ -84,6 +86,7 @@ class post {
* @param int $totalscore Total score
* @param bool $mailnow Should this post be mailed immediately
* @param bool $deleted Is the post deleted
* @param int $privatereplyto Which user this reply is intended for in a private reply situation
*/
public function __construct(
int $id,
Expand All @@ -100,7 +103,8 @@ public function __construct(
bool $hasattachments,
int $totalscore,
bool $mailnow,
bool $deleted
bool $deleted,
int $privatereplyto
) {
$this->id = $id;
$this->discussionid = $discussionid;
Expand All @@ -117,6 +121,7 @@ public function __construct(
$this->totalscore = $totalscore;
$this->mailnow = $mailnow;
$this->deleted = $deleted;
$this->privatereplyto = $privatereplyto;
}

/**
Expand Down Expand Up @@ -263,6 +268,25 @@ public function is_deleted() : bool {
return $this->deleted;
}

/**
* Is this post private?
*
* @return bool
*/
public function is_private_reply() : bool {
return !empty($this->privatereplyto);
}

/**
* Get the id of the user that this post was intended for.
*
* @return int
*/
public function get_private_reply_recipient_id() : int {
return $this->privatereplyto;
}


/**
* Get the post's age in seconds.
*
Expand All @@ -281,4 +305,14 @@ public function get_age() : int {
public function is_owned_by_user(stdClass $user) : bool {
return $this->get_author_id() == $user->id;
}

/**
* Check if the given post is a private reply intended for the given user.
*
* @param stdClass $user The user to check.
* @return bool
*/
public function is_private_reply_intended_for_user(stdClass $user) : bool {
return $this->get_private_reply_recipient_id() == $user->id;
}
}
17 changes: 4 additions & 13 deletions mod/forum/classes/local/exporters/author.php
Expand Up @@ -27,6 +27,7 @@
defined('MOODLE_INTERNAL') || die();

use mod_forum\local\entities\author as author_entity;
use mod_forum\local\exporters\group as group_exporter;
use core\external\exporter;
use renderer_base;

Expand Down Expand Up @@ -81,31 +82,21 @@ protected static function define_other_properties() {
'null' => NULL_ALLOWED
],
'groups' => [
'type' => group_exporter::read_properties_definition(),
'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' => [
'description' => 'The URL for the use profile page',
'type' => PARAM_URL,
'optional' => true,
'default' => null,
'null' => NULL_ALLOWED
],
'profileimage' => [
'description' => 'The URL for the use profile image',
'type' => PARAM_URL,
'optional' => true,
'default' => null,
Expand Down
110 changes: 110 additions & 0 deletions mod/forum/classes/local/exporters/group.php
@@ -0,0 +1,110 @@
<?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/>.

/**
* Course Group exporter.
*
* @package mod_forum
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @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;
use stdClass;

require_once($CFG->dirroot . '/mod/forum/lib.php');

/**
* Group exporter.
*
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class group extends exporter {
/** @var stdClass $group Group */
private $group;

/**
* Constructor.
*
* @param stdClass $group The group to export
* @param array $related The related data for the export.
*/
public function __construct(stdClass $group, array $related = []) {
$this->group = $group;
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
],
'urls' => [
'type' => [
'image' => [
'description' => 'The URL for the group image',
'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) {
return [
'id' => $group->id,
'urls' => [
'image' => $imageurl ? $imageurl->out(false) : null
]
];
}

/**
* Returns a list of objects that are related.
*
* @return array
*/
protected static function define_related() {
return [
'urlmanager' => 'mod_forum\local\managers\url',
'context' => 'context'
];
}
}

0 comments on commit bc4c733

Please sign in to comment.