Custom user tracker using logic hooks (code for share)

Idea created by Jaume Albaigès on Oct 29, 2015
    • sidhu sidhu
    • Bhavesh Patel
    • Vincent Amari
    • Ajay Kumar
    • Jaume Albaigès
    • Kristjan Mathiesen

    No questions in this post. Just wanted to share some code in case it might be useful to anybody. Some of you may find it easy, but I feel it can be of interest for not-so-Sugar-experts like me.

    As you may know, the Tracker module is not available in SugarCRM CE. Although the table exists in the database, the code does not populate it.

    In my case, I needed to log some user actions, so I have done the following:

    1) I didn't want to use the native SugarCRM tracker table, you never know what might happen in the future... :-), so I created a CustomTracker module through Module Builder. Added a user related field to keep the id of the tracked user and a dropdown field to log the action.

    2) Created /custom/Extension/modules/Users/Ext/LogicHooks/logic_hooks.php with this code:

    $hook_version = 1;
    $hook_array = Array();
    $hook_array['after_login'][] = Array(1, 'RegisterLogin', 'custom/modules/Users/LogicHooksCode/RegisterLogin.php', 'Users_RegisterLogin', 'RegisterLogin');
    $hook_array['login_failed'][] = Array(1, 'RegisterLoginKO', 'custom/modules/Users/LogicHooksCode/RegisterLoginKO.php', 'Users_RegisterLoginKO', 'RegisterLoginKO');
    $hook_array['before_logout'][] = Array(1, 'RegisterLogout', 'custom/modules/Users/LogicHooksCode/RegisterLogout.php', 'Users_RegisterLogout', 'RegisterLogout');

    As you may guess, I wanted to log successful logins, failed logins and logouts, so I used three available user logic hooks: after_login, login_failed and before_logout.

    3) Created three files, one for each logic hook, and put them in the path used in the prior step (custom/modules/Users/LogicHooksCode/). The location and the names for those files is arbitrary, they can be anywhere, but I found it consistent to put them inside custom/modules/Users structure. Here is the code for each file:

    3.1) Successful login:

    class Users_RegisterLogin
        public function RegisterLogin(&$bean, $event, $arguments)
            $tracker = new CustomTracker();
            $tracker->name = $bean->name.' - Login';
            $tracker->user_id_c = $bean->id;
            $tracker->action = 'login';

    3.2) Logout:

    class Users_RegisterLogout
        public function RegisterLogout(&$bean, $event, $arguments)
            $tracker = new CustomTracker();
            $tracker->name = $bean->name.' - Logout';
            $tracker->user_id_c = $bean->id;
            $tracker->action = 'logout';

    3.3) Failed login:

    After 3 failed attempts, user is deactivated and an email is sent to him/her.

    class Users_RegisterLoginKO
        public function RegisterLoginKO(&$bean, $event, $arguments)
            // Read the username provided in the login form
            if (isset($_REQUEST['user_name']) && $_REQUEST['user_name'] != '') {
                $tracker = new CustomTracker();
                $tracker->action = 'login_ko';

                // Search the username in the database
                $db =  DBManagerFactory::getInstance();
                $query = "SELECT id FROM users where user_name = '".$_REQUEST['user_name']."'";
                $result = $db->query($query, true);
                if ($result->num_rows > 0) {

                    // If the username provided matches a real user, get the id
                    $row = $db->fetchByAssoc($result);
                    $user = new User();

                    $tracker->user_id_c = $row['id'];
                    $tracker->name = $user->name.' - Login error';
                    // If there have been 3 or more faied login attempts,
                    // deactivate the user and send an email
                    if ($_SESSION['loginAttempts'] >= 3) {
                        $user->status = 'Inactive';
                        // Send an email
                        $emailObj = new Email();
                        $defaults = $emailObj->getSystemDefaultEmail();
                        $mail = new SugarPHPMailer();
                        $mail->From = $defaults['email'];
                        $mail->FromName = $defaults['name'];
                        $mail->Subject = 'Your SugarCRM user has been deactivated';
                        $mail->Body = 'Dear '.$user->name.', your SugarCRM user has been deactivated after 3 failed login attempts. Please contact your admin to activate it again, thank yougràcies.';
                } else {

                    // If the username provided in the login form does not match a real user,
                    // just track the action.
                    $tracker->name = $_REQUEST['user_name'].' - Login error';

    Hope this can be useful to anybody. By the way, comments to correct and optimize the code are always welcome.