Merge branch '2013.10' into 2014.11
authorPhilipp Schüle <p.schuele@metaways.de>
Fri, 19 Aug 2016 07:41:47 +0000 (09:41 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Fri, 19 Aug 2016 07:41:47 +0000 (09:41 +0200)
Change-Id: I8b1972e6af0c2b648fdbd89cbe21e77c3c2f5f67

tests/tine20/Tinebase/User/LdapTest.php
tine20/Calendar/Frontend/WebDAV/Container.php
tine20/Felamimail/Backend/Cache/Sql/Message.php
tine20/Setup/Frontend/Cli.php
tine20/Setup/Server/Cli.php
tine20/Tinebase/Config.php
tine20/Tinebase/User.php
tine20/Tinebase/User/ActiveDirectory.php
tine20/Tinebase/User/Ldap.php

index f3c9b86..f7cd080 100644 (file)
@@ -5,16 +5,11 @@
  * @package     Tinebase
  * @subpackage  User
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2008-2014 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2008-2016 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Lars Kneschke <l.kneschke@metaways.de>
  */
 
 /**
- * Test helper
- */
-require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
-
-/**
  * Test class for Tinebase_User_Ldap
  */
 class Tinebase_User_LdapTest extends TestCase
@@ -38,8 +33,20 @@ class Tinebase_User_LdapTest extends TestCase
             $this->markTestSkipped('LDAP backend not enabled');
         }
         $this->_backend = Tinebase_User::factory(Tinebase_User::LDAP);
+
+        parent::setUp();
     }
-    
+
+    /**
+     * tear down tests
+     */
+    protected function tearDown()
+    {
+        Tinebase_Config::getInstance()->set(Tinebase_Config::LDAP_OVERWRITE_CONTACT_FIELDS, array());
+
+        parent::tearDown();
+    }
+
     /**
      * try to add an user
      * 
@@ -216,14 +223,58 @@ class Tinebase_User_LdapTest extends TestCase
     
     /**
      * execute Tinebase_User::syncUser
+     *
+     * TODO test bday
      */
-    public function testSyncUser()
+    public function testSyncUsersContactData()
     {
-        $user = $this->testAddUser();
-        
-        Tinebase_User::syncUser($user, Tinebase_Application::getInstance()->isInstalled('Addressbook'));
+        Tinebase_Config::getInstance()->set(Tinebase_Config::LDAP_OVERWRITE_CONTACT_FIELDS, array(
+            'tel_work',
+            'jpegphoto'
+        ));
+
+        // add user in LDAP
+        $user = $this->_backend->addUserToSyncBackend(self::getTestRecord());
+        $this->_usernamesToDelete[] = $user->accountLoginName;
+
+        $syncedUser = Tinebase_User::syncUser($user);
+
+        // check if user is synced
+        $this->assertEquals(Tinebase_Model_User::VISIBILITY_DISPLAYED, $syncedUser->visibility,
+            print_r($syncedUser->toArray(), true));
+
+        // add+remove phone data in ldap and check if it is removed in adb, too
+        $syncOptions = array(
+            'syncContactData' => true,
+            'syncContactPhoto' => true,
+        );
+        $ldap = $this->_backend->getLdap();
+        $dn = $this->_backend->generateDn($syncedUser);
+        $number = '040-428457634';
+        $jpegImage = file_get_contents(dirname(dirname(dirname(dirname(__DIR__))))
+            . '/tine20/Admin/Setup/DemoData/persona_sclever.jpg');
+        $ldap->updateProperty($dn, array(
+            'telephonenumber' => $number,
+            'jpegphoto'       => $jpegImage,
+            //'birthdate'       => '2000-09-09'
+        ));
+        $syncedUser = Tinebase_User::syncUser($user, $syncOptions);
+        $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($syncedUser->getId());
+        $this->assertEquals($number, $contact->tel_work);
+        $this->assertEquals(1, $contact->jpegphoto);
+        //$this->assertEquals('2000-09-09 00:00:00', $contact->bday->toString());
+
+        // remove number + photo and sync again
+        $ldap->updateProperty($dn, array(
+            'telephonenumber' => '',
+            'jpegphoto'       => '',
+        ));
+        $syncedUser = Tinebase_User::syncUser($user, $syncOptions);
+        $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($syncedUser->getId());
+        $this->assertEquals('', $contact->tel_work);
+        $this->assertEquals(0, $contact->jpegphoto);
     }
-        
+
     /**
      * @return Tinebase_Model_FullUser
      */
index 1d6b9d5..735bd3f 100644 (file)
@@ -375,7 +375,7 @@ class Calendar_Frontend_WebDAV_Container extends Tinebase_WebDav_Container_Abstr
                     try {
                         $list       = Tinebase_Group::getInstance()->getGroupById($grant->account_id);
                     } catch (Tinebase_Exception_NotFound $tenf) {
-                        continue;
+                        continue 2;
                     }
 
                     // was: '/principals/groups/'
