Merge branch '2013.10' into 2014.11
[tine20] / tine20 / Tinebase / User / Sql.php
index 912ef5c..bb56c98 100644 (file)
@@ -216,7 +216,8 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             } catch (Tinebase_Exception_NotFound $tenf) {
                 // do nothing
             } catch (Exception $e) {
-                if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' User sql plugin failure: ' . $e);
+                if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' User sql plugin failure');
+                Tinebase_Exception::log($e);
             }
         }
             
@@ -256,6 +257,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
      * @return  Tinebase_Model_User the user object
      * @throws  Tinebase_Exception_NotFound
      * @throws  Tinebase_Exception_Record_Validation
+     * @throws  Tinebase_Exception_InvalidArgument
      */
     public function getUserByPropertyFromSqlBackend($_property, $_value, $_accountClass = 'Tinebase_Model_User')
     {
@@ -281,7 +283,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
         if ($row === false) {
             throw new Tinebase_Exception_NotFound('User with ' . $_property . ' = ' . $value . ' not found.');
         }
-        
+
         try {
             $account = new $_accountClass(NULL, TRUE);
             $account->setFromArray($row);
@@ -331,9 +333,9 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
     protected function _getUserSelectObject()
     {
         /*
-         * CASE WHEN `status` = 'enabled' THEN (CASE WHEN NOW() > `expires_at` THEN 'expired' 
-         * WHEN (`login_failures` > 5 AND `last_login_failure_at` + INTERVAL 15 MINUTE > NOW()) 
-         * THEN 'blocked' ELSE 'enabled' END) ELSE 'disabled' END
+         * CASE WHEN `status` = 'enabled' THEN (CASE WHEN DATE(NOW()) > `expires_at` THEN 'expired'
+         * WHEN ( `login_failures` > 5 AND DATE(`last_login_failure_at`) + INTERVAL '15' MINUTE > DATE(NOW())) THEN 'blocked'
+         * ELSE 'enabled' END) WHEN `status` = 'expired' THEN 'expired' ELSE 'disabled' END
          */
         
         $maxLoginFailures = Tinebase_Config::getInstance()->get(Tinebase_Config::MAX_LOGIN_FAILURES, 5);
@@ -347,11 +349,14 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             $loginFailuresCondition = '';
         }
         
-        $statusSQL = 'CASE WHEN ' . $this->_db->quoteIdentifier($this->rowNameMapping['accountStatus']) . ' = ' . $this->_db->quote('enabled') . ' THEN (';
-        $statusSQL .= 'CASE WHEN '.$this->_dbCommand->setDate('NOW()') .' > ' . $this->_db->quoteIdentifier($this->rowNameMapping['accountExpires'])
+        $statusSQL = 'CASE WHEN ' . $this->_db->quoteIdentifier($this->rowNameMapping['accountStatus']) . ' = ' . $this->_db->quote('enabled') . ' THEN ('
+            . 'CASE WHEN '.$this->_dbCommand->setDate('NOW()') .' > ' . $this->_db->quoteIdentifier($this->rowNameMapping['accountExpires'])
             . ' THEN ' . $this->_db->quote('expired')
-            . $loginFailuresCondition
-            . ' ELSE ' . $this->_db->quote('enabled') . ' END) ELSE ' . $this->_db->quote('disabled') . ' END';
+            . ' ' . $loginFailuresCondition
+            . ' ELSE ' . $this->_db->quote('enabled') . ' END)'
+            . ' WHEN ' . $this->_db->quoteIdentifier($this->rowNameMapping['accountStatus']) . ' = ' . $this->_db->quote('expired')
+                . ' THEN ' . $this->_db->quote('expired')
+            . ' ELSE ' . $this->_db->quote('disabled') . ' END';
         
         $select = $this->_db->select()
             ->from(SQL_TABLE_PREFIX . 'accounts', 
@@ -375,7 +380,15 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
                     'loginFailures'         => $this->rowNameMapping['loginFailures'],
                     'contact_id',
                     'openid',
-                    'visibility'
+                    'visibility',
+                    'created_by',
+                    'creation_time',
+                    'last_modified_by',
+                    'last_modified_time',
+                    'is_deleted',
+                    'deleted_time',
+                    'deleted_by',
+                    'seq',
                 )
             )
             ->joinLeft(
@@ -386,7 +399,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
                     'container_id'            => 'container_id'
                 )
             );
-        
+
         return $select;
     }
     
@@ -550,7 +563,8 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
      *
      * @param mixed   $_accountId
      * @param string  $_status
