1
0
Эх сурвалжийг харах

Ticket #4797 - Need Change Password feature always asks to change password.

AntonLV 2 жил өмнө
parent
commit
1867f0b93e

+ 45 - 56
inc/classes/BxDolAccount.php

@@ -291,15 +291,14 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
      */
      */
     public function updatePassword($sPassword, $iAccountId = false)
     public function updatePassword($sPassword, $iAccountId = false)
     {
     {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
         $sSalt = genRndSalt();
         $sSalt = genRndSalt();
         $sPasswordHash = encryptUserPwd($sPassword, $sSalt);
         $sPasswordHash = encryptUserPwd($sPassword, $sSalt);
-        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
-        $oAccountSender = BxDolAccount::getInstance();
 
 
         $this->_oQuery->logPassword($iId);
         $this->_oQuery->logPassword($iId);
-        $iPasswordExpired = $this->getPasswordExpiredDateByAccount($iAccountId);
         
         
-        if((int)$this->_oQuery->updatePassword($sPasswordHash, $sSalt, $iId, $iPasswordExpired) > 0) {
+        if((int)$this->_oQuery->updatePassword($sPasswordHash, $sSalt, $iId) > 0) {
             /**
             /**
              * @hooks
              * @hooks
              * @hookdef hook-account-edited 'account', 'edited' - hook on account edited $oAccount->updatePassword 
              * @hookdef hook-account-edited 'account', 'edited' - hook on account edited $oAccount->updatePassword 
@@ -311,10 +310,14 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
              *      - `action` - [string] action's name, can be reset_password
              *      - `action` - [string] action's name, can be reset_password
              * @hook @ref hook-account-edited
              * @hook @ref hook-account-edited
              */
              */
-            bx_alert('account', 'edited', $iId, $oAccountSender ? $oAccountSender->id() : $iId, array('action' => 'reset_password'));
+            bx_alert('account', 'edited', $iId, ($iSenderId = getLoggedId()) != 0 ? $iSenderId : $iId, [
+                'action' => 'reset_password'
+            ]);
+
             $this->doAudit($iId, '_sys_audit_action_account_reset_password');
             $this->doAudit($iId, '_sys_audit_action_account_reset_password');
             return true;
             return true;
         }
         }
+
         return false;
         return false;
     }
     }
     /**
     /**
@@ -847,54 +850,32 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
         return md5($a['email'] . $a['salt'] . BX_DOL_SECRET);
         return md5($a['email'] . $a['salt'] . BX_DOL_SECRET);
     }
     }
     
     
-    public function getPasswordExpiredDate($iPasswordExpiredForMembership, $iAccountId = false)
+    public function getPasswordChangedDate($mixedAccount = false)
     {
     {
-        if ($iPasswordExpiredForMembership == 0)
-            return 0;
-        
-        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
-        
-        $aAccountInfo = $this->_oQuery->getInfoById($iAccountId);
-                
-        $iLastPassChanged = $this->_oQuery->getLastPasswordChanged($iAccountId);
-        if ($iLastPassChanged == 0)
-            $iLastPassChanged = $aAccountInfo['added'];
+        if(($bEmpty = empty($mixedAccount)) || !is_array($mixedAccount))
+            $mixedAccount = $this->_oQuery->getInfoById(!$bEmpty ? (int)$mixedAccount : $this->_iAccountID);
 
 
-        return $iPasswordExpiredForMembership * 86400 + $iLastPassChanged;
+        $iLastChanged = (int)$mixedAccount['password_changed'];
+        return $iLastChanged ? $iLastChanged : (int)$mixedAccount['added'];
     }
     }
-    
-    public function getPasswordExpiredDateByAccount($iAccountId = false)
+
+    public function getPasswordExpiredDate($iPasswordExpiredForMembership, $mixedAccount = false)
     {
     {
-        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
-        
-        $oACL = BxDolAcl::getInstance();
-
-        $aProfiles = BxDolAccount::getInstance($iAccountId)->getProfiles();
-        $iPasswordExpiredForMembership = 0;
-        foreach ($aProfiles as $aProfile) {
-            $aMembersipInfo = $oACL->getMemberMembershipInfo($aProfile['id']);
-            $Memberships = [];
-            BxDolAclQuery::getInstance()->getLevels(['type' => 'by_id', 'value' => $aMembersipInfo['id']], $aMembership);
-            if($aMembership['password_expired'] > 0){
-                if ($iPasswordExpiredForMembership > 0 && $aMembership['password_expired'] < $iExpired)
-                    $iPasswordExpiredForMembership = $aMembership['password_expired'];
-                if ($iPasswordExpiredForMembership == 0 )
-                    $iPasswordExpiredForMembership = $aMembership['password_expired'];
-            }
-        }
+        if($iPasswordExpiredForMembership == 0)
+            return 0;
 
 
-        return $this->getPasswordExpiredDate($iPasswordExpiredForMembership, $iAccountId);  
+        return $iPasswordExpiredForMembership * 86400 + $this->getPasswordChangedDate($mixedAccount);
     }
     }
-    
+
     public function isNeedChangePassword($iAccountId = false, $oInformer = false)
     public function isNeedChangePassword($iAccountId = false, $oInformer = false)
     {
     {
         $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
         $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
-        
-        $aAccountInfo = $this->getInfo();
+
         list($sPageLink, $aPageParams) = bx_get_base_url_inline();
         list($sPageLink, $aPageParams) = bx_get_base_url_inline();
-        $bNeedRedirectToChangePassword = true;
 
 
-        if (isset($aPageParams['i']) && $aPageParams['i'] == 'account-settings-password')
+        $sChangePasswordUri = 'account-settings-password';
+        $bNeedRedirectToChangePassword = true;
+        if(isset($aPageParams['i']) && $aPageParams['i'] == $sChangePasswordUri)
             $bNeedRedirectToChangePassword = false;
             $bNeedRedirectToChangePassword = false;
 
 
         /**
         /**
@@ -908,31 +889,39 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
          *      - `override_result` - [bool] by ref, if Need Redirect To Change Password = true, otherwise = false, can be overridden in hook processing
          *      - `override_result` - [bool] by ref, if Need Redirect To Change Password = true, otherwise = false, can be overridden in hook processing
          * @hook @ref hook-account-is_need_to_change_password
          * @hook @ref hook-account-is_need_to_change_password
          */
          */
