Merge branch 'MDL-65017-master' of git://github.com/jleyva/moodle
authorAdrian Greeve <abgreeve@gmail.com>
Thu, 24 Oct 2019 05:53:01 +0000 (13:53 +0800)
committerAdrian Greeve <abgreeve@gmail.com>
Thu, 24 Oct 2019 05:53:01 +0000 (13:53 +0800)
mod/forum/classes/local/managers/capability.php
mod/forum/db/services.php
mod/forum/externallib.php
mod/forum/lang/en/deprecated.txt
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/post.php
mod/forum/tests/events_test.php
mod/forum/tests/externallib_test.php
mod/forum/tests/managers_capability_test.php
mod/forum/version.php

index b1fd17f..42bcda2 100644 (file)
@@ -36,6 +36,7 @@ use mod_forum\subscriptions;
 use context;
 use context_system;
 use stdClass;
+use moodle_exception;
 
 require_once($CFG->dirroot . '/mod/forum/lib.php');
 
@@ -430,28 +431,63 @@ class capability {
     }
 
     /**
-     * Can the user delete the post in this discussion?
+     * Verifies is the given user can delete a post.
      *
      * @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
+     * @param bool $hasreplies Whether the post has replies
      * @return bool
+     * @throws moodle_exception
      */
-    public function can_delete_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
+    public function validate_delete_post(stdClass $user, discussion_entity $discussion, post_entity $post,
+            bool $hasreplies = false) : void {
         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;
+            throw new moodle_exception('cannotdeletepost', 'forum');
+        }
+
+        $context = $this->get_context();
+        $ownpost = $post->is_owned_by_user($user);
+        $ineditingtime = $post->get_age() < $CFG->maxeditingtime;
+
+        if (!($ownpost && $ineditingtime && has_capability('mod/forum:deleteownpost', $context, $user) ||
+                has_capability('mod/forum:deleteanypost', $context, $user))) {
+
+            throw new moodle_exception('cannotdeletepost', 'forum');
+        }
+
+        if ($post->get_total_score()) {
+            throw new moodle_exception('couldnotdeleteratings', 'rating');
+        }
+
+        if ($hasreplies && !has_capability('mod/forum:deleteanypost', $context, $user)) {
+            throw new moodle_exception('couldnotdeletereplies', 'forum');
+        }
+    }
+
+
+    /**
+     * 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
+     * @param bool $hasreplies Whether the post has replies
+     * @return bool
+     */
+    public function can_delete_post(stdClass $user, discussion_entity $discussion, post_entity $post,
+            bool $hasreplies = false) : bool {
 
-            return ($ownpost && $ineditingtime && has_capability('mod/forum:deleteownpost', $context, $user)) ||
-                has_capability('mod/forum:deleteanypost', $context, $user);
+        try {
+            $this->validate_delete_post($user, $discussion, $post, $hasreplies);
+            return true;
+        } catch (moodle_exception $e) {
+            return false;
         }
     }
 
index aac784e..f6cee74 100644 (file)
@@ -175,4 +175,12 @@ $functions = array(
         'ajax' => true,
         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
     ),
+    'mod_forum_delete_post' => array(
+        'classname' => 'mod_forum_external',
+        'methodname' => 'delete_post',
+        'classpath' => 'mod/forum/externallib.php',
+        'description' => 'Deletes a post or a discussion completely when the post is the discussion topic.',
+        'type' => 'write',
+        'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+    ),
 );
