Last Login Users data

Hi All,

I am using SuiteCRM 7.7.9 version and i want the list of last logged in users data.

thanks in advance.

Regards,
kiran.

On a first look, I don’t see that data in the database. The “users” table doesn’t even seem to store the “last login time”.

I suppose you could store that data using a Workflow, and surely you could with a logic_hook:

http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_6.5/Module_Framework/Logic_Hooks/User_Hooks/

Maybe there’s an add-on already made for this? Try searching the SuiteCRM Store…

good luck

We tweaked the login information using logic hooks

We add cookies (for integration with another application) and also log last login
I added a custom field “userlastlogin” to the user record…
here is the code

<?php

if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

class logic_hooks_class
{
    function after_login_method($bean, $event, $arguments)
    {
        //logic
        global $current_user, $timedate;
        setcookie("SuiteCRMUserID", $current_user->id, time()+360000, "/" );
        setcookie("AccountingValidCies", $current_user->accesstocies_c,time()+360000, "/")        ;

        $focus = new User();
        $focus->retrieve($current_user->id)
        $focus->userlastlogin_c = $timedate->getInstance()->nowDb();
        $focus->save();
        
    }

    function login_failed_method($bean, $event, $arguments)
    {
        //logic
        setcookie("SuiteCRMUserID",  " login failed ", time()-36000,"/");

    }

    function before_logout_method($bean, $event, $arguments)
    {
        //logic
        setcookie("SuiteCRMUserID",  " bye! ", time()-36000,"/");


    }
}

?>
4 Likes

Thank you for posting this

I am looking to do something similar.

Were do you put this php file? I am on SuiteCRM 7.10 if it maters.

Also, is there a way to keep a running record of logins / logouts for each user? I am assuming a new database field connected to the user and a means of displaying it. If you have answers to both, great, but for now could work with just the database setup and php file code and use a database query tool to see the results.

Have you ever done this?

I am happy to help,
find documentation on logic hooks there are plenty
you put it in /custom/modules/users…
historical information?, yes you will need a new table linked to the user table…

Well, the good news is, I did not crash the system :slight_smile:

The bad news is, I am not getting the field populated.

I added the field and made it readonly
I added the field to both the editviewdefs and detailviewdefs layouts
I added the script (modified per below since I only needed the login field, not the cookies)
I Repair and Rebuild the system

So the field does show on the layouts and the field is readonly, but when the user logs in and out, and back in again, no data is shown in the new field.

Any ideas what I am missing?

See below for what I did.

Using the SuiteCRM GUI as Admin

SuiteCRM -> Admin -> Studio -> Users (module)
Fields -> Add
	Data Type: Date/Time
	Name: userlastlogin   (when it is stored, SuiteCRM will call it userlastlogin_c to show it was a user-custom field)
	Display Label: Last Login Date/Time:
	Inline Edit: UnCheck
	Importable: No
Layouts -> EditView
	Sync to Detail view: Check
	Scroll Down to row with Address Country taking full width and shrink to 1/2 width
	Drag and drop "Last Login Date/Time:" filed to space opened up

From the CLI


cd {root directory of SuiteCRM installation}
cd custom/modules/Users/metadata
nano editviewdefs.php
	Change
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogin_c',
			'label' => 'LBL_USERLASTLOGIN',
		  ),
		),
	to
				array (
				  0 => 'address_country',
				  1 =>
				  array (
					'name' => 'userlastlogin_c',
					'label' => 'LBL_USERLASTLOGIN',
					'type' => 'readonly',
				  ),
				),
cd {root directory of SuiteCRM installation}
cd custom/modules/Users
nano record-last-login-date-time-for-user.php
	<?php

	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

	class logic_hooks_class
	{
		function after_login_method($bean, $event, $arguments)
		{
			global $current_user, $timedate;
			$focus = new User();
			$focus->retrieve($current_user->id)
			$focus->userlastlogin_c = $timedate->getInstance()->nowDb();
			$focus->save();
			
		}
	}

	?>

From the SuiteCRM GUI

 
SuiteCRM -> Admin -> System (section) -> Repair -> Quick Repair and Rebuild

From the CLI


cd {root directory of SuiteCRM installation}
chown -R www-data:www-data .
chmod -R 755 .
chmod -R 775 cache custom modules themes data upload
chmod 775 config_override.php 2>/dev/null

But, as I said, the login date/time is not being populated to the field.

Any ideas?

OK,

Apparently, in addition to creating the file that does the action, you have to actually link that file to the hook.

So, do all the above and then …

I have seen two versions of how that is done, but neither one is working for me right now.

Version 1:
The file at /var/www/html/suiteayudacrm/custom/modules/Users/logic_hooks.php curently contains

