MDL-50426 message: optional permission check on message

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.
This commit is contained in:
Ryan Wyllie 2015-10-13 03:45:24 +00:00 committed by Dan Poltawski
parent e24188c881
commit cd0c9ac87d
8 changed files with 199 additions and 31 deletions

View 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})';

View 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();

View 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();

View 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;
}

View File

@ -113,6 +113,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.
*
@ -122,7 +137,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;
@ -130,7 +146,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));

File diff suppressed because one or more lines are too long

View File

@ -113,6 +113,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.
*
@ -122,7 +137,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;
@ -130,7 +146,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));

View 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));