-        bx_alert('account', 'is_need_to_change_password',  $iAccountId, false, ['override_result' => &$bNeedRedirectToChangePassword]);
-        
-        if ($aAccountInfo['password_expired'] > 0 && $aAccountInfo['password_expired'] < time() && $bNeedRedirectToChangePassword) {
-            if (getParam('sys_account_accounts_force_password_change_after_expiration') == 'on'){
-                header('Location: ' . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=account-settings-password'));
+        bx_alert('account', 'is_need_to_change_password',  $iAccountId, false, [
+            'override_result' => &$bNeedRedirectToChangePassword
+        ]);
+
+        if(!$bNeedRedirectToChangePassword)
+            return;
+
+        $aAccountInfo = $this->getInfo();
+        $aMembershipInfo = BxDolAcl::getInstance()->getMemberMembershipInfo($aAccountInfo['profile_id']);
+        $sChangePasswordUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sChangePasswordUri);
+
+        if(($iPasswordExpiredDate = $this->getPasswordExpiredDate($aMembershipInfo['password_expired'], $aAccountInfo)) && $iPasswordExpiredDate < time()) {
+            if(getParam('sys_account_accounts_force_password_change_after_expiration') == 'on') {
+                header('Location: ' . $sChangePasswordUrl);
                 exit;
                 exit;
             }
             }
             else {
             else {
                 if(!$oInformer)
                 if(!$oInformer)
                     $oInformer = BxDolInformer::getInstance();
                     $oInformer = BxDolInformer::getInstance();
 
 
-                $oInformer->add('sys-account-need-to-change-password', _t('_sys_txt_account_need_to_change_password', BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=account-settings-password')), BX_INFORMER_ALERT);
+                $oInformer->add('sys-account-need-to-change-password', _t('_sys_txt_account_need_to_change_password', $sChangePasswordUrl), BX_INFORMER_ALERT);
             }
             }
         }
         }
     }
     }
-    
-    public function doAudit($iAccountId, $sAction, $aData = array())
+
+    public function doAudit($iAccountId, $sAction, $aData = [])
     {
     {
         $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
         $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
-        bx_audit(
-            $iAccountId, 
-            'bx_accounts', 
-            $sAction,  
-            array('content_title' => $this->getEmail(), 'data' => $aData)
-        );
+
+        bx_audit($iAccountId, 'bx_accounts', $sAction,  [
+            'content_title' => $this->getEmail(), 
+            'data' => $aData
+        ]);
     }
     }
 
 
     /**
     /**

+ 24 - 26
inc/classes/BxDolAccountQuery.php

@@ -158,10 +158,13 @@ class BxDolAccountQuery extends BxDolDb implements iBxDolSingleton
      * @param $iAccountId - account id to update password for
      * @param $iAccountId - account id to update password for
      * @return number of affected rows
      * @return number of affected rows
      */
      */
