MDL-50426 message: optional permission check on message
authorRyan Wyllie <ryan@moodle.com>
Tue, 13 Oct 2015 03:45:24 +0000 (03:45 +0000)
committerDan Poltawski <dan@moodle.com>
Thu, 5 Nov 2015 08:20:39 +0000 (08:20 +0000)
Changed the messaging API to allow you to provide a parameter
that will cause the code to check if the sender of the message
has the correct permissions before the message is sent.

The ajax messaging (message button on profile page) has been
updated to perform these permission checks. This brings it
inline with the existing private message page.

lang/en/message.php
message/ajax.php
message/index.php
message/lib.php
message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-debug.js
message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-min.js
message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger.js
message/yui/src/messenger/js/manager.js

index a618353..76264ed 100644 (file)
@@ -143,6 +143,7 @@ $string['thisconversation'] = 'this conversation';
 $string['timenosee'] = 'Minutes since I was last seen online';
 $string['timesent'] = 'Time sent';
 $string['touserdoesntexist'] = 'You can not send a message to a user id ({$a}) that doesn\'t exist';
+$string['unabletomessageuser'] = 'You are not permitted to send a message to that user';
 $string['unblockcontact'] = 'Unblock contact';
 $string['unreadmessages'] = 'Unread messages ({$a})';
 $string['unreadnewmessages'] = 'New messages ({$a})';
