MDL-65093 core_message: users can't block any user they want

If blocking will have no effect (ie. you are attempting to block
the admin) the 'Block' button will not be shown and instead a
message will be shown explaining why you can not block the user.
This commit is contained in:
Mark Nelson 2019-07-04 14:55:30 +08:00
parent 06d046c1ff
commit 90403c5d9d
16 changed files with 201 additions and 16 deletions

View File

@ -39,6 +39,7 @@ $string['blockuserconfirm'] = 'Are you sure you want to block {$a}?';
$string['blockuserconfirmbutton'] = 'Block';
$string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
$string['cancelselection'] = 'Cancel message selection';
$string['cantblockuser'] = 'You are unable to block {$a} because they have a role with permission to message all users';
$string['contactableprivacy'] = 'Accept messages from:';
$string['contactableprivacy_onlycontacts'] = 'My contacts only';
$string['contactableprivacy_coursemember'] = 'My contacts and anyone in my courses';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -182,7 +182,8 @@ function(
isblocked: null,
iscontact: null,
isdeleted: null,
canmessage: null,
canmessage: null,
canmessageevenifblocked: null,
requirescontact: null,
contactrequests: []
};

View File

@ -1069,10 +1069,17 @@ function(
*/
var renderConfirmBlockUser = function(header, body, footer, user) {
if (user) {
return Str.get_string('blockuserconfirm', 'core_message', user.fullname)
.then(function(string) {
return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_BLOCK], string, '', true, false);
});
if (user.canmessageevenifblocked) {
return Str.get_string('cantblockuser', 'core_message', user.fullname)
.then(function(string) {
return showConfirmDialogue(header, body, footer, [], string, '', true, false);
});
} else {
return Str.get_string('blockuserconfirm', 'core_message', user.fullname)
.then(function(string) {
return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_BLOCK], string, '', true, false);
});
}
} else {
return hideConfirmDialogue(header, body, footer);
}

View File

