MDL-65132 core_message: Added WS to delete message for all users
authorcescobedo <carlos.escobedo@gmail.com>
Thu, 2 May 2019 14:07:20 +0000 (16:07 +0200)
committercescobedo <carlos.escobedo@gmail.com>
Mon, 6 May 2019 07:39:34 +0000 (09:39 +0200)
Also, added WS new return parameter candeletemessagesforallusers in get_conversation
and send_instant_message and added API support. This will be used to check
if the user can delete all messages in the conversation.

lib/db/services.php
message/externallib.php
message/tests/externallib_test.php
version.php

index 869a22f..708f2cc 100644 (file)
@@ -1407,6 +1407,16 @@ $functions = array(
         'ajax' => true,
         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
     ),
+    'core_message_delete_message_for_all_users' => array(
+        'classname' => 'core_message_external',
+        'methodname' => 'delete_message_for_all_users',
+        'classpath' => 'message/externallib.php',
+        'description' => 'Deletes a message for all users.',
+        'type' => 'write',
+        'capabilities' => 'moodle/site:deleteanymessage',
+        'ajax' => true,
+        'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+    ),
     'core_notes_create_notes' => array(
         'classname' => 'core_notes_external',
         'methodname' => 'create_notes',
index 4f23efa..0bddf88 100644 (file)
@@ -159,6 +159,9 @@ class core_message_external extends external_api {
         self::validate_context($context);
         require_capability('moodle/site:sendmessage', $context);
 
+        // Ensure the current user is allowed to delete message for everyone.
+        $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
+
         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
 
         //retrieve all tousers of the messages
@@ -205,6 +208,7 @@ class core_message_external extends external_api {
             if ($success) {
                 $resultmsg['msgid'] = $success;
                 $resultmsg['timecreated'] = time();
+                $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
                 $messageids[] = $success;
             } else {
                 // WARNINGS: for backward compatibility we return this errormessage.
@@ -257,6 +261,8 @@ class core_message_external extends external_api {
                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
                     'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
                     'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
+                    'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
+                        'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
                 )
             )
         );
@@ -1260,6 +1266,8 @@ class core_message_external extends external_api {
                 'messages' => new external_multiple_structure(
                     self::get_conversation_message_structure()
                 ),
+                'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
+                    'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
             )
         );
     }
@@ -4806,4 +4814,68 @@ class core_message_external extends external_api {
             ]
         );
     }
+
+    /**
+     * Returns description of method parameters
+     *
+     * @return external_function_parameters
+     * @since 3.7
+     */
+    public static function delete_message_for_all_users_parameters() {
+        return new external_function_parameters(
+            array(
+                'messageid' => new external_value(PARAM_INT, 'The message id'),
+                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
+            )
+        );
+    }
+    /**
+     * Deletes a message for all users
+     *
+     * @param  int $messageid the message id
+     * @param  int $userid the user id of who we want to delete the message for all users
+     * @return external_description
+     * @throws moodle_exception
+     * @since 3.7
+     */
+    public static function delete_message_for_all_users(int $messageid, int $userid) {
+        global $CFG;
+
+        // Check if private messaging between users is allowed.
+        if (empty($CFG->messaging)) {
+            throw new moodle_exception('disabled', 'message');
+        }
+
+        // Validate params.
+        $params = array(
+            'messageid' => $messageid,
+            'userid' => $userid
+        );
+        $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
+
+        // Validate context.
+        $context = context_system::instance();
+        self::validate_context($context);
+
+        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
+        core_user::require_active_user($user);
+
+        // Checks if a user can delete a message for all users.
+        if (core_message\api::can_delete_message_for_all_users($user->id, $params['messageid'])) {
+            \core_message\api::delete_message_for_all_users($params['messageid']);
+        } else {
+            throw new moodle_exception('You do not have permission to delete this message for everyone.');
+        }
+
+        return [];
+    }
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since 3.7
+     */
+    public static function delete_message_for_all_users_returns() {
+        return new external_warnings();
+    }
 }
index 5099995..1c9ed72 100644 (file)
@@ -7102,4 +7102,164 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals($expectedunreadcounts['types'][\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF],
             $counts['types'][\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF]);
     }
