3 * Tine 2.0 - http://www.tine20.org
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>
12 * Test class for Calendar_Controller_Event
16 class Calendar_Controller_EventTests extends Calendar_TestCase
19 * @var Calendar_Controller_Event controller unter test
21 protected $_controller;
25 * @see Calendar_TestCase::setUp()
27 public function setUp()
30 $this->_controller = Calendar_Controller_Event::getInstance();
36 * @return Calendar_Model_Event
38 public function testCreateEvent()
40 $event = $this->_getEvent();
41 $persistentEvent = $this->_controller->create($event);
43 $this->assertEquals($event->description, $persistentEvent->description);
44 $this->assertTrue($event->dtstart->equals($persistentEvent->dtstart));
45 $this->assertEquals(Tinebase_Core::getUserTimezone(), $persistentEvent->originator_tz);
47 return $persistentEvent;
51 * testCreateAlldayEventWithoutDtend
53 public function testCreateAlldayEventWithoutDtend()
55 $event = $this->_getEvent();
56 $event->is_all_day_event = true;
59 $persistentEvent = $this->_controller->create($event);
60 $persistentEvent->setTimezone(Tinebase_Core::getUserTimezone());
61 $this->assertEquals('2009-04-06 23:59:59', $persistentEvent->dtend->toString());
67 public function testGetEvent()
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});
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});
80 public function testGetRecurInstance()
82 // create event and invite admin group
83 $event = $this->_getEvent();
84 $event->rrule = 'FREQ=DAILY;INTERVAL=1';
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());
90 $deepLink = $nextOccurance->getDeepLink();
91 $id = basename($deepLink);
93 $recurInstance = $this->_controller->get($id);
94 $this->assertTrue($recurInstance->isRecurInstance());
95 $this->assertEquals($nextOccurance->getId(), $recurInstance->getId());
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);
109 public function testUpdateEvent()
111 $persistentEvent = $this->testCreateEvent();
113 $currentTz = Tinebase_Core::getUserTimezone();
114 Tinebase_Core::set(Tinebase_Core::USERTIMEZONE, 'farfaraway');
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!');
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!');
126 Tinebase_Core::set(Tinebase_Core::USERTIMEZONE, $currentTz);
129 public function testConcurrentUpdate()
131 $event = $this->testCreateEvent();
134 $resolvableConcurrentEvent1 = clone $event;
135 $resolvableConcurrentEvent1->dtstart = $resolvableConcurrentEvent1->dtstart->addMonth(1);
136 $resolvableConcurrentEvent1->dtend = $resolvableConcurrentEvent1->dtend->addMonth(1);
137 $resolvableConcurrentEvent1Update = $this->_controller->update($resolvableConcurrentEvent1);
140 $resolvableConcurrentEvent2 = clone $event;
141 $resolvableConcurrentEvent2->summary = 'Updated Event';
142 $resolvableConcurrentEvent2Update = $this->_controller->update($resolvableConcurrentEvent2);
144 $this->assertEquals($resolvableConcurrentEvent1Update->dtstart, $resolvableConcurrentEvent2Update->dtstart);
147 public function testUpdateAttendeeStatus()
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(),
156 $persistentEvent = $this->_controller->create($event);
158 foreach ($persistentEvent->attendee as $attender) {
159 $attender->status = Calendar_Model_Attender::STATUS_DECLINED;
160 $this->_controller->attenderStatusUpdate($persistentEvent, $attender, $attender->status_authkey);
164 $persistentEvent->last_modified_time = $this->_controller->get($persistentEvent->getId())->last_modified_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);
174 $currentUser = $updatedEvent->attendee
175 ->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)
176 ->filter('user_id', Tinebase_Core::getUser()->contact_id)
179 $pwulf = $updatedEvent->attendee
180 ->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)
181 ->filter('user_id', $this->_getPersonasContacts('pwulf')->getId())
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');
188 public function testUpdateMultiple()
190 $persistentEvent = $this->testCreateEvent();
192 $filter = new Calendar_Model_EventFilter(array(
193 array('field' => 'id', 'operator' => 'in', 'value' => array($persistentEvent->getId()))
197 'summary' => 'multipleTest'
200 $this->_controller->updateMultiple($filter, $data);
202 $updatedEvent = $this->_controller->get($persistentEvent->getId());
203 $this->assertEquals('multipleTest', $updatedEvent->summary);
206 public function testAttendeeBasics()
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()
215 $persistendEvent = $this->_controller->create($event);
216 $this->assertEquals(2, count($persistendEvent->attendee));
218 unset($persistendEvent->attendee[0]);
219 $updatedEvent = $this->_controller->update($persistendEvent);
220 $this->assertEquals(1, count($updatedEvent->attendee));
222 $updatedEvent->attendee->getFirstRecord()->role = Calendar_Model_Attender::ROLE_OPTIONAL;
223 $updatedEvent->attendee->getFirstRecord()->transp = Calendar_Model_Event::TRANSP_TRANSP;
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);
231 public function testAttendeeFilter()
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())
238 $this->_controller->create($event1);
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()),
245 $this->_controller->create($event2);
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()),
252 $this->_controller->create($event3);
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()
262 $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
263 $this->assertEquals(2, count($eventsFound), 'sclever attends to two events');
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()
273 $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
274 $this->assertEquals(1, count($eventsFound), 'pwulf attends to one events');
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(
281 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
282 'user_id' => $this->_getPersonasContacts('sclever')->getId()
285 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
286 'user_id' => $this->_getPersonasContacts('pwulf')->getId()
290 $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
291 $this->assertEquals(3, count($eventsFound), 'sclever OR pwulf attends to tree events');
294 public function testAttendeeGroupFilter()
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())
301 $this->_controller->create($event);
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(
307 'user_type' => Calendar_Model_AttenderFilter::USERTYPE_MEMBEROF,
308 'user_id' => $this->_getPersona('sclever')->accountPrimaryGroup
312 $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
313 $this->assertEquals(1, count($eventsFound), 'sclever is groupmember');
317 * @see 0006702: CalDAV: single event appears in personal and shared calendar
319 * TODO fix for pgsql: Failed asserting that 0 matches expected 1.
322 public function testAttendeeNotInFilter()
324 if ($this->_dbIsPgsql()) {
325 $this->markTestSkipped('0011674: problem with Attendee "NotIn" Filter (pgsql)');
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),
333 $this->_controller->create($event);
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(
340 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
341 'user_id' => $this->_personasContacts['sclever']->getId()
345 $eventsFound = $this->_controller->search($filter, new Tinebase_Model_Pagination());
346 $this->assertEquals(1, count($eventsFound), 'should be exactly one event');
348 Tinebase_Core::getUser()->contact_id,
349 $eventsFound->getFirstRecord()->attendee->getFirstRecord()->user_id,
350 'sclevers event should not be found');
354 * test get free busy info with single event
356 * @return Calendar_Model_Event
358 public function testGetFreeBusyInfo()
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())
365 $persistentEvent = $this->_controller->create($event);
367 $period = new Calendar_Model_EventFilter(array(array(
369 'operator' => 'within',
371 'from' => $persistentEvent->dtstart,
372 'until' => $persistentEvent->dtend
375 $fbinfo = $this->_controller->getFreeBusyInfo($period, $persistentEvent->attendee);
377 $this->assertGreaterThanOrEqual(2, count($fbinfo));
379 return $persistentEvent;
383 * test get free busy info with single event
385 * @return Calendar_Model_Event
387 public function testGetFreeBusyInfoWithGroup()
389 $event = $this->_getEvent();
390 $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
392 'user_id' => Tinebase_Group::getInstance()->getDefaultGroup(),
393 'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
394 'role' => Calendar_Model_Attender::ROLE_OPTIONAL,
397 $event->attendee = clone $attendee;
398 $persistentEvent = $this->_controller->create($event);
400 $period = new Calendar_Model_EventFilter(array(array(
402 'operator' => 'within',
404 'from' => $persistentEvent->dtstart,
405 'until' => $persistentEvent->dtend
408 $fbinfo = $this->_controller->getFreeBusyInfo($period, $attendee);
410 $this->assertGreaterThanOrEqual(1, count($fbinfo));
412 return $persistentEvent;
415 public function testSearchFreeTime()
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)
422 $event->rrule = 'FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,FR';
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'
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);
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);
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'
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);
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'
478 * events from deleted calendars should not be shown
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()
489 $this->_getTestCalendars()->addRecord($testCal);
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);
498 Tinebase_Container::getInstance()->deleteContainer($testCal, TRUE);
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()
506 )), NULL, FALSE, FALSE);
508 $this->assertFalse(in_array($persistentEvent->getId(), $events->getId()), 'event in deleted (display) container shuld not be found');
511 public function testCreateEventWithConflict()
513 $this->_testNeedsTransaction();
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())
520 $this->_controller->create($event);
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())
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;
536 if (! $exectionRaised) {
537 $this->fail('An expected exception has not been raised.');
539 $persitentConflictEvent = $this->_controller->create($conflictEvent, FALSE);
541 return $persitentConflictEvent;
544 public function testCreateEventWithConflictFromGroupMember()
546 $event = $this->_getEvent();
547 $event->attendee = $this->_getAttendee();
548 $this->_controller->create($event);
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())
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']));
565 $this->fail('An expected exception has not been raised.');
568 public function testCreateTransparentEventNoConflict()
570 $event = $this->_getEvent();
571 $event->attendee = $this->_getAttendee();
572 $this->_controller->create($event);
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())
581 $this->_controller->create($nonConflictEvent, TRUE);
584 public function testCreateNoConflictParallelTrasparentEvent()
586 $event = $this->_getEvent();
587 $event->attendee = $this->_getAttendee();
588 $event->transp = Calendar_Model_Event::TRANSP_TRANSP;
589 $this->_controller->create($event);
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())
597 $this->_controller->create($nonConflictEvent, TRUE);
600 public function testCreateNoConflictParallelAtendeeTrasparentEvent()
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);
608 $nonConflictEvent = $this->_getEvent();
609 $nonConflictEvent->attendee = $this->_getAttendee();
611 $this->_controller->create($nonConflictEvent, TRUE);
614 public function testCreateConflictResourceUnavailable()
616 $event = $this->_getEvent();
618 // create & add resource
619 $rt = new Calendar_Controller_ResourceTest();
621 $resource = $rt->testCreateResource();
622 $resource->busy_type = Calendar_Model_FreeBusy::FREEBUSY_BUSY_UNAVAILABLE;
623 Calendar_Controller_Resource::getInstance()->update($resource);
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()
630 $conflictEvent = clone $event;
631 $this->_controller->create($event);
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);
642 public function testUpdateWithConflictNoTimechange()
644 $persitentConflictEvent = $this->testCreateEventWithConflict();
645 $persitentConflictEvent->summary = 'only time updates should recheck free/busy';
647 $this->_controller->update($persitentConflictEvent, TRUE);
650 public function testUpdateWithConflictAttendeeChange()
652 $persitentConflictEvent = $this->testCreateEventWithConflict();
653 $persitentConflictEvent->summary = 'attendee adds should recheck free/busy';
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
662 $this->setExpectedException('Calendar_Exception_AttendeeBusy');
663 $this->_controller->update($persitentConflictEvent, TRUE);
666 public function testUpdateWithConflictWithTimechange()
668 $persitentConflictEvent = $this->testCreateEventWithConflict();
669 $persitentConflictEvent->summary = 'time updates should recheck free/busy';
670 $persitentConflictEvent->dtend->addHour(1);
672 $this->setExpectedException('Calendar_Exception_AttendeeBusy');
673 $this->_controller->update($persitentConflictEvent, TRUE);
676 public function testAttendeeAuthKeyPreserv()
678 $event = $this->_getEvent();
679 $event->attendee = $this->_getAttendee();
681 $persistendEvent = $this->_controller->create($event);
682 $newAuthKey = Tinebase_Record_Abstract::generateUID();
683 $persistendEvent->attendee->status_authkey = $newAuthKey;
685 $updatedEvent = $this->_controller->update($persistendEvent);
686 foreach ($updatedEvent->attendee as $attender) {
687 $this->assertNotEquals($newAuthKey, $attender->status_authkey);
691 public function testAttendeeStatusPreservViaSave()
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]);
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');
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');
708 public function testAttendeeSetStatus()
710 $event = $this->_getEvent();
711 $event->attendee = $this->_getAttendee();
712 unset($event->attendee[1]);
714 $persistendEvent = $this->_controller->create($event);
715 $attendee = $persistendEvent->attendee[0];
717 $attendee->status = Calendar_Model_Attender::STATUS_DECLINED;
718 $this->_controller->attenderStatusUpdate($persistendEvent, $attendee, $attendee->status_authkey);
720 $loadedEvent = $this->_controller->get($persistendEvent->getId());
721 $this->assertEquals(Calendar_Model_Attender::STATUS_DECLINED, $loadedEvent->attendee[0]->status, 'status not set');
725 public function testAttendeeStatusFilter()
727 $event = $this->_getEvent();
728 $event->attendee = $this->_getAttendee();
729 unset($event->attendee[1]);
731 $persistentEvent = $this->_controller->create($event);
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),
738 $events = $this->_controller->search($filter);
739 $this->assertEquals(1, count($events), 'event should be found, but is not');
741 $attender = $persistentEvent->attendee[0];
742 $attender->status = Calendar_Model_Attender::STATUS_DECLINED;
743 $this->_controller->update($persistentEvent);
745 $events = $this->_controller->search($filter);
746 $this->assertEquals(0, count($events), 'event should _not_ be found, but is');
750 public function testAttendeeDisplaycontainerContact()
752 $contact = Addressbook_Controller_Contact::getInstance()->create(new Addressbook_Model_Contact(array(
753 'n_given' => 'phpunit',
754 'n_family' => 'cal attender'
757 $event = $this->_getEvent();
758 $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
760 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
761 'user_id' => $contact->getId(),
762 'role' => Calendar_Model_Attender::ROLE_REQUIRED
765 $persistentEvent = $this->_controller->create($event);
766 $attender = $persistentEvent->attendee[0];
768 $this->assertTrue(empty($attender->displaycontainer_id), 'displaycontainer_id must not be set for contacts');
771 public function testAttendeeGroupMembersResolving()
773 if (Tinebase_User::getConfiguredBackend() === Tinebase_User::ACTIVEDIRECTORY) {
774 $this->markTestSkipped('only working in non-AD setups');
777 $defaultUserGroup = Tinebase_Group::getInstance()->getDefaultGroup();
778 Tinebase_Group::getInstance()->getDefaultAdminGroup();
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
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--;
796 $this->assertEquals($expectedAttendeeCount, count($persistentEvent->attendee),
797 'attendee: ' . print_r($persistentEvent->attendee->toArray(), true));
799 $groupAttender = $persistentEvent->attendee->find('user_type', Calendar_Model_Attender::USERTYPE_GROUP);
800 $persistentEvent->attendee->removeRecord($groupAttender);
802 $updatedPersistentEvent = $this->_controller->update($persistentEvent);
803 $this->assertEquals(1, count($updatedPersistentEvent->attendee));
806 public function testAttendeeGroupMembersChange()
808 $defaultAdminGroup = Tinebase_Group::getInstance()->getDefaultAdminGroup();
810 // create event and invite admin group
811 $event = $this->_getEvent();
813 // only events in future will be changed!
814 $event->dtstart = Tinebase_DateTime::now()->addHour(1);
815 $event->dtend = Tinebase_DateTime::now()->addHour(2);
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
823 $persistentEvent = $this->_controller->create($event);
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');
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);
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');
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);
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');
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);
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)');
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);
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');
884 public function testAttendeeGroupMembersAddUser()
887 // clean up if exists
888 $cleanupUser = Tinebase_User::getInstance()->getFullUserByLoginName('testAttendeeGroupMembersAddUser');
889 Tinebase_User::getInstance()->deleteUser($cleanupUser);
890 } catch (Exception $e) {
895 $defaultGroup = Tinebase_Group::getInstance()->getDefaultGroup();
897 // create event and invite admin group
898 $event = $this->_getEvent();
900 // only events in future will be changed!
901 $event->dtstart = Tinebase_DateTime::now()->addHour(1);
902 $event->dtend = Tinebase_DateTime::now()->addHour(2);
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
910 $persistentEvent = $this->_controller->create($event);
912 $newUser = $this->_createNewUser();
913 if (isset(Tinebase_Core::getConfig()->actionqueue)) {
914 Tinebase_ActionQueue::getInstance()->processQueue(10000);
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));
925 Admin_Controller_User::getInstance()->delete($newUser->getId());
926 if (isset(Tinebase_Core::getConfig()->actionqueue)) {
927 Tinebase_ActionQueue::getInstance()->processQueue(10000);
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)');
939 * testAttendeeGroupMembersRecurringAddUser
941 * FIXME 0007352: fix Calendar_Controller_EventTests::testAttendeeGroupMembersRecurringAddUser
943 public function testAttendeeGroupMembersRecurringAddUser()
945 $this->markTestIncomplete('test fails sometimes / needs fixing');
949 $cleanupUser = Tinebase_User::getInstance()->getFullUserByLoginName('testAttendeeGroupMembersAddUser');
950 Tinebase_User::getInstance()->deleteUser($cleanupUser);
951 } catch (Exception $e) {
955 $defaultGroup = Tinebase_Group::getInstance()->getDefaultGroup();
957 // create event and invite admin group
958 $event = $this->_getEvent();
959 $event->rrule = 'FREQ=DAILY;INTERVAL=1';
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
967 $persistentEvent = $this->_controller->create($event);
969 $newUser = $this->_createNewUser();
970 if (isset(Tinebase_Core::getConfig()->actionqueue)) {
971 Tinebase_ActionQueue::getInstance()->processQueue(10000);
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()));
978 $oldSeries = $events->filter('rrule_until', '/.+/', TRUE)->getFirstRecord();
979 $newSeries = $events->filter('rrule_until', '/^$/', TRUE)->getFirstRecord();
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');
994 Admin_Controller_User::getInstance()->delete($newUser->getId());
995 if (isset(Tinebase_Core::getConfig()->actionqueue)) {
996 Tinebase_ActionQueue::getInstance()->processQueue(10000);
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()));
1003 $newSeries = $events->filter('rrule_until', '/^$/', TRUE)->getFirstRecord();
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');
1012 protected function _createNewUser()
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'
1027 public function testRruleUntil()
1029 $event = $this->_getEvent();
1031 $event->rrule_until = Tinebase_DateTime::now();
1032 $persistentEvent = $this->_controller->create($event);
1033 $this->assertNull($persistentEvent->rrule_until, 'rrul_until is not unset');
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));
1040 public function testUpdateRecuingDtstart()
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);
1047 $this->assertEquals('2009-04-30 21:59:59', $persistentEvent->rrule->until->toString(), 'rrule is not adapted');
1049 $exception = clone $persistentEvent;
1050 $exception->dtstart->addDay(2);
1051 $exception->dtend->addDay(2);
1053 $exception->setId(NULL);
1054 unset($exception->rrule);
1055 unset($exception->exdate);
1056 $exception->setRecurId($event->getId());
1057 $persistentException = $this->_controller->create($exception);
1059 $persistentEvent->dtstart->addHour(5);
1060 $persistentEvent->dtend->addHour(5);
1062 $updatedEvent = $this->_controller->update($persistentEvent);
1064 $updatedException = $this->_controller->get($persistentException->getId());
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');
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)');
1081 * testUpdateRecurDtstartOverDst
1083 public function testUpdateRecurDtstartOverDst()
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,
1098 $persistentEvent = $this->_controller->create($event);
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
1105 // skip 27(exception), 31(exception), 03(until)
1106 $this->assertEquals(6, count($recurSet));
1108 $exceptionBeforeDstBoundary = clone $recurSet[1]; // 28.
1109 $persistentExceptionBeforeDstBoundary = $this->_controller->createRecurException($exceptionBeforeDstBoundary);
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);
1116 $persistentEvent->dtstart->addDay(5); //30.
1117 $persistentEvent->dtend->addDay(5);
1118 $from->addDay(5); //31
1119 $until->addDay(5); //08
1121 $this->_controller->get($persistentEvent);
1122 $persistentEvent->seq = 3; // satisfy modlog
1123 $updatedPersistenEvent = $this->_controller->update($persistentEvent);
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)
1130 // we don't 'see' the persistent exception from 28/
1131 $this->assertEquals(2, count($persistentEvents));
1133 $exceptions = $persistentEvents->filter('recurid', "/^{$persistentEvent->uid}-.*/", TRUE);
1134 $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($updatedPersistenEvent, $exceptions, $from, $until);
1137 $this->assertEquals(3, count($recurSet));
1140 public function testDeleteImplicitDeleteRcuringExceptions()
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);
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);
1156 unset($persistentEvent->rrule);
1157 $this->_controller->delete($persistentEvent);
1158 $this->setExpectedException('Tinebase_Exception_NotFound');
1159 $this->_controller->get($persistentException->getId());
1164 * - check here if content sequence of container has been increased
1166 public function testDeleteEvent()
1168 $event = $this->_getEvent();
1169 $persistentEvent = $this->_controller->create($event);
1171 $this->_controller->delete($persistentEvent->getId());
1173 $contentSeq = Tinebase_Container::getInstance()->getContentSequence($this->_getTestCalendar());
1174 $this->assertEquals(3, $contentSeq, 'container content seq should be increased 3 times!');
1176 $this->setExpectedException('Tinebase_Exception_NotFound');
1177 $this->_controller->get($persistentEvent->getId());
1181 * @todo use exception api once we have it!
1184 public function testDeleteRecurExceptions()
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);
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);
1200 $this->_controller->delete($persistentEvent->getId());
1201 $this->setExpectedException('Tinebase_Exception_NotFound');
1202 $this->_controller->get($persistentException->getId());
1205 public function testDeleteNonPersistentRecurException()
1207 $event = $this->_getEvent();
1208 $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1209 $persistentEvent = $this->_controller->create($event);
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);
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),
1225 $this->assertEquals(1, count($events));
1228 public function testDeletePersistentRecurException()
1230 $event = $this->_getEvent();
1231 $event->rrule = 'FREQ=DAILY;INTERVAL=1;UNTIL=2009-04-30 13:30:00';
1232 $persistentEvent = $this->_controller->create($event);
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);
1241 $this->_controller->delete($persistentException->getId());
1243 $persistentEvent = $this->_controller->get($persistentEvent->getId());
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),
1249 $this->assertEquals(1, count($events));
1252 public function testSetAlarm()
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
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');
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');
1275 * testSetAlarmOfRecurSeries
1277 public function testSetAlarmOfRecurSeries()
1279 $event = $this->_getEvent();
1280 $event->dtstart = Tinebase_DateTime::now()->addHour(1);
1281 $event->dtend = Tinebase_DateTime::now()->addHour(2);
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
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));
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');
1303 * testSetAlarmOfRecurSeriesException
1305 public function testSetAlarmOfRecurSeriesException()
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
1314 $persistentEvent = $this->_controller->create($event);
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);
1322 $baseEvent = $this->_controller->getRecurBaseEvent($persistentException);
1323 $this->_controller->getAlarms($baseEvent);
1325 $exceptions = $this->_controller->getRecurExceptions($persistentException);
1326 $nextOccurance = Calendar_Model_Rrule::computeNextOccurrence($baseEvent, $exceptions, Tinebase_DateTime::now());
1328 $nextAlarmEventStart = new Tinebase_DateTime(substr($baseEvent->alarms->getFirstRecord()->getOption('recurid'), -19));
1330 $this->assertTrue($nextOccurance->dtstart->equals($nextAlarmEventStart), 'next alarm got not adjusted');
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');
1338 * testAdoptAlarmTimeOfYearlyEvent
1340 * @see 0009320: Wrong notification on first occurrence exceptions
1342 public function testAdoptAlarmTimeOfYearlyEvent()
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
1354 $persistentEvent = $this->_controller->create($event);
1355 $alarm = $persistentEvent->alarms->getFirstRecord();
1356 $this->_controller->adoptAlarmTime($persistentEvent, $alarm);
1358 $now = Tinebase_DateTime::now();
1359 $year = $now->get('Y');
1360 if ($now->isLater(new Tinebase_DateTime($year . '-10-27'))) {
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));
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
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',
1386 $updatedAlarm = $alarmBackend->update($alarm);
1388 $updatedAlarm->sent_time = Tinebase_DateTime::now();
1389 $updatedAlarm->sent_status = Tinebase_Model_Alarm::STATUS_SUCCESS;
1390 $updatedAlarm->minutes_before = 2880;
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));
1398 public function testPeriodFilter()
1400 $this->testCreateEvent();
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'
1408 )), NULL, FALSE, FALSE);
1410 $this->assertEquals(0, count($events));
1414 * returns a simple event
1416 * @return Calendar_Model_Event
1419 * @todo replace with TestCase::_getEvent
1421 public function _getEvent($_now = FALSE, $mute = NULL)
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...',
1429 'container_id' => $this->_getTestCalendar()->getId(),
1430 Tinebase_Model_Grants::GRANT_EDIT => true,
1434 $event->dtstart = Tinebase_DateTime::now();
1435 $event->dtend = Tinebase_DateTime::now()->addMinute(15);
1443 * @see Calendar_TestCase::_getAttendee()
1445 protected function _getAttendee()
1447 return new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
1449 'user_id' => Tinebase_Core::getUser()->contact_id,
1450 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
1451 'role' => Calendar_Model_Attender::ROLE_REQUIRED
1454 'user_id' => Tinebase_Group::getInstance()->getDefaultGroup()->getId(),
1455 'user_type' => Calendar_Model_Attender::USERTYPE_GROUP,
1456 'role' => Calendar_Model_Attender::ROLE_REQUIRED
1462 * tests if customfields gets saved properly
1464 public function testCustomFields()
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(),
1473 'uiconfig' => array(
1474 'xtype' => Tinebase_Record_Abstract::generateUID(),
1476 'group' => 'unittest',
1483 Tinebase_CustomField::getInstance()->addCustomField($cfData);
1484 } catch (Zend_Db_Statement_Exception $zdse) {
1485 // custom field already exists
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',
1494 'container_id' => $this->_getTestCalendar()->getId(),
1495 Tinebase_Model_Grants::GRANT_EDIT => true,
1496 'customfields' => array('unittest' => 'Hello')
1499 $event = $this->_controller->create($event);
1501 $this->assertEquals('Hello', $event->customfields['unittest']);
1505 * @see 0010454: cli script for comparing calendars
1507 public function testCompareCalendars()
1509 $cal1 = $this->_testCalendar;
1510 $cal2 = $this->_getTestContainer('Calendar');
1512 $this->_buildCompareCalendarsFixture($cal1, $cal2);
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);
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));
1525 * create some events to compare
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)
1535 * @param Tinebase_Model_Container $cal1
1536 * @param Tinebase_Model_Container $cal2
1538 protected function _buildCompareCalendarsFixture($cal1, $cal2)
1540 $event1 = $this->_getEvent(true);
1541 $event1->summary = 'event 1';
1542 $this->_controller->create($event1);
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);
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);
1558 $event4->container_id = $cal2->getId();
1559 $this->_controller->create($event4);
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);
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);
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(
1581 'user_id' => Tinebase_Core::getUser()->contact_id,
1582 'user_type' => Calendar_Model_Attender::USERTYPE_USER,
1583 'role' => Calendar_Model_Attender::ROLE_REQUIRED,
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);
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);
1599 $event9->container_id = $cal2->getId();
1600 $this->_controller->create($event9);
1603 public function testRepairAttendee()
1605 $event = $this->_getEvent(true);
1606 $event->attendee = null;
1607 $persistentEvent = $this->_controller->create($event);
1609 $result = $this->_controller->repairAttendee($persistentEvent->container_id, Tinebase_DateTime::now()->subDay(1), Tinebase_DateTime::now());
1611 $this->assertEquals(1, $result, 'should repair 1 event');
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);
1620 * @see 0011130: handle bad originator timzone in VCALENDAR converter
1622 public function testBrokenTimezoneInEvent()
1624 $event = $this->_getEvent(true);
1625 $event->originator_tz = 'AWSTTTT';
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());