-     * @return unknown
+     * @return integer
+     * @throws Tinebase_Exception_InvalidArgument
      */
     public function setStatus($_accountId, $_status)
     {
@@ -572,7 +586,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
                 break;
                 
             case 'expired':
-                $accountData['expires_at'] = Tinebase_DateTime::getTimestamp();
+                $accountData['expires_at'] = Tinebase_DateTime::now()->getTimestamp();
                 break;
             
             default:
@@ -656,7 +670,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
      *
      * @param int $_accountId
      * @param string $_ipAddress
-     * @return void
+     * @return integer
      */
     public function setLoginTime($_accountId, $_ipAddress) 
     {
@@ -695,13 +709,13 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
      * update contact data(first name, last name, ...) of user in local sql storage
      * 
      * @param Addressbook_Model_Contact $contact
+     * @return integer
+     * @throws Exception
      */
     public function updateContactInSqlBackend(Addressbook_Model_Contact $_contact)
     {
         $contactId = $_contact->getId();
 
-        $accountsTable = new Tinebase_Db_Table(array('name' => SQL_TABLE_PREFIX . 'accounts'));
-
         $accountData = array(
             $this->rowNameMapping['accountDisplayName']  => $_contact->n_fileas,
             $this->rowNameMapping['accountFullName']     => $_contact->n_fn,
@@ -716,7 +730,7 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             $where = array(
                 $this->_db->quoteInto($this->_db->quoteIdentifier('contact_id') . ' = ?', $contactId)
             );
-            $accountsTable->update($accountData, $where);
+            return $accountsTable->update($accountData, $where);
 
         } catch (Exception $e) {
             Tinebase_TransactionManager::getInstance()->rollBack();
@@ -776,28 +790,13 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
 
         $oldUser = $this->getFullUserById($accountId);
         
-        $accountsTable = new Tinebase_Db_Table(array('name' => SQL_TABLE_PREFIX . 'accounts'));
-        
         if (empty($_user->contact_id)) {
             $_user->visibility = 'hidden';
             $_user->contact_id = null;
         }
-        
-        $accountData = array(
-            'login_name'        => $_user->accountLoginName,
-            'expires_at'        => ($_user->accountExpires instanceof DateTime ? $_user->accountExpires->get(Tinebase_Record_Abstract::ISO8601LONG) : NULL),
-            'primary_group_id'  => $_user->accountPrimaryGroup,
-            'home_dir'          => $_user->accountHomeDirectory,
-            'login_shell'       => $_user->accountLoginShell,
-            'openid'            => $_user->openid,
-            'visibility'        => $_user->visibility,
-            'contact_id'        => $_user->contact_id,
-            $this->rowNameMapping['accountDisplayName']  => $_user->accountDisplayName,
-            $this->rowNameMapping['accountFullName']     => $_user->accountFullName,
-            $this->rowNameMapping['accountFirstName']    => $_user->accountFirstName,
-            $this->rowNameMapping['accountLastName']     => $_user->accountLastName,
-            $this->rowNameMapping['accountEmailAddress'] => $_user->accountEmailAddress,
-        );
+        $accountData = $this->_recordToRawData($_user);
+        // don't update id
+        unset($accountData['id']);
         
         // ignore all other states (expired and blocked)
         if ($_user->accountStatus == Tinebase_User::STATUS_ENABLED) {
@@ -889,6 +888,23 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             $_user->contact_id = null;
         }
         
+        $accountData = $this->_recordToRawData($_user);
+        
+        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Adding user to SQL backend: ' . $_user->accountLoginName);
+        
+        $accountsTable->insert($accountData);
+            
+        return $this->getUserById($_user->getId(), 'Tinebase_Model_FullUser');
+    }
+    
+    /**
+     * converts record into raw data for adapter
+     *
+     * @param  Tinebase_Record_Abstract $_user
+     * @return array
+     */
+    protected function _recordToRawData($_user)
+    {
         $accountData = array(
             'id'                => $_user->accountId,
             'login_name'        => $_user->accountLoginName,
@@ -898,20 +914,31 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             'home_dir'          => $_user->accountHomeDirectory,
             'login_shell'       => $_user->accountLoginShell,
             'openid'            => $_user->openid,
-            'visibility'        => $_user->visibility, 
+            'visibility'        => $_user->visibility,
             'contact_id'        => $_user->contact_id,
             $this->rowNameMapping['accountDisplayName']  => $_user->accountDisplayName,
             $this->rowNameMapping['accountFullName']     => $_user->accountFullName,
             $this->rowNameMapping['accountFirstName']    => $_user->accountFirstName,
             $this->rowNameMapping['accountLastName']     => $_user->accountLastName,
             $this->rowNameMapping['accountEmailAddress'] => $_user->accountEmailAddress,
+            'created_by'            => $_user->created_by,
+            'creation_time'         => $_user->creation_time,
+            'last_modified_by'      => $_user->last_modified_by,
+            'last_modified_time'    => $_user->last_modified_time,
+            'is_deleted'            => $_user->is_deleted,
+            'deleted_time'          => $_user->deleted_time,
+            'deleted_by'            => $_user->deleted_by,
+            'seq'                   => $_user->seq,
         );
         
-        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Adding user to SQL backend: ' . $_user->accountLoginName);
+        $unsetIfEmpty = array('seq', 'creation_time', 'created_by', 'last_modified_by', 'last_modified_time', 'is_deleted', 'deleted_time', 'deleted_by');
+        foreach ($unsetIfEmpty as $property) {
+            if (empty($accountData[$property])) {
+                unset($accountData[$property]);
+            }
+        }
         
-        $accountsTable->insert($accountData);
-            
-        return $this->getUserById($_user->getId(), 'Tinebase_Model_FullUser');
+        return $accountData;
     }
     
     /**
@@ -971,10 +998,6 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
             );
             $accountsTable->delete($where);
 
-            $where  = array(
-                $this->_db->quoteInto($this->_db->quoteIdentifier('login_name') . ' = ?', $user->accountLoginName),
-            );
-            
             Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
         } catch (Exception $e) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' error while deleting account ' . $e->__toString());
@@ -1040,6 +1063,88 @@ class Tinebase_User_Sql extends Tinebase_User_Abstract
     }
 
     /**
+<<<<<<< HEAD
+     * send deactivation email to user
+     * 
+     * @param mixed $accountId
+     */
+    public function sendDeactivationNotification($accountId)
+    {
+        if (! Tinebase_Config::getInstance()->get(Tinebase_Config::ACCOUNT_DEACTIVATION_NOTIFICATION)) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . ' Deactivation notification disabled.');
+            return;
+        }
+        
+        try {
+            $user = $this->getFullUserById($accountId);
+            
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . ' Send deactivation notification to user ' . $user->accountLoginName);
+            
+            $translate = Tinebase_Translation::getTranslation('Tinebase');
+            
+            $view = new Zend_View();
+            $view->setScriptPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'views');
+            
+            $view->translate            = $translate;
+            $view->accountLoginName     = $user->accountLoginName;
+            // TODO add this?
+            //$view->deactivationDate     = $user->deactivationDate;
+            $view->tine20Url            = Tinebase_Core::getHostname();
+            
+            $messageBody = $view->render('deactivationNotification.php');
+            $messageSubject = $translate->_('Your Tine 2.0 account has been deactivated');
+            
+            $recipient = Addressbook_Controller_Contact::getInstance()->getContactByUserId($user->getId(), /* $_ignoreACL = */ true);
+            Tinebase_Notification::getInstance()->send(/* sender = */ null, array($recipient), $messageSubject, $messageBody);
+            
+        } catch (Exception $e) {
+            Tinebase_Exception::log($e);
+        }
+    }
+
+
+    /**
+     * returns number of current non-system users
+     *
+     * @return number
+     */
+    public function countNonSystemUsers()
+    {
+        $select = $select = $this->_db->select()
+            ->from(SQL_TABLE_PREFIX . 'accounts', 'COUNT(id)')
+            ->where($this->_db->quoteIdentifier('login_name') . " not in ('cronuser', 'calendarscheduling')");
+        $userCount = $this->_db->fetchOne($select);
+        return $userCount;
+    }
+
+    /**
+     * fetch creation time of the first/oldest user
+     *
+     * @return Tinebase_DateTime
+     */
+    public function getFirstUserCreationTime()
+    {
+        $schema = Tinebase_Db_Table::getTableDescriptionFromCache($this->_db->table_prefix . $this->_tableName, $this->_db);
+        $fallback = new Tinebase_DateTime('2014-12-01');
+        if (!isset($schema['creation_time'])) {
+            return $fallback;
+        }
+
+        $select = $select = $this->_db->select()
+            ->from(SQL_TABLE_PREFIX . 'accounts', 'creation_time')
+            ->where($this->_db->quoteIdentifier('login_name') . " not in ('cronuser', 'calendarscheduling')")
+            ->where($this->_db->quoteIdentifier('creation_time') . " is not null")
+            ->order('creation_time ASC')
+            ->limit(1);
+        $creationTime = $this->_db->fetchOne($select);
+
+        $result = (!empty($creationTime)) ? new Tinebase_DateTime($creationTime) : $fallback;
+        return $result;
+    }
+
+    /**
      * fetch all user ids from accounts table
      *
      * @return array