@@ -386,12 +386,12 @@ class Calendar_Frontend_WebDAV_Container extends Tinebase_WebDav_Container_Abstr
                     
                 case 'user':
                     if ((string)$this->_container->owner_id === (string)$grant->account_id) {
-                        continue;
+                        continue 2;
                     }
                     try {
                         $contact = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountId', $grant->account_id);
                     } catch (Tinebase_Exception_NotFound $tenf) {
-                        continue;
+                        continue 2;
                     }
 
                     // was: '/principals/users/'
index ceef8a3..6f98262 100644 (file)
@@ -107,21 +107,27 @@ class Felamimail_Backend_Cache_Sql_Message extends Tinebase_Backend_Sql_Abstract
     protected function _updateForeignKeys($_mode, Tinebase_Record_Abstract $_record)
     {
         if ($_mode == 'create') {
-            
             foreach ($this->_foreignTables as $key => $foreign) {
                 if (!isset($_record->{$key}) || empty($_record->{$key})) {
                     continue;
                 }
-                
-                //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $_field . ': ' . print_r($_record->{$_field}, TRUE));
-                
+
+                if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__
+                    . '::' . __LINE__ . ' ' . $key . ': ' . print_r($_record->{$key}, TRUE));
+
                 foreach ($_record->{$key} as $data) {
                     if ($key == 'flags') {
                         $data = array(
                             'flag'      => $data,
                             'folder_id' => $_record->folder_id
                         );
+                    } else {
+                        // need to filter input as 'name' could contain invalid chars (emojis, ...) here
+                        foreach ($data as $field => $value) {
+                            $data[$field] = Tinebase_Core::filterInputForDatabase($data[$field]);
+                        }
                     }
+
                     $data['message_id'] = $_record->getId();
                     $this->_db->insert($this->_tablePrefix . $foreign['table'], $data);
                 }
index e2ad2fc..f140fe7 100644 (file)
@@ -434,10 +434,12 @@ class Setup_Frontend_Cli
         if ($_opts->syncdeletedusers) {
             $options['deleteUsers'] = true;
         }
-
         if ($_opts->syncaccountstatus) {
             $options['syncAccountStatus'] = true;
         }
+        if ($_opts->syncontactphoto) {
+            $options['syncContactPhoto'] = true;
+        }
 
         Tinebase_User::syncUsers($options);
     }
index 388e104..0ffb4e1 100644 (file)
@@ -49,6 +49,7 @@ class Setup_Server_Cli implements Tinebase_Server_Interface
                     'onlyusers'             => 'Only usable with sync_accounts_from_ldap. Fetches only users and no groups from LDAP.',
                     'syncdeletedusers'      => 'Only usable with sync_accounts_from_ldap. Removes users from Tine 2.0 DB that no longer exist in LDAP',
                     'syncaccountstatus'     => 'Only usable with sync_accounts_from_ldap. Synchronizes current account status from LDAP',
+                    'syncontactphoto'       => 'Only usable with sync_accounts_from_ldap. Always syncs contact photo from ldap',
                 'sync_passwords_from_ldap'  => 'Synchronize user passwords from ldap',
                 'egw14import'               => 'Import user and groups from egw14
                          Examples: 
index e5628e4..20ac750 100644 (file)
@@ -136,7 +136,14 @@ class Tinebase_Config extends Tinebase_Config_Abstract
      * @var string
      */
     const LDAP_DISABLE_TLSREQCERT = 'ldapDisableTlsReqCert';
-    
+
+    /**
+     * overwritten ldap fields
+     *
+     * @var string
+     */
+    const LDAP_OVERWRITE_CONTACT_FIELDS = 'ldapOverwriteContactFields';
+
     /**
      * configure hook class for user sync
      *
@@ -499,6 +506,19 @@ class Tinebase_Config extends Tinebase_Config_Abstract
             'setBySetupModule'      => true,
             'default'               => false
         ),
+        // TODO should this be added to LDAP config array/struct?
+        // TODO does this depend on LDAP readonly option?
+        self::LDAP_OVERWRITE_CONTACT_FIELDS => array(
+            //_('Contact fields overwritten by LDAP')
+            'label'                 => 'Contact fields overwritten by LDAP',
+            //_('These fields are overwritten during LDAP sync if empty')
+            'description'           => 'These fields are overwritten during LDAP sync if empty',
+            'type'                  => 'array',
+            'clientRegistryInclude' => false,
+            'setByAdminModule'      => false,
+            'setBySetupModule'      => true,
+            'default'               => array()
+        ),
         self::SYNC_USER_HOOK_CLASS => array(
                                    //_('Configure hook class for user sync')
             'label'                 => 'Configure hook class for user sync',
index 1945a5c..f6ed098 100644 (file)
@@ -565,12 +565,12 @@ class Tinebase_User
             Tinebase_User::getInstance()->updateContactFromSyncBackend($syncedUser, $contact);
             $contact = self::_user2Contact($syncedUser, $contact);
 
-            if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
                 . ' new contact: ' . print_r($contact->toArray(), true)
                 . ' orig contact:' . print_r($originalContact->toArray(), true));
 
-            // TODO allow to diff jpegphoto, too / maybe this should only be done when called via CLI/cronjob
-            $diff = $contact->diff($originalContact, array('jpegphoto'));
+            $syncPhoto = isset($options['syncContactPhoto']) && $options['syncContactPhoto'];
+            $diff = $contact->diff($originalContact, $syncPhoto ? array() : array('jpegphoto'));
             if (! $diff->isEmpty() || ($originalContact->jpegphoto == 0 && ! empty($contact->jpegphoto))) {
                 // add modlog info
                 Tinebase_Timemachine_ModificationLog::setRecordMetaData($contact, 'update');
index 15db70f..5a1c2d8 100644 (file)
@@ -148,7 +148,7 @@ class Tinebase_User_ActiveDirectory extends Tinebase_User_Ldap
             $plugin->inspectAddUser($_user, $ldapData);
         }
 
-        $dn = $this->_generateDn($_user);
+        $dn = $this->generateDn($_user);
         
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  ldapData: ' . print_r($ldapData, true));
@@ -352,7 +352,7 @@ class Tinebase_User_ActiveDirectory extends Tinebase_User_Ldap
         
         // do we need to rename the entry?
         if ($rdn['CN'] != $ldapData['cn']) {
-            $newDN = $this->_generateDn($_account);
+            $newDN = $this->generateDn($_account);
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  rename ldap entry to: ' . $newDN);
             $this->_ldap->rename($dn, $newDN);
@@ -414,7 +414,7 @@ class Tinebase_User_ActiveDirectory extends Tinebase_User_Ldap
      * @param  Tinebase_Model_FullUser $_account
      * @return string
      */
-    protected function _generateDn(Tinebase_Model_FullUser $_account)
+    public function generateDn(Tinebase_Model_FullUser $_account)
     {
         $newDn = "cn={$_account->accountFullName},{$this->_baseDn}";
 
index 4d52fc1..b6652ee 100644 (file)
@@ -524,7 +524,7 @@ class Tinebase_User_Ldap extends Tinebase_User_Sql implements Tinebase_User_Inte
                 $groupsBackend->removeGroupMemberInSyncBackend($groupId, $_account);
             }
             
-            $newDN = $this->_generateDn($_account);
+            $newDN = $this->generateDn($_account);
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  rename ldap entry to: ' . $newDN);
             $this->_ldap->rename($dn, $newDN);
             
@@ -561,7 +561,7 @@ class Tinebase_User_Ldap extends Tinebase_User_Sql implements Tinebase_User_Inte
             $plugin->inspectAddUser($user, $ldapData);
         }
 