@ -88,7 +88,8 @@ define(['jquery'], function($) {
isblocked: member.isblocked,
iscontact: member.iscontact,
isdeleted: member.isdeleted,
canmessage: member.canmessage,
canmessage: member.canmessage,
canmessageevenifblocked: member.canmessageevenifblocked,
requirescontact: member.requirescontact,
contactrequests: member.contactrequests || []
};

View File

@ -1869,9 +1869,11 @@ class api {
*
* @param int $recipientid The recipient user id.
* @param int $senderid The sender user id.
* @param bool $evenifblocked This lets the user know, that even if the recipient has blocked the user
* the user is still able to send a message.
* @return bool true if user is permitted, false otherwise.
*/
public static function can_send_message(int $recipientid, int $senderid) : bool {
public static function can_send_message(int $recipientid, int $senderid, bool $evenifblocked = false) : bool {
$systemcontext = \context_system::instance();
if (!has_capability('moodle/site:sendmessage', $systemcontext, $senderid)) {
@ -1883,7 +1885,7 @@ class api {
}
// Check if the recipient can be messaged by the sender.
return self::can_contact_user($recipientid, $senderid);
return self::can_contact_user($recipientid, $senderid, $evenifblocked);
}
/**
@ -2966,9 +2968,11 @@ class api {
*
* @param int $recipientid
* @param int $senderid
* @param bool $evenifblocked This lets the user know, that even if the recipient has blocked the user
* the user is still able to send a message.
* @return bool true if recipient hasn't blocked sender and sender can contact to recipient, false otherwise.
*/
protected static function can_contact_user(int $recipientid, int $senderid) : bool {
protected static function can_contact_user(int $recipientid, int $senderid, bool $evenifblocked = false) : bool {
if (has_capability('moodle/site:messageanyuser', \context_system::instance(), $senderid) ||
$recipientid == $senderid) {
// The sender has the ability to contact any user across the entire site or themselves.
@ -2978,7 +2982,7 @@ class api {
// The initial value of $cancontact is null to indicate that a value has not been determined.
$cancontact = null;
if (self::is_blocked($recipientid, $senderid)) {
if (self::is_blocked($recipientid, $senderid) || $evenifblocked) {
// The recipient has specifically blocked this sender.
$cancontact = false;
}

View File

@ -589,9 +589,14 @@ class helper {
$data->requirescontact = null;
$data->canmessage = null;
$data->canmessageevenifblocked = null;
if ($includeprivacyinfo) {
$privacysetting = api::get_user_privacy_messaging_preference($member->id);
$data->requirescontact = $privacysetting == api::MESSAGE_PRIVACY_ONLYCONTACTS;
// Here we check that if the sender wanted to block the recipient, the recipient would
// still be able to message them regardless.
$data->canmessageevenifblocked = api::can_send_message($referenceuserid, $member->id, true);
$data->canmessage = !$data->isdeleted && api::can_send_message($member->id, $referenceuserid);
}

View File

@ -583,6 +583,11 @@ class core_message_external extends external_api {
throw new required_capability_exception($context, $capability, 'nopermissions', '');
}
// If the blocking is going to be useless then don't do it.
if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
return [];
}
if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
\core_message\api::block_user($params['userid'], $params['blockeduserid']);
}
@ -1290,6 +1295,8 @@ class core_message_external extends external_api {
'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
'canmessageevenifblocked' => new external_value(PARAM_BOOL,
'If the user can still message even if they get blocked'),
'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
];

View File

@ -3613,6 +3613,98 @@ class core_message_api_testcase extends core_message_messagelib_testcase {
$this->assertTrue(\core_message\api::can_send_message($student2->id, $teacher1->id));
}
/**
* Tests the user when blocked will not be able to send messages if they are blocked.
*/
public function test_can_send_message_even_if_blocked() {
$this->resetAfterTest();
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id, true));
}
/**
* Tests the user will be able to send a message even if they are blocked as the user
* has the capability 'moodle/site:messageanyuser'.
*/
public function test_can_send_message_even_if_blocked_with_message_any_user_cap() {
global $DB;
$this->resetAfterTest();
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduserrole->id, context_system::instance(), true);
$this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id, true));
}
/**
* Tests the user will be able to send a message even if they are blocked as the user
* has the capability 'moodle/site:readallmessages'.
*/
public function test_can_send_message_even_if_blocked_with_read_all_message_cap() {
global $DB;
$this->resetAfterTest();
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
assign_capability('moodle/site:readallmessages', CAP_ALLOW, $authenticateduserrole->id, context_system::instance(), true);
$this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id, true));
}
/**
* Tests the user can not always send a message if they are blocked just because they share a course.
*/
public function test_can_send_message_even_if_blocked_shared_course() {
$this->resetAfterTest();
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$course = self::getDataGenerator()->create_course();
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
$this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id, true));
}
/**
* Tests the user can always send a message even if they are blocked because they share a course and
* have the capability 'moodle/site:messageanyuser' at the course context.
*/
public function test_can_send_message_even_if_blocked_shared_course_with_message_any_user_cap() {
global $DB;
$this->resetAfterTest();
$editingteacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
$teacher = self::getDataGenerator()->create_user();
$student = self::getDataGenerator()->create_user();
$course = self::getDataGenerator()->create_course();
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, $editingteacherrole->id);
$this->getDataGenerator()->enrol_user($student->id, $course->id);
assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $editingteacherrole->id,
context_course::instance($course->id), true);
// Check that the second user can no longer send the first user a message.
$this->assertTrue(\core_message\api::can_send_message($student->id, $teacher->id, true));
}
/**
* Tests the user can post a message.
*/

View File

@ -0,0 +1,43 @@
@core @core_message @javascript
Feature: To be able to block users that we are able to or to see a message if we can not
In order to attempt to block a user
As a user
I need to be able to block a user or to see a message if we can not
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@emample.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | teacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following config values are set as admin:
| messaging | 1 |
Scenario: Block a user
Given I log in as "student1"
And I select "Student 2" user in messaging
And I open contact menu
And I click on "Block" "link" in the "[data-region='header-container']" "css_element"
And I should see "Are you sure you want to block Student 2?"
And I click on "Block" "button" in the "[data-region='confirm-dialogue']" "css_element"
And I should see "You have blocked this user."
And I log out
When I log in as "student2"
And I open messaging
And I select "Student 1" user in messaging
Then I should see "You are unable to message this user"
Scenario: Unable to block a user
Given I log in as "student1"
And I select "Teacher 1" user in messaging
And I open contact menu
When I click on "Block" "link" in the "[data-region='header-container']" "css_element"
Then I should see "You are unable to block Teacher 1"

View File

@ -1216,6 +1216,30 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals(1, $DB->count_records('message_users_blocked'));
}
/**
* Test blocking a user.
*/
public function test_block_user_when_ineffective() {
global $DB;
$this->resetAfterTest(true);
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$this->setUser($user1);
$authenticateduser = $DB->get_record('role', array('shortname' => 'user'));
assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, context_system::instance(), true);
// Blocking a user.
$return = core_message_external::block_user($user1->id, $user2->id);
$return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
$this->assertEquals(array(), $return);
$this->assertEquals(0, $DB->count_records('message_users_blocked'));
}
/**
* Test blocking a user with messaging disabled.
*/