index 6fc937d..624e723 100644 (file)
@@ -2043,4 +2043,113 @@ class mod_forum_external extends external_api {
     public static function set_pin_state_returns() {
         return discussion_exporter::get_read_structure();
     }
+
+    /**
+     * Returns description of method parameters
+     *
+     * @return external_function_parameters
+     * @since Moodle 3.8
+     */
+    public static function delete_post_parameters() {
+        return new external_function_parameters(
+            array(
+                'postid' => new external_value(PARAM_INT, 'Post to be deleted. It can be a discussion topic post.'),
+            )
+        );
+    }
+
+    /**
+     * Deletes a post or a discussion completely when the post is the discussion topic.
+     *
+     * @param int $postid post to be deleted, it can be a discussion topic post.
+     * @return array of warnings and the status (true if the post/discussion was deleted)
+     * @since Moodle 3.8
+     * @throws moodle_exception
+     */
+    public static function delete_post($postid) {
+        global $USER, $CFG;
+        require_once($CFG->dirroot . "/mod/forum/lib.php");
+
+        $params = self::validate_parameters(self::delete_post_parameters(),
+            array(
+                'postid' => $postid,
+            )
+        );
+        $warnings = array();
+        $vaultfactory = mod_forum\local\container::get_vault_factory();
+        $forumvault = $vaultfactory->get_forum_vault();
+        $discussionvault = $vaultfactory->get_discussion_vault();
+        $postvault = $vaultfactory->get_post_vault();
+        $postentity = $postvault->get_from_id($params['postid']);
+
+        if (empty($postentity)) {
+            throw new moodle_exception('invalidpostid', 'forum');
+        }
+
+        $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
+
+        if (empty($discussionentity)) {
+            throw new moodle_exception('notpartofdiscussion', 'forum');
+        }
+
+        $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
+        if (empty($forumentity)) {
+            throw new moodle_exception('invalidforumid', 'forum');
+        }
+
+        $context = $forumentity->get_context();
+
+        self::validate_context($context);
+
+        $managerfactory = mod_forum\local\container::get_manager_factory();
+        $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
+        $capabilitymanager = $managerfactory->get_capability_manager($forumentity);
+        $forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper();
+        $discussiondatamapper = $legacydatamapperfactory->get_discussion_data_mapper();
+        $postdatamapper = $legacydatamapperfactory->get_post_data_mapper();
+
+        $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id($USER, $postentity->get_id(),
+            $discussionentity->get_id(), true);
+        $hasreplies = $replycount > 0;
+
+        $capabilitymanager->validate_delete_post($USER, $discussionentity, $postentity, $hasreplies);
+
+        if (!$postentity->has_parent()) {
+            $status = forum_delete_discussion(
+                $discussiondatamapper->to_legacy_object($discussionentity),
+                false,
+                $forumentity->get_course_record(),
+                $forumentity->get_course_module_record(),
+                $forumdatamapper->to_legacy_object($forumentity)
+            );
+        } else {
+            $status = forum_delete_post(
+                $postdatamapper->to_legacy_object($postentity),
+                has_capability('mod/forum:deleteanypost', $context),
+                $forumentity->get_course_record(),
+                $forumentity->get_course_module_record(),
+                $forumdatamapper->to_legacy_object($forumentity)
+            );
+        }
+
+        $result = array();
+        $result['status'] = $status;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since Moodle 3.8
+     */
+    public static function delete_post_returns() {
+        return new external_single_structure(
+            array(
+                'status' => new external_value(PARAM_BOOL, 'True if the post/discussion was deleted, false otherwise.'),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
 }
index cddc5b1..1472327 100644 (file)
@@ -1,3 +1,4 @@
+cannotdeletediscussioninsinglediscussion,mod_forum
 inpagereplysubject,mod_forum
 overviewnumpostssince,mod_forum
 overviewnumunread,mod_forum
index 4232b42..4efc17b 100644 (file)
@@ -71,7 +71,6 @@ $string['cannotaddteacherforumto'] = 'Could not add converted teacher forum inst
 $string['cannotcreatediscussion'] = 'Could not create new discussion';
 $string['cannotcreateinstanceforteacher'] = 'Could not create new course module instance for the teacher forum';
 $string['cannotdeletepost'] = 'You can\'t delete this post!';
-$string['cannotdeletediscussioninsinglediscussion'] = 'You cannot delete the first post in a single discussion';
 $string['cannoteditposts'] = 'You can\'t edit other people\'s posts!';
 $string['cannotexportforum'] = 'You cannot export this forum';
 $string['cannotfinddiscussion'] = 'Could not find the discussion in this forum';
@@ -711,6 +710,7 @@ $string['forumsubjectdeleted'] = 'This forum post has been removed';
 $string['forumbodydeleted'] = 'The content of this forum post has been removed and can no longer be accessed.';
 
 // Deprecated since Moodle 3.8.
+$string['cannotdeletediscussioninsinglediscussion'] = 'You cannot delete the first post in a single discussion';
 $string['inpagereplysubject'] = 'Re: {$a}';
 $string['overviewnumpostssince'] = '{$a} posts since last login';
 $string['overviewnumunread'] = '{$a} total unread';
index 0f8902c..546c507 100644 (file)
@@ -3173,6 +3173,17 @@ function forum_delete_discussion($discussion, $fulldelete, $course, $cm, $forum)
         }
     }
 
+    $params = array(
+        'objectid' => $discussion->id,
+        'context' => context_module::instance($cm->id),
+        'other' => array(
+            'forumid' => $forum->id,
+        )
+    );
+    $event = \mod_forum\event\discussion_deleted::create($params);
+    $event->add_record_snapshot('forum_discussions', $discussion);
+    $event->trigger();
+
     return $result;
 }
 
index 342326c..2b95013 100644 (file)
@@ -369,73 +369,30 @@ if (!empty($forum)) {
     }
 
     $capabilitymanager = $managerfactory->get_capability_manager($forumentity);
-    $post = $postdatamapper->to_legacy_object($postentity);
-    $discussion = $discussiondatamapper->to_legacy_object($discussionentity);
-    $forum = $forumdatamapper->to_legacy_object($forumentity);
     $course = $forumentity->get_course_record();
+    $cm = $forumentity->get_course_module_record();
     $modcontext = $forumentity->get_context();
-    $coursecontext = context_course::instance($course->id);
-
-    if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) {
-        print_error('invalidcoursemodule');
-    }
 
     require_login($course, false, $cm);
 