index a05a03d..b4362d6 100644 (file)
@@ -48,8 +48,6 @@ switch ($action) {
     // Sending a message.
     case 'sendmessage':
 
-        require_capability('moodle/site:sendmessage', context_system::instance());
-
         $userid = required_param('userid', PARAM_INT);
         if (empty($userid) || isguestuser($userid) || $userid == $USER->id) {
             // Cannot send messags to self, nobody or a guest.
@@ -58,10 +56,17 @@ switch ($action) {
 
         $message = required_param('message', PARAM_RAW);
         $user2 = core_user::get_user($userid);
-        $messageid = message_post_message($USER, $user2, $message, FORMAT_MOODLE);
 
-        if (!$messageid) {
-            throw new moodle_exception('errorwhilesendingmessage', 'core_message');
+        // Only attempt to send the message if we have permission to message
+        // the recipient.
+        if (message_can_post_message($user2, $USER)) {
+            $messageid = message_post_message($USER, $user2, $message, FORMAT_MOODLE);
+
+            if (!$messageid) {
+                throw new moodle_exception('errorwhilesendingmessage', 'core_message');
+            }
+        } else {
+            throw new moodle_exception('unabletomessageuser', 'core_message');
         }
 
         $response = array();
index a7e38e9..7777799 100644 (file)
@@ -193,17 +193,12 @@ if ($deletemessageid and confirm_sesskey()) {
 $messageerror = null;
 if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $systemcontext)) {
     // Check that the user is not blocking us!!
-    if ($contact = $DB->get_record('message_contacts', array('userid' => $user2->id, 'contactid' => $user1->id))) {
-        if ($contact->blocked and !has_capability('moodle/site:readallmessages', $systemcontext)) {
-            $messageerror = get_string('userisblockingyou', 'message');
-        }
+    if (message_is_user_blocked($user2, $user1)) {
+        $messageerror = get_string('userisblockingyou', 'message');
     }
-    $userpreferences = get_user_preferences(NULL, NULL, $user2->id);
-
-    if (!empty($userpreferences['message_blocknoncontacts'])) {  // User is blocking non-contacts
-        if (empty($contact)) {   // We are not a contact!
-            $messageerror = get_string('userisblockingyounoncontact', 'message', fullname($user2));
-        }
+    // Check that we're not non-contact block by the user.
+    if (message_is_user_non_contact_blocked($user2, $user1)) {
+        $messageerror = get_string('userisblockingyounoncontact', 'message', fullname($user2));
     }
 
     if (empty($messageerror)) {
@@ -354,13 +349,9 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
                 } else {
                     // Display a warning if the current user is blocking non-contacts and is about to message to a non-contact
                     // Otherwise they may wonder why they never get a reply
-                    $blocknoncontacts = get_user_preferences('message_blocknoncontacts', '', $user1->id);
-                    if (!empty($blocknoncontacts)) {
-                        $contact = $DB->get_record('message_contacts', array('userid' => $user1->id, 'contactid' => $user2->id));
-                        if (empty($contact)) {
-                            $msg = get_string('messagingblockednoncontact', 'message', fullname($user2));
-                            echo html_writer::tag('span', $msg, array('id' => 'messagewarning'));
-                        }
+                    if (message_is_user_non_contact_blocked($user1, $user2)) {
+                        $msg = get_string('messagingblockednoncontact', 'message', fullname($user2));
+                        echo html_writer::tag('span', $msg, array('id' => 'messagewarning'));
                     }
 
                     $mform = new send_form();
index d384496..e038f4e 100644 (file)
@@ -2830,6 +2830,10 @@ function message_messenger_requirejs() {
         'sendmessage',
         'viewconversation',
     ), 'core_message');
+    $PAGE->requires->strings_for_js(array(
+        'userisblockingyou',
+        'userisblockingyounoncontact'
+    ), 'message');
     $PAGE->requires->string_for_js('error', 'core');
 
     $done = true;
@@ -2842,10 +2846,117 @@ function message_messenger_requirejs() {
  * @return void
  */
 function message_messenger_sendmessage_link_params($user) {
-    return array(
+    $params = array(
         'data-trigger' => 'core_message-messenger::sendmessage',
         'data-fullname' => fullname($user),
         'data-userid' => $user->id,
         'role' => 'button'
     );
+
+    if (message_is_user_non_contact_blocked($user)) {
+        $params['data-blocked-string'] = 'userisblockingyounoncontact';
+    } else if (message_is_user_blocked($user)) {
+        $params['data-blocked-string'] = 'userisblockingyou';
+    }
+
+    return $params;
+}
+
+/**
+ * Determines if a user is permitted to send another user a private message.
+ * If no sender is provided then it defaults to the logged in user.
+ *
+ * @param object $recipient User object.
+ * @param object $sender User object.
+ * @return bool true if user is permitted, false otherwise.
+ */
+function message_can_post_message($recipient, $sender = null) {
+    global $USER, $DB;
+
+    if (is_null($sender)) {
+        // The message is from the logged in user, unless otherwise specified.
+        $sender = $USER;
+    }
+
+    if (!has_capability('moodle/site:sendmessage', context_system::instance(), $sender)) {
+        return false;
+    }
+
+    // The recipient blocks messages from non-contacts and the
+    // sender isn't a contact.
+    if (message_is_user_non_contact_blocked($recipient, $sender)) {
+        return false;
+    }
+
+    // The recipient has specifically blocked this sender.
+    if (message_is_user_blocked($recipient, $sender)) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Checks if the recipient is allowing messages from users that aren't a
+ * contact. If not then it checks to make sure the sender is in the
+ * recipient's contacts.
+ *
+ * @param object $recipient User object.
+ * @param object $sender User object.
+ * @return bool true if $sender is blocked, false otherwise.
+ */
+function message_is_user_non_contact_blocked($recipient, $sender = null) {
+    global $USER, $DB;
+
+    if (is_null($sender)) {
+        // The message is from the logged in user, unless otherwise specified.
+        $sender = $USER;
+    }
+
+    $blockednoncontacts = get_user_preferences('message_blocknoncontacts', '', $recipient->id);
+    if (!empty($blockednoncontacts)) {
+        // Confirm the sender is a contact of the recipient.
+        $exists = $DB->record_exists('message_contacts', array('userid' => $recipient->id, 'contactid' => $sender->id));
+        if ($exists) {
+            // All good, the recipient is a contact of the sender.
+            return false;
+        } else {
+            // Oh no, the recipient is not a contact. Looks like we can't send the message.
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * Checks if the recipient has specifically blocked the sending user.
+ *
+ * Note: This function will always return false if the sender has the
+ * readallmessages capability at the system context level.
+ *
+ * @param object $recipient User object.
+ * @param object $sender User object.
+ * @return bool true if $sender is blocked, false otherwise.
+ */
+function message_is_user_blocked($recipient, $sender = null) {
+    global $USER, $DB;
+
+    if (is_null($sender)) {
+        // The message is from the logged in user, unless otherwise specified.
+        $sender = $USER;
+    }
+
+    $systemcontext = context_system::instance();
+    if (has_capability('moodle/site:readallmessages', $systemcontext, $sender)) {
+        return false;
+    }
+
+    if ($contact = $DB->get_record('message_contacts', array('userid' => $recipient->id, 'contactid' => $sender->id))) {
+        if ($contact->blocked) {
+            return true;
+        }
+    }
+
+    return false;
 }
index 3d73d5d..f24feb0 100644 (file)
Binary files a/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-debug.js and b/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-debug.js differ
index 8f60a30..5f5a098 100644 (file)
Binary files a/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-min.js and b/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger-min.js differ
index 3d73d5d..f24feb0 100644 (file)
Binary files a/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger.js and b/message/yui/build/moodle-core_message-messenger/moodle-core_message-messenger.js differ
index f22a2af..916d51d 100644 (file)
@@ -71,6 +71,21 @@ Y.namespace('M.core_message.messenger').Manager = Y.extend(MANAGER, Y.Base, {
         this._sendMessageDialog.show(e);
     },
 
+    /**
+     * Pop up an alert dialogue to notify the logged in user that they are blocked from
+     * messaging the target user.
+     *
+     * @method alertBlocked
+     * @param  {String} blockedString The identifier to retrieve the blocked user message.
+     * @param  {String} fullName The target user's full name.
+     */
+    alertBlocked: function(blockedString, fullName) {
+        new M.core.alert({
+            title: M.util.get_string('error', 'core'),
+            message: M.util.get_string(blockedString, 'message', fullName)
+        });
+    },
+
     /**
      * Register the events.
      *
@@ -80,7 +95,8 @@ Y.namespace('M.core_message.messenger').Manager = Y.extend(MANAGER, Y.Base, {
         var captureEvent = function(e) {
             var target = e.currentTarget,
                 userid = parseInt(target.getData('userid'), 10),
-                fullname = target.getData('fullname');
+                fullname = target.getData('fullname'),
+                blockedString = target.getData('blocked-string');
 
             if (!userid || !fullname) {
                 return;
@@ -88,7 +104,11 @@ Y.namespace('M.core_message.messenger').Manager = Y.extend(MANAGER, Y.Base, {
 
             // Pass the validation before preventing defaults.
             e.preventDefault();
-            this.sendMessage(userid, fullname, e);
+            if (blockedString) {
+                this.alertBlocked(blockedString, fullname);
+            } else {
+                this.sendMessage(userid, fullname, e);
+            }
         };
 
         this._events.push(Y.delegate('click', captureEvent, 'body', SELECTORS.MANAGER.SENDMESSAGE, this));