From 4ea254faf22d5a603656723fbe72934dc84073a1 Mon Sep 17 00:00:00 2001
From: Julien Boulen <julien.boulen@univ-rennes2.fr>
Date: Mon, 9 Jan 2023 14:41:01 +0100
Subject: [PATCH] MDL-66924 mod_forum: Allow users to see their own private
 messages

Allow users to see their own private messages even if they don't have
mod/forum:readprivatereplies capability

Add behat test to avoid MDL-67109 issue.

Co-authored-by: Martin Putzlocher <mputzi@users.noreply.github.com>
---
 .../classes/local/managers/capability.php     |  4 ++
 mod/forum/tests/behat/private_replies.feature | 18 +++++++-
 mod/forum/tests/managers_capability_test.php  | 41 ++++++++++++++-----
 3 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/mod/forum/classes/local/managers/capability.php b/mod/forum/classes/local/managers/capability.php
index 76e347f1175..8a7096b53cb 100644
--- a/mod/forum/classes/local/managers/capability.php
+++ b/mod/forum/classes/local/managers/capability.php
@@ -405,6 +405,10 @@ class capability {
      *
      */
     public function can_view_post_shell(stdClass $user, post_entity $post) : bool {
+        if ($post->is_owned_by_user($user)) {
+            return true;
+        }
+
         if (!$post->is_private_reply()) {
             return true;
         }
diff --git a/mod/forum/tests/behat/private_replies.feature b/mod/forum/tests/behat/private_replies.feature
index 364dc3d7fd6..003255487a3 100644
--- a/mod/forum/tests/behat/private_replies.feature
+++ b/mod/forum/tests/behat/private_replies.feature
@@ -48,7 +48,7 @@ Feature: Forum posts can be replied to in private
     When I follow "Answers to the homework"
     Then I should see "How about you and I have a meeting after class about plagiarism?"
 
-  Scenario: As the intended recipient I can see my own response
+  Scenario: As the intended recipient I can see private response to me
     Given I log out
     And I log in as "student1"
     And I am on "Science 101" course homepage
@@ -56,10 +56,24 @@ Feature: Forum posts can be replied to in private
     When I follow "Answers to the homework"
     Then I should see "How about you and I have a meeting after class about plagiarism?"
 
-  Scenario: As a non-privileged user I cannot see my own response
+  Scenario: As a non-privileged user I cannot see private response to others
     Given I log out
     And I log in as "student2"
     And I am on "Science 101" course homepage
     And I follow "Study discussions"
     When I follow "Answers to the homework"
     Then I should not see "How about you and I have a meeting after class about plagiarism?"
+
+  Scenario: As privileged user that can post but not read private replies I can see my own private reply
+    Given I log out
+    And the following "permission overrides" exist:
+      | capability                   | permission | role          | contextlevel | reference |
+      | mod/forum:postprivatereply   | Allow      | student       | System       |           |
+      | mod/forum:readprivatereplies | Prohibit   | student       | System       |           |
+    And I log in as "student2"
+    And I am on "Science 101" course homepage
+    When I reply "Answers to the homework" post from "Study discussions" forum with:
+      | Message         | Not yet. |
+      | Reply privately | 1        |
+    Then I should see "Not yet."
+    And I should not see "How about you and I have a meeting after class about plagiarism?"
diff --git a/mod/forum/tests/managers_capability_test.php b/mod/forum/tests/managers_capability_test.php
index fb5e5979f29..87a9a0bd4fe 100644
--- a/mod/forum/tests/managers_capability_test.php
+++ b/mod/forum/tests/managers_capability_test.php
@@ -1056,8 +1056,9 @@ class managers_capability_test extends \advanced_testcase {
         $discussion = $this->discussion;
         $post = $this->post;
 
+        $postproperties = ['parent' => $post->get_id(), 'userid' => $otheruser->id, 'privatereplyto' => $otheruser->id];
         $privatepost = $this->entityfactory->get_post_from_stdClass(
-            (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
+            (object) array_merge((array) $this->postrecord, $postproperties)
         );
 
         $this->prevent_capability('mod/forum:readprivatereplies');
@@ -1080,23 +1081,41 @@ class managers_capability_test extends \advanced_testcase {
 
         $discussion = $this->discussion;
         $post = $this->post;
-        $privatepost = $this->entityfactory->get_post_from_stdClass(
-            (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
-        );
-        $privateposttome = $this->entityfactory->get_post_from_stdClass(
-            (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $user->id])
+
+        $postproperties = ['parent' => $post->get_id(), 'userid' => $user->id, 'privatereplyto' => $user->id];
+        $privatepostfrommetome = $this->entityfactory->get_post_from_stdClass(
+            (object) array_merge((array) $this->postrecord, $postproperties)
         );
 
-        // Can always view public replies, and those to me.
+        $postproperties = ['parent' => $post->get_id(), 'userid' => $user->id, 'privatereplyto' => $otheruser->id];
+        $privatepostfrommetoother = $this->entityfactory->get_post_from_stdClass(
+            (object) array_merge((array) $this->postrecord, $postproperties)
+        );
+
+        $postproperties = ['parent' => $post->get_id(), 'userid' => $otheruser->id, 'privatereplyto' => $user->id];
+        $privatepostfromothertome = $this->entityfactory->get_post_from_stdClass(
+            (object) array_merge((array) $this->postrecord, $postproperties)
+        );
+
+        $postproperties = ['parent' => $post->get_id(), 'userid' => $otheruser->id, 'privatereplyto' => $otheruser->id];
+        $privatepostfromothertoother = $this->entityfactory->get_post_from_stdClass(
+            (object) array_merge((array) $this->postrecord, $postproperties)
+        );
+
+        // Can always view public replies, and private replies by me or to me.
         $this->prevent_capability('mod/forum:readprivatereplies');
         $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
-        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
-        $this->assertFalse($capabilitymanager->can_view_post_shell($this->user, $privatepost));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfrommetome));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfrommetoother));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfromothertome));
+        $this->assertFalse($capabilitymanager->can_view_post_shell($this->user, $privatepostfromothertoother));
 
         $this->give_capability('mod/forum:readprivatereplies');
         $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
-        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
-        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepost));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfrommetome));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfrommetoother));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfromothertome));
+        $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepostfromothertoother));
     }
 
     /**