df945f1535c00018f76615f1a62b9b856f70f134
[tine20] / tests / tine20 / Calendar / Controller / EventTests.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Calendar
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @copyright   Copyright (c) 2009-2016 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Cornelius Weiss <c.weiss@metaways.de>
9  */
10
11 /**
12  * Test class for Calendar_Controller_Event
13  * 
14  * @package     Calendar
15  */
16 class Calendar_Controller_EventTests extends Calendar_TestCase
17 {
18     /**
19      * @var Calendar_Controller_Event controller unter test
20      */
21     protected $_controller;
22     
23     /**
24      * (non-PHPdoc)
25      * @see Calendar_TestCase::setUp()
26      */
27     public function setUp()
28     {
29         parent::setUp();
30         $this->_controller = Calendar_Controller_Event::getInstance();
31     }
32     
33     /**
34      * testCreateEvent
35      * 
36      * @return Calendar_Model_Event
37      */
38     public function testCreateEvent()
39     {
40         $event = $this->_getEvent();
41         $persistentEvent = $this->_controller->create($event);
42         
43         $this->assertEquals($event->description, $persistentEvent->description);
44         $this->assertTrue($event->dtstart->equals($persistentEvent->dtstart));
45         $this->assertEquals(Tinebase_Core::getUserTimezone(), $persistentEvent->originator_tz);
46         
47         return $persistentEvent;
48     }
49     
50     /**
51      * testCreateAlldayEventWithoutDtend
52      */
53     public function testCreateAlldayEventWithoutDtend()
54     {
55         $event = $this->_getEvent();
56         $event->is_all_day_event = true;
57         $event->dtend = null;
58         
59         $persistentEvent = $this->_controller->create($event);
60         $persistentEvent->setTimezone(Tinebase_Core::getUserTimezone());
61         $this->assertEquals('2009-04-06 23:59:59', $persistentEvent->dtend->toString());
62     }
63     
64     /**
65      * testGetEvent
66      */
67     public function testGetEvent()
68     {
69         $persistentEvent = $this->testCreateEvent();
70         $this->assertTrue((bool) $persistentEvent->{Tinebase_Model_Grants::GRANT_READ});
71         $this->assertTrue((bool) $persistentEvent->{Tinebase_Model_Grants::GRANT_EDIT});
72         $this->assertTrue((bool) $persistentEvent->{Tinebase_Model_Grants::GRANT_DELETE});
73         
74         $loadedEvent = $this->_controller->get($persistentEvent->getId());
75         $this->assertTrue((bool) $loadedEvent->{Tinebase_Model_Grants::GRANT_READ});
76         $this->assertTrue((bool) $loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT});
77         $this->assertTrue((bool) $loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
78     }
79
80     public function testGetRecurInstance()
81     {
82         // create event and invite admin group
83         $event = $this->_getEvent();
84         $event->rrule = 'FREQ=DAILY;INTERVAL=1';
85
86         $persistentEvent = $this->_controller->create($event);
87         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
88         $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($persistentEvent, $exceptions, Tinebase_DateTime::now());
89
90         $deepLink = $nextOccurance->getDeepLink();
91         $id = basename($deepLink);
92
93         $recurInstance = $this->_controller->get($id);
94         $this->assertTrue($recurInstance->isRecurInstance());
95         $this->assertEquals($nextOccurance->getId(), $recurInstance->getId());
96
97         // create recur exception in the meantime
98         $nextOccurance->summary = 'exception';
99         $this->_controller->createRecurException($nextOccurance);
100         $recurInstance = $this->_controller->get($id);
101 //        print_r($recurInstance->toArray());
102         $this->assertFalse($recurInstance->isRecurInstance());
103         $this->assertEquals($nextOccurance->summary, $recurInstance->summary);
104     }
105
106     /**
107      * testUpdateEvent
108      */
109     public function testUpdateEvent()
110     {
111         $persistentEvent = $this->testCreateEvent();
112         
113         $currentTz = Tinebase_Core::getUserTimezone();
114         Tinebase_Core::set(Tinebase_Core::USERTIMEZONE, 'farfaraway');
115         
116         $persistentEvent->summary = 'Lunchtime';
117         $updatedEvent = $this->_controller->update($persistentEvent);
118         $this->assertEquals($persistentEvent->summary, $updatedEvent->summary);
119         $this->assertEquals($currentTz, $updatedEvent->originator_tz, 'originator_tz must not be touchet if dtsart is not updatet!');
120         
121         $updatedEvent->dtstart->addHour(1);
122         $updatedEvent->dtend->addHour(1);
123         $secondUpdatedEvent = $this->_controller->update($updatedEvent);
124         $this->assertEquals(Tinebase_Core::getUserTimezone(), $secondUpdatedEvent->originator_tz, 'originator_tz must be adopted if dtsart is updatet!');
125     
126         Tinebase_Core::set(Tinebase_Core::USERTIMEZONE, $currentTz);
127     }
128     
129     public function testConcurrentUpdate()
130     {
131         $event = $this->testCreateEvent();
132         
133         sleep(1);
134         $resolvableConcurrentEvent1 = clone $event;
135         $resolvableConcurrentEvent1->dtstart = $resolvableConcurrentEvent1->dtstart->addMonth(1);
136         $resolvableConcurrentEvent1->dtend = $resolvableConcurrentEvent1->dtend->addMonth(1);
137         $resolvableConcurrentEvent1Update = $this->_controller->update($resolvableConcurrentEvent1);
138         
139         sleep(1);
140         $resolvableConcurrentEvent2 = clone $event;
141         $resolvableConcurrentEvent2->summary = 'Updated Event';
142         $resolvableConcurrentEvent2Update = $this->_controller->update($resolvableConcurrentEvent2);
143         
144         $this->assertEquals($resolvableConcurrentEvent1Update->dtstart, $resolvableConcurrentEvent2Update->dtstart);
145     }
146     
147     public function testUpdateAttendeeStatus()
148     {
149         $event = $this->_getEvent();
150         $event->attendee = $this->_getAttendee();
151         $event->attendee[1] = new Calendar_Model_Attender(array(
152             'user_type' => Calendar_Model_Attender::USERTYPE_USER,
153             'user_id'   => $this->_getPersonasContacts('pwulf')->getId(),
154         ));
155         
156         $persistentEvent = $this->_controller->create($event);
157         
158         foreach ($persistentEvent->attendee as $attender) {
159             $attender->status = Calendar_Model_Attender::STATUS_DECLINED;
160             $this->_controller->attenderStatusUpdate($persistentEvent, $attender, $attender->status_authkey);
161         }
162         
163         
164         $persistentEvent->last_modified_time = $this->_controller->get($persistentEvent->getId())->last_modified_time;
165         
166         // update time
167         $persistentEvent->dtstart->addHour(2);
168         $persistentEvent->dtend->addHour(2);
169         // NOTE: in normal operations the status authkey is removed by resolveAttendee
170         //       we simulate this here by removeing the keys per hand. (also note that current user does not need an authkey)
171         $persistentEvent->attendee->status_authkey = null;
172         $updatedEvent = $this->_controller->update($persistentEvent);
173
174         $currentUser = $updatedEvent->attendee
175             ->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)
176             ->filter('user_id', Tinebase_Core::getUser()->contact_id)
177             ->getFirstRecord();
178             
179         $pwulf = $updatedEvent->attendee
180             ->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)
181             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId())
182             ->getFirstRecord();
183
184         $this->assertEquals(Calendar_Model_Attender::STATUS_DECLINED, $currentUser->status, 'current users status must not be touched');
185         $this->assertEquals(Calendar_Model_Attender::STATUS_NEEDSACTION, $pwulf->status, 'pwulfs status must be reset');
186     }
187     
188     public function testUpdateMultiple()
189     {
190         $persistentEvent = $this->testCreateEvent();
191         
192         $filter = new Calendar_Model_EventFilter(array(
193             array('field' => 'id', 'operator' => 'in', 'value' => array($persistentEvent->getId()))
194         ));
195         
196         $data = array(
197             'summary' => 'multipleTest'
198         );
199         
200         $this->_controller->updateMultiple($filter, $data);
201         
202         $updatedEvent = $this->_controller->get($persistentEvent->getId());
203         $this->assertEquals('multipleTest', $updatedEvent->summary);
204     }
205     
206     public function testAttendeeBasics()
207     {
208         $event = $this->_getEvent();
209         $event->attendee = $this->_getAttendee();
210         $event->attendee[1] = new Calendar_Model_Attender(array(
211             'user_type' => Calendar_Model_Attender::USERTYPE_USER,
212             'user_id'   => $this->_getPersonasContacts('pwulf')->getId()
213         ));
214         
215         $persistendEvent = $this->_controller->create($event);
216         $this->assertEquals(2, count($persistendEvent->attendee));
217         
218         unset($persistendEvent->attendee[0]);
219         $updatedEvent = $this->_controller->update($persistendEvent);
220         $this->assertEquals(1, count($updatedEvent->attendee));
221         
222         $updatedEvent->attendee->getFirstRecord()->role = Calendar_Model_Attender::ROLE_OPTIONAL;
223         $updatedEvent->attendee->getFirstRecord()->transp = Calendar_Model_Event::TRANSP_TRANSP;
224         
225         $secondUpdatedEvent = $this->_controller->update($updatedEvent);
226         $this->assertEquals(1, count($secondUpdatedEvent->attendee));
227         $this->assertEquals(Calendar_Model_Attender::ROLE_OPTIONAL, $secondUpdatedEvent->attendee->getFirstRecord()->role);
228         $this->assertEquals(Calendar_Model_Event::TRANSP_TRANSP, $secondUpdatedEvent->attendee->getFirstRecord()->transp);
229     }
230     
231     public function testAttendeeFilter()
232     {
233         $event1 = $this->_getEvent();
234         $event1->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
235             array('user_id' => Tinebase_Core::getUser()->contact_id),
236             array('user_id' => $this->_getPersonasContacts('pwulf')->getId())
237         ));
238         $this->_controller->create($event1);
239         
240         $event2 = $this->_getEvent();
241         $event2->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
242             array('user_id' => Tinebase_Core::getUser()->contact_id),
243             array('user_id' => $this->_getPersonasContacts('sclever')->getId()),
244         ));
245         $this->_controller->create($event2);
246         
247         $event3 = $this->_getEvent();
248         $event3->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
249             array('user_id' => Tinebase_Core::getUser()->contact_id),
250             array('user_id' => $this->_getPersonasContacts('sclever')->getId()),
251         ));
252         $this->_controller->create($event3);
253         
254         // test sclever
255         $filter = new Calendar_Model_EventFilter(array(
256             array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
257             array('field' => 'attender'    , 'operator' => 'equals', 'value' => array(
258                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
259                 'user_id'   => $this->_getPersonasContacts('sclever')->getId()
260             )),
261         ));
262         $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
263         $this->assertEquals(2, count($eventsFound), 'sclever attends to two events');
264         
265         // test pwulf
266         $filter = new Calendar_Model_EventFilter(array(
267             array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
268             array('field' => 'attender'    , 'operator' => 'equals', 'value' => array(
269                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
270                 'user_id'   => $this->_getPersonasContacts('pwulf')->getId()
271             )),
272         ));
273         $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
274         $this->assertEquals(1, count($eventsFound), 'pwulf attends to one events');
275         
276         // test sclever OR pwulf
277         $filter = new Calendar_Model_EventFilter(array(
278             array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
279             array('field' => 'attender'    , 'operator' => 'in',     'value' => array(
280                 array(
281                     'user_type' => Calendar_Model_Attender::USERTYPE_USER,
282                     'user_id'   => $this->_getPersonasContacts('sclever')->getId()
283                 ),
284                 array (
285                     'user_type' => Calendar_Model_Attender::USERTYPE_USER,
286                     'user_id'   => $this->_getPersonasContacts('pwulf')->getId()
287                 )
288             )),
289         ));
290         $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
291         $this->assertEquals(3, count($eventsFound), 'sclever OR pwulf attends to tree events');
292     }
293     
294     public function testAttendeeGroupFilter()
295     {
296         $event = $this->_getEvent();
297         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
298             array('user_id' => Tinebase_Core::getUser()->contact_id),
299             array('user_id' => $this->_getPersonasContacts('sclever')->getId())
300         ));
301         $this->_controller->create($event);
302         
303         $filter = new Calendar_Model_EventFilter(array(
304             array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
305             array('field' => 'attender'    , 'operator' => 'in',     'value' => array(
306                 array(
307                     'user_type' => Calendar_Model_AttenderFilter::USERTYPE_MEMBEROF,
308                     'user_id'   => $this->_getPersona('sclever')->accountPrimaryGroup
309                 )
310             )),
311         ));
312         $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
313         $this->assertEquals(1, count($eventsFound), 'sclever is groupmember');
314     }
315
316     /**
317      * @see 0006702: CalDAV: single event appears in personal and shared calendar
318      *
319      * TODO fix for pgsql: Failed asserting that 0 matches expected 1.
320      *
321      */
322     public function testAttendeeNotInFilter()
323     {
324         if ($this->_dbIsPgsql()) {
325             $this->markTestSkipped('0011674: problem with Attendee "NotIn" Filter (pgsql)');
326         }
327
328         foreach(array(Tinebase_Core::getUser()->contact_id, $this->_personasContacts['sclever']->getId()) as $attId) {
329             $event = $this->_getEvent();
330             $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
331                     array('user_id' => $attId),
332             ));
333             $this->_controller->create($event);
334         }
335     
336         $filter = new Calendar_Model_EventFilter(array(
337                 array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
338                 array('field' => 'attender'    , 'operator' => 'notin',  'value' => array(
339                         array(
340                                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
341                                 'user_id'   => $this->_personasContacts['sclever']->getId()
342                         )
343                 )),
344         ));
345         $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
346         $this->assertEquals(1, count($eventsFound), 'should be exactly one event');
347         $this->assertEquals(
348                 Tinebase_Core::getUser()->contact_id, 
349                 $eventsFound->getFirstRecord()->attendee->getFirstRecord()->user_id,
350                 'sclevers event should not be found');
351     }
352     
353     /**
354      * test get free busy info with single event
355      * 
356      * @return Calendar_Model_Event
357      */
358     public function testGetFreeBusyInfo()
359     {
360         $event = $this->_getEvent();
361         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
362             array('user_id' => $this->_getPersonasContacts('sclever')->getId()),
363             array('user_id' => $this->_getPersonasContacts('pwulf')->getId())
364         ));
365         $persistentEvent = $this->_controller->create($event);
366
367         $period = new Calendar_Model_EventFilter(array(array(
368             'field'     => 'period',
369             'operator'  => 'within',
370             'value'     => array(
371                 'from'      => $persistentEvent->dtstart,
372                 'until'     => $persistentEvent->dtend
373             ),
374         )));
375         $fbinfo = $this->_controller->getFreeBusyInfo($period, $persistentEvent->attendee);
376        
377         $this->assertGreaterThanOrEqual(2, count($fbinfo));
378         
379         return $persistentEvent;
380     }
381
382     /**
383      * test get free busy info with single event
384      *
385      * @return Calendar_Model_Event
386      */
387     public function testGetFreeBusyInfoWithGroup()
388     {
389         $event = $this->_getEvent();
390         $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
391             array(
392                 'user_id' => Tinebase_Group::getInstance()->getDefaultGroup(),
393                 'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
394                 'role' => Calendar_Model_Attender::ROLE_OPTIONAL,
395             ),
396         ));
397         $event->attendee = clone $attendee;
398         $persistentEvent = $this->_controller->create($event);
399
400         $period = new Calendar_Model_EventFilter(array(array(
401             'field'     => 'period',
402             'operator'  => 'within',
403             'value'     => array(
404                 'from'      => $persistentEvent->dtstart,
405                 'until'     => $persistentEvent->dtend
406             ),
407         )));
408         $fbinfo = $this->_controller->getFreeBusyInfo($period, $attendee);
409
410         $this->assertGreaterThanOrEqual(1, count($fbinfo));
411
412         return $persistentEvent;
413     }
414
415     public function testSearchFreeTime()
416     {
417         $event = $this->_getEvent();
418         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
419             array('user_id' => $this->_getPersonasContacts('sclever')->getId(), 'user_type' => Calendar_Model_Attender::USERTYPE_USER),
420             array('user_id' => $this->_getPersonasContacts('pwulf')->getId(), 'user_type' => Calendar_Model_Attender::USERTYPE_USER)
421         ));
422         $event->rrule = 'FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,FR';
423
424         $options = array(
425             'constraints' => array(array(
426                 'dtstart'   => $event->dtstart->getClone()->setHour(6),
427                 'dtend'     => $event->dtstart->getClone()->setHour(22),
428                 'rrule'     => 'FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR'
429             )),
430         );
431
432         $result = $this->_controller->searchFreeTime($event, $options);
433         static::assertEquals(1, $result->count());
434         /** @var Calendar_Model_Event $suggestedEvent */
435         $suggestedEvent = $result->getFirstRecord();
436         $dtstartExpected = $event->dtstart->getClone()->addDay(1)->setHour(6); // '2009-04-07 06:00:00'
437         $dtendExpected = $event->dtend->getClone()->addDay(1)->setHour(6); // '2009-04-07 06:30:00'
438         static::assertEquals($dtstartExpected, $suggestedEvent->dtstart);
439         static::assertEquals($dtendExpected, $suggestedEvent->dtend);
440
441         $newEvent = clone $event;
442         $newEvent->rrule = null;
443         $newEvent->dtstart = $dtstartExpected->getClone()->addMinute(29); // '2009-04-07 06:29:00'
444         $newEvent->dtend = $dtendExpected->getClone(); // '2009-04-07 06:30:00'
445         $this->_controller->create($newEvent);
446         $newEvent->setId(null);
447         $newEvent->uid = null;
448         $newEvent->attendee->id = null;
449         $newEvent->attendee->cal_event_id = null;
450         $newEvent->dtstart->addDay(7); // '2009-04-14 06:29:00'
451         $newEvent->dtend->addDay(7); // '2009-04-14 06:30:00'
452         $this->_controller->create($newEvent);
453
454         $result = $this->_controller->searchFreeTime($event, $options);
455         static::assertEquals(1, $result->count());
456         /** @var Calendar_Model_Event $suggestedEvent */
457         $suggestedEvent = $result->getFirstRecord();
458         static::assertEquals($dtstartExpected->addMinute(30), $suggestedEvent->dtstart); // '2009-04-07 06:30:00'
459         static::assertEquals($dtendExpected->addMinute(30), $suggestedEvent->dtend); // '2009-04-07 07:00:00'
460
461         $newEvent->setId(null);
462         $newEvent->uid = null;
463         $newEvent->attendee->id = null;
464         $newEvent->attendee->cal_event_id = null;
465         $newEvent->dtstart->addMinute(1); // '2009-04-14 06:30:00'
466         $newEvent->dtend->addMinute(1); // '2009-04-14 06:31:00'
467         $this->_controller->create($newEvent);
468
469         $result = $this->_controller->searchFreeTime($event, $options);
470         static::assertEquals(1, $result->count());
471         /** @var Calendar_Model_Event $suggestedEvent */
472         $suggestedEvent = $result->getFirstRecord();
473         static::assertEquals($dtstartExpected->addMinute(15), $suggestedEvent->dtstart); // '2009-04-07 06:45:00'
474         static::assertEquals($dtendExpected->addMinute(15), $suggestedEvent->dtend); // '2009-04-07 07:15:00'
475     }
476     
477     /**
478      * events from deleted calendars should not be shown
479      */
480     public function testSearchEventFromDeletedCalendar() {
481         $testCal = Tinebase_Container::getInstance()->addContainer(new Tinebase_Model_Container(array(
482             'name'           => 'PHPUnit test calendar',
483             'type'           => Tinebase_Model_Container::TYPE_PERSONAL,
484             'owner_id'       => Tinebase_Core::getUser(),
485             'backend'        => $this->_backend->getType(),
486             'application_id' => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId()
487         ), true));
488         
489         $this->_getTestCalendars()->addRecord($testCal);
490         
491         // create event in testcal
492         $event = $this->_getEvent();
493         $event->container_id = $testCal->getId();
494         $event->attendee = $this->_getAttendee();
495         $persistentEvent = $this->_controller->create($event);
496
497         // delete testcal
498         Tinebase_Container::getInstance()->deleteContainer($testCal, TRUE);
499         
500         // search by attendee
501         $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
502             array('field' => 'attender', 'operator' => 'equals', 'value' => array(
503                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
504                 'user_id'   => $this->_getTestUserContact()->getId()
505             ))
506         )), NULL, FALSE, FALSE);
507         
508         $this->assertFalse(in_array($persistentEvent->getId(), $events->getId()), 'event in deleted (display) container shuld not be found');
509     }
510     
511     public function testCreateEventWithConflict()
512     {
513         $this->_testNeedsTransaction();
514         
515         $event = $this->_getEvent();
516         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
517             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
518             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
519         ));
520         $this->_controller->create($event);
521         
522         $conflictEvent = $this->_getEvent();
523         $conflictEvent->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
524             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
525             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
526         ));
527         
528         try {
529             $exectionRaised = FALSE;
530             $this->_controller->create($conflictEvent, TRUE);
531         } catch (Calendar_Exception_AttendeeBusy $busyException) {
532             $fbData = $busyException->toArray();
533             $this->assertGreaterThanOrEqual(2, count($fbData['freebusyinfo']));
534             $exectionRaised = TRUE;
535         }
536         if (! $exectionRaised) {
537             $this->fail('An expected exception has not been raised.');
538         }
539         $persitentConflictEvent = $this->_controller->create($conflictEvent, FALSE);
540         
541         return $persitentConflictEvent;
542     }
543     
544     public function testCreateEventWithConflictFromGroupMember()
545     {
546         $event = $this->_getEvent();
547         $event->attendee = $this->_getAttendee();
548         $this->_controller->create($event);
549         
550         $conflictEvent = $this->_getEvent();
551         $conflictEvent->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
552             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
553             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
554         ));
555         
556         try {
557             $this->_controller->create($conflictEvent, TRUE);
558             $this->assertTrue(false, 'Failed to detect conflict from groupmember');
559         } catch (Calendar_Exception_AttendeeBusy $busyException) {
560             $fbData = $busyException->toArray();
561             $this->assertGreaterThanOrEqual(2, count($fbData['freebusyinfo']));
562             return;
563         }
564         
565         $this->fail('An expected exception has not been raised.');
566     }
567     
568     public function testCreateTransparentEventNoConflict()
569     {
570         $event = $this->_getEvent();
571         $event->attendee = $this->_getAttendee();
572         $this->_controller->create($event);
573         
574         $nonConflictEvent = $this->_getEvent();
575         $nonConflictEvent->transp = Calendar_Model_Event::TRANSP_TRANSP;
576         $nonConflictEvent->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
577             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
578             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
579         ));
580         
581         $this->_controller->create($nonConflictEvent, TRUE);
582     }
583     
584     public function testCreateNoConflictParallelTrasparentEvent()
585     {
586         $event = $this->_getEvent();
587         $event->attendee = $this->_getAttendee();
588         $event->transp = Calendar_Model_Event::TRANSP_TRANSP;
589         $this->_controller->create($event);
590         
591         $nonConflictEvent = $this->_getEvent();
592         $nonConflictEvent->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
593             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('sclever')->getId()),
594             array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => $this->_getPersonasContacts('pwulf')->getId())
595         ));
596         
597         $this->_controller->create($nonConflictEvent, TRUE);
598     }
599     
600     public function testCreateNoConflictParallelAtendeeTrasparentEvent()
601     {
602         $event = $this->_getEvent();
603         $event->attendee = $this->_getAttendee();
604         unset ($event->attendee[1]); // no group here
605         $event->attendee->transp = Calendar_Model_Event::TRANSP_TRANSP;
606         $this->_controller->create($event);
607         
608         $nonConflictEvent = $this->_getEvent();
609         $nonConflictEvent->attendee = $this->_getAttendee();
610         
611         $this->_controller->create($nonConflictEvent, TRUE);
612     }
613
614     public function testCreateConflictResourceUnavailable()
615     {
616         $event = $this->_getEvent();
617
618         // create & add resource
619         $rt = new Calendar_Controller_ResourceTest();
620         $rt->setUp();
621         $resource = $rt->testCreateResource();
622         $resource->busy_type = Calendar_Model_FreeBusy::FREEBUSY_BUSY_UNAVAILABLE;
623         Calendar_Controller_Resource::getInstance()->update($resource);
624
625         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(new Calendar_Model_Attender(array(
626             'user_type' => Calendar_Model_Attender::USERTYPE_RESOURCE,
627             'user_id'   => $resource->getId()
628         ))));
629
630         $conflictEvent = clone $event;
631         $this->_controller->create($event);
632         try {
633             $this->_controller->create($conflictEvent, TRUE);
634             $this->fail('Calendar_Exception_AttendeeBusy was not thrown');
635         } catch (Calendar_Exception_AttendeeBusy $abe) {
636             $fb = $abe->getFreeBusyInfo();
637             $this->assertEquals(Calendar_Model_FreeBusy::FREEBUSY_BUSY_UNAVAILABLE, $fb[0]->type);
638         }
639
640     }
641
642     public function testUpdateWithConflictNoTimechange()
643     {
644         $persitentConflictEvent = $this->testCreateEventWithConflict();
645         $persitentConflictEvent->summary = 'only time updates should recheck free/busy';
646         
647         $this->_controller->update($persitentConflictEvent, TRUE);
648     }
649     
650     public function testUpdateWithConflictAttendeeChange()
651     {
652         $persitentConflictEvent = $this->testCreateEventWithConflict();
653         $persitentConflictEvent->summary = 'attendee adds should recheck free/busy';
654         
655         $defaultUserGroup = Tinebase_Group::getInstance()->getDefaultGroup();
656         $persitentConflictEvent->attendee->addRecord(new Calendar_Model_Attender(array(
657             'user_id'   => $defaultUserGroup->getId(),
658             'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
659             'role'      => Calendar_Model_Attender::ROLE_REQUIRED
660         )));
661         
662         $this->setExpectedException('Calendar_Exception_AttendeeBusy');
663         $this->_controller->update($persitentConflictEvent, TRUE);
664     }
665     
666     public function testUpdateWithConflictWithTimechange()
667     {
668         $persitentConflictEvent = $this->testCreateEventWithConflict();
669         $persitentConflictEvent->summary = 'time updates should recheck free/busy';
670         $persitentConflictEvent->dtend->addHour(1);
671         
672         $this->setExpectedException('Calendar_Exception_AttendeeBusy');
673         $this->_controller->update($persitentConflictEvent, TRUE);
674     }
675
676     public function testAttendeeAuthKeyPreserv()
677     {
678         $event = $this->_getEvent();
679         $event->attendee = $this->_getAttendee();
680         
681         $persistendEvent = $this->_controller->create($event);
682         $newAuthKey = Tinebase_Record_Abstract::generateUID();
683         $persistendEvent->attendee->status_authkey = $newAuthKey;
684         
685         $updatedEvent = $this->_controller->update($persistendEvent);
686         foreach ($updatedEvent->attendee as $attender) {
687             $this->assertNotEquals($newAuthKey, $attender->status_authkey);
688         }
689     }
690     
691     public function testAttendeeStatusPreservViaSave()
692     {
693         $event = $this->_getEvent();
694         $event->attendee = $this->_getAttendee();
695         $event->attendee[0]->user_id = Tinebase_User::getInstance()->getUserByLoginName('sclever')->contact_id;
696         $event->attendee[0]->status = Calendar_Model_Attender::STATUS_ACCEPTED;
697         unset($event->attendee[1]);
698         
699         $persistendEvent = $this->_controller->create($event);
700         $this->assertEquals(Calendar_Model_Attender::STATUS_NEEDSACTION, $persistendEvent->attendee[0]->status, 'creation of other attedee must not set status');
701         
702         $persistendEvent->attendee[0]->status = Calendar_Model_Attender::STATUS_ACCEPTED;
703         $persistendEvent->attendee[0]->status_authkey = NULL;
704         $updatedEvent = $this->_controller->update($persistendEvent);
705         $this->assertEquals(Calendar_Model_Attender::STATUS_NEEDSACTION, $updatedEvent->attendee[0]->status, 'updateing of other attedee must not set status');
706     }
707     
708     public function testAttendeeSetStatus()
709     {
710         $event = $this->_getEvent();
711         $event->attendee = $this->_getAttendee();
712         unset($event->attendee[1]);
713         
714         $persistendEvent = $this->_controller->create($event);
715         $attendee = $persistendEvent->attendee[0];
716         
717         $attendee->status = Calendar_Model_Attender::STATUS_DECLINED;
718         $this->_controller->attenderStatusUpdate($persistendEvent, $attendee, $attendee->status_authkey);
719         
720         $loadedEvent = $this->_controller->get($persistendEvent->getId());
721         $this->assertEquals(Calendar_Model_Attender::STATUS_DECLINED, $loadedEvent->attendee[0]->status, 'status not set');
722         
723     }
724     
725     public function testAttendeeStatusFilter()
726     {
727         $event = $this->_getEvent();
728         $event->attendee = $this->_getAttendee();
729         unset($event->attendee[1]);
730         
731         $persistentEvent = $this->_controller->create($event);
732         
733         $filter = new Calendar_Model_EventFilter(array(
734             array('field' => 'uid',             'operator' => 'equals', 'value' => $persistentEvent->uid),
735             array('field' => 'attender_status', 'operator' => 'not',    'value' => Calendar_Model_Attender::STATUS_DECLINED),
736         ));
737         
738         $events = $this->_controller->search($filter);
739         $this->assertEquals(1, count($events), 'event should be found, but is not');
740         
741         $attender = $persistentEvent->attendee[0];
742         $attender->status = Calendar_Model_Attender::STATUS_DECLINED;
743         $this->_controller->update($persistentEvent);
744         
745         $events = $this->_controller->search($filter);
746         $this->assertEquals(0, count($events), 'event should _not_ be found, but is');
747         
748     }
749     
750     public function testAttendeeDisplaycontainerContact()
751     {
752         $contact = Addressbook_Controller_Contact::getInstance()->create(new Addressbook_Model_Contact(array(
753            'n_given'  => 'phpunit',
754            'n_family' => 'cal attender'
755         )));
756          
757         $event = $this->_getEvent();
758         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
759             array(
760                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
761                 'user_id'   => $contact->getId(),
762                 'role'      => Calendar_Model_Attender::ROLE_REQUIRED
763             ),
764         ));
765         $persistentEvent = $this->_controller->create($event);
766         $attender = $persistentEvent->attendee[0];
767         
768         $this->assertTrue(empty($attender->displaycontainer_id), 'displaycontainer_id must not be set for contacts');
769     }
770     
771     public function testAttendeeGroupMembersResolving()
772     {
773         if (Tinebase_User::getConfiguredBackend() === Tinebase_User::ACTIVEDIRECTORY) {
774             $this->markTestSkipped('only working in non-AD setups');
775         }
776
777         $defaultUserGroup = Tinebase_Group::getInstance()->getDefaultGroup();
778         Tinebase_Group::getInstance()->getDefaultAdminGroup();
779         
780         $event = $this->_getEvent();
781         $event->attendee = $this->_getAttendee();
782         $event->attendee[1] = new Calendar_Model_Attender(array(
783             'user_id'   => $defaultUserGroup->getId(),
784             'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
785             'role'      => Calendar_Model_Attender::ROLE_REQUIRED
786         ));
787         
788         $persistentEvent = $this->_controller->create($event);
789         $defaultUserGroupMembers = Tinebase_Group::getInstance()->getGroupMembers($defaultUserGroup->getId());
790         // user as attender + group + all members
791         $expectedAttendeeCount = 1 + 1 + count($defaultUserGroupMembers);
792         if (in_array(Tinebase_Core::getUser()->getId(), $defaultUserGroupMembers)) {
793             // remove suppressed user (only if user is member of default group)
794             $expectedAttendeeCount--;
795         }
796         $this->assertEquals($expectedAttendeeCount, count($persistentEvent->attendee),
797             'attendee: ' . print_r($persistentEvent->attendee->toArray(), true));
798         
799         $groupAttender = $persistentEvent->attendee->find('user_type', Calendar_Model_Attender::USERTYPE_GROUP);
800         $persistentEvent->attendee->removeRecord($groupAttender);
801         
802         $updatedPersistentEvent = $this->_controller->update($persistentEvent);
803         $this->assertEquals(1, count($updatedPersistentEvent->attendee));
804     }
805     
806     public function testAttendeeGroupMembersChange()
807     {
808         $defaultAdminGroup = Tinebase_Group::getInstance()->getDefaultAdminGroup();
809         
810         // create event and invite admin group
811         $event = $this->_getEvent();
812         
813         // only events in future will be changed!
814         $event->dtstart = Tinebase_DateTime::now()->addHour(1);
815         $event->dtend = Tinebase_DateTime::now()->addHour(2);
816         
817         $event->attendee = $this->_getAttendee();
818         $event->attendee[1] = new Calendar_Model_Attender(array(
819             'user_id'   => $defaultAdminGroup->getId(),
820             'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
821             'role'      => Calendar_Model_Attender::ROLE_REQUIRED
822         ));
823         $persistentEvent = $this->_controller->create($event);
824         
825         // assert test condition
826         $pwulf = $persistentEvent->attendee
827             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
828             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId());
829         $this->assertEquals(0, count($pwulf), 'invalid test condition, pwulf should not be member or admin group');
830         
831         Admin_Controller_Group::getInstance()->addGroupMember($defaultAdminGroup->getId(), $this->_getPersonasContacts('pwulf')->account_id);
832         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
833             Tinebase_ActionQueue::getInstance()->processQueue(10000);
834         }
835         
836         $loadedEvent = $this->_controller->get($persistentEvent->getId());
837         // assert pwulf is in
838         $pwulf = $loadedEvent->attendee
839             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
840             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId());
841         $this->assertEquals(1, count($pwulf), 'pwulf is not attender of event, but should be');
842         
843         
844         Admin_Controller_Group::getInstance()->removeGroupMember($defaultAdminGroup->getId(), $this->_getPersonasContacts('pwulf')->account_id);
845         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
846             Tinebase_ActionQueue::getInstance()->processQueue(10000);
847         }
848         
849         $loadedEvent = $this->_controller->get($persistentEvent->getId());
850         // assert pwulf is missing
851         $pwulf = $loadedEvent->attendee
852             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
853             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId());
854         $this->assertEquals(0, count($pwulf), 'pwulf is attender of event, but not should be');
855         
856         // Test the same with update
857         $group = Admin_Controller_Group::getInstance()->get($defaultAdminGroup->getId());
858         $group->members = array_merge(Admin_Controller_Group::getInstance()->getGroupMembers($defaultAdminGroup->getId()), array(Tinebase_Helper::array_value('pwulf', Zend_Registry::get('personas'))->getId()));
859         Admin_Controller_Group::getInstance()->update($group);
860         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
861             Tinebase_ActionQueue::getInstance()->processQueue(10000);
862         }
863         
864         // assert pwulf is in
865         $loadedEvent = $this->_controller->get($persistentEvent->getId());
866         $pwulf = $loadedEvent->attendee
867             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
868             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId());
869         $this->assertEquals(1, count($pwulf), 'pwulf is not attender of event, but should be (via update)');
870         
871         $group->members = array_diff(Admin_Controller_Group::getInstance()->getGroupMembers($defaultAdminGroup->getId()), array(Tinebase_Helper::array_value('pwulf', Zend_Registry::get('personas'))->getId()));
872         Admin_Controller_Group::getInstance()->update($group);
873         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
874             Tinebase_ActionQueue::getInstance()->processQueue(10000);
875         }
876         // assert pwulf is missing
877         $loadedEvent = $this->_controller->get($persistentEvent->getId());
878         $pwulf = $loadedEvent->attendee
879             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
880             ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId());
881         $this->assertEquals(0, count($pwulf), 'pwulf is attender of event, but not should be');
882     }
883     
884     public function testAttendeeGroupMembersAddUser()
885     {
886         try {
887             // clean up if exists
888             $cleanupUser = Tinebase_User::getInstance()->getFullUserByLoginName('testAttendeeGroupMembersAddUser');
889             Tinebase_User::getInstance()->deleteUser($cleanupUser);
890         } catch (Exception $e) {
891             // do nothing
892         }
893         
894         
895         $defaultGroup = Tinebase_Group::getInstance()->getDefaultGroup();
896         
897         // create event and invite admin group
898         $event = $this->_getEvent();
899         
900         // only events in future will be changed!
901         $event->dtstart = Tinebase_DateTime::now()->addHour(1);
902         $event->dtend = Tinebase_DateTime::now()->addHour(2);
903         
904         $event->attendee = $this->_getAttendee();
905         $event->attendee[1] = new Calendar_Model_Attender(array(
906             'user_id'   => $defaultGroup->getId(),
907             'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
908             'role'      => Calendar_Model_Attender::ROLE_REQUIRED
909         ));
910         $persistentEvent = $this->_controller->create($event);
911         
912         $newUser = $this->_createNewUser();
913         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
914             Tinebase_ActionQueue::getInstance()->processQueue(10000);
915         }
916         
917         // check if this user was added to event
918         $loadedEvent = $this->_controller->get($persistentEvent->getId());
919         $user = $loadedEvent->attendee
920             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
921             ->filter('user_id', $newUser->contact_id);
922         $this->assertEquals(1, count($user), 'added user is not attender of event, but should be. user: ' . print_r($newUser->toArray(), TRUE));
923         
924         // cleanup user
925         Admin_Controller_User::getInstance()->delete($newUser->getId());
926         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
927             Tinebase_ActionQueue::getInstance()->processQueue(10000);
928         }
929         
930         // check if user was removed from event
931         $loadedEvent = $this->_controller->get($persistentEvent->getId());
932         $user = $loadedEvent->attendee
933             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
934             ->filter('user_id', $newUser->contact_id);
935         $this->assertEquals(0, count($user), 'added user is attender of event, but should be (after deleting user)');
936     }
937     
938     /**
939      * testAttendeeGroupMembersRecurringAddUser
940      * 
941      * FIXME 0007352: fix Calendar_Controller_EventTests::testAttendeeGroupMembersRecurringAddUser
942      */
943     public function testAttendeeGroupMembersRecurringAddUser()
944     {
945         $this->markTestIncomplete('test fails sometimes / needs fixing');
946         
947         try {
948             // cleanup if exists
949             $cleanupUser = Tinebase_User::getInstance()->getFullUserByLoginName('testAttendeeGroupMembersAddUser');
950             Tinebase_User::getInstance()->deleteUser($cleanupUser);
951         } catch (Exception $e) {
952             // do nothing
953         }
954         
955         $defaultGroup = Tinebase_Group::getInstance()->getDefaultGroup();
956         
957         // create event and invite admin group
958         $event = $this->_getEvent();
959         $event->rrule = 'FREQ=DAILY;INTERVAL=1';
960         
961         $event->attendee = $this->_getAttendee();
962         $event->attendee[1] = new Calendar_Model_Attender(array(
963             'user_id'   => $defaultGroup->getId(),
964             'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
965             'role'      => Calendar_Model_Attender::ROLE_REQUIRED
966         ));
967         $persistentEvent = $this->_controller->create($event);
968
969         $newUser = $this->_createNewUser();
970         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
971             Tinebase_ActionQueue::getInstance()->processQueue(10000);
972         }
973         
974         $events = $this->_backend->search(new Calendar_Model_EventFilter(array(
975             array('field' => 'container_id', 'operator' => 'in', 'value' => $this->_getTestCalendars()->getId()),
976         )), new Tinebase_Model_Pagination(array()));
977         
978         $oldSeries = $events->filter('rrule_until', '/.+/', TRUE)->getFirstRecord();
979         $newSeries = $events->filter('rrule_until', '/^$/', TRUE)->getFirstRecord();
980         
981         $this->assertEquals(2, $events->count(), 'recur event must be splitted '. print_r($events->toArray(), TRUE));
982         // check if this user was added to event
983         $this->_controller->get($persistentEvent->getId());
984         $user = $oldSeries->attendee
985             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
986             ->filter('user_id', $newUser->contact_id);
987         $this->assertEquals(0, count($user), 'added user is attender of old event, but should not be');
988         $user = $newSeries->attendee
989             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
990             ->filter('user_id', $newUser->contact_id);
991         $this->assertEquals(1, count($user), 'added user is not attender of new event, but should be');
992         
993         // cleanup user
994         Admin_Controller_User::getInstance()->delete($newUser->getId());
995         if (isset(Tinebase_Core::getConfig()->actionqueue)) {
996             Tinebase_ActionQueue::getInstance()->processQueue(10000);
997         }
998         
999         $events = $this->_backend->search(new Calendar_Model_EventFilter(array(
1000             array('field' => 'container_id', 'operator' => 'in', 'value' => $this->_getTestCalendars()->getId()),
1001         )), new Tinebase_Model_Pagination(array()));
1002         
1003         $newSeries = $events->filter('rrule_until', '/^$/', TRUE)->getFirstRecord();
1004         
1005         // check if this user was deleted from event
1006         $user = $newSeries->attendee
1007             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
1008             ->filter('user_id', $newUser->contact_id);
1009         $this->assertEquals(0, count($user), 'deleted user is attender of new event, but should not be');
1010     }
1011
1012     protected function _createNewUser()
1013     {
1014         $pw = Tinebase_Record_Abstract::generateUID(10) . '*A53x';
1015         $newUser = Admin_Controller_User::getInstance()->create(new Tinebase_Model_FullUser(array(
1016             'accountLoginName'      => 'testAttendeeGroupMembersAddUser',
1017             'accountStatus'         => 'enabled',
1018             'accountExpires'        => NULL,
1019             'accountPrimaryGroup'   => Tinebase_Group::getInstance()->getDefaultGroup()->getId(),
1020             'accountLastName'       => 'Tine 2.0',
1021             'accountFirstName'      => 'PHPUnit',
1022             'accountEmailAddress'   => 'phpunit@metaways.de'
1023         )), $pw, $pw);
1024         return $newUser;
1025     }
1026
1027     public function testRruleUntil()
1028     {
1029         $event = $this->_getEvent();
1030         
1031         $event->rrule_until = Tinebase_DateTime::now();
1032         $persistentEvent = $this->_controller->create($event);
1033         $this->assertNull($persistentEvent->rrule_until, 'rrul_until is not unset');
1034         
1035         $persistentEvent->rrule = 'FREQ=YEARLY;INTERVAL=1;BYMONTH=2;UNTIL=2010-04-01 21:59:59';
1036         $updatedEvent = $this->_controller->update($persistentEvent);
1037         $this->assertEquals('2010-04-01 21:59:59', $updatedEvent->rrule_until->get(Tinebase_Record_Abstract::ISO8601LONG));
1038     }
1039     
1040     public function testUpdateRecuingDtstart()
1041     {
1042         $event = $this->_getEvent();
1043         $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 21:59:59';
1044         $event->exdate = array(new Tinebase_DateTime('2009-04-07 13:00:00'));
1045         $persistentEvent = $this->_controller->create($event);
1046         
1047         $this->assertEquals('2009-04-30 21:59:59', $persistentEvent->rrule->until->toString(), 'rrule is not adapted');
1048         
1049         $exception = clone $persistentEvent;
1050         $exception->dtstart->addDay(2);
1051         $exception->dtend->addDay(2);
1052         
1053         $exception->setId(NULL);
1054         unset($exception->rrule);
1055         unset($exception->exdate);
1056         $exception->setRecurId($event->getId());
1057         $persistentException = $this->_controller->create($exception);
1058         
1059         $persistentEvent->dtstart->addHour(5);
1060         $persistentEvent->dtend->addHour(5);
1061         
1062         $updatedEvent = $this->_controller->update($persistentEvent);
1063         
1064         $updatedException = $this->_controller->get($persistentException->getId());
1065         
1066         $this->assertEquals(1, count($updatedEvent->exdate), 'failed to reset exdate');
1067         $this->assertEquals('2009-04-08 18:00:00', $updatedEvent->exdate[0]->get(Tinebase_Record_Abstract::ISO8601LONG), 'failed to update exdate');
1068         $this->assertEquals('2009-04-08 18:00:00', substr($updatedException->recurid, -19), 'failed to update persistent exception');
1069         $this->assertEquals('2009-04-30 21:59:59', Calendar_Model_Rrule::getRruleFromString($updatedEvent->rrule)->until->get(Tinebase_Record_Abstract::ISO8601LONG), 'until in rrule must not be changed');
1070         $this->assertEquals('2009-04-30 21:59:59', $updatedEvent->rrule_until->get(Tinebase_Record_Abstract::ISO8601LONG), 'rrule_until must not be changed');
1071         
1072         $updatedEvent->dtstart->subHour(5);
1073         $updatedEvent->dtend->subHour(5);
1074         $secondUpdatedEvent = $this->_controller->update($updatedEvent);
1075         $secondUpdatedException = $this->_controller->get($persistentException->getId());
1076         $this->assertEquals('2009-04-08 13:00:00', $secondUpdatedEvent->exdate[0]->get(Tinebase_Record_Abstract::ISO8601LONG), 'failed to update exdate (sub)');
1077         $this->assertEquals('2009-04-08 13:00:00', substr($secondUpdatedException->recurid, -19), 'failed to update persistent exception (sub)');
1078     }
1079     
1080     /**
1081      * testUpdateRecurDtstartOverDst
1082      */
1083     public function testUpdateRecurDtstartOverDst()
1084     {
1085         // note: 2009-03-29 Europe/Berlin switched to DST
1086         $event = new Calendar_Model_Event(array(
1087             'uid'           => Tinebase_Record_Abstract::generateUID(),
1088             'summary'       => 'Abendessen',
1089             'dtstart'       => '2009-03-25 18:00:00',
1090             'dtend'         => '2009-03-25 18:30:00',
1091             'originator_tz' => 'Europe/Berlin',
1092             'rrule'         => 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-02 21:59:59',
1093             'exdate'        => '2009-03-27 18:00:00,2009-03-31 17:00:00',
1094             'container_id'  => $this->_getTestCalendar()->getId(),
1095             Tinebase_Model_Grants::GRANT_EDIT     => true,
1096         ));
1097         
1098         $persistentEvent = $this->_controller->create($event);
1099         
1100         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
1101         $from = new Tinebase_DateTime('2009-03-26 00:00:00');
1102         $until = new Tinebase_DateTime('2009-04-03 23:59:59');
1103         $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until); // 9 days
1104         
1105         // skip 27(exception), 31(exception), 03(until)
1106         $this->assertEquals(6, count($recurSet));
1107         
1108         $exceptionBeforeDstBoundary = clone $recurSet[1]; // 28. 
1109         $persistentExceptionBeforeDstBoundary = $this->_controller->createRecurException($exceptionBeforeDstBoundary);
1110         
1111         $updatedBaseEvent = $this->_controller->getRecurBaseEvent($recurSet[5]);
1112         $recurSet[5]->last_modified_time = $updatedBaseEvent->last_modified_time;
1113         $exceptionAfterDstBoundary = clone $recurSet[5]; // 02.
1114         $persistentExceptionAfterDstBoundary = $this->_controller->createRecurException($exceptionAfterDstBoundary);
1115         
1116         $persistentEvent->dtstart->addDay(5); //30.
1117         $persistentEvent->dtend->addDay(5);
1118         $from->addDay(5); //31
1119         $until->addDay(5); //08
1120         
1121         $this->_controller->get($persistentEvent);
1122         $persistentEvent->seq = 3; // satisfy modlog
1123         $updatedPersistenEvent = $this->_controller->update($persistentEvent);
1124         
1125         $persistentEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
1126             array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from, 'until' => $until)),
1127             array('field' => 'uid', 'operator' => 'equals', 'value' => $persistentEvent->uid)
1128         )));
1129         
1130         // we don't 'see' the persistent exception from 28/
1131         $this->assertEquals(2, count($persistentEvents));
1132                 
1133         $exceptions = $persistentEvents->filter('recurid', "/^{$persistentEvent->uid}-.*/", TRUE);
1134         $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($updatedPersistenEvent, $exceptions, $from, $until);
1135         
1136         // 31, 01, 02
1137         $this->assertEquals(3, count($recurSet));
1138     }
1139     
1140     public function testDeleteImplicitDeleteRcuringExceptions()
1141     {
1142         $event = $this->_getEvent();
1143         $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1144         $event->exdate = array(new Tinebase_DateTime('2009-04-07 13:00:00'));
1145         $persistentEvent = $this->_controller->create($event);
1146         
1147         $exception = clone $persistentEvent;
1148         $exception->dtstart->addDay(2);
1149         $exception->dtend->addDay(2);
1150         $exception->setId(NULL);
1151         unset($exception->rrule);
1152         unset($exception->exdate);
1153         $exception->setRecurId($persistentEvent->getId());
1154         $persistentException = $this->_controller->create($exception);
1155         
1156         unset($persistentEvent->rrule);
1157         $this->_controller->delete($persistentEvent);
1158         $this->setExpectedException('Tinebase_Exception_NotFound');
1159         $this->_controller->get($persistentException->getId());
1160     }
1161     
1162     /**
1163      * test delete event
1164      * - check here if content sequence of container has been increased
1165      */
1166     public function testDeleteEvent()
1167     {
1168         $event = $this->_getEvent();
1169         $persistentEvent = $this->_controller->create($event);
1170         
1171         $this->_controller->delete($persistentEvent->getId());
1172         
1173         $contentSeq = Tinebase_Container::getInstance()->getContentSequence($this->_getTestCalendar());
1174         $this->assertEquals(3, $contentSeq, 'container content seq should be increased 3 times!');
1175         
1176         $this->setExpectedException('Tinebase_Exception_NotFound');
1177         $this->_controller->get($persistentEvent->getId());
1178     }
1179     
1180     /**
1181      * @todo use exception api once we have it!
1182      *
1183      */
1184     public function testDeleteRecurExceptions()
1185     {
1186         $event = $this->_getEvent();
1187         $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1188         $event->exdate = array(new Tinebase_DateTime('2009-04-07 13:00:00'));
1189         $persistentEvent = $this->_controller->create($event);
1190         
1191         $exception = clone $persistentEvent;
1192         $exception->dtstart->addDay(2);
1193         $exception->dtend->addDay(2);
1194         $exception->setId(NULL);
1195         unset($exception->rrule);
1196         unset($exception->exdate);
1197         $exception->setRecurId($persistentEvent->getId());
1198         $persistentException = $this->_controller->create($exception);
1199         
1200         $this->_controller->delete($persistentEvent->getId());
1201         $this->setExpectedException('Tinebase_Exception_NotFound');
1202         $this->_controller->get($persistentException->getId());
1203     }
1204     
1205     public function testDeleteNonPersistentRecurException()
1206     {
1207         $event = $this->_getEvent();
1208         $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1209         $persistentEvent = $this->_controller->create($event);
1210         
1211         // create an exception (a fallout)
1212         $exception = clone $persistentEvent;
1213         $exception->dtstart->addDay(3);
1214         $exception->dtend->addDay(3);
1215         $exception->summary = 'Abendbrot';
1216         $exception->recurid = $exception->uid . '-' . $exception->dtstart->get(Tinebase_Record_Abstract::ISO8601LONG);
1217         $persistentEventWithExdate = $this->_controller->createRecurException($exception, true);
1218         
1219         $persistentEvent = $this->_controller->get($persistentEvent->getId());
1220         $this->assertEquals('Tinebase_DateTime', get_class($persistentEventWithExdate->exdate[0]));
1221         $this->assertEquals($persistentEventWithExdate->exdate[0]->format('c'), $persistentEvent->exdate[0]->format('c'));
1222         $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
1223             array('field' => 'uid',     'operator' => 'equals', 'value' => $persistentEvent->uid),
1224         )));
1225         $this->assertEquals(1, count($events));
1226     }
1227     
1228     public function testDeletePersistentRecurException()
1229     {
1230         $event = $this->_getEvent();
1231         $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1232         $persistentEvent = $this->_controller->create($event);
1233         
1234         $exception = clone $persistentEvent;
1235         $exception->dtstart->addDay(3);
1236         $exception->dtend->addDay(3);
1237         $exception->summary = 'Abendbrot';
1238         $exception->recurid = $exception->uid . '-' . $exception->dtstart->get(Tinebase_Record_Abstract::ISO8601LONG);
1239         $persistentException = $this->_controller->createRecurException($exception);
1240         
1241         $this->_controller->delete($persistentException->getId());
1242         
1243         $persistentEvent = $this->_controller->get($persistentEvent->getId());
1244         
1245         $this->assertEquals('Tinebase_DateTime', get_class($persistentEvent->exdate[0]));
1246         $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
1247             array('field' => 'uid',     'operator' => 'equals', 'value' => $persistentEvent->uid),
1248         )));
1249         $this->assertEquals(1, count($events));
1250     }
1251     
1252     public function testSetAlarm()
1253     {
1254         $event = $this->_getEvent();
1255         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(
1256             new Tinebase_Model_Alarm(array(
1257                 'minutes_before' => 30
1258             ), TRUE)
1259         ));
1260         $persistentEvent = $this->_controller->create($event);
1261         $alarmTime = clone $persistentEvent->dtstart;
1262         $alarmTime->subMinute(30);
1263         $this->assertTrue($alarmTime->equals($persistentEvent->alarms->getFirstRecord()->alarm_time), 'initial alarm is not at expected time');
1264         
1265         
1266         $persistentEvent->dtstart->addHour(5);
1267         $persistentEvent->dtend->addHour(5);
1268         $updatedEvent = $this->_controller->update($persistentEvent);
1269         $alarmTime = clone $updatedEvent->dtstart;
1270         $alarmTime->subMinute(30);
1271         $this->assertTrue($alarmTime->equals($updatedEvent->alarms->getFirstRecord()->alarm_time), 'alarm of updated event is not adjusted');
1272     }
1273     
1274     /**
1275      * testSetAlarmOfRecurSeries
1276      */
1277     public function testSetAlarmOfRecurSeries()
1278     {
1279         $event = $this->_getEvent();
1280         $event->dtstart = Tinebase_DateTime::now()->addHour(1);
1281         $event->dtend = Tinebase_DateTime::now()->addHour(2);
1282         
1283         $event->rrule = 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=1';
1284         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(
1285             new Tinebase_Model_Alarm(array(
1286                 'minutes_before' => 30
1287             ), TRUE)
1288         ));
1289         $persistentEvent = $this->_controller->create($event);
1290         $alarm = $persistentEvent->alarms->getFirstRecord();
1291         $this->assertEquals($event->dtstart->subMinute(30)->toString(), $alarm->alarm_time->toString(),
1292             'inital alarm fails: ' . print_r($alarm->toArray(), TRUE));
1293         
1294         // move whole series
1295         $persistentEvent->dtstart->addHour(5);
1296         $persistentEvent->dtend->addHour(5);
1297         $updatedEvent = $this->_controller->update($persistentEvent);
1298         $this->assertEquals($persistentEvent->dtstart->subMinute(30)->toString(), $updatedEvent->alarms->getFirstRecord()->alarm_time->toString(),
1299             'update alarm fails');
1300     }
1301     
1302     /**
1303      * testSetAlarmOfRecurSeriesException
1304      */
1305     public function testSetAlarmOfRecurSeriesException()
1306     {
1307         $event = $this->_getEvent();
1308         $event->rrule = 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=1';
1309         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(
1310             new Tinebase_Model_Alarm(array(
1311                 'minutes_before' => 30
1312             ), TRUE)
1313         ));
1314         $persistentEvent = $this->_controller->create($event);
1315         
1316         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
1317         $exception = Calendar_Model_Rrule::computeNextOccurrence($persistentEvent, $exceptions, new Tinebase_DateTime());
1318         $exception->dtstart->subHour(6);
1319         $exception->dtend->subHour(6);
1320         $persistentException = $this->_controller->createRecurException($exception);
1321         
1322         $baseEvent = $this->_controller->getRecurBaseEvent($persistentException);
1323         $this->_controller->getAlarms($baseEvent);
1324         
1325         $exceptions = $this->_controller->getRecurExceptions($persistentException);
1326         $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, $exceptions, Tinebase_DateTime::now());
1327         
1328         $nextAlarmEventStart = new Tinebase_DateTime(substr($baseEvent->alarms->getFirstRecord()->getOption('recurid'), -19));
1329         
1330         $this->assertTrue($nextOccurance->dtstart->equals($nextAlarmEventStart), 'next alarm got not adjusted');
1331         
1332         $alarmTime = clone $persistentException->dtstart;
1333         $alarmTime->subMinute(30);
1334         $this->assertTrue($alarmTime->equals($persistentException->alarms->getFirstRecord()->alarm_time), 'alarmtime of persistent exception is not correnct/set');
1335     }
1336     
1337     /**
1338      * testAdoptAlarmTimeOfYearlyEvent
1339      * 
1340      * @see 0009320: Wrong notification on first occurrence exceptions
1341      */
1342     public function testAdoptAlarmTimeOfYearlyEvent()
1343     {
1344         $event = $this->_getEvent();
1345         $event->dtstart = new Tinebase_DateTime('2012-10-26 22:00:00');
1346         $event->dtend = new Tinebase_DateTime('2012-10-27 21:59:00');
1347         $event->is_all_day_event = 1;
1348         $event->rrule = 'FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=27;INTERVAL=1';
1349         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(
1350             new Tinebase_Model_Alarm(array(
1351                 'minutes_before' => 2880
1352             ), TRUE)
1353         ));
1354         $persistentEvent = $this->_controller->create($event);
1355         $alarm = $persistentEvent->alarms->getFirstRecord();
1356         $this->_controller->adoptAlarmTime($persistentEvent, $alarm);
1357         
1358         $now = Tinebase_DateTime::now();
1359         $year = $now->get('Y');
1360         if ($now->isLater(new Tinebase_DateTime($year . '-10-27'))) {
1361             $year++;
1362         }
1363         // might be at 22:00 or 23.00 (daylight saving ...)
1364         // TODO verify that (@see 0011404: fix failing testAdoptAlarmTimeOfYearlyEvent)
1365         $expectedAlarmTimes = array($year . '-10-24 22:00:00', $year . '-10-24 23:00:00');
1366         $this->assertTrue(in_array($alarm->alarm_time->toString(), $expectedAlarmTimes),
1367             'alarm time mismatch:' . print_r($alarm->toArray(), true)
1368             . ' expected: ' . print_r($expectedAlarmTimes, true));
1369
1370         if ($now->isLater(new Tinebase_DateTime($year . '-10-24'))) {
1371             // FIXME test fails if current date is between 10-24 and 10-27
1372             // @see 0011404: fix failing testAdoptAlarmTimeOfYearlyEvent
1373             return;
1374         }
1375         
1376         // mock send alarm and check next occurrence
1377         $alarm->sent_status = Tinebase_Model_Alarm::STATUS_PENDING;
1378         $alarm->sent_time = new Tinebase_DateTime('2012-10-24 22:01:03');
1379         $alarm->alarm_time = new Tinebase_DateTime('2013-10-24 22:00:00');
1380         $alarm->options = '{"custom":false,"minutes_before":2880,"recurid":"' . $persistentEvent->uid . '-2013-10-26 22:00:00"}';
1381         $alarmBackend = new Tinebase_Backend_Sql(array(
1382             'modelName' => 'Tinebase_Model_Alarm', 
1383             'tableName' => 'alarm',
1384         ));
1385         
1386         $updatedAlarm = $alarmBackend->update($alarm);
1387         
1388         $updatedAlarm->sent_time = Tinebase_DateTime::now();
1389         $updatedAlarm->sent_status = Tinebase_Model_Alarm::STATUS_SUCCESS;
1390         $updatedAlarm->minutes_before = 2880;
1391         
1392         $this->_controller->adoptAlarmTime($persistentEvent, $updatedAlarm, 'instance');
1393         $this->assertTrue(in_array($updatedAlarm->alarm_time->toString(), $expectedAlarmTimes),
1394             'alarm time mismatch:' . print_r($updatedAlarm->toArray(), true)
1395             . ' expected: ' . print_r($expectedAlarmTimes, true));
1396     }
1397     
1398     public function testPeriodFilter()
1399     {
1400         $this->testCreateEvent();
1401         
1402         $events = $this->_controller->search(new Calendar_Model_EventFilter(array(
1403             array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()),
1404             array('field' => 'period', 'operator' => 'within', 'value' => array(
1405                 'from'  => '2009-04-07',
1406                 'until' => '2010-04-07'
1407             ))
1408         )), NULL, FALSE, FALSE);
1409         
1410         $this->assertEquals(0, count($events));
1411     }
1412     
1413     /**
1414      * returns a simple event
1415      *
1416      * @return Calendar_Model_Event
1417      * @param bool $_now
1418      * @param bool $mute
1419      * @todo replace with TestCase::_getEvent
1420      */
1421     public function _getEvent($_now = FALSE, $mute = NULL)
1422     {
1423         $event = new Calendar_Model_Event(array(
1424             'summary'     => 'Mittagspause',
1425             'dtstart'     => '2009-04-06 13:00:00',
1426             'dtend'       => '2009-04-06 13:30:00',
1427             'description' => 'Wieslaw Brudzinski: Das Gesetz garantiert zwar die Mittagspause, aber nicht das Mittagessen...',
1428         
1429             'container_id' => $this->_getTestCalendar()->getId(),
1430             Tinebase_Model_Grants::GRANT_EDIT    => true,
1431         ));
1432         
1433         if ($_now) {
1434             $event->dtstart = Tinebase_DateTime::now();
1435             $event->dtend = Tinebase_DateTime::now()->addMinute(15);
1436         }
1437         
1438         return $event;
1439     }
1440     
1441     /**
1442      * (non-PHPdoc)
1443      * @see Calendar_TestCase::_getAttendee()
1444      */
1445     protected function _getAttendee()
1446     {
1447         return new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
1448             array(
1449                 'user_id'   => Tinebase_Core::getUser()->contact_id,
1450                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
1451                 'role'      => Calendar_Model_Attender::ROLE_REQUIRED
1452             ),
1453             array(
1454                 'user_id'   => Tinebase_Group::getInstance()->getDefaultGroup()->getId(),
1455                 'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
1456                 'role'      => Calendar_Model_Attender::ROLE_REQUIRED
1457             )
1458         ));
1459     }
1460     
1461     /**
1462      * tests if customfields gets saved properly
1463      */
1464     public function testCustomFields()
1465     {
1466         $cfData = new Tinebase_Model_CustomField_Config(array(
1467             'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(),
1468             'name'              => 'unittest',
1469             'model'             => 'Calendar_Model_Event',
1470             'definition'        => array(
1471                 'label' => Tinebase_Record_Abstract::generateUID(),
1472                 'type'  => 'string',
1473                 'uiconfig' => array(
1474                     'xtype'  => Tinebase_Record_Abstract::generateUID(),
1475                     'length' => 10,
1476                     'group'  => 'unittest',
1477                     'order'  => 100,
1478                 )
1479             )
1480         ));
1481     
1482         try {
1483             Tinebase_CustomField::getInstance()->addCustomField($cfData);
1484         } catch (Zend_Db_Statement_Exception $zdse) {
1485             // custom field already exists
1486         }
1487     
1488         $event = new Calendar_Model_Event(array(
1489             'summary'     => 'Abendessen',
1490             'dtstart'     => '2014-04-06 18:00:00',
1491             'dtend'       => '2014-04-06 19:00:00',
1492             'description' => 'Guten Appetit',
1493             
1494             'container_id' => $this->_getTestCalendar()->getId(),
1495             Tinebase_Model_Grants::GRANT_EDIT    => true,
1496             'customfields' => array('unittest' => 'Hello')
1497         ));
1498         
1499         $event = $this->_controller->create($event);
1500         
1501         $this->assertEquals('Hello', $event->customfields['unittest']);
1502     }
1503
1504     /**
1505      * @see 0010454: cli script for comparing calendars
1506      */
1507     public function testCompareCalendars()
1508     {
1509         $cal1 = $this->_testCalendar;
1510         $cal2 = $this->_getTestContainer('Calendar');
1511         
1512         $this->_buildCompareCalendarsFixture($cal1, $cal2);
1513         
1514         $from = Tinebase_DateTime::now()->subDay(1);
1515         $until = Tinebase_DateTime::now()->addWeek(2);
1516         $result = Calendar_Controller_Event::getInstance()->compareCalendars($cal1->getId(), $cal2->getId(), $from, $until);
1517         
1518         $this->assertEquals(2, count($result['matching']), 'events 3+4 / 8+9 should have matched: ' . print_r($result['matching']->toArray(), true));
1519         $this->assertEquals(1, count($result['changed']), 'event 5 should appear in changed: ' . print_r($result['changed']->toArray(), true));
1520         $this->assertEquals(1, count($result['missingInCal1']), 'event 2 should miss from cal1: ' . print_r($result['missingInCal1']->toArray(), true));
1521         $this->assertEquals(1, count($result['missingInCal2']), 'event 6 should miss from cal2 ' . print_r($result['missingInCal2']->toArray(), true));
1522     }
1523     
1524     /**
1525      *  create some events to compare
1526      *  
1527      * - event1: in calendar 1
1528      * - event2: only in calendar 2
1529      * - event3+4: in both calendars
1530      * - event5: slightly different from event1 (same summary) / in cal2
1531      * - event6: only in cal1 (next week)
1532      * - event7: only in displaycontainer
1533      * - event8+9: in both calendars (whole day)
1534      * 
1535      * @param Tinebase_Model_Container $cal1
1536      * @param Tinebase_Model_Container $cal2
1537      */
1538     protected function _buildCompareCalendarsFixture($cal1, $cal2)
1539     {
1540         $event1 = $this->_getEvent(true);
1541         $event1->summary = 'event 1';
1542         $this->_controller->create($event1);
1543         
1544         $event2 =  $this->_getEvent(true);
1545         $event2->dtstart->addDay(1);
1546         $event2->dtend->addDay(1);
1547         $event2->summary = 'event 2';
1548         $event2->container_id = $cal2->getId();
1549         $this->_controller->create($event2);
1550         
1551         $event3 = $this->_getEvent(true);
1552         $event3->dtstart->addDay(2);
1553         $event3->dtend->addDay(2);
1554         $event3->summary = 'event 3';
1555         $event4 = clone $event3;
1556         $this->_controller->create($event3);
1557         
1558         $event4->container_id = $cal2->getId();
1559         $this->_controller->create($event4);
1560         
1561         $event5 = $this->_getEvent(true);
1562         $event5->summary = 'event 1';
1563         $event5->dtstart->addMinute(30);
1564         $event5->container_id = $cal2->getId();
1565         $this->_controller->create($event5);
1566         
1567         // this tests weekly processing, too
1568         $event6 = $this->_getEvent(true);
1569         $event6->summary = 'event 6';
1570         $event6->dtstart->addDay(8);
1571         $event6->dtend->addDay(8);
1572         $this->_controller->create($event6);
1573         
1574         // add event that is only in displaycontainer (should not appear in report)
1575         $currentDefault = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::DEFAULTCALENDAR, Tinebase_Core::getUser()->getId());
1576         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $cal1->getId());
1577         $event7 = $this->_getEvent(true);
1578         $event7->summary = 'event 7';
1579         $event7->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
1580             array(
1581                 'user_id'   => Tinebase_Core::getUser()->contact_id,
1582                 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
1583                 'role'      => Calendar_Model_Attender::ROLE_REQUIRED,
1584             ),
1585         ));
1586         Tinebase_Core::set(Tinebase_Core::USER, $this->_personas['sclever']);
1587         $cal3 = $this->_getTestContainer('Calendar');
1588         $event7->container_id = $cal3->getId();
1589         $this->_controller->create($event7);
1590         Tinebase_Core::set(Tinebase_Core::USER, $this->_originalTestUser);
1591         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $currentDefault);
1592         
1593         $event8 = $this->_getEvent(true);
1594         $event8->summary = 'event 8';
1595         $event8->is_all_day_event = true;
1596         $event9 = clone $event8;
1597         $this->_controller->create($event8);
1598         
1599         $event9->container_id = $cal2->getId();
1600         $this->_controller->create($event9);
1601     }
1602     
1603     public function testRepairAttendee()
1604     {
1605         $event = $this->_getEvent(true);
1606         $event->attendee = null;
1607         $persistentEvent = $this->_controller->create($event);
1608         
1609         $result = $this->_controller->repairAttendee($persistentEvent->container_id, Tinebase_DateTime::now()->subDay(1), Tinebase_DateTime::now());
1610         
1611         $this->assertEquals(1, $result, 'should repair 1 event');
1612         
1613         $repairedEvent = $this->_controller->get($persistentEvent->getId());
1614         $this->assertEquals(1, count($repairedEvent->attendee));
1615         $ownAttender = Calendar_Model_Attender::getOwnAttender($repairedEvent->attendee);
1616         $this->assertTrue($ownAttender !== null);
1617     }
1618
1619     /**
1620      * @see 0011130: handle bad originator timzone in VCALENDAR converter
1621      */
1622     public function testBrokenTimezoneInEvent()
1623     {
1624         $event = $this->_getEvent(true);
1625         $event->originator_tz = 'AWSTTTT';
1626         try {
1627             $event = $this->_controller->create($event);
1628             $this->fail('should throw Tinebase_Exception_Record_Validation because of bad TZ: ' . print_r($event->toArray(), true));
1629         } catch (Tinebase_Exception_Record_Validation $terv) {
1630             $this->assertEquals('Bad Timezone: AWSTTTT', $terv->getMessage());
1631         }
1632     }
1633 }