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