<?php
// Do not store anything in this file that is not part of the array or the hook version.  This file will
// be automatically rebuilt in the future.
 $hook_version = 1;
$hook_array = Array();
// position, file, function
$hook_array['after_login'] = Array();
$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
?>

so I added to that

$hook_array['after_login'][] = Array(99, 'Record last user login date and time', 'logic_hooks_class.php','logic_hooks_class', 'after_login_method');

Making the full file now

<?php
// Do not store anything in this file that is not part of the array or the hook version.  This file will
// be automatically rebuilt in the future.
 $hook_version = 1;
$hook_array = Array();
// position, file, function
$hook_array['after_login'] = Array();
$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
$hook_array['after_login'][] = Array(99, 'Record last user login date and time', 'logic_hooks_class.php','logic_hooks_class', 'after_login_method');
?>

I also changed the name of the file from record-last-login-date-time-for-user.php to logic_hooks_class.php

After a Quick Repair and a login/logout/login still no entry in the new field

Version 2
There was another post that said to add entries using the extensions framework, which appeared to be talking about a way to add logic hook actions and protect the edits from future upgrades wiping them out, but I could not really follow the whole code suggestions there.

So I am close, but no cigar.

Any ideas?

In case it matters, I did manually add to the SQL database an entry for userlastlogin_c for one of my users and when I brought up that user’s profile, it does show properly, so the issue is not the field or layout edits; it is the logic of my coding.

At this point I have exhausted my level of expertise (I know, that did not take much) so any help would be appreciated.

One thing I did figure out

The path I declared to the file logic_hooks_class.php assumed the current working directory was the same directory as the calling file but it is not. Curse those relative paths …

So I edited the path to the logic_hooks_class.php file and made it relative to the SutieCRM root directory as in

$hook_array['after_login'][] = Array(99, 'Record last user login date and time', 'custom/modules/Users/logic_hooks_class.php','logic_hooks_class', 'after_login_method');

I think that did now make a difference and I think the file is now being called since it did change how I have to login; I get a blank screen then refresh the URL and I am in.

The userlastlogin_c field is NOT being populated though.

So although that is not in itself good, at least I now think the hook is calling the file.

But now I need to correct what the code in the file is doing.

Hopefully you have some ideas.

You’re not supposed to add the field on the database, you should do it from Studio (or manually in the vardefs).

When you do a QR&R, you need to scroll to the bottom and click a button that says “sync database with vardefs” if there is one there. Did you check this?

I did add the field using Studio and it does show properly.

I manually added DATA to the database to check if it was displaying properly in the layout, which it is.

The issue is getting the script, triggered by the after_login hook, to populate the database, which it is currently NOT doing.

Ah ok, sorry.

Can you check the returns from each function, to see which part is not working? The “retrieve”, etc.

I have it working!

Thank you for pointing me in the right direction.

So, in one posting, here is what I did in SuiteCRM 7.10.11 to have the User->Profile page display a field showing when the User last logged in

Using the SuiteCRM GUI (this part I had correct all along - Thanks to the Sugar?Suite CRM development folks …)

SuiteCRM -> Admin -> Studio -> Users (module)
Fields -> Add
	Data Type: Date/Time
	Name: userlastlogin   (when it is stored, SuiteCRM will call it userlastlogin_c to show it was a user-custom field)
	Display Label: Last Login Date/Time:
	Inline Edit: UnCheck
	Importable: No
Layouts -> EditView
	Sync to Detail view: Check
	Scroll Down to row with "Address Country" taking full width and shrink it to 1/2 width
	Drag and drop "Last Login Date/Time:" field to space opened up

From the CLI (had to change this part)

cd {root directory of SuiteCRM installation}
cd custom/modules/Users/metadata
nano editviewdefs.php
	Change
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogin_c',
			'label' => 'LBL_USERLASTLOGIN',
		  ),
		),
	to
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogin_c',
			'label' => 'LBL_USERLASTLOGIN',
			'type' => 'readonly',
		  ),
		),
cd {root directory of SuiteCRM installation}
cd custom/modules/Users
nano record_user_login.php
	<?php

	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

	class record_user_login_class
	{
			function record_user_login_method($bean, $event, $arguments)
			{
					global $timedate;
					$bean->userlastlogin_c = $timedate->nowDb();
					$bean->save();
			}
	}

	?>