-    public function updatePassword($sPasswordHash, $sSalt, $iAccountId, $iPasswordExpired)
+    public function updatePassword($sPasswordHash, $sSalt, $iAccountId)
     {
     {
-        $sQuery = $this->prepare("UPDATE `sys_accounts` SET `password` = ?, `salt` = ?, `password_expired` = ? WHERE `id`= ?", $sPasswordHash, $sSalt, $iPasswordExpired, $iAccountId);
-        return $this->query($sQuery);
+        return $this->query("UPDATE `sys_accounts` SET `password` = :password, `salt` = :salt, `password_changed` = UNIX_TIMESTAMP() WHERE `id` = :id", [
+            'id' => $iAccountId,
+            'password' => $sPasswordHash,
+            'salt' => $sSalt
+        ]);
     }
     }
 
 
     /**
     /**
@@ -173,23 +176,24 @@ class BxDolAccountQuery extends BxDolDb implements iBxDolSingleton
      */
      */
     public function logPassword($iAccountId)
     public function logPassword($iAccountId)
     {
     {
-        $iCountPassword = (int)getParam('sys_account_accounts_password_log_count');
-        
-        if ($iCountPassword > 0){
-            $sSql = $this->prepare("SELECT `password`, `salt` FROM `sys_accounts` WHERE `id` = ?", $iAccountId);
-            $aAccount = $this->getRow($sSql);
-
-            $sQuery = "INSERT INTO `sys_accounts_password` (`password`, `password_changed`, `salt`, `account_id`) VALUES(:password, :password_changed, :salt, :account_id)";
-            $aBindings = array(
-               'password' => $aAccount['password'],
-               'password_changed' => time(),
-               'salt' => $aAccount['salt'],
-               'account_id' => $iAccountId,
-            );
-            $this->query($sQuery, $aBindings);
-            
-            $this->query($this->prepare("DELETE FROM `sys_accounts_password` WHERE `id` NOT IN (SELECT `id` FROM (SELECT `id` FROM `sys_accounts_password` WHERE `account_id` = ? ORDER BY `password_changed` DESC LIMIT 0, " . getParam('sys_account_accounts_password_log_count') . ") a)", $iAccountId));
-        }
+        $iCount = (int)getParam('sys_account_accounts_password_log_count');
+        if($iCount <= 0)
+            return;
+
+        $aAccount = $this->getRow("SELECT `password`, `password_changed`, `salt` FROM `sys_accounts` WHERE `id` = :id", [
+            'id' => $iAccountId
+        ]);
+
+        $this->query("INSERT INTO `sys_accounts_password` SET " . $this->arrayToSQL([
+            'account_id' => $iAccountId,
+            'password' => $aAccount['password'],
+            'password_changed' => $aAccount['password_changed'],
+            'salt' => $aAccount['salt'],
+        ]));
+
+        $this->query("DELETE FROM `sys_accounts_password` WHERE `id` NOT IN (SELECT `id` FROM (SELECT `id` FROM `sys_accounts_password` WHERE `account_id` = :account_id ORDER BY `password_changed` DESC LIMIT 0, " . $iCount . ") AS `tap`)", [
+            'account_id' => $iAccountId
+        ]);
     }
     }
     
     
     public function getLastPasswordChanged($iAccountId)
     public function getLastPasswordChanged($iAccountId)
@@ -204,12 +208,6 @@ class BxDolAccountQuery extends BxDolDb implements iBxDolSingleton
         return $this->getAll($sSql);
         return $this->getAll($sSql);
     }
     }
     
     
-    public function updatePasswordExpired($iAccountId, $iPasswordExpired)
-    {
-        $sQuery = $this->prepare("UPDATE `sys_accounts` SET `password_expired` = ? WHERE `id`= ?", $iPasswordExpired, $iAccountId);
-        return $this->query($sQuery);
-    }
-    
     /**
     /**
      * Update last logged in time
      * Update last logged in time
      * @param  int    $iID account id
      * @param  int    $iID account id

+ 24 - 3
inc/classes/BxDolAclQuery.php

@@ -105,6 +105,10 @@ class BxDolAclQuery extends BxDolDb implements iBxDolSingleton
             case 'password_can_expired':
             case 'password_can_expired':
                 $sWhereClause .= "AND `tal`.`PasswordExpired` <> 0";
                 $sWhereClause .= "AND `tal`.`PasswordExpired` <> 0";
                 break;
                 break;
+            
+            case 'password_expired_notify':
+                $sWhereClause .= "AND `tal`.`PasswordExpired` <> 0 AND tal`.`PasswordExpiredNotify` <> 0";
+                break;
 
 
             case 'all':
             case 'all':
                 break;
                 break;
@@ -239,6 +243,7 @@ class BxDolAclQuery extends BxDolDb implements iBxDolSingleton
                     `sys_acl_levels`.`QuotaSize` AS `quota_size`,
                     `sys_acl_levels`.`QuotaSize` AS `quota_size`,
                     `sys_acl_levels`.`QuotaNumber` AS `quota_number`,
                     `sys_acl_levels`.`QuotaNumber` AS `quota_number`,
                     `sys_acl_levels`.`QuotaMaxFileSize` AS `quota_max_file_size`,
                     `sys_acl_levels`.`QuotaMaxFileSize` AS `quota_max_file_size`,
+                    `sys_acl_levels`.`PasswordExpired` AS `password_expired`,
                     UNIX_TIMESTAMP(`sys_acl_levels_members`.`DateStarts`) as `date_starts`,
                     UNIX_TIMESTAMP(`sys_acl_levels_members`.`DateStarts`) as `date_starts`,
                     UNIX_TIMESTAMP(`sys_acl_levels_members`.`DateExpires`) as `date_expires`,
                     UNIX_TIMESTAMP(`sys_acl_levels_members`.`DateExpires`) as `date_expires`,
                     `sys_acl_levels_members`.`State` AS `state`,
                     `sys_acl_levels_members`.`State` AS `state`,
@@ -263,7 +268,8 @@ class BxDolAclQuery extends BxDolDb implements iBxDolSingleton
                 `tal`.`Name` AS `name`,
                 `tal`.`Name` AS `name`,
                 `tal`.`QuotaSize` AS `quota_size`,
                 `tal`.`QuotaSize` AS `quota_size`,
                 `tal`.`QuotaNumber` AS `quota_number`,
                 `tal`.`QuotaNumber` AS `quota_number`,
-                `tal`.`QuotaMaxFileSize` AS `quota_max_file_size`
+                `tal`.`QuotaMaxFileSize` AS `quota_max_file_size`,
+                `tal`.`PasswordExpired` AS `password_expired`
             FROM `sys_acl_levels` AS `tal`
             FROM `sys_acl_levels` AS `tal`
             WHERE `tal`.`ID`=?
             WHERE `tal`.`ID`=?
             LIMIT 1", $iLevel);
             LIMIT 1", $iLevel);
@@ -470,11 +476,26 @@ class BxDolAclQuery extends BxDolDb implements iBxDolSingleton
         );
         );
     }
     }
 
 
-    function getProfilesByMembership($mixedLevelId)
+    function getProfilesByMembership($mixedLevelId, $aParams = [])
     {
     {
+        $sSelectClause = $sJoinClause = $sWhereClause = '';
+
     	$aSqlParts = $this->getContentByLevelAsSQLPart('sys_profiles', 'id', $mixedLevelId);
     	$aSqlParts = $this->getContentByLevelAsSQLPart('sys_profiles', 'id', $mixedLevelId);
+        if(isset($aSqlParts['join'], $aSqlParts['where'])) {
+            $sJoinClause = $aSqlParts['join'];
+            $sWhereClause = $aSqlParts['where'];
+        }
+
+        if(isset($aParams['password_expired'], $aParams['password_expired_notify'])) {
+            $iExpire = (int)$aParams['password_expired'] * 86400;
+            $iNotify = ($iExpire - (int)$aParams['password_expired_notify']) * 86400;
+
+            $sSelectClause .= ", `ta`.`email` AS `email`, IF(`ta`.`password_changed` <> 0, `ta`.`password_changed`, `ta`.`added`) + " . $iExpire . " AS `password_expired`";
+            $sJoinClause .= " LEFT JOIN `sys_accounts` AS `ta` ON `sys_profiles`.`account_id`=`ta`.`id`";
+            $sWhereClause .= " AND IF(`ta`.`password_changed` <> 0, `ta`.`password_changed`, `ta`.`added`) + " . $iNotify . " < UNIX_TIMESTAMP() AND IF(`ta`.`password_changed` <> 0, `ta`.`password_changed`, `ta`.`added`) + " . $iExpire . " >= UNIX_TIMESTAMP()";
+        }
 
 
-    	return $this->getAll("SELECT `sys_profiles`.* FROM `sys_profiles`" . $aSqlParts['join'] . " WHERE 1" . $aSqlParts['where']);
+    	return $this->getAll("SELECT `sys_profiles`.*" . $sSelectClause . " FROM `sys_profiles`" . $sJoinClause . " WHERE 1" . $sWhereClause);
     }
     }
 
 
     function getProfilesByAction($mixedActionName, $aParams = [])
     function getProfilesByAction($mixedActionName, $aParams = [])

+ 15 - 25
inc/classes/BxDolCronAccount.php

@@ -24,42 +24,32 @@ class BxDolCronAccount extends BxDolCron
     {
     {
         set_time_limit(0);
         set_time_limit(0);
         ignore_user_abort();
         ignore_user_abort();
-        
-        $aEmails = [];
-        
+
         /* password expired soon email */
         /* password expired soon email */
         bx_import('BxTemplAcl');
         bx_import('BxTemplAcl');
 
 
         $oAclDb = BxDolAclQuery::getInstance();
         $oAclDb = BxDolAclQuery::getInstance();
