Stealth user profile field and Online Users block - coding problem

Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Number of replies: 15
Picture of Plugin developers

Hi.
I have added a user profile field named stealth in my Moodle 1.9.15 site.

 

Now how on earth do I access this stealth field data in a php file???

I'm trying to modify Andy J. Davis' online users block so that if the stealth field is ticked, then the user's avatar and username will not appear in the online user block. Thus the user will have privacy, especially after midnight....ah, there is method to my madness.

In the block_online_users.php file of the Online Users block, I have tried the below code, but alas, it doesn't work.

            /* Somewhere around line 138 */

            foreach ($users as $user) {
                if ($user->profile_field_stealth == "1")
                    continue; //i.e., don't display the avatar data, just loop back up
                ...
             }

Any help will be appreciated and if you help me to solve this, your name will be acknowledged in my blog on Moodle 'innovations'. That is if I manage to create a stealth mode for the user on my Moodle 1.9.15 production site.

Many thanks.
Frankie Kam, Malaysia

Average of ratings: -
In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
printing the Object will help you:

            foreach ($users as $user) {
echo '<pre>';
print_r($user);
echo '</pre>';
                $users[$user->id]->fullname = fullname($user);
            }

You cannot access custom fields there: the query reads the user table but not the ones required for accessing the custom fields data.

