1<?php 2 3namespace Sabre\CalDAV\Schedule; 4 5use Sabre\HTTP\Request; 6 7class ScheduleDeliverTest extends \Sabre\DAVServerTest { 8 9 public $setupCalDAV = true; 10 public $setupCalDAVScheduling = true; 11 public $setupACL = true; 12 public $autoLogin = 'user1'; 13 14 public $caldavCalendars = [ 15 [ 16 'principaluri' => 'principals/user1', 17 'uri' => 'cal', 18 ], 19 [ 20 'principaluri' => 'principals/user2', 21 'uri' => 'cal', 22 ], 23 ]; 24 25 function setUp() { 26 27 $this->calendarObjectUri = '/calendars/user1/cal/object.ics'; 28 29 parent::setUp(); 30 31 } 32 33 function testNewInvite() { 34 35 $newObject = <<<ICS 36BEGIN:VCALENDAR 37BEGIN:VEVENT 38UID:foo 39DTSTART:20140811T230000Z 40ORGANIZER:mailto:user1.sabredav@sabredav.org 41ATTENDEE:mailto:user2.sabredav@sabredav.org 42END:VEVENT 43END:VCALENDAR 44ICS; 45 46 $this->deliver(null, $newObject); 47 $this->assertItemsInInbox('user2', 1); 48 49 $expected = <<<ICS 50BEGIN:VCALENDAR 51BEGIN:VEVENT 52UID:foo 53DTSTART:20140811T230000Z 54ORGANIZER:mailto:user1.sabredav@sabredav.org 55ATTENDEE;SCHEDULE-STATUS=1.2:mailto:user2.sabredav@sabredav.org 56END:VEVENT 57END:VCALENDAR 58ICS; 59 60 $this->assertVObjEquals( 61 $expected, 62 $newObject 63 ); 64 65 } 66 67 function testNewOnWrongCollection() { 68 69 $newObject = <<<ICS 70BEGIN:VCALENDAR 71BEGIN:VEVENT 72UID:foo 73DTSTART:20140811T230000Z 74ORGANIZER:mailto:user1.sabredav@sabredav.org 75ATTENDEE:mailto:user2.sabredav@sabredav.org 76END:VEVENT 77END:VCALENDAR 78ICS; 79 80 $this->calendarObjectUri = '/calendars/user1/object.ics'; 81 $this->deliver(null, $newObject); 82 $this->assertItemsInInbox('user2', 0); 83 84 85 } 86 function testNewInviteSchedulingDisabled() { 87 88 $newObject = <<<ICS 89BEGIN:VCALENDAR 90BEGIN:VEVENT 91UID:foo 92DTSTART:20140811T230000Z 93ORGANIZER:mailto:user1.sabredav@sabredav.org 94ATTENDEE:mailto:user2.sabredav@sabredav.org 95END:VEVENT 96END:VCALENDAR 97ICS; 98 99 $this->deliver(null, $newObject, true); 100 $this->assertItemsInInbox('user2', 0); 101 102 } 103 function testUpdatedInvite() { 104 105 $newObject = <<<ICS 106BEGIN:VCALENDAR 107BEGIN:VEVENT 108UID:foo 109DTSTART:20140811T230000Z 110ORGANIZER:mailto:user1.sabredav@sabredav.org 111ATTENDEE:mailto:user2.sabredav@sabredav.org 112END:VEVENT 113END:VCALENDAR 114ICS; 115 $oldObject = <<<ICS 116BEGIN:VCALENDAR 117BEGIN:VEVENT 118UID:foo 119DTSTART:20140811T230000Z 120ORGANIZER:mailto:user1.sabredav@sabredav.org 121END:VEVENT 122END:VCALENDAR 123ICS; 124 125 $this->deliver($oldObject, $newObject); 126 $this->assertItemsInInbox('user2', 1); 127 128 $expected = <<<ICS 129BEGIN:VCALENDAR 130BEGIN:VEVENT 131UID:foo 132DTSTART:20140811T230000Z 133ORGANIZER:mailto:user1.sabredav@sabredav.org 134ATTENDEE;SCHEDULE-STATUS=1.2:mailto:user2.sabredav@sabredav.org 135END:VEVENT 136END:VCALENDAR 137ICS; 138 139 $this->assertVObjEquals( 140 $expected, 141 $newObject 142 ); 143 144 145 } 146 function testUpdatedInviteSchedulingDisabled() { 147 148 $newObject = <<<ICS 149BEGIN:VCALENDAR 150BEGIN:VEVENT 151UID:foo 152DTSTART:20140811T230000Z 153ORGANIZER:mailto:user1.sabredav@sabredav.org 154ATTENDEE:mailto:user2.sabredav@sabredav.org 155END:VEVENT 156END:VCALENDAR 157ICS; 158 $oldObject = <<<ICS 159BEGIN:VCALENDAR 160BEGIN:VEVENT 161UID:foo 162DTSTART:20140811T230000Z 163ORGANIZER:mailto:user1.sabredav@sabredav.org 164END:VEVENT 165END:VCALENDAR 166ICS; 167 168 $this->deliver($oldObject, $newObject, true); 169 $this->assertItemsInInbox('user2', 0); 170 171 } 172 173 function testUpdatedInviteWrongPath() { 174 175 $newObject = <<<ICS 176BEGIN:VCALENDAR 177BEGIN:VEVENT 178UID:foo 179DTSTART:20140811T230000Z 180ORGANIZER:mailto:user1.sabredav@sabredav.org 181ATTENDEE:mailto:user2.sabredav@sabredav.org 182END:VEVENT 183END:VCALENDAR 184ICS; 185 $oldObject = <<<ICS 186BEGIN:VCALENDAR 187BEGIN:VEVENT 188UID:foo 189DTSTART:20140811T230000Z 190ORGANIZER:mailto:user1.sabredav@sabredav.org 191END:VEVENT 192END:VCALENDAR 193ICS; 194 195 $this->calendarObjectUri = '/calendars/user1/inbox/foo.ics'; 196 $this->deliver($oldObject, $newObject); 197 $this->assertItemsInInbox('user2', 0); 198 199 } 200 201 function testDeletedInvite() { 202 203 $newObject = null; 204 205 $oldObject = <<<ICS 206BEGIN:VCALENDAR 207BEGIN:VEVENT 208UID:foo 209DTSTART:20140811T230000Z 210ORGANIZER:mailto:user1.sabredav@sabredav.org 211ATTENDEE:mailto:user2.sabredav@sabredav.org 212END:VEVENT 213END:VCALENDAR 214ICS; 215 216 $this->deliver($oldObject, $newObject); 217 $this->assertItemsInInbox('user2', 1); 218 219 } 220 221 function testDeletedInviteSchedulingDisabled() { 222 223 $newObject = null; 224 225 $oldObject = <<<ICS 226BEGIN:VCALENDAR 227BEGIN:VEVENT 228UID:foo 229DTSTART:20140811T230000Z 230ORGANIZER:mailto:user1.sabredav@sabredav.org 231ATTENDEE:mailto:user2.sabredav@sabredav.org 232END:VEVENT 233END:VCALENDAR 234ICS; 235 236 $this->deliver($oldObject, $newObject, true); 237 $this->assertItemsInInbox('user2', 0); 238 239 } 240 241 /** 242 * A MOVE request will trigger an unbind on a scheduling resource. 243 * 244 * However, we must not treat it as a cancellation, it just got moved to a 245 * different calendar. 246 */ 247 function testUnbindIgnoredOnMove() { 248 249 $newObject = null; 250 251 $oldObject = <<<ICS 252BEGIN:VCALENDAR 253BEGIN:VEVENT 254UID:foo 255DTSTART:20140811T230000Z 256ORGANIZER:mailto:user1.sabredav@sabredav.org 257ATTENDEE:mailto:user2.sabredav@sabredav.org 258END:VEVENT 259END:VCALENDAR 260ICS; 261 262 263 $this->server->httpRequest->setMethod('MOVE'); 264 $this->deliver($oldObject, $newObject); 265 $this->assertItemsInInbox('user2', 0); 266 267 } 268 269 function testDeletedInviteWrongUrl() { 270 271 $newObject = null; 272 273 $oldObject = <<<ICS 274BEGIN:VCALENDAR 275BEGIN:VEVENT 276UID:foo 277DTSTART:20140811T230000Z 278ORGANIZER:mailto:user1.sabredav@sabredav.org 279ATTENDEE:mailto:user2.sabredav@sabredav.org 280END:VEVENT 281END:VCALENDAR 282ICS; 283 284 $this->calendarObjectUri = '/calendars/user1/inbox/foo.ics'; 285 $this->deliver($oldObject, $newObject); 286 $this->assertItemsInInbox('user2', 0); 287 288 } 289 290 function testReply() { 291 292 $oldObject = <<<ICS 293BEGIN:VCALENDAR 294BEGIN:VEVENT 295UID:foo 296DTSTART:20140811T230000Z 297ORGANIZER:mailto:user2.sabredav@sabredav.org 298ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2.sabredav@sabredav.org 299ATTENDEE:mailto:user1.sabredav@sabredav.org 300ATTENDEE:mailto:user3.sabredav@sabredav.org 301END:VEVENT 302END:VCALENDAR 303ICS; 304 305 $newObject = <<<ICS 306BEGIN:VCALENDAR 307BEGIN:VEVENT 308UID:foo 309DTSTART:20140811T230000Z 310ORGANIZER:mailto:user2.sabredav@sabredav.org 311ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2.sabredav@sabredav.org 312ATTENDEE;PARTSTAT=ACCEPTED:mailto:user1.sabredav@sabredav.org 313ATTENDEE:mailto:user3.sabredav@sabredav.org 314END:VEVENT 315END:VCALENDAR 316ICS; 317 318 $this->putPath('calendars/user2/cal/foo.ics', $oldObject); 319 320 $this->deliver($oldObject, $newObject); 321 $this->assertItemsInInbox('user2', 1); 322 $this->assertItemsInInbox('user1', 0); 323 324 $expected = <<<ICS 325BEGIN:VCALENDAR 326BEGIN:VEVENT 327UID:foo 328DTSTART:20140811T230000Z 329ORGANIZER;SCHEDULE-STATUS=1.2:mailto:user2.sabredav@sabredav.org 330ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2.sabredav@sabredav.org 331ATTENDEE;PARTSTAT=ACCEPTED:mailto:user1.sabredav@sabredav.org 332ATTENDEE:mailto:user3.sabredav@sabredav.org 333END:VEVENT 334END:VCALENDAR 335ICS; 336 337 $this->assertVObjEquals( 338 $expected, 339 $newObject 340 ); 341 342 } 343 344 345 346 function testInviteUnknownUser() { 347 348 $newObject = <<<ICS 349BEGIN:VCALENDAR 350BEGIN:VEVENT 351UID:foo 352DTSTART:20140811T230000Z 353ORGANIZER:mailto:user1.sabredav@sabredav.org 354ATTENDEE:mailto:user3.sabredav@sabredav.org 355END:VEVENT 356END:VCALENDAR 357ICS; 358 359 $this->deliver(null, $newObject); 360 361 $expected = <<<ICS 362BEGIN:VCALENDAR 363BEGIN:VEVENT 364UID:foo 365DTSTART:20140811T230000Z 366ORGANIZER:mailto:user1.sabredav@sabredav.org 367ATTENDEE;SCHEDULE-STATUS=3.7:mailto:user3.sabredav@sabredav.org 368END:VEVENT 369END:VCALENDAR 370ICS; 371 372 $this->assertVObjEquals( 373 $expected, 374 $newObject 375 ); 376 377 } 378 379 function testInviteNoInboxUrl() { 380 381 $newObject = <<<ICS 382BEGIN:VCALENDAR 383BEGIN:VEVENT 384UID:foo 385DTSTART:20140811T230000Z 386ORGANIZER:mailto:user1.sabredav@sabredav.org 387ATTENDEE:mailto:user2.sabredav@sabredav.org 388END:VEVENT 389END:VCALENDAR 390ICS; 391 392 $this->server->on('propFind', function($propFind) { 393 $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-inbox-URL', null, 403); 394 }); 395 $this->deliver(null, $newObject); 396 397 $expected = <<<ICS 398BEGIN:VCALENDAR 399BEGIN:VEVENT 400UID:foo 401DTSTART:20140811T230000Z 402ORGANIZER:mailto:user1.sabredav@sabredav.org 403ATTENDEE;SCHEDULE-STATUS=5.2:mailto:user2.sabredav@sabredav.org 404END:VEVENT 405END:VCALENDAR 406ICS; 407 408 $this->assertVObjEquals( 409 $expected, 410 $newObject 411 ); 412 413 } 414 415 function testInviteNoCalendarHomeSet() { 416 417 $newObject = <<<ICS 418BEGIN:VCALENDAR 419BEGIN:VEVENT 420UID:foo 421DTSTART:20140811T230000Z 422ORGANIZER:mailto:user1.sabredav@sabredav.org 423ATTENDEE:mailto:user2.sabredav@sabredav.org 424END:VEVENT 425END:VCALENDAR 426ICS; 427 428 $this->server->on('propFind', function($propFind) { 429 $propFind->set('{' . Plugin::NS_CALDAV . '}calendar-home-set', null, 403); 430 }); 431 $this->deliver(null, $newObject); 432 433 $expected = <<<ICS 434BEGIN:VCALENDAR 435BEGIN:VEVENT 436UID:foo 437DTSTART:20140811T230000Z 438ORGANIZER:mailto:user1.sabredav@sabredav.org 439ATTENDEE;SCHEDULE-STATUS=5.2:mailto:user2.sabredav@sabredav.org 440END:VEVENT 441END:VCALENDAR 442ICS; 443 444 $this->assertVObjEquals( 445 $expected, 446 $newObject 447 ); 448 449 } 450 function testInviteNoDefaultCalendar() { 451 452 $newObject = <<<ICS 453BEGIN:VCALENDAR 454BEGIN:VEVENT 455UID:foo 456DTSTART:20140811T230000Z 457ORGANIZER:mailto:user1.sabredav@sabredav.org 458ATTENDEE:mailto:user2.sabredav@sabredav.org 459END:VEVENT 460END:VCALENDAR 461ICS; 462 463 $this->server->on('propFind', function($propFind) { 464 $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-default-calendar-URL', null, 403); 465 }); 466 $this->deliver(null, $newObject); 467 468 $expected = <<<ICS 469BEGIN:VCALENDAR 470BEGIN:VEVENT 471UID:foo 472DTSTART:20140811T230000Z 473ORGANIZER:mailto:user1.sabredav@sabredav.org 474ATTENDEE;SCHEDULE-STATUS=5.2:mailto:user2.sabredav@sabredav.org 475END:VEVENT 476END:VCALENDAR 477ICS; 478 479 $this->assertVObjEquals( 480 $expected, 481 $newObject 482 ); 483 484 } 485 function testInviteNoScheduler() { 486 487 $newObject = <<<ICS 488BEGIN:VCALENDAR 489BEGIN:VEVENT 490UID:foo 491DTSTART:20140811T230000Z 492ORGANIZER:mailto:user1.sabredav@sabredav.org 493ATTENDEE:mailto:user2.sabredav@sabredav.org 494END:VEVENT 495END:VCALENDAR 496ICS; 497 498 $this->server->removeAllListeners('schedule'); 499 $this->deliver(null, $newObject); 500 501 $expected = <<<ICS 502BEGIN:VCALENDAR 503BEGIN:VEVENT 504UID:foo 505DTSTART:20140811T230000Z 506ORGANIZER:mailto:user1.sabredav@sabredav.org 507ATTENDEE;SCHEDULE-STATUS=5.2:mailto:user2.sabredav@sabredav.org 508END:VEVENT 509END:VCALENDAR 510ICS; 511 512 $this->assertVObjEquals( 513 $expected, 514 $newObject 515 ); 516 517 } 518 function testInviteNoACLPlugin() { 519 520 $this->setupACL = false; 521 parent::setUp(); 522 523 $newObject = <<<ICS 524BEGIN:VCALENDAR 525BEGIN:VEVENT 526UID:foo 527DTSTART:20140811T230000Z 528ORGANIZER:mailto:user1.sabredav@sabredav.org 529ATTENDEE:mailto:user2.sabredav@sabredav.org 530END:VEVENT 531END:VCALENDAR 532ICS; 533 534 $this->deliver(null, $newObject); 535 536 $expected = <<<ICS 537BEGIN:VCALENDAR 538BEGIN:VEVENT 539UID:foo 540DTSTART:20140811T230000Z 541ORGANIZER:mailto:user1.sabredav@sabredav.org 542ATTENDEE;SCHEDULE-STATUS=5.2:mailto:user2.sabredav@sabredav.org 543END:VEVENT 544END:VCALENDAR 545ICS; 546 547 $this->assertVObjEquals( 548 $expected, 549 $newObject 550 ); 551 552 } 553 554 protected $calendarObjectUri; 555 556 function deliver($oldObject, &$newObject, $disableScheduling = false) { 557 558 $this->server->httpRequest->setUrl($this->calendarObjectUri); 559 if ($disableScheduling) { 560 $this->server->httpRequest->setHeader('Schedule-Reply','F'); 561 } 562 563 if ($oldObject && $newObject) { 564 // update 565 $this->putPath($this->calendarObjectUri, $oldObject); 566 567 $stream = fopen('php://memory','r+'); 568 fwrite($stream, $newObject); 569 rewind($stream); 570 $modified = false; 571 572 $this->server->emit('beforeWriteContent', [ 573 $this->calendarObjectUri, 574 $this->server->tree->getNodeForPath($this->calendarObjectUri), 575 &$stream, 576 &$modified 577 ]); 578 if ($modified) { 579 $newObject = $stream; 580 } 581 582 } elseif ($oldObject && !$newObject) { 583 // delete 584 $this->putPath($this->calendarObjectUri, $oldObject); 585 586 $this->caldavSchedulePlugin->beforeUnbind( 587 $this->calendarObjectUri 588 ); 589 } else { 590 591 // create 592 $stream = fopen('php://memory','r+'); 593 fwrite($stream, $newObject); 594 rewind($stream); 595 $modified = false; 596 $this->server->emit('beforeCreateFile', [ 597 $this->calendarObjectUri, 598 &$stream, 599 $this->server->tree->getNodeForPath(dirname($this->calendarObjectUri)), 600 &$modified 601 ]); 602 603 if ($modified) { 604 $newObject = $stream; 605 } 606 } 607 608 } 609 610 611 /** 612 * Creates or updates a node at the specified path. 613 * 614 * This circumvents sabredav's internal server apis, so all events and 615 * access control is skipped. 616 * 617 * @param string $path 618 * @param string $data 619 * @return void 620 */ 621 function putPath($path, $data) { 622 623 list($parent, $base) = \Sabre\HTTP\UrlUtil::splitPath($path); 624 $parentNode = $this->server->tree->getNodeForPath($parent); 625 626 /* 627 if ($parentNode->childExists($base)) { 628 $childNode = $parentNode->getChild($base); 629 $childNode->put($data); 630 } else {*/ 631 $parentNode->createFile($base, $data); 632 //} 633 634 } 635 636 function assertItemsInInbox($user, $count) { 637 638 $inboxNode = $this->server->tree->getNodeForPath('calendars/'.$user.'/inbox'); 639 $this->assertEquals($count, count($inboxNode->getChildren())); 640 641 } 642 643 function assertVObjEquals($expected, $actual) { 644 645 $format = function($data) { 646 647 $data = trim($data, "\r\n"); 648 $data = str_replace("\r","", $data); 649 // Unfolding lines. 650 $data = str_replace("\n ", "", $data); 651 652 return $data; 653 654 }; 655 656 $this->assertEquals( 657 $format($expected), 658 $format($actual) 659 ); 660 661 } 662 663} 664 665