From ab8c76cf27dc0a90eaf24ed9fb5a852e1b1c2fdf Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Wed, 13 Aug 2014 14:37:31 -0500
Subject: [PATCH] i18n: Save browser language on login

This will help if the user has "Browser Preference" selected as the
preferred language. When email correspondence needs to be sent to the user,
the browser_lang extra attribute can be used as a backup to to the user's
language preference in the event that the language preference is set to auto
(Browser Preference).
---
 include/class.auth.php       | 18 ++++++++-----
 include/class.client.php     | 33 ++++++++++++++++++++++++
 include/class.i18n.php       |  5 ++--
 include/class.staff.php      | 50 ++++++++++++++++++++++++++++--------
 include/staff/system.inc.php |  4 +++
 5 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/include/class.auth.php b/include/class.auth.php
index 4a97ab01a..f67b01237 100644
--- a/include/class.auth.php
+++ b/include/class.auth.php
@@ -32,6 +32,10 @@ abstract class AuthenticatedUser {
 
         return false;
     }
+
+    // Signal method to allow performing extra things when a user is logged
+    // into the sysem
+    function onLogin($bk) {}
 }
 
 interface AuthDirectorySearch {
@@ -427,14 +431,10 @@ abstract class StaffAuthenticationBackend  extends AuthenticationBackend {
             sprintf(_S("%s logged in [%s], via %s"), $staff->getUserName(),
                 $_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug.
 
-        $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() '
-            .' WHERE staff_id='.db_input($staff->getId());
-        db_query($sql);
-
-        //Tag the authkey.
+        // Tag the authkey.
         $authkey = $bk::$id.':'.$authkey;
 
-        //Now set session crap and lets roll baby!
+        // Now set session crap and lets roll baby!
         $authsession = &$_SESSION['_auth']['staff'];
 
         $authsession = array(); //clear.
@@ -452,6 +452,9 @@ abstract class StaffAuthenticationBackend  extends AuthenticationBackend {
         if ($bk->supportsInteractiveAuthentication())
             $staff->cancelResetTokens();
 
+        // Update last-used language, login time, etc
+        $staff->onLogin($bk);
+
         return true;
     }
 
@@ -628,6 +631,9 @@ abstract class UserAuthenticationBackend  extends AuthenticationBackend {
         if ($bk->supportsInteractiveAuthentication() && ($acct=$user->getAccount()))
             $acct->cancelResetTokens();
 
+        // Update last-used language, login time, etc
+        $user->onLogin($bk);
+
         return true;
     }
 
diff --git a/include/class.client.php b/include/class.client.php
index 21d230047..cfa492bfc 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -314,10 +314,17 @@ class  EndUser extends AuthenticatedUser {
 
         return $stats;
     }
+
+    function onLogin($bk) {
+        if ($account = $this->getAccount())
+            $account->onLogin($bk);
+    }
 }
 
 class ClientAccount extends UserAccount {
 
+    var $_extra;
+
     function checkPassword($password, $autoupdate=true) {
 
         /*bcrypt based password match*/
@@ -353,6 +360,32 @@ class ClientAccount extends UserAccount {
         unset($_SESSION['_client']['reset-token']);
     }
 
+    function getExtraAttr($attr=false) {
+        if (!isset($this->_extra))
+            $this->_extra = JsonDataParser::decode($this->ht['extra']);
+
+        return $attr ? $this->_extra[$attr] : $this->_extra;
+    }
+
+    function setExtraAttr($attr, $value) {
+        $this->getExtraAttr();
+        $this->_extra[$attr] = $value;
+    }
+
+    function onLogin($bk) {
+        $this->setExtraAttr('browser_lang',
+            Internationalization::getCurrentLanguage());
+        $this->save();
+    }
+
+    function save($refetch=false) {
+        // Serialize the extra column on demand
+        if (isset($this->_extra)) {
+            $this->extra = JsonDataEncoder::encode($this->_extra);
+        }
+        return parent::save($refetch);
+    }
+
     function update($vars, &$errors) {
         global $cfg;
 
diff --git a/include/class.i18n.php b/include/class.i18n.php
index 2f5619c05..bcaf6a4ec 100644
--- a/include/class.i18n.php
+++ b/include/class.i18n.php
@@ -363,10 +363,11 @@ class Internationalization {
 
         $user = $user ?: $thisstaff ?: $thisclient;
         if ($user && method_exists($user, 'getLanguage'))
-            return $user->getLanguage();
+            if ($lang = $user->getLanguage())
+                return $lang;
 
         // Support the flag buttons for guests
-        if ((!$user || $user != $thisstaff) && isset($session))
+        if ((!$user || $user != $thisstaff) && $session)
             return $session;
 
         return self::getDefaultLanguage();
diff --git a/include/class.staff.php b/include/class.staff.php
index b9b50ce10..9738abf28 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -67,7 +67,6 @@ class Staff extends AuthenticatedUser {
         $this->teams = $this->ht['teams'] = array();
         $this->group = $this->dept = null;
         $this->departments = $this->stats = array();
-        $this->config = new Config('staff.'.$this->id);
 
         //WE have to patch info here to support upgrading from old versions.
         if(($time=strtotime($this->ht['passwdreset']?$this->ht['passwdreset']:$this->ht['added'])))
@@ -98,7 +97,7 @@ class Staff extends AuthenticatedUser {
     }
 
     function getInfo() {
-        return $this->config->getInfo() + $this->getHashtable();
+        return $this->getHashtable();
     }
 
     // AuthenticatedUser implementation...
@@ -278,13 +277,15 @@ class Staff extends AuthenticatedUser {
     }
 
     function getLanguage() {
+        // XXX: This should just return the language preference. Caching
+        //      should be done elsewhere
         static $cached = false;
         if (!$cached)
             $cached = &$_SESSION['staff:lang'];
 
         if (!$cached) {
-            $cached = $this->config->get('lang',
-                Internationalization::getDefaultLanguage());
+            $cached = $this->ht['lang']
+                ?: Internationalization::getDefaultLanguage();
         }
         return $cached;
     }
@@ -434,6 +435,39 @@ class Staff extends AuthenticatedUser {
         return ($stats=$this->getTicketsStats())?$stats['closed']:0;
     }
 
+    function getExtraAttr($attr=false) {
+        if (!isset($this->extra))
+            $this->extra = JsonDataParser::decode($this->ht['extra']);
+
+        return $attr ? $this->extra[$attr] : $this->extra;
+    }
+
+    function setExtraAttr($attr, $value, $commit=true) {
+        $this->getExtraAttr();
+        $this->extra[$attr] = $value;
+
+        if ($commit) {
+            $sql='UPDATE '.STAFF_TABLE.' SET '
+                .'`extra`='.db_input(JsonDataEncoder::encode($this->extra))
+                .' WHERE staff_id='.db_input($this->getId());
+            db_query($sql);
+        }
+    }
+
+    function onLogin($bk) {
+        // Update last apparent language preference
+        $this->setExtraAttr('browser_lang',
+            Internationalization::getCurrentLanguage(),
+            false);
+
+        $sql='UPDATE '.STAFF_TABLE.' SET '
+            // Update time of last login
+            .'  `lastlogin`=NOW() '
+            .', `extra`='.db_input(JsonDataEncoder::encode($this->extra))
+            .' WHERE staff_id='.db_input($this->getId());
+         db_query($sql);
+    }
+
     //Staff profile update...unfortunately we have to separate it from admin update to avoid potential issues
     function updateProfile($vars, &$errors) {
         global $cfg;
@@ -498,7 +532,6 @@ class Staff extends AuthenticatedUser {
 
         if($errors) return false;
 
-        $this->config->set('lang', $vars['lang']);
         $_SESSION['staff:lang'] = null;
         TextDomain::configureForUser($this);
 
@@ -516,8 +549,8 @@ class Staff extends AuthenticatedUser {
             .' ,max_page_size='.db_input($vars['max_page_size'])
             .' ,auto_refresh_rate='.db_input($vars['auto_refresh_rate'])
             .' ,default_signature_type='.db_input($vars['default_signature_type'])
-            .' ,default_paper_size='.db_input($vars['default_paper_size']);
-
+            .' ,default_paper_size='.db_input($vars['default_paper_size'])
+            .' ,lang='.db_input($vars['lang']);
 
         if($vars['passwd1']) {
             $sql.=' ,change_passwd=0, passwdreset=NOW(), passwd='.db_input(Passwd::hash($vars['passwd1']));
@@ -586,9 +619,6 @@ class Staff extends AuthenticatedUser {
 
             //Cleanup Team membership table.
             db_query('DELETE FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId()));
-
-            // Destrory config settings
-            $this->config->destroy();
         }
 
         Signal::send('model.deleted', $this);
diff --git a/include/staff/system.inc.php b/include/staff/system.inc.php
index 4238e3dbe..2e21c21a6 100644
--- a/include/staff/system.inc.php
+++ b/include/staff/system.inc.php
@@ -33,6 +33,10 @@ $extensions = array(
             'name' => 'phar',
             'desc' => __('Highly recommended for plugins and language packs')
             ),
+        'intl' => array(
+            'name' => 'intl',
+            'desc' => __('Highly recommended for non western european language content')
+            ),
         );
 
 ?>
-- 
GitLab