You should add a new custom capability and make use of it with has_capability().: this solution is probably far from your scenario where I guess the user should be able to take the decision by her/his own.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
this is a potential patch for your hack:

         if ($users = $DB->get_records_sql($sql, $params, 0, 50)) {   // We'll just take the most recent 50 maximum
             foreach ($users as $user) {
-                $users[$user->id]->fullname = fullname($user);
+                require_once("$CFG->dirroot/user/profile/lib.php");
+                profile_load_custom_fields($user);
+                if (isset($user->profile) && !empty($user->profile['stealth'])) {
+                    unset($users[$user->id]); // i.e., don't display the avatar data, just loop back up
+                } else {
+                    $users[$user->id]->fullname = fullname($user);
+                }
             }
         } else {
             $users = array();

It should work but:

  1. it will add extra queries depending on the number of online users;
  2. it breaks the 50 limit since it will be "50 - those stealthed".

A better hack for your solution is to add the custom field directly changing the SQL query: this will give you the best efficiency.

Note: you cannot use continue but unset().

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Ooopss... the exercise has been done on a 2.0. For 1.9, replace:

profile_load_custom_fields($user);

with:

$user->profile = (array)profile_user_record($user->id);

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Hi Matteo

INCREDIBLE! FANTASTICO! FAR OUT! WAY TO GO! AWESOME! 
It worked!!!

I remarked the red if() code starting from line 108 of the file block_online_users.php, and replaced it with blue code that you gave. The code you gave me gave some critical errors (I think that you were thinking Moodle 2.x), so I made some slight changes to suit Moodle 1.9.x. 

        /* 
            if ($users = get_records_sql($SQL, 0, 50)) {   // We'll just take the most recent 50 maximum 
            foreach ($users as $user) { 
                $users[$user->id]->fullname = fullname($user); 
            } 
        } else { 
            $users = array(); 
        } 
        */ 
         
         if ($users = get_records_sql($SQL, 0, 50)) {   // We'll just take the most recent 50 maximum 
             foreach ($users as $user) { 
                require_once("$CFG->dirroot/user/profile/lib.php"); 
                $user->profile = (array)profile_user_record($user->id); 
                if (isset($user->profile) && !empty($user->profile['stealth'])) { 
                    unset($users[$user->id]); // i.e., don't display the avatar data, just loop back up 
                } else { 
                    $users[$user->id]->fullname = fullname($user); 
                } 
             } 
         } else {         
                $users = array(); 
        }

Before ticking the "Stealth mode" checkbox (field stealth):

After I have ticked the checkbox and updated the profile settings.:

 

You are a pure genius. You've earned you slot on my blog and on MoodleNews. 

Frankie Kam 

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
appreciated!

For completeness' sake, I've made a minor mistake - potentially a PHP warning, if enabled, but see below for the details - in coding my proposal:

...
+                if (isset($user->profile) && !empty($user->profile['stealth'])) {
...

should be:

...
+                if (isset($user->profile['stealth']) && !empty($user->profile['stealth'])) {
...

to avoid potential PHP warnings (if enabled) when a user never set that field in her/his profile.

That being said, in case of a checkbox profile field, the field will be always returned as part of the profile (== no PHP warning at all) so it is correct to simply use:

...
+                if (!empty($user->profile['stealth'])) {
...

Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Hi Matteo

As promised, I've posted my blog entry on your PHP code and our work on this Stealth feature,

http://moodurian.blogspot.com/2012/01/how-your-moodle-users-can-hide.html

Also expect a blog posting on http://www.moodlenews.com in a few days time. I've submitted it for review. Up to Joseph to approve it. If OK, then it will be released for public viewing.

Thanks for everything!
Frankie Kam 

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Hi Matteo

I've added a new user profile field named busy.

Then modified the block_online_users.php file to check for the busy field - if it is checked, then the username will appear on the online_users block with the text "(busy)" appended to the username.

 

         if ($users = get_records_sql($SQL, 0, 50)) {   // We'll just take the most recent 50 maximum
             foreach ($users as $user) {
                require_once("$CFG->dirroot/user/profile/lib.php");
                $user->profile = (array)profile_user_record($user->id);
                if (isset($user->profile) && !empty($user->profile['stealth']))
                {   
                    //Invisible status
                    unset($users[$user->id]); // i.e., don't display the avatar data, just loop back up
                } else if (isset($user->profile) && !empty($user->profile['busy']))
                        {   //Append the word "(busy)" to the username
                            $users[$user->id]->fullname = fullname($user)." (busy)";
                        }
                        else {  //Normal visible status
                                $users[$user->id]->fullname = fullname($user);
                        }
             }
         } else {        
                $users = array();
        }

This is now possible:


Regards
Frankie Kam

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Yet another development. This time, the adminisrator can see the number of invisible users. Surf to :
http://moodurian.blogspot.com/2012/01/how-to-be-invisible-on-online-users.html

Frankie Kam 

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Cool approve! You've solved functional issue #2 in http://moodle.org/mod/forum/discuss.php?d=193840#p844395.

Issue #1 is the performance price (however, cheap) to have this coding flexibility.

Happy hacking wink,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Matteo

What if instead of using a checkbox, I used a Menu Choice. How do I access the data? I want to check if the mood variable has the value "Happy" selected, for example.

You probably know where I'm heading with this... wink

Frankie Kam

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
the menu field is just text:

  1. '', when the user hasn't set the profile field yet;
  2. '<a_mood>', when the user has set the profile field with one of the configured moods, {happy,sad,confused,joyful}

i.e.:

                if ('<a_mood>' === $user->profile['mood']) {

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

Hi Matteo.

Ah, you hit the nail on the head again. I've done this for my Moodle site.

by doing this...

and this...

One more Moodlenews.com post coming up....

Thanks once again
Frankie Kam

Average of ratings: Useful (1)
In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
"blank" is not equal to ''. See below my suggestion:

                if ('' === $user->profile['mood']) {
                    $users[$user->id] = fullname($user);
                } else {

Your code works as expected because of there's no option called blank right now.
Note: use 4 spaces instead of tabs.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Stealth user profile field and Online Users block - coding problem

by Frankie Kam -
Picture of Plugin developers

What's issue #2?

In reply to Frankie Kam

Re: Stealth user profile field and Online Users block - coding problem

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Frankie,
it is the 2nd in my cons: "it breaks the 50 limit since it will be "50 - those stealthed". Now you've given evidence that someone is invisible and 50 will be correctly evaluated by the user looking at the numbers in the block.

Matteo