-        $dn = $this->_generateDn($user);
+        $dn = $this->generateDn($user);
         
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  ldapData: ' . print_r($ldapData, true));
@@ -709,10 +709,9 @@ class Tinebase_User_Ldap extends Tinebase_User_Sql implements Tinebase_User_Inte
      * @param  Tinebase_Model_FullUser $_account
      * @return string
      */
-    protected function _generateDn(Tinebase_Model_FullUser $_account)
+    public function generateDn(Tinebase_Model_FullUser $_account)
     {
         $baseDn = $this->_baseDn;
-
         $uidProperty = array_search('uid', $this->_rowNameMapping);
         $newDn = "uid={$_account->$uidProperty},{$baseDn}";
 
@@ -987,22 +986,20 @@ class Tinebase_User_Ldap extends Tinebase_User_Sql implements Tinebase_User_Inte
             'adr_one_region'        => 'st',
         );
 
-        foreach ($_userData as $key => $value) {
-            if (is_int($key)) {
-                continue;
-            }
-
-            $keyMapping = array_search($key, $rowNameMapping);
-
-            if ($keyMapping !== FALSE) {
-                switch($keyMapping) {
+        $overwrittenFields = Tinebase_Config::getInstance()->get(Tinebase_Config::LDAP_OVERWRITE_CONTACT_FIELDS)->toArray();
+        foreach ($rowNameMapping as $tineKey => $ldapKey) {
+            if (isset($_userData[$ldapKey])) {
+                switch ($tineKey) {
                     case 'bday':
-                        $_contact->$keyMapping = Tinebase_DateTime::createFromFormat('Y-m-d', $value[0]);
+                        $_contact->$tineKey = Tinebase_DateTime::createFromFormat('Y-m-d', $_userData[$ldapKey][0]);
                         break;
                     default:
-                        $_contact->$keyMapping = $value[0];
+                        $_contact->$tineKey = $_userData[$ldapKey][0];
                         break;
                 }
+            } else if (in_array($tineKey, $overwrittenFields)) {
+                // should empty values in ldap overwrite tine values
+                $_contact->$tineKey = '';
             }
         }
     }