Merge branch '2013.10' into 2014.11
authorPhilipp Schüle <p.schuele@metaways.de>
Mon, 25 Jan 2016 08:03:01 +0000 (09:03 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Mon, 25 Jan 2016 08:03:01 +0000 (09:03 +0100)
1  2 
tine20/Calendar/Setup/Update/Release8.php

@@@ -171,305 -171,92 +171,307 @@@ class Calendar_Setup_Update_Release8 ex
       */
      public function update_3()
      {
 -        $declaration = new Setup_Backend_Schema_Field_Xml('
 -            <field>
 -                <name>etag</name>
 -                <type>text</type>
 -                <length>60</length>
 -            </field>');
 -        $this->_backend->addCol('cal_events', $declaration);
 -        
 -        $declaration = new Setup_Backend_Schema_Index_Xml('
 -            <index>
 -                <name>etag</name>
 +        if (! $this->_backend->columnExists('etag', 'cal_events')) {
 +            $declaration = new Setup_Backend_Schema_Field_Xml('
                  <field>
                      <name>etag</name>
 -                </field>
 -            </index>');
 -        $this->_backend->addIndex('cal_events', $declaration);
 +                    <type>text</type>
 +                    <length>60</length>
 +                </field>');
 +            $this->_backend->addCol('cal_events', $declaration);
 +
 +            $declaration = new Setup_Backend_Schema_Index_Xml('
 +                <index>
 +                    <name>etag</name>
 +                    <field>
 +                        <name>etag</name>
 +                    </field>
 +                </index>');
 +            $this->_backend->addIndex('cal_events', $declaration);
 +        }
 +        
          $this->setTableVersion('cal_events', 7);
          $this->setApplicationVersion('Calendar', '8.4');
      }
      
      /**
 +     * - update import / export
 +     */
 +    public function update_4()
 +    {
 +        Setup_Controller::getInstance()->createImportExportDefinitions(Tinebase_Application::getInstance()->getApplicationByName('Calendar'));
 +        $this->setTableVersion('cal_events', 7);
 +        $this->setApplicationVersion('Calendar', '8.5');
 +    }
 +    
 +    /**
       * adds external_seq col
       * 
       * @see 0009890: improve external event invitation support
       */
 -    public function update_4()
 +    public function update_5()
      {
 -        $seqCol = '<field>
 -            <name>external_seq</name>
 -            <type>integer</type>
 -            <notnull>true</notnull>
 -            <default>0</default>
 -        </field>';
 -        
 -        $declaration = new Setup_Backend_Schema_Field_Xml($seqCol);
 -        $this->_backend->addCol('cal_events', $declaration);
 +        if (! $this->_backend->columnExists('external_seq', 'cal_events')) {
 +            $seqCol = '<field>
 +                <name>external_seq</name>
 +                <type>integer</type>
 +                <notnull>true</notnull>
 +                <default>0</default>
 +            </field>';
 +            
 +            $declaration = new Setup_Backend_Schema_Field_Xml($seqCol);
 +            $this->_backend->addCol('cal_events', $declaration);
 +        }
          
 -        $this->setTableVersion('cal_events', 8);
 -        $this->setApplicationVersion('Calendar', '8.5');
 +        $this->setTableVersion('cal_events', '8');
 +        $this->setApplicationVersion('Calendar', '8.6');
      }
      
      /**
       * add rrule index
       * 
       * @see 0010214: improve calendar performance / yearly base events
 +     *
 +     * TODO re-enable this when it is fixed for postgresql
 +     * @see 0011194: only drop index if it exists
       */
 -    public function update_5()
 +    public function update_6()
 +    {
 +//        $declaration = new Setup_Backend_Schema_Index_Xml('
 +//            <index>
 +//                <name>rrule</name>
 +//                <field>
 +//                    <name>rrule</name>
 +//                </field>
 +//            </index>');
 +//        try {
 +//            $this->_backend->addIndex('cal_events', $declaration);
 +//        } catch (Zend_Db_Statement_Exception $e) {
 +//            Tinebase_Exception::log($e);
 +//        }
 +        
 +        $this->setTableVersion('cal_events', '9');
 +        $this->setApplicationVersion('Calendar', '8.7');
 +    }
 +
 +    /**
 +     * repair missing displaycontainer_id
 +     */
 +    public function update_7()
      {
 +        $allUser = $this->_db->query(
 +            "SELECT " . $this->_db->quoteIdentifier('id') . "," . $this->_db->quoteIdentifier('contact_id') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "accounts") .
 +            " WHERE " . $this->_db->quoteIdentifier("contact_id") . " IS NOT NULL"
 +        )->fetchAll(Zend_Db::FETCH_ASSOC);
 +
 +        $contactUserMap = array();
 +        foreach ($allUser as $id => $user) {
 +            $contactUserMap[$user['contact_id']] = $user['id'];
 +        }
 +
 +        // find all user/groupmember attendees with missing displaycontainer
 +        $attendees = $this->_db->query(
 +            "SELECT DISTINCT" . $this->_db->quoteIdentifier('user_type') . "," . $this->_db->quoteIdentifier('user_id') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_attendee") .
 +            " WHERE " . $this->_db->quoteIdentifier("displaycontainer_id") . " IS  NULL" .
 +            "  AND " . $this->_db->quoteIdentifier("user_type") . $this->_db->quoteInto(" IN (?)", array('user', 'groupmemeber')) .
 +            "  AND " . $this->_db->quoteIdentifier("user_id") . $this->_db->quoteInto(" IN (?)", array_keys($contactUserMap))
 +        )->fetchAll(Zend_Db::FETCH_ASSOC);
 +
 +        // find all user/groupmember attendees with missing displaycontainer
 +        $attendees = array_merge($attendees, $this->_db->query(
 +            "SELECT DISTINCT" . $this->_db->quoteIdentifier('user_type') . "," . $this->_db->quoteIdentifier('user_id') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_attendee") .
 +            " WHERE " . $this->_db->quoteIdentifier("displaycontainer_id") . " IS  NULL" .
 +            "  AND " . $this->_db->quoteIdentifier("user_type") . $this->_db->quoteInto(" IN (?)", array('resource'))
 +        )->fetchAll(Zend_Db::FETCH_ASSOC));
 +
 +        $resources = $this->_db->query(
 +            "SELECT " . $this->_db->quoteIdentifier('id') . "," . $this->_db->quoteIdentifier('container_id') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_resources")
 +        )->fetchAll(Zend_Db::FETCH_ASSOC);
 +
 +        $resourceContainerMap = array();
 +        foreach ($resources as $resource) {
 +            $resourceContainerMap[$resource['id']] = $resource['container_id'];
 +        }
 +
 +        foreach ($attendees as $attendee) {
 +            //find out displaycontainer
 +            if ($attendee['user_type'] != 'resource') {
 +                $userAccountId = $contactUserMap[$attendee['user_id']];
 +                try {
 +                    $attendee['displaycontainerId'] = Calendar_Controller_Event::getDefaultDisplayContainerId($userAccountId);
 +                } catch (Tinebase_Exception_NotFound $tenf) {
 +                    Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " Could not find user with id " . $attendee['user_id']);
 +                    continue;
 +                }
 +            } else {
 +                $attendee['displaycontainerId'] = $resourceContainerMap[$attendee['user_id']];
 +            }
 +
 +            // update displaycontainer
 +            $this->_db->query(
 +                "UPDATE" . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_attendee") .
 +                " SET " . $this->_db->quoteIdentifier("displaycontainer_id") . " = " . $this->_db->quote($attendee['displaycontainerId']) .
 +                " WHERE " . $this->_db->quoteIdentifier("user_type") . " = " . $this->_db->quote($attendee['user_type']) .
 +                "  AND " . $this->_db->quoteIdentifier("user_id") . " = " . $this->_db->quote($attendee['user_id'])
 +            );
 +        }
 +
 +        $this->setApplicationVersion('Calendar', '8.8');
 +    }
 +
 +    /**
 +     * identify base event via new base_event_id field instead of UID
 +     */
 +    public function update_8()
 +    {
 +        /* find possibly broken events
 +         SELECT group_concat(id), uid, count(id) as cnt from tine20_cal_events
 +             WHERE rrule IS NOT NULL
 +             GROUP BY uid
 +             HAVING cnt > 1;
 +         */
 +
 +        $declaration = new Setup_Backend_Schema_Field_Xml('
 +            <field>
 +                <name>base_event_id</name>
 +                <type>text</type>
 +                <length>40</length>
 +            </field>');
 +        $this->_backend->addCol('cal_events', $declaration);
 +
          $declaration = new Setup_Backend_Schema_Index_Xml('
              <index>
 -                <name>rrule</name>
 +                <name>base_event_id</name>
                  <field>
 -                    <name>rrule</name>
 +                    <name>base_event_id</name>
                  </field>
              </index>');
 -        try {
 -            $this->_backend->addIndex('cal_events', $declaration);
 -        } catch (Zend_Db_Statement_Exception $e) {
 -            Tinebase_Exception::log($e);
 +        $this->_backend->addIndex('cal_events', $declaration);
 +
 +        // find all events with rrule
 +        $events = $this->_db->query(
 +            "SELECT " . $this->_db->quoteIdentifier('id') .
 +                 ', ' . $this->_db->quoteIdentifier('uid') .
 +                 ', ' . $this->_db->quoteIdentifier('container_id') .
 +                 ', ' . $this->_db->quoteIdentifier('created_by') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") .
 +            " WHERE " . $this->_db->quoteIdentifier("rrule") . " IS NOT NULL" .
 +              " AND " . $this->_db->quoteIdentifier("is_deleted") . " = " . $this->_db->quote(0, Zend_Db::INT_TYPE)
 +        )->fetchAll(Zend_Db::FETCH_ASSOC);
 +
 +        // update all exdates in same container
 +        foreach($events as $event) {
 +            $this->_db->query(
 +                "UPDATE " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") .
 +                  " SET " . $this->_db->quoteIdentifier('base_event_id') . ' = ' . $this->_db->quote($event['id']) .
 +                " WHERE " . $this->_db->quoteIdentifier('uid') . ' = ' . $this->_db->quote($event['uid']) .
 +                  " AND " . $this->_db->quoteIdentifier("container_id") . ' = ' . $this->_db->quote($event['container_id']) .
 +                  " AND " . $this->_db->quoteIdentifier("recurid") . " IS NOT NULL" .
 +                  " AND " . $this->_db->quoteIdentifier("is_deleted") . " = " . $this->_db->quote(0, Zend_Db::INT_TYPE)
 +            );
          }
 -        
 -        $this->setTableVersion('cal_events', '9');
 -        $this->setApplicationVersion('Calendar', '8.6');
 +
 +        // find all container move exdates
 +        $danglingExdates = $this->_db->query(
 +            "SELECT " . $this->_db->quoteIdentifier('uid') .
 +                ', ' . $this->_db->quoteIdentifier('id') .
 +                ', ' . $this->_db->quoteIdentifier('created_by') .
 +            " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") .
 +            " WHERE " . $this->_db->quoteIdentifier("recurid") . " IS NOT NULL" .
 +              " AND " . $this->_db->quoteIdentifier("base_event_id") . " IS NULL" .
 +              " AND " . $this->_db->quoteIdentifier("is_deleted") . " = " . $this->_db->quote(0, Zend_Db::INT_TYPE)
 +        )->fetchAll(Zend_Db::FETCH_ASSOC);
 +
 +        // try to match by creator
 +        foreach ($danglingExdates as $exdate) {
 +            $possibleBaseEvents = array();
 +            $matches = array_filter($events, function ($event) use ($exdate, $possibleBaseEvents) {
 +                if ($event['uid'] == $exdate['uid']) {
 +                    $possibleBaseEvents[] = $event;
 +                    return $event['created_by'] == $exdate['created_by'];
 +                }
 +                return false;
 +            });
 +
 +            switch(count($matches)) {
 +                case 0:
 +                    // no match :-(
 +                    if (count($possibleBaseEvents) == 0) {
 +                        // garbage? exdate without any base event
 +                        Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " dangling exdate with id {$exdate['id']}");
 +                        continue 2;
 +                    }
 +                    Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " no match for exdate with id {$exdate['id']}");
 +                    $baseEvent = current($possibleBaseEvents);
 +                    break;
 +                case 1:
 +                    // exact match :-)
 +                    $baseEvent = current($matches);
 +                    break;
 +                default:
 +                    // to much matches :-(
 +                    Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " multiple matches for exdate with id {$exdate['id']}");
 +                    $baseEvent = current($matches);
 +            }
 +
 +            $this->_db->query(
 +                "UPDATE " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") .
 +                " SET " . $this->_db->quoteIdentifier('base_event_id') . ' = ' . $this->_db->quote($baseEvent['id']) .
 +                " WHERE " . $this->_db->quoteIdentifier('id') . ' = ' . $this->_db->quote($exdate['id'])
 +            );
 +        }
 +
 +        $this->setTableVersion('cal_events', '10');
 +        $this->setApplicationVersion('Calendar', '8.9');
 +    }
 +
 +    /**
 +     * @see 0011266: increase size of event fields summary and location
 +     */
 +    public function update_9()
 +    {
 +        $fieldsToChange = array('location', 'summary');
 +
 +        foreach ($fieldsToChange as $name) {
 +            $seqCol = '<field>
 +                <name>' . $name . '</name>
 +                <type>text</type>
 +                <length>1024</length>
 +            </field>';
 +
 +            $declaration = new Setup_Backend_Schema_Field_Xml($seqCol);
 +            $this->_backend->alterCol('cal_events', $declaration);
 +        }
 +
 +        $this->setTableVersion('cal_events', 11);
 +        $this->setApplicationVersion('Calendar', '8.10');
      }
  
      /**
       * force activesync calendar resync for iOS devices
       */
 -    public function update_6()
 +    public function update_10()
      {
-         $deviceBackend = new ActiveSync_Backend_Device();
-         $usersWithiPhones = $deviceBackend->search(new ActiveSync_Model_DeviceFilter(array(
-             'devicetype' => 'iphone'
-         )))->owner_id;
+         if (Tinebase_Application::getInstance()->isInstalled('ActiveSync')) {
+             $deviceBackend = new ActiveSync_Backend_Device();
+             $usersWithiPhones = $deviceBackend->search(new ActiveSync_Model_DeviceFilter(array(
+                 'devicetype' => 'iphone'
+             )))->owner_id;
  
-         $activeSyncController = ActiveSync_Controller::getInstance();
-         foreach($usersWithiPhones as $userId) {
-             try {
-                 $activeSyncController->resetSyncForUser($userId, 'Calendar');
-             } catch (Exception $e) {
-                 Tinebase_Exception::log($e, /* suppress trace */ false);
+             $activeSyncController = ActiveSync_Controller::getInstance();
+             foreach ($usersWithiPhones as $userId) {
+                 try {
+                     $activeSyncController->resetSyncForUser($userId, 'Calendar');
+                 } catch (Exception $e) {
+                     Tinebase_Exception::log($e, /* suppress trace */ false);
+                 }
              }
          }
  
 -        $this->setApplicationVersion('Calendar', '8.7');
 +        $this->setApplicationVersion('Calendar', '8.11');
      }
  }