1f2948fcfc8d1b8fa2249e0c6328db99f8e3f8cc
[tine20] / tine20 / Calendar / Frontend / Json.php
1 <?php
2 /**
3  * Tine 2.0
4  * 
5  * @package     Calendar
6  * @subpackage  Frontend
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)
10  */
11
12 /**
13  * json interface for calendar
14  * 
15  * @package     Calendar
16  * @subpackage  Frontend
17  */
18 class Calendar_Frontend_Json extends Tinebase_Frontend_Json_Abstract
19 {
20     /**
21      * app name
22      * 
23      * @var string
24      */
25     protected $_applicationName = 'Calendar';
26     
27     /**
28      * creates an exception instance of a recurring event
29      *
30      * NOTE: deleting persistent exceptions is done via a normal delete action
31      *       and handled in the controller
32      * 
33      * @param  array       $recordData
34      * @param  bool        $deleteInstance
35      * @param  bool        $deleteAllFollowing
36      * @param  bool        $checkBusyConflicts
37      * @return array       exception Event | updated baseEvent
38      * 
39      * @todo replace $_allFollowing param with $range
40      * @deprecated replace with create/update/delete
41      */
42     public function createRecurException($recordData, $deleteInstance, $deleteAllFollowing, $checkBusyConflicts = FALSE)
43     {
44         $event = new Calendar_Model_Event(array(), TRUE);
45         $event->setFromJsonInUsersTimezone($recordData);
46         
47         $returnEvent = Calendar_Controller_Event::getInstance()->createRecurException($event, $deleteInstance, $deleteAllFollowing, $checkBusyConflicts);
48         
49         return $this->getEvent($returnEvent->getId());
50     }
51     
52     /**
53      * deletes existing events
54      *
55      * @param array $_ids
56      * @param string $range
57      * @return string
58      */
59     public function deleteEvents($ids, $range = Calendar_Model_Event::RANGE_THIS)
60     {
61         return $this->_delete($ids, Calendar_Controller_Event::getInstance(), array($range));
62     }
63     
64     /**
65      * deletes existing resources
66      *
67      * @param array $_ids 
68      * @return string
69      */
70     public function deleteResources($ids)
71     {
72         return $this->_delete($ids, Calendar_Controller_Resource::getInstance());
73     }
74     
75     /**
76      * deletes a recur series
77      *
78      * @param  array $recordData
79      * @return void
80      */
81     public function deleteRecurSeries($recordData)
82     {
83         $event = new Calendar_Model_Event(array(), TRUE);
84         $event->setFromJsonInUsersTimezone($recordData);
85         
86         Calendar_Controller_Event::getInstance()->deleteRecurSeries($event);
87         return array('success' => true);
88     }
89     
90     /**
91      * Return a single event
92      *
93      * @param   string $id
94      * @return  array record data
95      */
96     public function getEvent($id)
97     {
98         return $this->_get($id, Calendar_Controller_Event::getInstance());
99     }
100     
101     /**
102      * Returns registry data of the calendar.
103      *
104      * @return mixed array 'variable name' => 'data'
105      * 
106      * @todo move exception handling (no default calender found) to another place?
107      */
108     public function getRegistryData()
109     {
110         $defaultCalendarId = Tinebase_Core::getPreference('Calendar')->getValue(Calendar_Preference::DEFAULTCALENDAR);
111         try {
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();
116             }
117         } catch (Exception $e) {
118             // remove default cal pref
119             Tinebase_Core::getPreference('Calendar')->deleteUserPref(Calendar_Preference::DEFAULTCALENDAR);
120             $defaultCalendarArray = array();
121         }
122         
123         $importDefinitions = $this->_getImportDefinitions();
124         $allCalendarResources = Calendar_Controller_Resource::getInstance()->getAll()->toArray();
125         
126         $registryData = array(
127             'defaultContainer'          => $defaultCalendarArray,
128             'defaultImportDefinition'   => $importDefinitions['default'],
129             'importDefinitions'         => $importDefinitions,
130             'calendarResources'         => $allCalendarResources
131         );
132         
133         return $registryData;
134     }
135     
136     /**
137      * get default addressbook
138      * 
139      * @return array
140      */
141     public function getDefaultCalendar() 
142    {
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;
148     }
149     
150     /**
151      * import contacts
152      * 
153      * @param string $tempFileId to import
154      * @param string $definitionId
155      * @param array $importOptions
156      * @param array $clientRecordData
157      * @return array
158      */
159     public function importEvents($tempFileId, $definitionId, $importOptions, $clientRecordData = array())
160     {
161         return $this->_import($tempFileId, $definitionId, $importOptions, $clientRecordData);
162     }
163     
164     /**
165      * creates a scheduled import
166      * 
167      * @param string $remoteUrl
168      * @param string $interval
169      * @param string $importOptions
170      * @return array
171      */
172     public function importRemoteEvents($remoteUrl, $interval, $importOptions)
173     {
174         // Determine which plugin should be used to import
175         switch ($importOptions['sourceType']) {
176             case 'remote_caldav':
177                 $plugin = 'Calendar_Import_CalDAV';
178                 break;
179             default:
180                 $plugin = 'Calendar_Import_Ical';
181         }
182
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(
188                 'plugin' => $plugin,
189                 'importFileByScheduler' => $importOptions['sourceType'] != 'remote_caldav',
190             )),
191             'model'             => 'Calendar_Model_Event',
192             'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(),
193         ), true));
194
195         $result = $this->_recordToJson($record);
196
197         return $result;
198     }
199     
200     /**
201      * get addressbook import definitions
202      * 
203      * @return array
204      * 
205      * @todo generalize this
206      */
207     protected function _getImportDefinitions()
208     {
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'),
212         ));
213         
214         $definitionConverter = new Tinebase_Convert_ImportExportDefinition_Json();
215         
216         try {
217             $importDefinitions = Tinebase_ImportExportDefinition::getInstance()->search($filter);
218             $defaultDefinition = $this->_getDefaultImportDefinition($importDefinitions);
219             $result = array(
220                 'results'               => $definitionConverter->fromTine20RecordSet($importDefinitions),
221                 'totalcount'            => count($importDefinitions),
222                 'default'               => ($defaultDefinition) ? $definitionConverter->fromTine20Model($defaultDefinition) : array(),
223             );
224         } catch (Exception $e) {
225             Tinebase_Exception::log($e);
226             $result = array(
227                 array(
228                     'results'               => array(),
229                     'totalcount'            => 0,
230                     'default'               => array(),
231                 )
232             );
233         }
234         
235         return $result;
236     }
237     
238     /**
239      * get default definition
240      * 
241      * @param Tinebase_Record_RecordSet $_importDefinitions
242      * @return Tinebase_Model_ImportExportDefinition
243      * 
244      * @todo generalize this
245      */
246     protected function _getDefaultImportDefinition($_importDefinitions)
247     {
248         try {
249             $defaultDefinition = Tinebase_ImportExportDefinition::getInstance()->getByName('cal_import_ical');
250         } catch (Tinebase_Exception_NotFound $tenf) {
251             if (count($_importDefinitions) > 0) {
252                 $defaultDefinition = $_importDefinitions->getFirstRecord();
253             } else {
254                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' No import definitions found for Calendar');
255                 $defaultDefinition = NULL;
256             }
257         }
258         
259         return $defaultDefinition;
260     }
261     
262     /**
263      * Return a single resouece
264      *
265      * @param   string $id
266      * @return  array record data
267      */
268     public function getResource($id)
269     {
270         return $this->_get($id, Calendar_Controller_Resource::getInstance());
271     }
272     
273     /**
274      * Search for events matching given arguments
275      *
276      * @param  array $_filter
277      * @param  array $_paging
278      * @return array
279      */
280     public function searchEvents($filter, $paging)
281     {
282         $controller = Calendar_Controller_Event::getInstance();
283         
284         $decodedPagination = $this->_prepareParameter($paging);
285         $pagination = new Tinebase_Model_Pagination($decodedPagination);
286         $clientFilter = $filter = $this->_decodeFilter($filter, 'Calendar_Model_EventFilter');
287
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);
291         
292         $periodFilter = $filter->getFilter('period');
293         
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);
300             }
301         }
302         
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));
307             
308             $fixed->addFilter($periodFilter);
309             
310             $og = new Calendar_Model_EventFilter(array(), 'OR');
311             $og->addFilterGroup($fixed);
312             $og->addFilterGroup($clientFilter);
313             
314             $filter = new Calendar_Model_EventFilter(array(), 'AND');
315             $filter->addFilterGroup($og);
316         }
317         
318         $records = $controller->search($filter, $pagination, FALSE);
319         
320         $result = $this->_multipleRecordsToJson($records, $clientFilter, $pagination);
321         
322         return array(
323             'results'       => $result,
324             'totalcount'    => count($result),
325             'filter'        => $clientFilter->toArray(TRUE),
326         );
327     }
328     
329     /**
330      * get default period filter
331      * 
332      * @return Calendar_Model_PeriodFilter
333      */
334     protected function _getDefaultPeriodFilter()
335     {
336         $now = Tinebase_DateTime::now()->setTime(0,0,0);
337         
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(
341             'field' => 'period',
342             'operator' => 'within',
343             'value' => array("from" => $from, "until" => $until)
344         ));
345         
346         return $periodFilter;
347     }
348     
349     /**
350      * Search for resources matching given arguments
351      *
352      * @param  array $_filter
353      * @param  array $_paging
354      * @return array
355      */
356     public function searchResources($filter, $paging)
357     {
358         return $this->_search($filter, $paging, Calendar_Controller_Resource::getInstance(), 'Calendar_Model_ResourceFilter', true);
359     }
360     
361     /**
362      * creates/updates an event / recur
363      *
364      * @param   array   $recordData
365      * @param   bool    $checkBusyConflicts
366      * @param   string  $range
367      * @return  array   created/updated event
368      */
369     public function saveEvent($recordData, $checkBusyConflicts = FALSE, $range = Calendar_Model_Event::RANGE_THIS)
370     {
371         return $this->_save($recordData, Calendar_Controller_Event::getInstance(), 'Event', 'id', array($checkBusyConflicts, $range));
372     }
373     
374     /**
375      * creates/updates a Resource
376      *
377      * @param   array   $recordData
378      * @return  array   created/updated Resource
379      */
380     public function saveResource($recordData)
381     {
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;
385         }
386         
387         return $this->_save($recordData, Calendar_Controller_Resource::getInstance(), 'Resource');
388     }
389     
390     /**
391      * sets attendee status for an attender on the given event
392      * 
393      * NOTE: for recur events we implicitly create an exceptions on demand
394      *
395      * @param  array         $eventData
396      * @param  array         $attenderData
397      * @param  string        $authKey
398      * @return array         complete event
399      */
400     public function setAttenderStatus($eventData, $attenderData, $authKey)
401     {
402         $event    = new Calendar_Model_Event($eventData);
403         $attender = new Calendar_Model_Attender($attenderData);
404         
405         Calendar_Controller_Event::getInstance()->attenderStatusUpdate($event, $attender, $authKey);
406         
407         return $this->getEvent($event->getId());
408     }
409     
410     /**
411      * updated a recur series
412      *
413      * @param  array $recordData
414      * @param  bool  $checkBusyConflicts
415      * @noparamyet  JSONstring $returnPeriod NOT IMPLEMENTED YET
416      * @return array 
417      */
418     public function updateRecurSeries($recordData, $checkBusyConflicts = FALSE /*, $returnPeriod*/)
419     {
420         $recurInstance = new Calendar_Model_Event(array(), TRUE);
421         $recurInstance->setFromJsonInUsersTimezone($recordData);
422         
423         //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(print_r($recurInstance->toArray(), true));
424         
425         $baseEvent = Calendar_Controller_Event::getInstance()->updateRecurSeries($recurInstance, $checkBusyConflicts);
426         
427         return $this->getEvent($baseEvent->getId());
428     }
429     
430     /**
431      * prepares an iMIP (RFC 6047) Message
432      * 
433      * @param array $iMIP
434      * @return array prepared iMIP part
435      */
436     public function iMIPPrepare($iMIP)
437     {
438         $iMIPMessage = $iMIP instanceof Calendar_Model_iMIP ? $iMIP : new Calendar_Model_iMIP($iMIP);
439         $iMIPFrontend = new Calendar_Frontend_iMIP();
440         
441         $iMIPMessage->preconditionsChecked = FALSE;
442         $iMIPFrontend->prepareComponent($iMIPMessage);
443         $iMIPMessage->setTimezone(Tinebase_Core::getUserTimezone());
444         return $iMIPMessage->toArray();
445     }
446     
447     /**
448      * process an iMIP (RFC 6047) Message
449      * 
450      * @param array  $iMIP
451      * @param string $status
452      * @return array prepared iMIP part
453      */
454     public function iMIPProcess($iMIP, $status=null)
455     {
456         $iMIPMessage = new Calendar_Model_iMIP($iMIP);
457         $iMIPFrontend = new Calendar_Frontend_iMIP();
458         
459         $iMIPFrontend->process($iMIPMessage, $status);
460         
461         return $this->iMIPPrepare($iMIPMessage);
462     }
463
464     /**
465      * @param array $_attendee
466      * @param array $_periods
467      * @param array $_ignoreUIDs
468      * @return array
469      */
470     public function getFreeBusyInfo($_attendee, $_periods, $_ignoreUIDs = array())
471     {
472         $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $_attendee);
473         $periods = new Calendar_Model_EventFilter($_periods);
474
475         $fbInfo = Calendar_Controller_Event::getInstance()->getFreeBusyInfo($periods, $attendee, $_ignoreUIDs);
476
477         return $fbInfo->toArray();
478     }
479 }