1<?php 2 3namespace Sabre\CalDAV\Schedule; 4 5use Sabre\CalDAV; 6use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; 7use Sabre\DAV; 8use Sabre\DAVACL; 9use Sabre\HTTP; 10 11class FreeBusyRequestTest extends \PHPUnit_Framework_TestCase { 12 13 protected $plugin; 14 protected $server; 15 protected $aclPlugin; 16 protected $request; 17 protected $authPlugin; 18 protected $caldavBackend; 19 20 function setUp() { 21 22 $caldavNS = '{' . CalDAV\Plugin::NS_CALDAV . '}'; 23 $calendars = [ 24 [ 25 'principaluri' => 'principals/user2', 26 'id' => 1, 27 'uri' => 'calendar1', 28 $caldavNS . 'calendar-timezone' => "BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nEND:VTIMEZONE\r\nEND:VCALENDAR", 29 ], 30 [ 31 'principaluri' => 'principals/user2', 32 'id' => 2, 33 'uri' => 'calendar2', 34 $caldavNS . 'schedule-calendar-transp' => new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT), 35 ], 36 ]; 37 $calendarobjects = [ 38 1 => ['1.ics' => [ 39 'uri' => '1.ics', 40 'calendardata' => 'BEGIN:VCALENDAR 41BEGIN:VEVENT 42DTSTART:20110101T130000 43DURATION:PT1H 44END:VEVENT 45END:VCALENDAR', 46 'calendarid' => 1, 47 ]], 48 2 => ['2.ics' => [ 49 'uri' => '2.ics', 50 'calendardata' => 'BEGIN:VCALENDAR 51BEGIN:VEVENT 52DTSTART:20110101T080000 53DURATION:PT1H 54END:VEVENT 55END:VCALENDAR', 56 'calendarid' => 2, 57 ]] 58 59 ]; 60 61 $principalBackend = new DAVACL\PrincipalBackend\Mock(); 62 $this->caldavBackend = new CalDAV\Backend\MockScheduling($calendars, $calendarobjects); 63 64 $tree = [ 65 new DAVACL\PrincipalCollection($principalBackend), 66 new CalDAV\CalendarRoot($principalBackend, $this->caldavBackend), 67 ]; 68 69 $this->request = HTTP\Sapi::createFromServerArray([ 70 'CONTENT_TYPE' => 'text/calendar', 71 ]); 72 $this->response = new HTTP\ResponseMock(); 73 74 $this->server = new DAV\Server($tree); 75 $this->server->httpRequest = $this->request; 76 $this->server->httpResponse = $this->response; 77 78 $this->aclPlugin = new DAVACL\Plugin(); 79 $this->aclPlugin->allowUnauthenticatedAccess = false; 80 $this->server->addPlugin($this->aclPlugin); 81 82 $authBackend = new DAV\Auth\Backend\Mock(); 83 $authBackend->setPrincipal('principals/user1'); 84 $this->authPlugin = new DAV\Auth\Plugin($authBackend); 85 // Forcing authentication to work. 86 $this->authPlugin->beforeMethod($this->request, $this->response); 87 $this->server->addPlugin($this->authPlugin); 88 89 // CalDAV plugin 90 $this->plugin = new CalDAV\Plugin(); 91 $this->server->addPlugin($this->plugin); 92 93 // Scheduling plugin 94 $this->plugin = new Plugin(); 95 $this->server->addPlugin($this->plugin); 96 97 } 98 99 function testWrongContentType() { 100 101 $this->server->httpRequest = new HTTP\Request( 102 'POST', 103 '/calendars/user1/outbox', 104 ['Content-Type' => 'text/plain'] 105 ); 106 107 $this->assertNull( 108 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) 109 ); 110 111 } 112 113 function testNotFound() { 114 115 $this->server->httpRequest = new HTTP\Request( 116 'POST', 117 '/calendars/user1/blabla', 118 ['Content-Type' => 'text/calendar'] 119 ); 120 121 $this->assertNull( 122 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) 123 ); 124 125 } 126 127 function testNotOutbox() { 128 129 $this->server->httpRequest = new HTTP\Request( 130 'POST', 131 '/calendars/user1/inbox', 132 ['Content-Type' => 'text/calendar'] 133 ); 134 135 $this->assertNull( 136 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) 137 ); 138 139 } 140 141 /** 142 * @expectedException Sabre\DAV\Exception\BadRequest 143 */ 144 function testNoItipMethod() { 145 146 $this->server->httpRequest = new HTTP\Request( 147 'POST', 148 '/calendars/user1/outbox', 149 ['Content-Type' => 'text/calendar'] 150 ); 151 152 $body = <<<ICS 153BEGIN:VCALENDAR 154BEGIN:VFREEBUSY 155END:VFREEBUSY 156END:VCALENDAR 157ICS; 158 159 $this->server->httpRequest->setBody($body); 160 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); 161 162 } 163 164 /** 165 * @expectedException \Sabre\DAV\Exception\NotImplemented 166 */ 167 function testNoVFreeBusy() { 168 169 $this->server->httpRequest = new HTTP\Request( 170 'POST', 171 '/calendars/user1/outbox', 172 ['Content-Type' => 'text/calendar'] 173 ); 174 175 $body = <<<ICS 176BEGIN:VCALENDAR 177METHOD:REQUEST 178BEGIN:VEVENT 179END:VEVENT 180END:VCALENDAR 181ICS; 182 183 $this->server->httpRequest->setBody($body); 184 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); 185 186 } 187 188 /** 189 * @expectedException Sabre\DAV\Exception\Forbidden 190 */ 191 function testIncorrectOrganizer() { 192 193 $this->server->httpRequest = new HTTP\Request( 194 'POST', 195 '/calendars/user1/outbox', 196 ['Content-Type' => 'text/calendar'] 197 ); 198 199 200 $body = <<<ICS 201BEGIN:VCALENDAR 202METHOD:REQUEST 203BEGIN:VFREEBUSY 204ORGANIZER:mailto:john@wayne.org 205END:VFREEBUSY 206END:VCALENDAR 207ICS; 208 209 $this->server->httpRequest->setBody($body); 210 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); 211 212 } 213 214 /** 215 * @expectedException Sabre\DAV\Exception\BadRequest 216 */ 217 function testNoAttendees() { 218 219 $this->server->httpRequest = new HTTP\Request( 220 'POST', 221 '/calendars/user1/outbox', 222 ['Content-Type' => 'text/calendar'] 223 ); 224 225 $body = <<<ICS 226BEGIN:VCALENDAR 227METHOD:REQUEST 228BEGIN:VFREEBUSY 229ORGANIZER:mailto:user1.sabredav@sabredav.org 230END:VFREEBUSY 231END:VCALENDAR 232ICS; 233 234 $this->server->httpRequest->setBody($body); 235 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); 236 237 } 238 239 /** 240 * @expectedException Sabre\DAV\Exception\BadRequest 241 */ 242 function testNoDTStart() { 243 244 $this->server->httpRequest = new HTTP\Request( 245 'POST', 246 '/calendars/user1/outbox', 247 ['Content-Type' => 'text/calendar'] 248 ); 249 250 $body = <<<ICS 251BEGIN:VCALENDAR 252METHOD:REQUEST 253BEGIN:VFREEBUSY 254ORGANIZER:mailto:user1.sabredav@sabredav.org 255ATTENDEE:mailto:user2.sabredav@sabredav.org 256END:VFREEBUSY 257END:VCALENDAR 258ICS; 259 260 $this->server->httpRequest->setBody($body); 261 $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); 262 263 } 264 265 function testSucceed() { 266 267 $this->server->httpRequest = new HTTP\Request( 268 'POST', 269 '/calendars/user1/outbox', 270 ['Content-Type' => 'text/calendar'] 271 ); 272 273 $body = <<<ICS 274BEGIN:VCALENDAR 275METHOD:REQUEST 276BEGIN:VFREEBUSY 277ORGANIZER:mailto:user1.sabredav@sabredav.org 278ATTENDEE:mailto:user2.sabredav@sabredav.org 279ATTENDEE:mailto:user3.sabredav@sabredav.org 280DTSTART:20110101T080000Z 281DTEND:20110101T180000Z 282END:VFREEBUSY 283END:VCALENDAR 284ICS; 285 286 $this->server->httpRequest->setBody($body); 287 288 // Lazily making the current principal an admin. 289 $this->aclPlugin->adminPrincipals[] = 'principals/user1'; 290 291 $this->assertFalse( 292 $this->plugin->httpPost($this->server->httpRequest, $this->response) 293 ); 294 295 $this->assertEquals(200, $this->response->status); 296 $this->assertEquals([ 297 'Content-Type' => ['application/xml'], 298 ], $this->response->getHeaders()); 299 300 $strings = [ 301 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 302 '<d:href>mailto:user3.sabredav@sabredav.org</d:href>', 303 '<cal:request-status>2.0;Success</cal:request-status>', 304 '<cal:request-status>3.7;Could not find principal</cal:request-status>', 305 'FREEBUSY:20110101T120000Z/20110101T130000Z', 306 ]; 307 308 foreach ($strings as $string) { 309 $this->assertTrue( 310 strpos($this->response->body, $string) !== false, 311 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body 312 ); 313 } 314 315 $this->assertTrue( 316 strpos($this->response->body, 'FREEBUSY;FBTYPE=BUSY:20110101T080000Z/20110101T090000Z') == false, 317 'The response body did contain free busy info from a transparent calendar.' 318 ); 319 320 } 321 322 /** 323 * Testing if the freebusy request still works, even if there are no 324 * calendars in the target users' account. 325 */ 326 function testSucceedNoCalendars() { 327 328 // Deleting calendars 329 $this->caldavBackend->deleteCalendar(1); 330 $this->caldavBackend->deleteCalendar(2); 331 332 $this->server->httpRequest = new HTTP\Request( 333 'POST', 334 '/calendars/user1/outbox', 335 ['Content-Type' => 'text/calendar'] 336 ); 337 338 $body = <<<ICS 339BEGIN:VCALENDAR 340METHOD:REQUEST 341BEGIN:VFREEBUSY 342ORGANIZER:mailto:user1.sabredav@sabredav.org 343ATTENDEE:mailto:user2.sabredav@sabredav.org 344DTSTART:20110101T080000Z 345DTEND:20110101T180000Z 346END:VFREEBUSY 347END:VCALENDAR 348ICS; 349 350 $this->server->httpRequest->setBody($body); 351 352 // Lazily making the current principal an admin. 353 $this->aclPlugin->adminPrincipals[] = 'principals/user1'; 354 355 $this->assertFalse( 356 $this->plugin->httpPost($this->server->httpRequest, $this->response) 357 ); 358 359 $this->assertEquals(200, $this->response->status); 360 $this->assertEquals([ 361 'Content-Type' => ['application/xml'], 362 ], $this->response->getHeaders()); 363 364 $strings = [ 365 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 366 '<cal:request-status>2.0;Success</cal:request-status>', 367 ]; 368 369 foreach ($strings as $string) { 370 $this->assertTrue( 371 strpos($this->response->body, $string) !== false, 372 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body 373 ); 374 } 375 376 } 377 378 function testNoCalendarHomeFound() { 379 380 $this->server->httpRequest = new HTTP\Request( 381 'POST', 382 '/calendars/user1/outbox', 383 ['Content-Type' => 'text/calendar'] 384 ); 385 386 $body = <<<ICS 387BEGIN:VCALENDAR 388METHOD:REQUEST 389BEGIN:VFREEBUSY 390ORGANIZER:mailto:user1.sabredav@sabredav.org 391ATTENDEE:mailto:user2.sabredav@sabredav.org 392DTSTART:20110101T080000Z 393DTEND:20110101T180000Z 394END:VFREEBUSY 395END:VCALENDAR 396ICS; 397 398 $this->server->httpRequest->setBody($body); 399 400 // Lazily making the current principal an admin. 401 $this->aclPlugin->adminPrincipals[] = 'principals/user1'; 402 403 // Removing the calendar home 404 $this->server->on('propFind', function(DAV\PropFind $propFind) { 405 406 $propFind->set('{' . Plugin::NS_CALDAV . '}calendar-home-set', null, 403); 407 408 }); 409 410 $this->assertFalse( 411 $this->plugin->httpPost($this->server->httpRequest, $this->response) 412 ); 413 414 $this->assertEquals(200, $this->response->status); 415 $this->assertEquals([ 416 'Content-Type' => ['application/xml'], 417 ], $this->response->getHeaders()); 418 419 $strings = [ 420 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 421 '<cal:request-status>3.7;No calendar-home-set property found</cal:request-status>', 422 ]; 423 424 foreach ($strings as $string) { 425 $this->assertTrue( 426 strpos($this->response->body, $string) !== false, 427 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body 428 ); 429 } 430 431 } 432 433 function testNoInboxFound() { 434 435 $this->server->httpRequest = new HTTP\Request( 436 'POST', 437 '/calendars/user1/outbox', 438 ['Content-Type' => 'text/calendar'] 439 ); 440 441 $body = <<<ICS 442BEGIN:VCALENDAR 443METHOD:REQUEST 444BEGIN:VFREEBUSY 445ORGANIZER:mailto:user1.sabredav@sabredav.org 446ATTENDEE:mailto:user2.sabredav@sabredav.org 447DTSTART:20110101T080000Z 448DTEND:20110101T180000Z 449END:VFREEBUSY 450END:VCALENDAR 451ICS; 452 453 $this->server->httpRequest->setBody($body); 454 455 // Lazily making the current principal an admin. 456 $this->aclPlugin->adminPrincipals[] = 'principals/user1'; 457 458 // Removing the inbox 459 $this->server->on('propFind', function(DAV\PropFind $propFind) { 460 461 $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-inbox-URL', null, 403); 462 463 }); 464 465 $this->assertFalse( 466 $this->plugin->httpPost($this->server->httpRequest, $this->response) 467 ); 468 469 $this->assertEquals(200, $this->response->status); 470 $this->assertEquals([ 471 'Content-Type' => ['application/xml'], 472 ], $this->response->getHeaders()); 473 474 $strings = [ 475 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 476 '<cal:request-status>3.7;No schedule-inbox-URL property found</cal:request-status>', 477 ]; 478 479 foreach ($strings as $string) { 480 $this->assertTrue( 481 strpos($this->response->body, $string) !== false, 482 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body 483 ); 484 } 485 486 } 487 488 function testSucceedUseVAVAILABILITY() { 489 490 $this->server->httpRequest = new HTTP\Request( 491 'POST', 492 '/calendars/user1/outbox', 493 ['Content-Type' => 'text/calendar'] 494 ); 495 496 $body = <<<ICS 497BEGIN:VCALENDAR 498METHOD:REQUEST 499BEGIN:VFREEBUSY 500ORGANIZER:mailto:user1.sabredav@sabredav.org 501ATTENDEE:mailto:user2.sabredav@sabredav.org 502DTSTART:20110101T080000Z 503DTEND:20110101T180000Z 504END:VFREEBUSY 505END:VCALENDAR 506ICS; 507 508 $this->server->httpRequest->setBody($body); 509 510 // Lazily making the current principal an admin. 511 $this->aclPlugin->adminPrincipals[] = 'principals/user1'; 512 513 // Adding VAVAILABILITY manually 514 $this->server->on('propFind', function(DAV\PropFind $propFind) { 515 516 $propFind->handle('{' . Plugin::NS_CALDAV . '}calendar-availability', function() { 517 518 $avail = <<<ICS 519BEGIN:VCALENDAR 520BEGIN:VAVAILABILITY 521DTSTART:20110101T000000Z 522DTEND:20110102T000000Z 523BEGIN:AVAILABLE 524DTSTART:20110101T090000Z 525DTEND:20110101T170000Z 526END:AVAILABLE 527END:VAVAILABILITY 528END:VCALENDAR 529ICS; 530 return $avail; 531 532 }); 533 534 }); 535 536 $this->assertFalse( 537 $this->plugin->httpPost($this->server->httpRequest, $this->response) 538 ); 539 540 $this->assertEquals(200, $this->response->status); 541 $this->assertEquals([ 542 'Content-Type' => ['application/xml'], 543 ], $this->response->getHeaders()); 544 545 $strings = [ 546 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 547 '<cal:request-status>2.0;Success</cal:request-status>', 548 'FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T080000Z/20110101T090000Z', 549 'FREEBUSY:20110101T120000Z/20110101T130000Z', 550 'FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T170000Z/20110101T180000Z', 551 ]; 552 553 foreach ($strings as $string) { 554 $this->assertTrue( 555 strpos($this->response->body, $string) !== false, 556 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body 557 ); 558 } 559 560 } 561 562 /* 563 function testNoPrivilege() { 564 565 $this->markTestIncomplete('Currently there\'s no "no privilege" situation'); 566 567 $this->server->httpRequest = HTTP\Sapi::createFromServerArray(array( 568 'CONTENT_TYPE' => 'text/calendar', 569 'REQUEST_METHOD' => 'POST', 570 'REQUEST_URI' => '/calendars/user1/outbox', 571 )); 572 573 $body = <<<ICS 574BEGIN:VCALENDAR 575METHOD:REQUEST 576BEGIN:VFREEBUSY 577ORGANIZER:mailto:user1.sabredav@sabredav.org 578ATTENDEE:mailto:user2.sabredav@sabredav.org 579DTSTART:20110101T080000Z 580DTEND:20110101T180000Z 581END:VFREEBUSY 582END:VCALENDAR 583ICS; 584 585 $this->server->httpRequest->setBody($body); 586 587 $this->assertFalse( 588 $this->plugin->httpPost($this->server->httpRequest, $this->response) 589 ); 590 591 $this->assertEquals(200, $this->response->status); 592 $this->assertEquals([ 593 'Content-Type' => 'application/xml', 594 ], $this->response->getHeaders()); 595 596 $strings = [ 597 '<d:href>mailto:user2.sabredav@sabredav.org</d:href>', 598 '<cal:request-status>3.7;No calendar-home-set property found</cal:request-status>', 599 ]; 600 601 foreach($strings as $string) { 602 $this->assertTrue( 603 strpos($this->response->body, $string)!==false, 604 'The response body did not contain: ' . $string .'Full response: ' . $this->response->body 605 ); 606 } 607 608 609 }*/ 610 611} 612