\n";
@@ -122,18 +123,30 @@ class block_online_users extends block_base {
$this->content->text .= ''.$OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false));
$this->content->text .= get_string('guestuser').'
';
- } else {
+ } else { // Not a guest user.
$this->content->text .= '';
- }
- if ($canshowicon and ($USER->id != $user->id) and !isguestuser($user)) { // Only when logged in and messaging active etc
- $anchortagcontents = $OUTPUT->pix_icon('t/message', get_string('messageselectadd'));
- $anchorurl = new moodle_url('/message/index.php', array('id' => $user->id));
- $anchortag = html_writer::link($anchorurl, $anchortagcontents,
- array('title' => get_string('messageselectadd')));
- $this->content->text .= ''.$anchortag.'
';
+ if ($USER->id == $user->id) {
+ $action = ($user->uservisibility != null && $user->uservisibility == 0) ? 'show' : 'hide';
+ $anchortagcontents = $OUTPUT->pix_icon('t/' . $action,
+ get_string('online_status:' . $action, 'block_online_users'));
+ $anchortag = html_writer::link("", $anchortagcontents,
+ array('title' => get_string('online_status:' . $action, 'block_online_users'),
+ 'data-action' => $action, 'data-userid' => $user->id, 'id' => 'change-user-visibility'));
+
+ $this->content->text .= '' . $anchortag . '
';
+ } else {
+ if ($canshowicon) { // Only when logged in and messaging active etc.
+ $anchortagcontents = $OUTPUT->pix_icon('t/message', get_string('messageselectadd'));
+ $anchorurl = new moodle_url('/message/index.php', array('id' => $user->id));
+ $anchortag = html_writer::link($anchorurl, $anchortagcontents,
+ array('title' => get_string('messageselectadd')));
+
+ $this->content->text .= ''.$anchortag.'
';
+ }
+ }
}
$this->content->text .= "\n";
}
diff --git a/blocks/online_users/classes/fetcher.php b/blocks/online_users/classes/fetcher.php
index 1c6d15aac3a..20f706f97e2 100644
--- a/blocks/online_users/classes/fetcher.php
+++ b/blocks/online_users/classes/fetcher.php
@@ -67,6 +67,8 @@ class fetcher {
* @param int $courseid The course id to check
*/
protected function set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid) {
+ global $USER, $DB;
+
$timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache.
$groupmembers = "";
@@ -74,6 +76,7 @@ class fetcher {
$groupby = "";
$lastaccess = ", lastaccess";
$timeaccess = ", ul.timeaccess AS lastaccess";
+ $uservisibility = ", up.value AS uservisibility";
$params = array();
$userfields = \user_picture::fields('u', array('username'));
@@ -85,52 +88,75 @@ class fetcher {
$groupby = "GROUP BY $userfields";
$lastaccess = ", MAX(u.lastaccess) AS lastaccess";
$timeaccess = ", MAX(ul.timeaccess) AS lastaccess";
+ $uservisibility = ", MAX(up.value) AS uservisibility";
$params['currentgroup'] = $currentgroup;
}
$params['now'] = $now;
$params['timefrom'] = $timefrom;
+ $params['userid'] = $USER->id;
+ $params['name'] = 'block_online_users_uservisibility';
+
if ($sitelevel) {
- $sql = "SELECT $userfields $lastaccess
+ $sql = "SELECT $userfields $lastaccess $uservisibility
FROM {user} u $groupmembers
+ LEFT JOIN {user_preferences} up ON up.userid = u.id
+ AND up.name = :name
WHERE u.lastaccess > :timefrom
AND u.lastaccess <= :now
AND u.deleted = 0
+ AND (" . $DB->sql_cast_char2int('up.value') . " = 1
+ OR up.value IS NULL
+ OR u.id = :userid)
$groupselect $groupby
ORDER BY lastaccess DESC ";
$csql = "SELECT COUNT(u.id)
- FROM {user} u $groupmembers
- WHERE u.lastaccess > :timefrom
- AND u.lastaccess <= :now
- AND u.deleted = 0
- $groupselect";
-
+ FROM {user} u $groupmembers
+ LEFT JOIN {user_preferences} up ON up.userid = u.id
+ AND up.name = :name
+ WHERE u.lastaccess > :timefrom
+ AND u.lastaccess <= :now
+ AND u.deleted = 0
+ AND (" . $DB->sql_cast_char2int('up.value') . " = 1
+ OR up.value IS NULL
+ OR u.id = :userid)
+ $groupselect";
} else {
// Course level - show only enrolled users for now.
// TODO: add a new capability for viewing of all users (guests+enrolled+viewing).
list($esqljoin, $eparams) = get_enrolled_sql($context);
$params = array_merge($params, $eparams);
- $sql = "SELECT $userfields $timeaccess
+ $sql = "SELECT $userfields $timeaccess $uservisibility
FROM {user_lastaccess} ul $groupmembers, {user} u
JOIN ($esqljoin) euj ON euj.id = u.id
+ LEFT JOIN {user_preferences} up ON up.userid = u.id
+ AND up.name = :name
WHERE ul.timeaccess > :timefrom
AND u.id = ul.userid
AND ul.courseid = :courseid
AND ul.timeaccess <= :now
AND u.deleted = 0
+ AND (" . $DB->sql_cast_char2int('up.value') . " = 1
+ OR up.value IS NULL
+ OR u.id = :userid)
$groupselect $groupby
ORDER BY lastaccess DESC";
$csql = "SELECT COUNT(u.id)
FROM {user_lastaccess} ul $groupmembers, {user} u
JOIN ($esqljoin) euj ON euj.id = u.id
+ LEFT JOIN {user_preferences} up ON up.userid = u.id
+ AND up.name = :name
WHERE ul.timeaccess > :timefrom
AND u.id = ul.userid
AND ul.courseid = :courseid
AND ul.timeaccess <= :now
AND u.deleted = 0
+ AND (" . $DB->sql_cast_char2int('up.value') . " = 1
+ OR up.value IS NULL
+ OR u.id = :userid)
$groupselect";
$params['courseid'] = $courseid;
diff --git a/blocks/online_users/classes/privacy/provider.php b/blocks/online_users/classes/privacy/provider.php
index 50d0280bc3f..3f29a8e980c 100644
--- a/blocks/online_users/classes/privacy/provider.php
+++ b/blocks/online_users/classes/privacy/provider.php
@@ -24,23 +24,47 @@
namespace block_online_users\privacy;
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\writer;
+use core_privacy\local\request\transform;
+
defined('MOODLE_INTERNAL') || die();
/**
- * Privacy Subsystem for block_online_users implementing null_provider.
+ * Privacy Subsystem for block_online_users.
*
* @copyright 2018 Zig Tan
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class provider implements \core_privacy\local\metadata\null_provider {
+class provider implements
+ \core_privacy\local\metadata\provider,
+ \core_privacy\local\request\user_preference_provider {
/**
- * Get the language string identifier with the component's language
- * file to explain why this plugin stores no data.
+ * Describe all the places where this plugin stores personal data.
*
- * @return string
+ * @param collection $collection Collection of items to add metadata to.
+ * @return collection Collection with our added items.
*/
- public static function get_reason() : string {
- return 'privacy:metadata';
+ public static function get_metadata(collection $collection) : collection {
+
+ $collection->add_user_preference('block_online_users_uservisibility',
+ 'privacy:metadata:preference:uservisibility');
+
+ return $collection;
+ }
+
+ /**
+ * Export user preferences controlled by this plugin.
+ *
+ * @param int $userid ID of the user we are exporting data form.
+ */
+ public static function export_user_preferences(int $userid) {
+
+ $uservisibility = get_user_preferences('block_online_users_uservisibility', 1, $userid);
+
+ writer::export_user_preference('block_online_users',
+ 'block_online_users_uservisibility', transform::yesno($uservisibility),
+ get_string('privacy:metadata:preference:uservisibility', 'block_online_users'));
}
}
diff --git a/blocks/online_users/lang/en/block_online_users.php b/blocks/online_users/lang/en/block_online_users.php
index ff79ce502b6..c6bc0223f1a 100644
--- a/blocks/online_users/lang/en/block_online_users.php
+++ b/blocks/online_users/lang/en/block_online_users.php
@@ -30,7 +30,9 @@ $string['numusers'] = '{$a} online users';
$string['online_users:addinstance'] = 'Add a new online users block';
$string['online_users:myaddinstance'] = 'Add a new online users block to Dashboard';
$string['online_users:viewlist'] = 'View list of online users';
+$string['online_status:hide'] = 'Hide my online status from other users';
+$string['online_status:show'] = 'Show my online status to other users';
$string['periodnminutes'] = 'last {$a} minutes';
$string['pluginname'] = 'Online users';
$string['timetosee'] = 'Remove after inactivity (minutes)';
-$string['privacy:metadata'] = 'The Online users block only shows data stored in other locations.';
+$string['privacy:metadata:preference:uservisibility'] = 'Online status visible to other users in the Online users block.';
diff --git a/blocks/online_users/lib.php b/blocks/online_users/lib.php
new file mode 100644
index 00000000000..0c760803630
--- /dev/null
+++ b/blocks/online_users/lib.php
@@ -0,0 +1,46 @@
+.
+
+/**
+ * Contains functions called by core.
+ *
+ * @package block_online_users
+ * @copyright 2018 Mihail Geshoski
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Callback to define user preferences.
+ *
+ * @return array
+ */
+function block_online_users_user_preferences() {
+ $preferences = array();
+ $preferences['block_online_users_uservisibility'] = array(
+ 'type' => PARAM_INT,
+ 'null' => NULL_NOT_ALLOWED,
+ 'default' => 1,
+ 'choices' => array(0, 1),
+ 'permissioncallback' => function($user, $preferencename) {
+ global $USER;
+ return $user->id == $USER->id;
+ }
+ );
+
+ return $preferences;
+}
diff --git a/blocks/online_users/styles.css b/blocks/online_users/styles.css
index 90be20393c0..bebee5abc1b 100644
--- a/blocks/online_users/styles.css
+++ b/blocks/online_users/styles.css
@@ -11,7 +11,8 @@
vertical-align: text-bottom;
}
-.block_online_users .content .list li.listentry .message {
+.block_online_users .content .list li.listentry .message,
+.block_online_users .content .list li.listentry .uservisibility {
float: right;
margin-top: 3px;
}
diff --git a/blocks/online_users/tests/behat/block_online_users_course.feature b/blocks/online_users/tests/behat/block_online_users_course.feature
index e86e4d8c1e0..20b0d950f1e 100644
--- a/blocks/online_users/tests/behat/block_online_users_course.feature
+++ b/blocks/online_users/tests/behat/block_online_users_course.feature
@@ -39,3 +39,35 @@ Feature: The online users block allow you to see who is currently online
And I should see "Student 1" in the "Online users" "block"
And I should not see "Student 2" in the "Online users" "block"
And I should see "2 online users" in the "Online users" "block"
+
+ @javascript
+ Scenario: Hide/show user's online status from/to other users in the online users block on course page
+ Given I log in as "teacher1"
+ And I am on "Course 1" course homepage with editing mode on
+ And I add the "Online users" block
+ And I log out
+ When I log in as "student1"
+ And I am on "Course 1" course homepage
+ Then "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ Then I should see "1 online user" in the "Online users" "block"
+ And I should see "Teacher 1" in the "Online users" "block"
+ And I should not see "Student 1" in the "Online users" "block"
+ And I log out
+ When I log in as "student1"
+ And I am on "Course 1" course homepage
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ Then I should see "2 online users" in the "Online users" "block"
+ And I should see "Teacher 1" in the "Online users" "block"
+ And I should see "Student 1" in the "Online users" "block"
diff --git a/blocks/online_users/tests/behat/block_online_users_dashboard.feature b/blocks/online_users/tests/behat/block_online_users_dashboard.feature
index 34207c5cdea..0d01207a605 100644
--- a/blocks/online_users/tests/behat/block_online_users_dashboard.feature
+++ b/blocks/online_users/tests/behat/block_online_users_dashboard.feature
@@ -26,3 +26,29 @@ Feature: The online users block allow you to see who is currently online on dash
And I should see "Student 1" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should see "3 online users" in the "Online users" "block"
+
+ @javascript
+ Scenario: Hide/show user's online status from/to other users in the online users block on dashboard
+ Given I log in as "student1"
+ And I should see "1 online user" in the "Online users" "block"
+ And I should see "Student 1" in the "Online users" "block"
+ And "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "student2"
+ Then I should see "1 online user" in the "Online users" "block"
+ And I should see "Student 2" in the "Online users" "block"
+ And I should not see "Student 1" in the "Online users" "block"
+ And I log out
+ When I log in as "student1"
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "student2"
+ Then I should see "2 online users" in the "Online users" "block"
+ And I should see "Student 2" in the "Online users" "block"
+ And I should see "Student 1" in the "Online users" "block"
diff --git a/blocks/online_users/tests/behat/block_online_users_frontpage.feature b/blocks/online_users/tests/behat/block_online_users_frontpage.feature
index 6237d3d436f..0c5bbddaf9e 100644
--- a/blocks/online_users/tests/behat/block_online_users_frontpage.feature
+++ b/blocks/online_users/tests/behat/block_online_users_frontpage.feature
@@ -49,3 +49,38 @@ Feature: The online users block allow you to see who is currently online on fron
And I should see "Student 1" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should see "3 online users" in the "Online users" "block"
+
+ @javascript
+ Scenario: Hide/show user's online status from/to other users in the online users block on front page
+ Given I log in as "admin"
+ And I am on site homepage
+ And I navigate to "Turn editing on" node in "Front page settings"
+ And I add the "Online users" block
+ And I log out
+ When I log in as "student1"
+ And I am on site homepage
+ Then "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "student2"
+ And I am on site homepage
+ Then I should see "2 online user" in the "Online users" "block"
+ And I should see "Admin" in the "Online users" "block"
+ And I should see "Student 2" in the "Online users" "block"
+ And I should not see "Student 1" in the "Online users" "block"
+ And I log out
+ When I log in as "student1"
+ And I am on site homepage
+ Then "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+ When I click on "#change-user-visibility" "css_element"
+ And I wait "1" seconds
+ Then "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+ And I log out
+ When I log in as "student2"
+ And I am on site homepage
+ Then I should see "3 online users" in the "Online users" "block"
+ And I should see "Admin" in the "Online users" "block"
+ And I should see "Student 2" in the "Online users" "block"
+ And I should see "Student 1" in the "Online users" "block"
diff --git a/blocks/online_users/tests/online_users_test.php b/blocks/online_users/tests/online_users_test.php
index 9ff1e3cb14d..946e456fbed 100644
--- a/blocks/online_users/tests/online_users_test.php
+++ b/blocks/online_users/tests/online_users_test.php
@@ -148,4 +148,134 @@ class block_online_users_testcase extends advanced_testcase {
$this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users at site level');
$this->assertEquals(12, $usercount, 'There was a problem counting the number of online users at site level');
}
+
+ /**
+ * Check user visibility setting for course group members.
+ */
+ public function test_user_visibility_course1_group1_members() {
+ global $CFG;
+
+ $groupid = $this->data['group1']->id;
+ $now = time();
+ $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+ $context = context_course::instance($this->data['course1']->id);
+ $courseid = $this->data['course1']->id;
+ $user1 = $this->data['user1'];
+ $user2 = $this->data['user2'];
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(3, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user1 as logged user.
+ $this->setUser($user1);
+ // Set visibility to 'hide' for user1.
+ set_user_preference('block_online_users_uservisibility', 0);
+ // Test if the fetcher gets all the users including user1.
+ $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(3, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ // Test if the fetcher gets all the users excluding user1.
+ $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should not be displayed in the online users block.
+ $this->assertEquals(2, $usercount);
+ $this->assertFalse(array_key_exists($user1->id, $users));
+ }
+
+ /**
+ * Check user visibility setting at course level.
+ */
+ public function test_user_visibility_courses() {
+ global $CFG;
+
+ $currentgroup = null;
+ $now = time();
+ $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+ $context = context_course::instance($this->data['course1']->id);
+ $courseid = $this->data['course1']->id;
+ $user1 = $this->data['user1'];
+ $user2 = $this->data['user2'];
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ // Test if the fetcher gets all the users including user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(9, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user1 as logged user.
+ $this->setUser($user1);
+ // Set visibility to 'hide' for user1.
+ set_user_preference('block_online_users_uservisibility', 0);
+ // Test if the fetcher gets all the users including user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(9, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ // Test if the fetcher gets all the users excluding user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should not be displayed in the online users block.
+ $this->assertEquals(8, $usercount);
+ $this->assertFalse(array_key_exists($user1->id, $users));
+ }
+
+ /**
+ * Check user visibility setting at site level.
+ */
+ public function test_user_visibility_sitelevel() {
+ global $CFG;
+
+ $currentgroup = null;
+ $now = time();
+ $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+ $context = context_system::instance();
+ $user1 = $this->data['user1'];
+ $user2 = $this->data['user2'];
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ // Test if the fetcher gets all the users including user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, true);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(12, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user1 as logged user.
+ $this->setUser($user1);
+ // Set visibility to 'hide' for user1.
+ set_user_preference('block_online_users_uservisibility', 0);
+ // Test if the fetcher gets all the users including user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, true);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should be displayed in the online users block.
+ $this->assertEquals(12, $usercount);
+ $this->assertTrue(array_key_exists($user1->id, $users));
+ // Set user2 as logged user.
+ $this->setUser($user2);
+ // Test if the fetcher gets all the users excluding user1.
+ $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, true);
+ $users = $onlineusers->get_users();
+ $usercount = $onlineusers->count_users();
+ // User1 should not be displayed in the online users block.
+ $this->assertEquals(11, $usercount);
+ $this->assertFalse(array_key_exists($user1->id, $users));
+ }
}
diff --git a/blocks/online_users/version.php b/blocks/online_users/version.php
index 6bbce9fa393..1db749f211e 100644
--- a/blocks/online_users/version.php
+++ b/blocks/online_users/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version = 2018051401; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2018050800; // Requires this Moodle version
$plugin->component = 'block_online_users'; // Full name of the plugin (used for diagnostics)
diff --git a/lib/db/services.php b/lib/db/services.php
index 976108971c7..3493fcafed5 100644
--- a/lib/db/services.php
+++ b/lib/db/services.php
@@ -1353,6 +1353,7 @@ $functions = array(
'description' => 'Set user preferences.',
'type' => 'write',
'capabilities' => 'moodle/site:config',
+ 'ajax' => true
),
'core_user_agree_site_policy' => array(
'classname' => 'core_user_external',