cd {root directory of SuiteCRM installation}
cd custom/modules/Users
nano logic_hooks.php
	Change 
		<?php
		// Do not store anything in this file that is not part of the array or the hook version.  This file will
		// be automatically rebuilt in the future.
		 $hook_version = 1;
		$hook_array = Array();
		// position, file, function
		$hook_array['after_login'] = Array();
		$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
		?>
	to  (ie add the last line)
		<?php
		// Do not store anything in this file that is not part of the array or the hook version.  This file will
		// be automatically rebuilt in the future.
		 $hook_version = 1;
		$hook_array = Array();
		// position, file, function
		$hook_array['after_login'] = Array();
		$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
		$hook_array['after_login'][] = Array(99, 'Record last user login date and time', 'custom/modules/Users/record_user_login.php','record_user_login_class', 'record_user_login_method');
		?>

Back to the SuiteCRM GUI

SuiteCRM -> Admin -> System (section) -> Repair -> Quick Repair and Rebuild

And back to the CLI (maybe not necessary every time, but it never hurts to ensure correct permissions)

cd {root directory of SuiteCRM installation}
chown -R www-data:www-data .
chmod -R 755 .
chmod -R 775 cache custom modules themes data upload
chmod 775 config_override.php 2>/dev/null

It works!

Thanks to all who posted code snippets in this and other forums.

Open Source RULES!

1 Like

I have been using the above with a custom Report to see who has been logging in but I realized that without any indication of how long they were logged in, it was incomplete information.

So, I added another field for collecting logout data added a script to populate that, and and edited the report to show both. It provides a more useful set of information. See new, complete code, below.

If anyone has figured out how to store this information in a table so we can view a history of the login/logout per User, feel free to add to this. I know it could be done by direct access to the sql code, but I am hoping to stay within the $bean-> structure.

So, to track and report on user login/logout activity:

  1. Create new fields in the User module to store the most recent login/logout per User
  2. Add the new fields to the Editview and Detailview of the User module
  3. Add script to populate the fields on login and logout
  4. Create a Report to show the most recent login and logout by User
  1. Create new fields in the User module to store the most recent login/logout per User
    Using the SuiteCRM Web Interface: SuiteCRM -> Admin -> Studio -> Users (module)

Fields -> Add
	Data Type: Date/Time
	Name: userlastlogin   (when it is stored, SuiteCRM will call it userlastlogin_c to show it was a user-custom field)
	Display Label: Last Login:
	Inline Edit: UnCheck
	Importable: No
	(wait, it takes a while)
Fields -> Add
	Data Type: Date/Time
	Name: userlastlogout   (when it is stored, SuiteCRM will call it userlastlogout_c to show it was a user-custom field)
	Display Label: Last Logout:
	Inline Edit: UnCheck
	Importable: No
	(wait, it takes a while)
  1. Add the new fields to the Editview and Detailview of the User module
    Using the SuiteCRM Web Interface: SuiteCRM -> Admin -> Studio -> Users (module) -> Layouts -> EditView

	Sync to Detail view: Check
	Scroll Down to row with "Address Country" taking full width and shrink it to 1/2 width
	Add a row after the "Address Country" row
	Drag and drop "Last Login" field to new row then shrink to 1/2 width
	Drag and drop "Last Logout" field to new row on right side

Using the CLI

cd {root directory of SuiteCRM installation}
cd custom/modules/Users/metadata
nano editviewdefs.php
	Change
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogin_c',
			'label' => 'LBL_USERLASTLOGIN',
		  ),
		),
	to
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogin_c',
			'label' => 'LBL_USERLASTLOGIN',
			'type' => 'readonly',
		  ),
		),
	and
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogout_c',
			'label' => 'LBL_USERLASTLOGOUT',
		  ),
		),
	to
		array (
		  0 => 'address_country',
		  1 =>
		  array (
			'name' => 'userlastlogout_c',
			'label' => 'LBL_USERLASTLOGOUT',
			'type' => 'readonly',
		  ),
		),
  1. Add script to populate the fields on login and logout
    Using the CLI
cd {root directory of SuiteCRM installation}
cd custom/modules/Users
nano record_user_login.php
	<?php

	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

	class record_user_login_class
	{
			function record_user_login_method($bean, $event, $arguments)
			{
					global $timedate;
					$bean->userlastlogin_c = $timedate->nowDb();
					$bean->save();
			}
	}

	?>
nano record_user_logout.php
	<?php

	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

	class record_user_logout_class
	{
			function record_user_logout_method($bean, $event, $arguments)
			{
					global $timedate;
					$bean->userlastlogout_c = $timedate->nowDb();
					$bean->save();
			}
	}

	?>