-    if (!$capabilitymanager->can_delete_post($USER, $discussionentity, $postentity)) {
-        redirect(
-                $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
-                get_string('cannotdeletepost', 'forum'),
-                null,
-                \core\output\notification::NOTIFY_ERROR
-            );
-    }
-
     $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id(
         $USER, $postentity->get_id(), $discussionentity->get_id(), true);
 
     if (!empty($confirm) && confirm_sesskey()) {
-        // User has confirmed the delete.
-        // Check user capability to delete post.
-        $timepassed = time() - $post->created;
-        if ($post->totalscore) {
-            redirect(
-                    $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
-                    get_string('couldnotdeleteratings', 'rating'),
-                    null,
-                    \core\output\notification::NOTIFY_ERROR
-                );
-        } else if ($replycount && !has_capability('mod/forum:deleteanypost', $modcontext)) {
-            redirect(
-                    $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
-                    get_string('couldnotdeletereplies', 'forum'),
-                    null,
-                    \core\output\notification::NOTIFY_ERROR
-                );
-        } else {
-            if (!$postentity->has_parent()) {
-                // Post is a discussion topic as well, so delete discussion.
-                if ($forum->type == 'single') {
-                    redirect(
-                            $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
-                            get_string('cannotdeletediscussioninsinglediscussion', 'forum'),
-                            null,
-                            \core\output\notification::NOTIFY_ERROR
-                        );
-                }
-                forum_delete_discussion($discussion, false, $course, $cm, $forum);
+        // Do further checks and delete the post.
+        $hasreplies = $replycount > 0;
 
-                $params = array(
-                    'objectid' => $discussion->id,
-                    'context' => $modcontext,
-                    'other' => array(
-                        'forumid' => $forum->id,
-                    )
-                );
+        try {
+            $capabilitymanager->validate_delete_post($USER, $discussionentity, $postentity, $hasreplies);
 
-                $event = \mod_forum\event\discussion_deleted::create($params);
-                $event->add_record_snapshot('forum_discussions', $discussion);
-                $event->trigger();
+            if (!$postentity->has_parent()) {
+                forum_delete_discussion(
+                    $discussiondatamapper->to_legacy_object($discussionentity),
+                    false,
+                    $forumentity->get_course_record(),
+                    $forumentity->get_course_module_record(),
+                    $forumdatamapper->to_legacy_object($forumentity)
+                );
 
                 redirect(
                     $urlfactory->get_forum_view_url_from_forum($forumentity),
@@ -443,20 +400,16 @@ if (!empty($forum)) {
                     null,
                     \core\output\notification::NOTIFY_SUCCESS
                 );
-
             } else {
-                $deleted = forum_delete_post($post, has_capability('mod/forum:deleteanypost', $modcontext), $course, $cm, $forum);
-
-                if (!$deleted) {
-                    redirect(
-                            $urlfactory->get_discussion_view_url_from_post($postentity),
-                            get_string('errorwhiledelete', 'forum'),
-                            null,
-                            \core\output\notification::NOTIFY_ERROR
-                        );
-                }
+                forum_delete_post(
+                    $postdatamapper->to_legacy_object($postentity),
+                    has_capability('mod/forum:deleteanypost', $modcontext),
+                    $forumentity->get_course_record(),
+                    $forumentity->get_course_module_record(),
+                    $forumdatamapper->to_legacy_object($forumentity)
+                );
 
-                if ($forum->type == 'single') {
+                if ($forumentity->get_type() == 'single') {
                     // Single discussion forums are an exception.
                     // We show the forum itself since it only has one discussion thread.
                     $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity);
@@ -471,10 +424,29 @@ if (!empty($forum)) {
                     \core\output\notification::NOTIFY_SUCCESS
                 );
             }
+        } catch (Exception $e) {
+            redirect(
+                $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
+                $e->getMessage(),
+                null,
+                \core\output\notification::NOTIFY_ERROR
+            );
         }
 
-
     } else {
+
+        if (!$capabilitymanager->can_delete_post($USER, $discussionentity, $postentity)) {
+            redirect(
+                    $urlfactory->get_discussion_view_url_from_discussion($discussionentity),
+                    get_string('cannotdeletepost', 'forum'),
+                    null,
+                    \core\output\notification::NOTIFY_ERROR
+                );
+        }
+
+        $post = $postdatamapper->to_legacy_object($postentity);
+        $forum = $forumdatamapper->to_legacy_object($forumentity);
+
         // User just asked to delete something.
         forum_set_return();
         $PAGE->navbar->add(get_string('delete', 'forum'));
index 9bbd159..b4ee7ed 100644 (file)
@@ -1626,22 +1626,35 @@ class mod_forum_events_testcase extends advanced_testcase {
         $sink = $this->redirectEvents();
         forum_delete_discussion($discussion, true, $course, $cm, $forum);
         $events = $sink->get_events();
-        // We will have 3 events. One for the discussion (creating a discussion creates a post), and two for the posts.
-        $this->assertCount(3, $events);
+        // We will have 4 events. One for the discussion, another one for the discussion topic post, and two for the posts.
+        $this->assertCount(4, $events);
 
         // Loop through the events and check they are valid.
         foreach ($events as $event) {
-            $post = $posts[$event->objectid];
-
-            // Check that the event contains the expected values.
-            $this->assertInstanceOf('\mod_forum\event\post_deleted', $event);
-            $this->assertEquals(context_module::instance($forum->cmid), $event->get_context());
-            $expected = array($course->id, 'forum', 'delete post', "discuss.php?d={$discussion->id}", $post->id, $forum->cmid);
-            $this->assertEventLegacyLogData($expected, $event);
-            $url = new \moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id));
-            $this->assertEquals($url, $event->get_url());
-            $this->assertEventContextNotUsed($event);
-            $this->assertNotEmpty($event->get_name());
+
+            if ($event->objectid == $discussion->id) {
+                // Check that the event contains the expected values.
+                $this->assertInstanceOf('\mod_forum\event\discussion_deleted', $event);
+                $this->assertEquals(context_module::instance($forum->cmid), $event->get_context());
+                $expected = array($course->id, 'forum', 'delete discussion', "view.php?id={$forum->cmid}",
+                    $forum->id, $forum->cmid);
+                $this->assertEventLegacyLogData($expected, $event);
+                $url = new \moodle_url('/mod/forum/view.php', array('id' => $forum->cmid));
+                $this->assertEquals($url, $event->get_url());
+                $this->assertEventContextNotUsed($event);
+                $this->assertNotEmpty($event->get_name());
+            } else {
+                $post = $posts[$event->objectid];
+                // Check that the event contains the expected values.
+                $this->assertInstanceOf('\mod_forum\event\post_deleted', $event);
+                $this->assertEquals(context_module::instance($forum->cmid), $event->get_context());
+                $expected = array($course->id, 'forum', 'delete post', "discuss.php?d={$discussion->id}", $post->id, $forum->cmid);
+                $this->assertEventLegacyLogData($expected, $event);
+                $url = new \moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id));
+                $this->assertEquals($url, $event->get_url());
+                $this->assertEventContextNotUsed($event);
+                $this->assertNotEmpty($event->get_name());
+            }
         }
     }
 
index 7ef7955..7ee3275 100644 (file)
@@ -2498,4 +2498,110 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
         $this->assertEquals(0, $posts['posts'][0]['messagetrust']);
         $this->assertEquals($cleantext, $posts['posts'][0]['message']);
     }
