Merge branch '2013.10' into 2014.11
authorPhilipp Schüle <p.schuele@metaways.de>
Wed, 20 Jan 2016 14:29:37 +0000 (15:29 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 20 Jan 2016 14:29:37 +0000 (15:29 +0100)
Conflicts:
tests/tine20/Calendar/Controller/RecurTest.php
tine20/Calendar/Setup/setup.xml

Change-Id: I2ba9af2c9b5d45b7df8814b4afd87ce26462b839

1  2 
tests/tine20/Calendar/Controller/RecurTest.php
tests/tine20/Calendar/Frontend/ActiveSyncTest.php
tine20/ActiveSync/Controller.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Frontend/ActiveSync.php
tine20/Calendar/Setup/Update/Release8.php
tine20/Calendar/Setup/setup.xml

@@@ -466,8 -466,8 +466,8 @@@ class Calendar_Controller_RecurTest ext
              'dtstart'       => '2011-04-21 10:00:00',
              'dtend'         => '2011-04-21 12:00:00',
              'originator_tz' => 'Europe/Berlin',
-             'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2011-04-27 21:59:59',
+             'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2011-04-28 21:59:59',
 -            'container_id'  => $this->_testCalendar->getId()
 +            'container_id'  => $this->_getTestCalendar()->getId()
          ));
          
          $persistentEvent = $this->_controller->create($event);
          
          $updatedBaseEvent = $this->_controller->getRecurBaseEvent($recurSet[3]);
          $recurSet[3]->last_modified_time = $updatedBaseEvent->last_modified_time;
-         $newBaseEvent = $this->_controller->createRecurException($recurSet[3], FALSE, TRUE);
+         $newBaseEvent = $this->_controller->createRecurException($recurSet[3], FALSE, TRUE); // split at 25
          
          $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
 +            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
              array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from, 'until' => $until),
          ))));
          
Simple merge
Simple merge
@@@ -196,10 -196,17 +196,17 @@@ class Calendar_Frontend_ActiveSync exte
          'samsunggtn7000', // Samsung Galaxy Note 
          'samsunggti9300', // Samsung Galaxy S-3
      );
-     
+     /**
+      * folder id which is currenttly synced
+      *
+      * @var string
+      */
+     protected $_syncFolderId = null;
      /**
       * (non-PHPdoc)
 -     * @see ActiveSync_Controller_Abstract::__construct()
 +     * @see ActiveSync_Frontend_Abstract::__construct()
       */
      public function __construct(Syncroton_Model_IDevice $_device, DateTime $_syncTimeStamp)
      {
@@@ -231,223 -216,41 +231,241 @@@ class Calendar_Setup_Update_Release8 ex
       * 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');
      }
 -    public function update_6()
+     /**
+      * force activesync calendar resync for iOS devices
+      */
 -        $this->setApplicationVersion('Calendar', '8.7');
++    public function update_10()
+     {
+         $deviceBackend = new ActiveSync_Backend_Device();
+         $usersWithiPhones = $deviceBackend->search(new ActiveSync_Model_DeviceFilter(array(
+             'devicetype' => 'iphone'
+         )), NULL, 'owner_id');
+         $activeSyncController = ActiveSync_Controller::getInstance();
+         foreach($usersWithiPhones as $userId) {
+             $activeSyncController->resetSyncForUser($userId, 'Calendar');
+         }
++        $this->setApplicationVersion('Calendar', '8.11');
+     }
  }
@@@ -2,7 -2,7 +2,7 @@@
  <application>
      <name>Calendar</name>
      <!-- gettext('Calendar') -->   
-     <version>8.10</version>
 -    <version>8.7</version>
++    <version>8.11</version>
      <order>15</order>
      <status>enabled</status>
      <tables>