-        $oAccountDb = BxDolAccountQuery::getInstance();
 
 
+        $aEmails = [];
         $aMemberships = [];
         $aMemberships = [];
-        $oAclDb->getLevels(['type' => 'password_can_expired'], $aMemberships, false);
+        $oAclDb->getLevels(['type' => 'password_expired_notify'], $aMemberships, false);
 
 
         foreach($aMemberships as $aMembership) {
         foreach($aMemberships as $aMembership) {
-            $aProfiles = $oAclDb->getProfilesByMembership([$aMembership['id']]);
+            $aProfiles = $oAclDb->getProfilesByMembership([$aMembership['id']], [
+                'password_expired' => $aMembership['password_expired'], 
+                'password_expired_notify' => $aMembership['password_expired_notify']
+            ]);
+
             foreach($aProfiles as $aProfile) {
             foreach($aProfiles as $aProfile) {
-                $oAccount = BxDolAccount::getInstance($aProfile['account_id']);
-                if(!$oAccount)
+                if(in_array($aProfile['email'], $aEmails))
                     continue;
                     continue;
 
 
-                $iPasswordExpired = $oAccount->getPasswordExpiredDate($aMembership['password_expired']);
-                $aAccountInfo = $oAccountDb->getInfoById($aProfile['account_id']);
-                $iLastPassChanged = $oAccountDb->getLastPasswordChanged($aProfile['account_id']);
-                if (
-                    !in_array($aAccountInfo['email'], $aEmails) 
-                    && ($aMembership['password_expired'] - $aMembership['password_expired_notify']) * 86400 + $iLastPassChanged < time()
-                    && $iPasswordExpired >= time()
-                ){
-                    $aPlus = array();
-                    $aPlus['expired_date'] = date('d.m.Y', $iPasswordExpired);
-                    $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('t_AccountPasswordExpired', $aPlus);
-
-                    sendMail($aAccountInfo['email'], $aTemplate['Subject'], $aTemplate['Body'], $aProfile['id']);
-                    $aEmails[] = $aAccountInfo['email'];
-                }
-
-                $oAccountDb->updatePasswordExpired($aProfile['account_id'], $iPasswordExpired);
+                $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('t_AccountPasswordExpired', [
+                    'expired_date' => date('d.m.Y', $aProfile['password_expired'])
+                ]);
+
+                sendMail($aProfile['email'], $aTemplate['Subject'], $aTemplate['Body'], $aProfile['id']);
+                $aEmails[] = $aProfile['email'];                
             }
             }
         }
         }
 
 