+
+    /**
+     * Test delete a discussion.
+     */
+    public function test_delete_post_discussion() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        // Setup test data.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $user = $this->getDataGenerator()->create_user();
+        $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+        self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
+
+        // Add a discussion.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+
+        $this->setUser($user);
+        $result = mod_forum_external::delete_post($discussion->firstpost);
+        $result = external_api::clean_returnvalue(mod_forum_external::delete_post_returns(), $result);
+        $this->assertTrue($result['status']);
+        $this->assertEquals(0, $DB->count_records('forum_posts', array('id' => $discussion->firstpost)));
+        $this->assertEquals(0, $DB->count_records('forum_discussions', array('id' => $discussion->id)));
+    }
+
+    /**
+     * Test delete a post.
+     */
+    public function test_delete_post_post() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        // Setup test data.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $user = $this->getDataGenerator()->create_user();
+        $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+        self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
+
+        // Add a discussion.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+        $parentpost = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
+
+        // Add a post.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $record->discussion = $discussion->id;
+        $record->parent = $parentpost->id;
+        $post = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
+
+        $this->setUser($user);
+        $result = mod_forum_external::delete_post($post->id);
+        $result = external_api::clean_returnvalue(mod_forum_external::delete_post_returns(), $result);
+        $this->assertTrue($result['status']);
+        $this->assertEquals(1, $DB->count_records('forum_posts', array('discussion' => $discussion->id)));
+        $this->assertEquals(1, $DB->count_records('forum_discussions', array('id' => $discussion->id)));
+    }
+
+    /**
+     * Test delete a different user post.
+     */
+    public function test_delete_post_other_user_post() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        // Setup test data.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $user = $this->getDataGenerator()->create_user();
+        $otheruser = $this->getDataGenerator()->create_user();
+        $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+        self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
+        self::getDataGenerator()->enrol_user($otheruser->id, $course->id, $role->id);
+
+        // Add a discussion.
+        $record = array();
+        $record['course'] = $course->id;
+        $record['forum'] = $forum->id;
+        $record['userid'] = $user->id;
+        $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+        $parentpost = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
+
+        // Add a post.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $record->discussion = $discussion->id;
+        $record->parent = $parentpost->id;
+        $post = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
+
+        $this->setUser($otheruser);
+        $this->expectExceptionMessage(get_string('cannotdeletepost', 'forum'));
+        mod_forum_external::delete_post($post->id);
+    }
 }