+
+    /**
+     * Test delete_message for all users.
+     */
+    public function test_delete_message_for_all_users() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Create fake data to test it.
+        list($user1, $user2, $user3, $convgroup, $convindividual) = $this->create_delete_message_test_data();
+
+        // Send message as user1 to group conversation.
+        $messageid1 = testhelper::send_fake_message_to_conversation($user1, $convgroup->id);
+        $messageid2 = testhelper::send_fake_message_to_conversation($user2, $convgroup->id);
+
+        // User1 deletes the first message for all users of group conversation.
+        // First, we have to allow user1 (Teacher) can delete messages for all users.
+        $editingteacher = $DB->get_record('role', ['shortname' => 'editingteacher']);
+        assign_capability('moodle/site:deleteanymessage', CAP_ALLOW, $editingteacher->id, context_system::instance());
+
+        $this->setUser($user1);
+
+        // Now, user1 deletes message for all users.
+        $return = core_message_external::delete_message_for_all_users($messageid1, $user1->id);
+        $return = external_api::clean_returnvalue(core_message_external::delete_message_for_all_users_returns(), $return);
+        // Check if everything is ok.
+        $this->assertEquals(array(), $return);
+
+        // Check we have 3 records on message_user_actions with the mark MESSAGE_ACTION_DELETED.
+        $muas = $DB->get_records('message_user_actions', array('messageid' => $messageid1), 'userid ASC');
+        $this->assertCount(3, $muas);
+        $mua1 = array_shift($muas);
+        $mua2 = array_shift($muas);
+        $mua3 = array_shift($muas);
+
+        $this->assertEquals($user1->id, $mua1->userid);
+        $this->assertEquals($messageid1, $mua1->messageid);
+        $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
+        $this->assertEquals($user2->id, $mua2->userid);
+        $this->assertEquals($messageid1, $mua2->messageid);
+        $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
+        $this->assertEquals($user3->id, $mua3->userid);
+        $this->assertEquals($messageid1, $mua3->messageid);
+        $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
+    }
+
+    /**
+     * Test delete_message for all users with messaging disabled.
+     */
+    public function test_delete_message_for_all_users_messaging_disabled() {
+        global $CFG;
+
+        $this->resetAfterTest();
+
+        // Create fake data to test it.
+        list($user1, $user2, $user3, $convgroup, $convindividual) = $this->create_delete_message_test_data();
+
+        // Send message as user1 to group conversation.
+        $messageid = testhelper::send_fake_message_to_conversation($user1, $convgroup->id);
+
+        $this->setUser($user1);
+
+        // Disable messaging.
+        $CFG->messaging = 0;
+
+        // Ensure an exception is thrown.
+        $this->expectException('moodle_exception');
+        core_message_external::delete_message_for_all_users($messageid, $user1->id);
+    }
+
+    /**
+     * Test delete_message for all users with no permission.
+     */
+    public function test_delete_message_for_all_users_no_permission() {
+        $this->resetAfterTest();
+
+        // Create fake data to test it.
+        list($user1, $user2, $user3, $convgroup, $convindividual) = $this->create_delete_message_test_data();
+
+        // Send message as user1 to group conversation.
+        $messageid = testhelper::send_fake_message_to_conversation($user1, $convgroup->id);
+
+        $this->setUser($user2);
+
+        // Try as user2 to delete a message for all users without permission to do it.
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage('You do not have permission to delete this message for everyone.');
+        core_message_external::delete_message_for_all_users($messageid, $user2->id);
+    }
+
+    /**
+     * Test delete_message for all users in a private conversation.
+     */
+    public function test_delete_message_for_all_users_private_conversation() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        // Create fake data to test it.
+        list($user1, $user2, $user3, $convgroup, $convindividual) = $this->create_delete_message_test_data();
+
+        // Send message as user1 to private conversation.
+        $messageid = testhelper::send_fake_message_to_conversation($user1, $convindividual->id);
+
+        // First, we have to allow user1 (Teacher) can delete messages for all users.
+        $editingteacher = $DB->get_record('role', ['shortname' => 'editingteacher']);
+        assign_capability('moodle/site:deleteanymessage', CAP_ALLOW, $editingteacher->id, context_system::instance());
+
+        $this->setUser($user1);
+
+        // Try as user1 to delete a private message for all users on individual conversation.
+        // User1 should not delete message for all users in a private conversations despite being a teacher.
+        // Because is a teacher in a course and not in a system context.
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage('You do not have permission to delete this message for everyone.');
+        core_message_external::delete_message_for_all_users($messageid, $user1->id);
+    }
+
+    /**
+     * Helper to seed the database with initial state with data.
+     */
+    protected function create_delete_message_test_data() {
+        // Create some users.
+        $user1 = self::getDataGenerator()->create_user();
+        $user2 = self::getDataGenerator()->create_user();
+        $user3 = self::getDataGenerator()->create_user();
+
+        // Create a course and enrol the users.
+        $course = $this->getDataGenerator()->create_course();
+        $coursecontext = context_course::instance($course->id);
+        $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'editingteacher');
+        $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
+        $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student');
+
+        // Create a group and added the users into.
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
+        groups_add_member($group1->id, $user1->id);
+        groups_add_member($group1->id, $user2->id);
+        groups_add_member($group1->id, $user3->id);
+
+        // Create a group conversation linked with the course.
+        $convgroup = \core_message\api::create_conversation(
+            \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
+            [$user1->id, $user2->id, $user3->id],
+            'Group test delete for everyone', \core_message\api::MESSAGE_CONVERSATION_ENABLED,
+            'core_group',
+            'groups',
+            $group1->id,
+            context_course::instance($course->id)->id
+        );
+
+        // Create and individual conversation.
+        $convindividual = \core_message\api::create_conversation(
+            \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
+            [$user1->id, $user2->id]
+        );
+
+        return [$user1, $user2, $user3, $convgroup, $convindividual];
+    }
 }
index a7b5515..9dbdfb4 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2019050300.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2019050300.01;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.