7 * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
8 * @author Cornelius Weiss <c.weiss@metaways.de>
9 * @copyright Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
13 * json interface for calendar
16 * @subpackage Frontend
18 class Calendar_Frontend_Json extends Tinebase_Frontend_Json_Abstract
25 protected $_applicationName = 'Calendar';
28 * creates an exception instance of a recurring event
30 * NOTE: deleting persistent exceptions is done via a normal delete action
31 * and handled in the controller
33 * @param array $recordData
34 * @param bool $deleteInstance
35 * @param bool $deleteAllFollowing
36 * @param bool $checkBusyConflicts
37 * @return array exception Event | updated baseEvent
39 * @todo replace $_allFollowing param with $range
40 * @deprecated replace with create/update/delete
42 public function createRecurException($recordData, $deleteInstance, $deleteAllFollowing, $checkBusyConflicts = FALSE)
44 $event = new Calendar_Model_Event(array(), TRUE);
45 $event->setFromJsonInUsersTimezone($recordData);
47 $returnEvent = Calendar_Controller_Event::getInstance()->createRecurException($event, $deleteInstance, $deleteAllFollowing, $checkBusyConflicts);
49 return $this->getEvent($returnEvent->getId());
53 * deletes existing events
56 * @param string $range
59 public function deleteEvents($ids, $range = Calendar_Model_Event::RANGE_THIS)
61 return $this->_delete($ids, Calendar_Controller_Event::getInstance(), array($range));
65 * deletes existing resources
70 public function deleteResources($ids)
72 return $this->_delete($ids, Calendar_Controller_Resource::getInstance());
76 * deletes a recur series
78 * @param array $recordData
81 public function deleteRecurSeries($recordData)
83 $event = new Calendar_Model_Event(array(), TRUE);
84 $event->setFromJsonInUsersTimezone($recordData);
86 Calendar_Controller_Event::getInstance()->deleteRecurSeries($event);
87 return array('success' => true);
91 * Return a single event
94 * @return array record data
96 public function getEvent($id)
98 return $this->_get($id, Calendar_Controller_Event::getInstance());
102 * Returns registry data of the calendar.
104 * @return mixed array 'variable name' => 'data'
106 * @todo move exception handling (no default calender found) to another place?
108 public function getRegistryData()
110 $defaultCalendarId = Tinebase_Core::getPreference('Calendar')->getValue(Calendar_Preference::DEFAULTCALENDAR);
112 $defaultCalendarArray = Tinebase_Container::getInstance()->getContainerById($defaultCalendarId)->toArray();
113 $defaultCalendarArray['account_grants'] = Tinebase_Container::getInstance()->getGrantsOfAccount(Tinebase_Core::getUser(), $defaultCalendarId)->toArray();
114 if ($defaultCalendarArray['type'] != Tinebase_Model_Container::TYPE_SHARED) {
115 $defaultCalendarArray['ownerContact'] = Addressbook_Controller_Contact::getInstance()->getContactByUserId($defaultCalendarArray['owner_id'])->toArray();
117 } catch (Exception $e) {
118 // remove default cal pref
119 Tinebase_Core::getPreference('Calendar')->deleteUserPref(Calendar_Preference::DEFAULTCALENDAR);
120 $defaultCalendarArray = array();
123 $importDefinitions = $this->_getImportDefinitions();
124 $allCalendarResources = Calendar_Controller_Resource::getInstance()->getAll()->toArray();
126 $registryData = array(
127 'defaultContainer' => $defaultCalendarArray,
128 'defaultImportDefinition' => $importDefinitions['default'],
129 'importDefinitions' => $importDefinitions,
130 'calendarResources' => $allCalendarResources
133 return $registryData;
137 * get default addressbook
141 public function getDefaultCalendar()
143 $defaultCalendar = Calendar_Controller_Event::getInstance()->getDefaultCalendar();
144 $defaultCalendarArray = $defaultCalendar->toArray();
145 $defaultCalendarArray['account_grants'] = Tinebase_Container::getInstance()->getGrantsOfAccount(Tinebase_Core::getUser(), $defaultCalendar->getId())->toArray();
146 Tinebase_Core::getLogger()->notice(print_r($defaultCalendar, true));
147 return $defaultCalendarArray;
153 * @param string $tempFileId to import
154 * @param string $definitionId
155 * @param array $importOptions
156 * @param array $clientRecordData
159 public function importEvents($tempFileId, $definitionId, $importOptions, $clientRecordData = array())
161 return $this->_import($tempFileId, $definitionId, $importOptions, $clientRecordData);
165 * creates a scheduled import
167 * @param string $remoteUrl
168 * @param string $interval
169 * @param string $importOptions
172 public function importRemoteEvents($remoteUrl, $interval, $importOptions)
174 // Determine which plugin should be used to import
175 switch ($importOptions['sourceType']) {
176 case 'remote_caldav':
177 $plugin = 'Calendar_Import_CalDAV';
180 $plugin = 'Calendar_Import_Ical';
183 $record = Tinebase_Controller_ScheduledImport::getInstance()->create( new Tinebase_Model_Import(array(
184 'source' => $remoteUrl,
185 'sourcetype' => Tinebase_Model_Import::SOURCETYPE_REMOTE,
186 'interval' => $interval,
187 'options' => array_replace($importOptions, array(
189 'importFileByScheduler' => $importOptions['sourceType'] != 'remote_caldav',
191 'model' => 'Calendar_Model_Event',
192 'application_id' => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(),
195 $result = $this->_recordToJson($record);
201 * get addressbook import definitions
205 * @todo generalize this
207 protected function _getImportDefinitions()
209 $filter = new Tinebase_Model_ImportExportDefinitionFilter(array(
210 array('field' => 'application_id', 'operator' => 'equals', 'value' => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId()),
211 array('field' => 'type', 'operator' => 'equals', 'value' => 'import'),
214 $definitionConverter = new Tinebase_Convert_ImportExportDefinition_Json();
217 $importDefinitions = Tinebase_ImportExportDefinition::getInstance()->search($filter);
218 $defaultDefinition = $this->_getDefaultImportDefinition($importDefinitions);
220 'results' => $definitionConverter->fromTine20RecordSet($importDefinitions),
221 'totalcount' => count($importDefinitions),
222 'default' => ($defaultDefinition) ? $definitionConverter->fromTine20Model($defaultDefinition) : array(),
224 } catch (Exception $e) {
225 Tinebase_Exception::log($e);
228 'results' => array(),
230 'default' => array(),
239 * get default definition
241 * @param Tinebase_Record_RecordSet $_importDefinitions
242 * @return Tinebase_Model_ImportExportDefinition
244 * @todo generalize this
246 protected function _getDefaultImportDefinition($_importDefinitions)
249 $defaultDefinition = Tinebase_ImportExportDefinition::getInstance()->getByName('cal_import_ical');
250 } catch (Tinebase_Exception_NotFound $tenf) {
251 if (count($_importDefinitions) > 0) {
252 $defaultDefinition = $_importDefinitions->getFirstRecord();
254 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' No import definitions found for Calendar');
255 $defaultDefinition = NULL;
259 return $defaultDefinition;
263 * Return a single resouece
266 * @return array record data
268 public function getResource($id)
270 return $this->_get($id, Calendar_Controller_Resource::getInstance());
274 * Search for events matching given arguments
276 * @param array $_filter
277 * @param array $_paging
280 public function searchEvents($filter, $paging)
282 $controller = Calendar_Controller_Event::getInstance();
284 $decodedPagination = $this->_prepareParameter($paging);
285 $pagination = new Tinebase_Model_Pagination($decodedPagination);
286 $clientFilter = $filter = $this->_decodeFilter($filter, 'Calendar_Model_EventFilter');
288 // find out if fixed calendars should be used
289 $fixedCalendars = Calendar_Config::getInstance()->get(Calendar_Config::FIXED_CALENDARS);
290 $useFixedCalendars = is_array($fixedCalendars) && ! empty($fixedCalendars);
292 $periodFilter = $filter->getFilter('period');
294 // add period filter per default to prevent endless search
295 if (! $periodFilter) {
296 $periodFilter = $this->_getDefaultPeriodFilter();
297 // periodFilter will be added to fixed filter when using fixed calendars
298 if (! $useFixedCalendars) {
299 $filter->addFilter($periodFilter);
303 // add fixed calendar on demand
304 if ($useFixedCalendars) {
305 $fixed = new Calendar_Model_EventFilter(array(), 'AND');
306 $fixed->addFilter( new Tinebase_Model_Filter_Text('container_id', 'in', $fixedCalendars));
308 $fixed->addFilter($periodFilter);
310 $og = new Calendar_Model_EventFilter(array(), 'OR');
311 $og->addFilterGroup($fixed);
312 $og->addFilterGroup($clientFilter);
314 $filter = new Calendar_Model_EventFilter(array(), 'AND');
315 $filter->addFilterGroup($og);
318 $records = $controller->search($filter, $pagination, FALSE);
320 $result = $this->_multipleRecordsToJson($records, $clientFilter, $pagination);
323 'results' => $result,
324 'totalcount' => count($result),
325 'filter' => $clientFilter->toArray(TRUE),
330 * get default period filter
332 * @return Calendar_Model_PeriodFilter
334 protected function _getDefaultPeriodFilter()
336 $now = Tinebase_DateTime::now()->setTime(0,0,0);
338 $from = $now->getClone()->subMonth(Calendar_Config::getInstance()->get(Calendar_Config::MAX_JSON_DEFAULT_FILTER_PERIOD_FROM, 0));
339 $until = $now->getClone()->addMonth(Calendar_Config::getInstance()->get(Calendar_Config::MAX_JSON_DEFAULT_FILTER_PERIOD_UNTIL, 1));
340 $periodFilter = new Calendar_Model_PeriodFilter(array(
342 'operator' => 'within',
343 'value' => array("from" => $from, "until" => $until)
346 return $periodFilter;
350 * Search for resources matching given arguments
352 * @param array $_filter
353 * @param array $_paging
356 public function searchResources($filter, $paging)
358 return $this->_search($filter, $paging, Calendar_Controller_Resource::getInstance(), 'Calendar_Model_ResourceFilter', true);
362 * creates/updates an event / recur
364 * @param array $recordData
365 * @param bool $checkBusyConflicts
366 * @param string $range
367 * @return array created/updated event
369 public function saveEvent($recordData, $checkBusyConflicts = FALSE, $range = Calendar_Model_Event::RANGE_THIS)
371 return $this->_save($recordData, Calendar_Controller_Event::getInstance(), 'Event', 'id', array($checkBusyConflicts, $range));
375 * creates/updates a Resource
377 * @param array $recordData
378 * @return array created/updated Resource
380 public function saveResource($recordData)
382 $recordData['grants'] = new Tinebase_Record_RecordSet('Tinebase_Model_Grants', $recordData['grants']);
383 if(array_key_exists ('max_number_of_people', $recordData) && $recordData['max_number_of_people'] == '') {
384 $recordData['max_number_of_people'] = null;
387 return $this->_save($recordData, Calendar_Controller_Resource::getInstance(), 'Resource');
391 * sets attendee status for an attender on the given event
393 * NOTE: for recur events we implicitly create an exceptions on demand
395 * @param array $eventData
396 * @param array $attenderData
397 * @param string $authKey
398 * @return array complete event
400 public function setAttenderStatus($eventData, $attenderData, $authKey)
402 $event = new Calendar_Model_Event($eventData);
403 $attender = new Calendar_Model_Attender($attenderData);
405 Calendar_Controller_Event::getInstance()->attenderStatusUpdate($event, $attender, $authKey);
407 return $this->getEvent($event->getId());
411 * updated a recur series
413 * @param array $recordData
414 * @param bool $checkBusyConflicts
415 * @noparamyet JSONstring $returnPeriod NOT IMPLEMENTED YET
418 public function updateRecurSeries($recordData, $checkBusyConflicts = FALSE /*, $returnPeriod*/)
420 $recurInstance = new Calendar_Model_Event(array(), TRUE);
421 $recurInstance->setFromJsonInUsersTimezone($recordData);
423 //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(print_r($recurInstance->toArray(), true));
425 $baseEvent = Calendar_Controller_Event::getInstance()->updateRecurSeries($recurInstance, $checkBusyConflicts);
427 return $this->getEvent($baseEvent->getId());
431 * prepares an iMIP (RFC 6047) Message
434 * @return array prepared iMIP part
436 public function iMIPPrepare($iMIP)
438 $iMIPMessage = $iMIP instanceof Calendar_Model_iMIP ? $iMIP : new Calendar_Model_iMIP($iMIP);
439 $iMIPFrontend = new Calendar_Frontend_iMIP();
441 $iMIPMessage->preconditionsChecked = FALSE;
442 $iMIPFrontend->prepareComponent($iMIPMessage);
443 $iMIPMessage->setTimezone(Tinebase_Core::getUserTimezone());
444 return $iMIPMessage->toArray();
448 * process an iMIP (RFC 6047) Message
451 * @param string $status
452 * @return array prepared iMIP part
454 public function iMIPProcess($iMIP, $status=null)
456 $iMIPMessage = new Calendar_Model_iMIP($iMIP);
457 $iMIPFrontend = new Calendar_Frontend_iMIP();
459 $iMIPFrontend->process($iMIPMessage, $status);
461 return $this->iMIPPrepare($iMIPMessage);
465 * @param array $_attendee
466 * @param array $_periods
467 * @param array $_ignoreUIDs
470 public function getFreeBusyInfo($_attendee, $_periods, $_ignoreUIDs = array())
472 $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $_attendee);
473 $periods = new Calendar_Model_EventFilter($_periods);
475 $fbInfo = Calendar_Controller_Event::getInstance()->getFreeBusyInfo($periods, $attendee, $_ignoreUIDs);
477 return $fbInfo->toArray();