index cd7d66c..3c1e68e 100644 (file)
@@ -1187,4 +1187,98 @@ class mod_forum_managers_capability_testcase extends advanced_testcase {
         $this->prevent_capability('mod/forum:readprivatereplies');
         $this->assertFalse($capabilitymanager->can_view_any_private_reply($this->user));
     }
+
+
+    /**
+     * Test delete a post with ratings.
+     */
+    public function test_validate_delete_post_with_ratings() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        // Setup test data.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $user = $this->getDataGenerator()->create_user();
+        $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+        self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
+
+        // Add a discussion.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $record->created =
+        $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+
+        // Add rating.
+        $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
+        $post->totalscore = 80;
+        $DB->update_record('forum_posts', $post);
+
+        $vaultfactory = mod_forum\local\container::get_vault_factory();
+        $forumvault = $vaultfactory->get_forum_vault();
+        $discussionvault = $vaultfactory->get_discussion_vault();
+        $postvault = $vaultfactory->get_post_vault();
+
+        $postentity = $postvault->get_from_id($post->id);
+        $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
+        $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
+        $capabilitymanager = $this->managerfactory->get_capability_manager($forumentity);
+
+        $this->setUser($user);
+        $this->expectExceptionMessage(get_string('couldnotdeleteratings', 'rating'));
+        $capabilitymanager->validate_delete_post($user, $discussionentity, $postentity, false);
+    }
+
+    /**
+     * Test delete a post with replies.
+     */
+    public function test_validate_delete_post_with_replies() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        // Setup test data.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $user = $this->getDataGenerator()->create_user();
+        $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+        self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
+
+        // Add a discussion.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $record->created =
+        $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+
+        $parentpost = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
+        // Add a post.
+        $record = new stdClass();
+        $record->course = $course->id;
+        $record->userid = $user->id;
+        $record->forum = $forum->id;
+        $record->discussion = $discussion->id;
+        $record->parent = $parentpost->id;
+        $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
+
+        $vaultfactory = mod_forum\local\container::get_vault_factory();
+        $forumvault = $vaultfactory->get_forum_vault();
+        $discussionvault = $vaultfactory->get_discussion_vault();
+        $postvault = $vaultfactory->get_post_vault();
+
+        $postentity = $postvault->get_from_id($parentpost->id);
+        $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
+        $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
+        $capabilitymanager = $this->managerfactory->get_capability_manager($forumentity);
+
+        $this->setUser($user);
+        // Get reply count.
+        $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id(
+            $user, $postentity->get_id(), $discussionentity->get_id(), true);
+        $this->expectExceptionMessage(get_string('couldnotdeletereplies', 'forum'));
+        $capabilitymanager->validate_delete_post($user, $discussionentity, $postentity, $replycount);
+    }
+
 }
index 9411f9f..89aebb9 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2019071902;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2019071903;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2019051100;       // Requires this Moodle version
 $plugin->component = 'mod_forum';      // Full name of the plugin (used for diagnostics)