+ 1 - 1
install/sql/system.sql

@@ -1378,7 +1378,7 @@ CREATE TABLE `sys_accounts` (
   `referred` varchar(255) NOT NULL DEFAULT '',
   `referred` varchar(255) NOT NULL DEFAULT '',
   `login_attempts` tinyint(4) NOT NULL DEFAULT '0',
   `login_attempts` tinyint(4) NOT NULL DEFAULT '0',
   `locked` tinyint(4) NOT NULL DEFAULT '0',
   `locked` tinyint(4) NOT NULL DEFAULT '0',
-  `password_expired` int(11) NOT NULL DEFAULT '0',
+  `password_changed` int(11) NOT NULL DEFAULT '0',
   `active` int(11) NOT NULL DEFAULT '0',
   `active` int(11) NOT NULL DEFAULT '0',
   PRIMARY KEY (`id`),
   PRIMARY KEY (`id`),
   UNIQUE KEY `email` (`email`(191)),
   UNIQUE KEY `email` (`email`(191)),

+ 3 - 3
modules/boonex/english/data/langs/system/en.xml

@@ -2569,7 +2569,7 @@ If it is not enabled then please consider implement this optimization, since it
 <p>{account_output}</p>
 <p>{account_output}</p>
 {email_footer}]]></string>
 {email_footer}]]></string>
      <string name="_sys_et_txt_body_account_password_expired"><![CDATA[{email_header}
      <string name="_sys_et_txt_body_account_password_expired"><![CDATA[{email_header}
-<p>Your password will expired in {expired_date}</p>
+<p>Your password will expire {expired_date}</p>
 <p>Please, sign-in and change password</p>
 <p>Please, sign-in and change password</p>
 {email_footer}]]></string>
 {email_footer}]]></string>
     <string name="_sys_et_txt_body_pruning"><![CDATA[{email_header}
     <string name="_sys_et_txt_body_pruning"><![CDATA[{email_header}
@@ -2630,7 +2630,7 @@ If it is not enabled then please consider implement this optimization, since it
         <string name="_sys_et_txt_name_account_change_status_suspended"><![CDATA[Account status changed to suspended]]></string>
         <string name="_sys_et_txt_name_account_change_status_suspended"><![CDATA[Account status changed to suspended]]></string>
         <string name="_sys_et_txt_name_manage_approve"><![CDATA[Approve: Contact content's author]]></string>
         <string name="_sys_et_txt_name_manage_approve"><![CDATA[Approve: Contact content's author]]></string>
 	<string name="_sys_et_txt_name_system_account"><![CDATA[New Accounts]]></string>
 	<string name="_sys_et_txt_name_system_account"><![CDATA[New Accounts]]></string>
-        <string name="_sys_et_txt_name_system_account_password_expired"><![CDATA[Expired Password]]></string>
+        <string name="_sys_et_txt_name_system_account_password_expired"><![CDATA[Password will expire]]></string>
 	<string name="_sys_et_txt_name_system_pruning"><![CDATA[Pruning result]]></string>
 	<string name="_sys_et_txt_name_system_pruning"><![CDATA[Pruning result]]></string>
 	<string name="_sys_et_txt_name_upgrade_failed"><![CDATA[Upgrade failed]]></string>
 	<string name="_sys_et_txt_name_upgrade_failed"><![CDATA[Upgrade failed]]></string>
 	<string name="_sys_et_txt_name_upgrade_modules_failed"><![CDATA[Modules upgrade failed]]></string>
 	<string name="_sys_et_txt_name_upgrade_modules_failed"><![CDATA[Modules upgrade failed]]></string>
@@ -2653,7 +2653,7 @@ If it is not enabled then please consider implement this optimization, since it
         <string name="_sys_et_txt_subject_account_change_status_suspended"><![CDATA[Account suspended]]></string>
         <string name="_sys_et_txt_subject_account_change_status_suspended"><![CDATA[Account suspended]]></string>
         <string name="_sys_et_txt_subject_manage_approve"><![CDATA[Approvement. A question about '{content_title}'.]]></string>
         <string name="_sys_et_txt_subject_manage_approve"><![CDATA[Approvement. A question about '{content_title}'.]]></string>
 	<string name="_sys_et_txt_subject_account"><![CDATA[{site_name} {account_count} accounts created yesterday]]></string>
 	<string name="_sys_et_txt_subject_account"><![CDATA[{site_name} {account_count} accounts created yesterday]]></string>
-        <string name="_sys_et_txt_subject_account_password_expired"><![CDATA[{site_name} - your password will expired soon]]></string>
+        <string name="_sys_et_txt_subject_account_password_expired"><![CDATA[Your password will expire soon]]></string>
 	<string name="_sys_et_txt_subject_pruning"><![CDATA[{site_name} pruning result]]></string>
 	<string name="_sys_et_txt_subject_pruning"><![CDATA[{site_name} pruning result]]></string>
 	<string name="_sys_et_txt_subject_upgrade_failed"><![CDATA[{site_name} upgrade failed]]></string>
 	<string name="_sys_et_txt_subject_upgrade_failed"><![CDATA[{site_name} upgrade failed]]></string>
 	<string name="_sys_et_txt_subject_upgrade_modules_failed"><![CDATA[Modules upgrade failed on {site_name}]]></string>
 	<string name="_sys_et_txt_subject_upgrade_modules_failed"><![CDATA[Modules upgrade failed on {site_name}]]></string>

+ 6 - 0
modules/boonex/russian/data/langs/system/ru.xml

@@ -2544,6 +2544,10 @@
 {email_footer}]]></string>
 {email_footer}]]></string>
     <string name="_sys_et_txt_body_account"><![CDATA[{email_header}
     <string name="_sys_et_txt_body_account"><![CDATA[{email_header}
 <p>{account_output}</p>
 <p>{account_output}</p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_account_password_expired"><![CDATA[{email_header}
+<p>Срок действия вашего пароля истекает {expired_date}</p>
+<p>Пожалуйста, войдите в систему и измените пароль.</p>
 {email_footer}]]></string>
 {email_footer}]]></string>
     <string name="_sys_et_txt_body_pruning"><![CDATA[{email_header}
     <string name="_sys_et_txt_body_pruning"><![CDATA[{email_header}
 <p>{pruning_output}</p>
 <p>{pruning_output}</p>
@@ -2603,6 +2607,7 @@
         <string name="_sys_et_txt_name_account_change_status_suspended"><![CDATA[Статус аккаунта изменён на Заблокированный]]></string>
         <string name="_sys_et_txt_name_account_change_status_suspended"><![CDATA[Статус аккаунта изменён на Заблокированный]]></string>
         <string name="_sys_et_txt_name_manage_approve"><![CDATA[Одобрение: Связаться с автором контента]]></string>
         <string name="_sys_et_txt_name_manage_approve"><![CDATA[Одобрение: Связаться с автором контента]]></string>
 	<string name="_sys_et_txt_name_system_account"><![CDATA[Новые аккаунты]]></string>
 	<string name="_sys_et_txt_name_system_account"><![CDATA[Новые аккаунты]]></string>
+        <string name="_sys_et_txt_name_system_account_password_expired"><![CDATA[Срок действия пароля истекает]]></string>
 	<string name="_sys_et_txt_name_system_pruning"><![CDATA[Результат очистки]]></string>
 	<string name="_sys_et_txt_name_system_pruning"><![CDATA[Результат очистки]]></string>
 	<string name="_sys_et_txt_name_upgrade_failed"><![CDATA[Обновление не удалось]]></string>
 	<string name="_sys_et_txt_name_upgrade_failed"><![CDATA[Обновление не удалось]]></string>
 	<string name="_sys_et_txt_name_upgrade_modules_failed"><![CDATA[Обновление модулей не удалось]]></string>
 	<string name="_sys_et_txt_name_upgrade_modules_failed"><![CDATA[Обновление модулей не удалось]]></string>
@@ -2626,6 +2631,7 @@
         <string name="_sys_et_txt_subject_manage_approve"><![CDATA[Одобрение. Вопрос о '{content_title}'.]]></string>
         <string name="_sys_et_txt_subject_manage_approve"><![CDATA[Одобрение. Вопрос о '{content_title}'.]]></string>
         <string name="_sys_et_txt_body_manage_approve"><![CDATA[]]></string>
         <string name="_sys_et_txt_body_manage_approve"><![CDATA[]]></string>
 	<string name="_sys_et_txt_subject_account"><![CDATA[{site_name} - {account_count} аккаунтов, созданных вчера]]></string>
 	<string name="_sys_et_txt_subject_account"><![CDATA[{site_name} - {account_count} аккаунтов, созданных вчера]]></string>
+        <string name="_sys_et_txt_subject_account_password_expired"><![CDATA[Срок действия вашего пароля скоро истечет]]></string>
 	<string name="_sys_et_txt_subject_pruning"><![CDATA[{site_name} - результат очистки]]></string>
 	<string name="_sys_et_txt_subject_pruning"><![CDATA[{site_name} - результат очистки]]></string>
 	<string name="_sys_et_txt_subject_upgrade_failed"><![CDATA[{site_name} - обновление не удалось]]></string>
 	<string name="_sys_et_txt_subject_upgrade_failed"><![CDATA[{site_name} - обновление не удалось]]></string>
 	<string name="_sys_et_txt_subject_upgrade_modules_failed"><![CDATA[Не удалось обновить модули на сайте {site_name}]]></string>
 	<string name="_sys_et_txt_subject_upgrade_modules_failed"><![CDATA[Не удалось обновить модули на сайте {site_name}]]></string>

+ 62 - 52
template/scripts/BxBaseFormAccount.php

@@ -114,14 +114,15 @@ class BxFormAccountCheckerHelper extends BxDolFormCheckerHelper
  */
  */
 class BxBaseFormAccount extends BxTemplFormView
 class BxBaseFormAccount extends BxTemplFormView
 {
 {
-	static $FIELD_EMAIL = 'email';
+    static $FIELD_EMAIL = 'email';
     static $FIELD_PASSWORD = 'password';
     static $FIELD_PASSWORD = 'password';
+    static $FIELD_PASSWORD_CHANGED = 'password_changed';
     static $FIELD_SALT = 'salt';
     static $FIELD_SALT = 'salt';
     static $FIELD_ADDED = 'added';
     static $FIELD_ADDED = 'added';
     static $FIELD_CHANGED = 'changed';
     static $FIELD_CHANGED = 'changed';
     static $FIELD_IP = 'ip';
     static $FIELD_IP = 'ip';
     static $FIELD_REFERRED = 'referred';
     static $FIELD_REFERRED = 'referred';
-	static $FIELD_PHONE = 'phone';
+    static $FIELD_PHONE = 'phone';
 
 
     protected $_bSetPendingApproval = false;
     protected $_bSetPendingApproval = false;
 
 
@@ -176,81 +177,90 @@ class BxBaseFormAccount extends BxTemplFormView
 
 
     public function insert ($aValsToAdd = array(), $isIgnore = false)
     public function insert ($aValsToAdd = array(), $isIgnore = false)
     {
     {
+        $iNow = time();
+
     	$sEmail = isset($aValsToAdd[self::$FIELD_EMAIL]) ? $aValsToAdd[self::$FIELD_EMAIL] : $this->getCleanValue(self::$FIELD_EMAIL);
     	$sEmail = isset($aValsToAdd[self::$FIELD_EMAIL]) ? $aValsToAdd[self::$FIELD_EMAIL] : $this->getCleanValue(self::$FIELD_EMAIL);
     	$sEmail = trim(strtolower($sEmail));
     	$sEmail = trim(strtolower($sEmail));
-		
-		$sPhone = isset($aValsToAdd[self::$FIELD_PHONE]) ? $aValsToAdd[self::$FIELD_PHONE] : $this->getCleanValue(self::$FIELD_PHONE);
+
+        $sPhone = isset($aValsToAdd[self::$FIELD_PHONE]) ? $aValsToAdd[self::$FIELD_PHONE] : $this->getCleanValue(self::$FIELD_PHONE);
     	$sPhone = trim(strtolower($sPhone));
     	$sPhone = trim(strtolower($sPhone));
-    	
+
         $sPwd = isset($aValsToAdd[self::$FIELD_PASSWORD]) ? $aValsToAdd[self::$FIELD_PASSWORD] : $this->getCleanValue(self::$FIELD_PASSWORD);
         $sPwd = isset($aValsToAdd[self::$FIELD_PASSWORD]) ? $aValsToAdd[self::$FIELD_PASSWORD] : $this->getCleanValue(self::$FIELD_PASSWORD);
         $sSalt = genRndSalt();
         $sSalt = genRndSalt();
         $sPasswordHash = encryptUserPwd($sPwd, $sSalt);
         $sPasswordHash = encryptUserPwd($sPwd, $sSalt);
 
 
-        $aValsToAdd = array_merge($aValsToAdd, array (
-        	self::$FIELD_EMAIL => $sEmail, 
+        return parent::insert(array_merge($aValsToAdd, [
+            self::$FIELD_EMAIL => $sEmail, 
             self::$FIELD_PASSWORD => $sPasswordHash,
             self::$FIELD_PASSWORD => $sPasswordHash,
+            self::$FIELD_PASSWORD_CHANGED => $iNow,
             self::$FIELD_SALT => $sSalt,
             self::$FIELD_SALT => $sSalt,
-            self::$FIELD_ADDED => time(),
-            self::$FIELD_CHANGED => time(),
+            self::$FIELD_ADDED => $iNow,
+            self::$FIELD_CHANGED => $iNow,
             self::$FIELD_IP => getVisitorIP(),
             self::$FIELD_IP => getVisitorIP(),
             self::$FIELD_REFERRED => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
             self::$FIELD_REFERRED => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
-			self::$FIELD_PHONE => $sPhone,
-        ));
-        return parent::insert ($aValsToAdd, $isIgnore);
+            self::$FIELD_PHONE => $sPhone,
+        ]), $isIgnore);
     }
     }
 
 
-    function update ($val, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    function update ($val, $aValsToAdd = [], &$aTrackTextFieldsChanges = null)
     {
     {
-        $sPwd = $this->getCleanValue(self::$FIELD_PASSWORD);
-        if ($sPwd) {
+        $oDb = BxDolAccountQuery::getInstance();
+        $iNow = time();
+
+        $_aValsToAdd = [
+            self::$FIELD_CHANGED => $iNow
+        ];        
+
+        if(($sPwd = $this->getCleanValue(self::$FIELD_PASSWORD))) {
+            $oDb->logPassword($val);
+
             $sSalt = genRndSalt();
             $sSalt = genRndSalt();
-            $sPasswordHash = encryptUserPwd($sPwd, $sSalt);
-            
-            $oAccount = BxDolAccount::getInstance($val, true);
-            $iPasswordExpired = $oAccount->getPasswordExpiredDateByAccount($val);
-            
-            BxDolAccountQuery::getInstance()->logPassword($val);
-            BxDolAccountQuery::getInstance()->updatePasswordExpired($val, $iPasswordExpired);
+            $sPasswordHash = encryptUserPwd($sPwd, $sSalt);            
+
+            $_aValsToAdd = array_merge($_aValsToAdd, [
+                self::$FIELD_PASSWORD => $sPasswordHash,
+                self::$FIELD_PASSWORD_CHANGED => $iNow,
+                self::$FIELD_SALT => $sSalt
+            ]);
         }
         }
 
 
-        $aValsToAdd = array_merge(
-            $aValsToAdd,
-            array (self::$FIELD_CHANGED => time()),
-            $sPwd ? array (self::$FIELD_PASSWORD => $sPasswordHash, self::$FIELD_SALT => $sSalt) : array()
-        );
-        
-        $bResult = parent::update ($val, $aValsToAdd, $aTrackTextFieldsChanges);
-        
-        if ($bResult){
-            $oAccount = BxDolAccount::getInstance($val, true);
-            if ($oAccount) { 
-                $aAccountInfo = $oAccount->getInfo();
-                /**
-                 * @hooks
-                 * @hookdef hook-account-change_receive_news 'account', 'change_receive_news' - hook after change receive_news parameter for account
-                 * - $unit_name - equals `system`
-                 * - $action - equals `change_receive_news` 
-                 * - $object_id - not used 
-                 * - $sender_id - not used 
-                 * - $extra_params - array of additional params with the following array keys:
-                 *      - `account_id` - [int] account id 
-                 *      - `old_value` - [bool] old value for receive_news parameter
-                 *      - `new_value` - [bool] new value for receive_news parameter
-                 *      - `email` - [string] account's email
-                 * @hook @ref hook-account-change_receive_news
-                 */
-                bx_alert('account', 'change_receive_news', 0, false, array('account_id' => $val, 'old_value' => $aAccountInfo['receive_news'], 'new_value' => $this->getCleanValue('receive_news'), 'email' => $aAccountInfo['email']));
-            }
+        $aInfoOld = $oDb->getInfoById($val);
+
+        $bResult = parent::update($val, array_merge($aValsToAdd, $_aValsToAdd), $aTrackTextFieldsChanges);
+        if($bResult) {
+            $aInfoNew = $oDb->getInfoById($val);
+
+            /**
+             * @hooks
+             * @hookdef hook-account-change_receive_news 'account', 'change_receive_news' - hook after change receive_news parameter for account
+             * - $unit_name - equals `system`
+             * - $action - equals `change_receive_news` 
+             * - $object_id - not used 
+             * - $sender_id - not used 
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `account_id` - [int] account id 
+             *      - `old_value` - [bool] old value for receive_news parameter
+             *      - `new_value` - [bool] new value for receive_news parameter
+             *      - `email` - [string] account's email
+             * @hook @ref hook-account-change_receive_news
+             */
+            bx_alert('account', 'change_receive_news', 0, false, [
+                'account_id' => $val, 
+                'old_value' => $aInfoOld['receive_news'], 
+                'new_value' => $aInfoNew['receive_news'], 
+                'email' => $aInfoNew['email']]
+            );
         }
         }
+
         return $bResult;
         return $bResult;
     }
     }
 
 
-	protected function genCustomInputAgreement ($aInput)
+    protected function genCustomInputAgreement ($aInput)
     {
     {
     	$oPermalink = BxDolPermalinks::getInstance();
     	$oPermalink = BxDolPermalinks::getInstance();
         return '<div>' . _t('_sys_form_account_input_agreement_value', bx_absolute_url($oPermalink->permalink('page.php?i=terms')), bx_absolute_url($oPermalink->permalink('page.php?i=privacy'))) . '</div>';
         return '<div>' . _t('_sys_form_account_input_agreement_value', bx_absolute_url($oPermalink->permalink('page.php?i=terms')), bx_absolute_url($oPermalink->permalink('page.php?i=privacy'))) . '</div>';
     }
     }
-    
+
     protected function _setCustomError ($s)
     protected function _setCustomError ($s)
     {
     {
         $this->aInputs['do_submit']['error'] = $s;
         $this->aInputs['do_submit']['error'] = $s;

+ 9 - 9
template/scripts/BxBaseServiceAccount.php

@@ -836,14 +836,12 @@ class BxBaseServiceAccount extends BxDol
      */
      */
     public function generateUserNewPwd($iAccountId)
     public function generateUserNewPwd($iAccountId)
     {
     {
-        $sPwd = genRndPwd(8, false);
+        $sPassword = genRndPwd(8, false);
         $sSalt = genRndSalt();
         $sSalt = genRndSalt();
-        $sPasswordHash = encryptUserPwd($sPwd, $sSalt);
-        
-        $oAccount = BxDolAccount::getInstance($iAccountId);
-        $iPasswordExpired = $oAccount->getPasswordExpiredDateByAccount($iAccountId);
-        
-        $this->_oAccountQuery->updatePassword($sPasswordHash, $sSalt, $iAccountId, $iPasswordExpired);
+        $sPasswordHash = encryptUserPwd($sPassword, $sSalt);
+
+        $this->_oAccountQuery->logPassword($iAccountId);
+        $this->_oAccountQuery->updatePassword($sPasswordHash, $sSalt, $iAccountId);
 
 
         /**
         /**
          * @hooks
          * @hooks
@@ -856,9 +854,11 @@ class BxBaseServiceAccount extends BxDol
          *      - `action` - [string] can be forgot_password/change_password or $sDisplayName  (display name for current form)
          *      - `action` - [string] can be forgot_password/change_password or $sDisplayName  (display name for current form)
          * @hook @ref hook-account-edited
          * @hook @ref hook-account-edited
          */
          */
-        bx_alert('account', 'edited', $iAccountId, $iAccountId, array('action' => 'forgot_password'));
+        bx_alert('account', 'edited', $iAccountId, $iAccountId, [
+            'action' => 'forgot_password'
+        ]);
 
 
-        return $sPwd;
+        return $sPassword;
     }
     }
 
 
     protected function _confirmEmail($sKey)
     protected function _confirmEmail($sKey)