/** * delete duplicate events defined by an event filter * * @param Calendar_Model_EventFilter $filter * @param boolean $dryrun * @return integer number of deleted events */ public function deleteDuplicateEvents($filter, $dryrun = TRUE) { if ($dryrun && Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' - Running in dry run mode - using filter: ' . print_r($filter->toArray(), true)); } $duplicateFields = array('summary', 'dtstart', 'dtend'); $select = $this->_db->select(); $select->from(array($this->_tableName => $this->_tablePrefix . $this->_tableName), $duplicateFields); $select->where($this->_db->quoteIdentifier($this->_tableName . '.is_deleted') . ' = 0'); $this->_addFilter($select, $filter); $select->group($duplicateFields)->having('count(*) > 1'); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $select); } $rows = $this->_fetch($select, self::FETCH_ALL); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($rows, TRUE)); } $toDelete = array(); foreach ($rows as $row) { $index = $row['summary'] . ' / ' . $row['dtstart'] . ' - ' . $row['dtend']; $filter = new Calendar_Model_EventFilter(array(array('field' => 'summary', 'operator' => 'equals', 'value' => $row['summary']), array('field' => 'dtstart', 'operator' => 'equals', 'value' => new Tinebase_DateTime($row['dtstart'])), array('field' => 'dtend', 'operator' => 'equals', 'value' => new Tinebase_DateTime($row['dtend'])))); $pagination = new Tinebase_Model_Pagination(array('sort' => array($this->_tableName . '.last_modified_time', $this->_tableName . '.creation_time'))); $select = $this->_db->select(); $select->from(array($this->_tableName => $this->_tablePrefix . $this->_tableName)); $select->where($this->_db->quoteIdentifier($this->_tableName . '.is_deleted') . ' = 0'); $this->_addFilter($select, $filter); $pagination->appendPaginationSql($select); $rows = $this->_fetch($select, self::FETCH_ALL); $events = $this->_rawDataToRecordSet($rows); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($events->toArray(), TRUE)); } $deleteIds = $events->getArrayOfIds(); // keep the first array_shift($deleteIds); if (!empty($deleteIds)) { $deleteContainerIds = $events->container_id; $origContainer = array_shift($deleteContainerIds); if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Deleting ' . count($deleteIds) . ' duplicates of: ' . $index . ' in container_ids ' . implode(',', $deleteContainerIds) . ' (origin container: ' . $origContainer . ')'); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($deleteIds, TRUE)); } $toDelete = array_merge($toDelete, $deleteIds); } else { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' No duplicates found for ' . $index); } } } if (empty($toDelete)) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' No duplicates found.'); } $result = 0; } else { $result = $dryrun ? count($toDelete) : $this->delete($toDelete); } return $result; }
/** * returns freebusy information for given period and given attendee * * @todo merge overlapping events to one freebusy entry * * @param array of array with from and until $_periods * @param Tinebase_Record_RecordSet of Calendar_Model_Attender $_attendee * @param array of UIDs $_ignoreUIDs * @return Tinebase_Record_RecordSet of Calendar_Model_FreeBusy */ public function getFreeBusyInfo($_periods, $_attendee, $_ignoreUIDs = array()) { $fbInfoSet = new Tinebase_Record_RecordSet('Calendar_Model_FreeBusy'); // map groupmembers to users $attendee = clone $_attendee; $attendee->addIndices(array('user_type')); $groupmembers = $attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER); $groupmembers->user_type = Calendar_Model_Attender::USERTYPE_USER; // base filter data $filterData = array(array('field' => 'attender', 'operator' => 'in', 'value' => $_attendee), array('field' => 'transp', 'operator' => 'equals', 'value' => Calendar_Model_Event::TRANSP_OPAQUE)); // add all periods to filterdata $periodFilters = array(); foreach ($_periods as $period) { $periodFilters[] = array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $period['from'], 'until' => $period['until'])); } $filterData[] = array('condition' => 'OR', 'filters' => $periodFilters); // finaly create filter $filter = new Calendar_Model_EventFilter($filterData); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' free/busy filter: ' . print_r($filter->toArray(), true)); } $events = $this->search($filter, new Tinebase_Model_Pagination(), FALSE, FALSE); foreach ($_periods as $period) { Calendar_Model_Rrule::mergeRecurrenceSet($events, $period['from'], $period['until']); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' value: ' . print_r($events->toArray(), true)); } // create a typemap $typeMap = array(); foreach ($attendee as $attender) { if (!(isset($typeMap[$attender['user_type']]) || array_key_exists($attender['user_type'], $typeMap))) { $typeMap[$attender['user_type']] = array(); } $typeMap[$attender['user_type']][$attender['user_id']] = array(); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__ . ' value: ' . print_r($typeMap, true)); } // generate freeBusyInfos foreach ($events as $event) { // skip events with ignoreUID if (in_array($event->uid, $_ignoreUIDs)) { continue; } // check if event is conflicting one of the given periods $conflicts = FALSE; foreach ($_periods as $period) { if ($event->dtstart->isEarlier($period['until']) && $event->dtend->isLater($period['from'])) { $conflicts = TRUE; break; } } if (!$conflicts) { continue; } // map groupmembers to users $event->attendee->addIndices(array('user_type')); $groupmembers = $event->attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER); $groupmembers->user_type = Calendar_Model_Attender::USERTYPE_USER; foreach ($event->attendee as $attender) { // skip declined/transp events if ($attender->status == Calendar_Model_Attender::STATUS_DECLINED || $attender->transp == Calendar_Model_Event::TRANSP_TRANSP) { continue; } if ((isset($typeMap[$attender->user_type]) || array_key_exists($attender->user_type, $typeMap)) && (isset($typeMap[$attender->user_type][$attender->user_id]) || array_key_exists($attender->user_id, $typeMap[$attender->user_type]))) { $fbInfo = new Calendar_Model_FreeBusy(array('user_type' => $attender->user_type, 'user_id' => $attender->user_id, 'dtstart' => clone $event->dtstart, 'dtend' => clone $event->dtend, 'type' => Calendar_Model_FreeBusy::FREEBUSY_BUSY), true); if ($event->{Tinebase_Model_Grants::GRANT_READ}) { $fbInfo->event = clone $event; unset($fbInfo->event->attendee); } //$typeMap[$attender->user_type][$attender->user_id][] = $fbInfo; $fbInfoSet->addRecord($fbInfo); } } } return $fbInfoSet; }