chown www-data:www-data record_user_login.php record_user_logout.php
chmod +x record_user_login.php record_user_logout.php
nano logic_hooks.php
	Change 
		<?php
		// Do not store anything in this file that is not part of the array or the hook version.  This file will
		// be automatically rebuilt in the future.
		 $hook_version = 1;
		$hook_array = Array();
		// position, file, function
		$hook_array['after_login'] = Array();
		$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
		?>
	to  (ie add the last 2 lines)
		<?php
		// Do not store anything in this file that is not part of the array or the hook version.  This file will
		// be automatically rebuilt in the future.
		 $hook_version = 1;
		$hook_array = Array();
		// position, file, function
		$hook_array['after_login'] = Array();
		$hook_array['after_login'][] = Array(1, 'SugarFeed old feed entry remover', 'modules/SugarFeed/SugarFeedFlush.php','SugarFeedFlush', 'flushStaleEntries');
		$hook_array['after_login'][] = Array(98, 'Record last user login date and time', 'custom/modules/Users/record_user_login.php','record_user_login_class', 'record_user_login_method');
		$hook_array['before_logout'][] = Array(99, 'Record last user logout date and time', 'custom/modules/Users/record_user_logout.php','record_user_logout_class', 'record_user_logout_method');
		?>

Using the SuiteCRM web interface

	SuiteCRM -> Admin -> System (section) -> Repair -> Quick Repair and Rebuild
	(when the screen refreshes, scroll to the bottom in case it requires a manual sync of vardefs and database)

Using the CLI (maybe not necessary every time, but it never hurts to ensure correct permissions)

	cd {root directory of SuiteCRM installation}
	chown -R www-data:www-data .
	chmod -R 755 .
	chmod -R 775 cache custom modules themes data upload
	chmod 775 config_override.php 2>/dev/null

4)Create a Report to show the most recent login and logout by User
Using the SuiteCRM web interface

SuiteCRM -> All -> Reports -> Create Report
	Name: Last Login / Logout
	Module: Users
	Moule Tree: Users (select)
	Fileds: First Name, Last Name, User Name, Last Login, Last Logout

Logout
Login
SuiteCRM - All -> Reports -> Click on Last Login / Logout
It should now show your last login and logout (the ones you just did)

That’s it!

From now on, just go to Reports-> Last Login / Logout and you get a list of the most recent login and logout for each user.

You can infer that if the last login is after the last logout, the User is currently logged in, but that is not always true so only use it as an indicator.

1 Like

Thanks, once again. You might like to know that I have this post referenced here so one day we can start moving more of these things into our Documentation Site (Technical blog) section.

https://github.com/salesagility/SuiteDocs/issues/206

So, I have the new module setup, the relationship table and the code to populate the tables so I can now create a historical log of the users’ login and logout activity.

Problem is, the subpanel in Users that shows the user activity has a “Create” dropdown button on it that would allow a User to add in additional, nonsense entries.

I cannot figure out how to delete the button in the subpanel and I’d also like to make it so the editview, quick create and full create forms are not availalbe, but I don’t know how to do that. Do you know how I can do that and I’ll add to my instructions and post the complete solution here?

What is “the relationship table”? I searched your previous instructions but I didn’t see the creation of a relationship (or maybe I missed it :blink:)

Have you tried customizing the subpaneldefs of where you want to remove the “create button”?

I did just figure out how to edit the Layoutdefs for the subpanel and have successfully removed the Action buttons from it so that is now good. (Why is it that after working all day on something and then, having no success, posting for help, you then find an answer (to at least part of the question) ?)

I’ll include the subpanel edits in my final documentation when I post here the final solution.

There was no need for a relationship table in the above solution since I was just storing the most recent login/logout in each user’s dbase table and the normal setup for adding fields into the Users module allowed that to happen with the right hooks automatically populating the data.

The solution I wanted and have now figured out (except the disabling of Editview, … to make it read-only) was to store the history of login/logout by user so I could see not only the most recent login/logout but the full history. So for that, I need a one-to-many relationship from Users (one) to a new module I created called useractivity (many) and that is where I have a relationship table. Yes, I know for one-to-many I could do it without a relationship table, but that’s how SuiteCRM sets it up when I use Module Builder and Studio so I went with the flow.

So all that is now remaining is to figure out how to disable any view that would allow C®UD operations by the user (Create,Update,Delete) and only allow Read operations, so I am trying to figure out how to disable Editview, QuickCreate View, … .

I assume if I just delete the views I will create broken links so looking for a better way.

If all you need is a subpanel (not the list view) I suggest dropping the relatinship (so, no new module, and no unwanted edit views etc), and just creating a new subpanel under users with a custom SQL query to fetch your data directly from the database.

This example might help:
https://suitecrm.com/suitecrm/forum/suitecrm-7-0-discussion/19222-subpanels-cases#66668

I am going to save that post for another application so thank you.

In this case, yes, I do want a listview so the administrator can get a list of all users login/logout history.

I just figured out a (backdoor?) way to make everything read-only so I’ll put together the instructions and post.
If I am screwing something up with what I do, PLEASE let me know.

Thank you for your quick replies.