1<?php
2
3namespace Sabre\CalDAV;
4
5use
6    Sabre\DAVACL,
7    Sabre\DAV,
8    Sabre\HTTP,
9    DateTime,
10    DateTimeZone;
11
12class PluginTest extends \PHPUnit_Framework_TestCase {
13
14    /**
15     * @var DAV\Server
16     */
17    protected $server;
18    /**
19     * @var Plugin
20     */
21    protected $plugin;
22    protected $response;
23    /**
24     * @var Backend\PDO
25     */
26    protected $caldavBackend;
27
28    function setup() {
29
30        $this->caldavBackend = new Backend\Mock(array(
31            array(
32                'id' => 1,
33                'uri' => 'UUID-123467',
34                'principaluri' => 'principals/user1',
35                '{DAV:}displayname' => 'user1 calendar',
36                '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
37                '{http://apple.com/ns/ical/}calendar-order' => '1',
38                '{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
39                '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VEVENT','VTODO']),
40            ),
41            array(
42                'id' => 2,
43                'uri' => 'UUID-123468',
44                'principaluri' => 'principals/user1',
45                '{DAV:}displayname' => 'user1 calendar2',
46                '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
47                '{http://apple.com/ns/ical/}calendar-order' => '1',
48                '{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
49                '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VEVENT','VTODO']),
50            )
51        ), array(
52            1 => array(
53                'UUID-2345' => array(
54                    'calendardata' => TestUtil::getTestCalendarData(),
55                )
56            )
57        ));
58        $principalBackend = new DAVACL\PrincipalBackend\Mock();
59        $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read',array('principals/user1'));
60        $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write',array('principals/user1'));
61        $principalBackend->addPrincipal(array(
62            'uri' => 'principals/admin/calendar-proxy-read',
63        ));
64        $principalBackend->addPrincipal(array(
65            'uri' => 'principals/admin/calendar-proxy-write',
66        ));
67
68        $calendars = new CalendarRoot($principalBackend,$this->caldavBackend);
69        $principals = new Principal\Collection($principalBackend);
70
71        $root = new DAV\SimpleCollection('root');
72        $root->addChild($calendars);
73        $root->addChild($principals);
74
75        $this->server = new DAV\Server($root);
76        $this->server->sapi = new HTTP\SapiMock();
77        $this->server->debugExceptions = true;
78        $this->server->setBaseUri('/');
79        $this->plugin = new Plugin();
80        $this->server->addPlugin($this->plugin);
81
82        // Adding ACL plugin
83        $this->server->addPlugin(new DAVACL\Plugin());
84
85        // Adding Auth plugin, and ensuring that we are logged in.
86        $authBackend = new DAV\Auth\Backend\Mock();
87        $authBackend->setPrincipal('principals/user1');
88        $authPlugin = new DAV\Auth\Plugin($authBackend, 'SabreDAV');
89        $authPlugin->beforeMethod(new \Sabre\HTTP\Request(), new \Sabre\HTTP\Response());
90        $this->server->addPlugin($authPlugin);
91
92        // This forces a login
93        $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response());
94
95        $this->response = new HTTP\ResponseMock();
96        $this->server->httpResponse = $this->response;
97
98    }
99
100    function testSimple() {
101
102        $this->assertEquals(array('MKCALENDAR'), $this->plugin->getHTTPMethods('calendars/user1/randomnewcalendar'));
103        $this->assertEquals(array('calendar-access','calendar-proxy'), $this->plugin->getFeatures());
104        $this->assertEquals(
105            'caldav',
106            $this->plugin->getPluginInfo()['name']
107        );
108
109    }
110
111    function testUnknownMethodPassThrough() {
112
113        $request = HTTP\Sapi::createFromServerArray(array(
114            'REQUEST_METHOD' => 'MKBREAKFAST',
115            'REQUEST_URI'    => '/',
116        ));
117
118        $this->server->httpRequest = $request;
119        $this->server->exec();
120
121        $this->assertEquals(501, $this->response->status,'Incorrect status returned. Full response body:' . $this->response->body);
122
123    }
124
125    function testReportPassThrough() {
126
127        $request = HTTP\Sapi::createFromServerArray(array(
128            'REQUEST_METHOD'    => 'REPORT',
129            'HTTP_CONTENT_TYPE' => 'application/xml',
130            'REQUEST_URI'       => '/',
131        ));
132        $request->setBody('<?xml version="1.0"?><s:somereport xmlns:s="http://www.rooftopsolutions.nl/NS/example" />');
133
134        $this->server->httpRequest = $request;
135        $this->server->exec();
136
137        $this->assertEquals(415, $this->response->status);
138
139    }
140
141    function testMkCalendarBadLocation() {
142
143        $request = HTTP\Sapi::createFromServerArray(array(
144            'REQUEST_METHOD' => 'MKCALENDAR',
145            'REQUEST_URI'    => '/blabla',
146        ));
147
148        $body = '<?xml version="1.0" encoding="utf-8" ?>
149   <C:mkcalendar xmlns:D="DAV:"
150                 xmlns:C="urn:ietf:params:xml:ns:caldav">
151     <D:set>
152       <D:prop>
153         <D:displayname>Lisa\'s Events</D:displayname>
154         <C:calendar-description xml:lang="en"
155   >Calendar restricted to events.</C:calendar-description>
156         <C:supported-calendar-component-set>
157           <C:comp name="VEVENT"/>
158         </C:supported-calendar-component-set>
159         <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
160   PRODID:-//Example Corp.//CalDAV Client//EN
161   VERSION:2.0
162   BEGIN:VTIMEZONE
163   TZID:US-Eastern
164   LAST-MODIFIED:19870101T000000Z
165   BEGIN:STANDARD
166   DTSTART:19671029T020000
167   RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
168   TZOFFSETFROM:-0400
169   TZOFFSETTO:-0500
170   TZNAME:Eastern Standard Time (US & Canada)
171   END:STANDARD
172   BEGIN:DAYLIGHT
173   DTSTART:19870405T020000
174   RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
175   TZOFFSETFROM:-0500
176   TZOFFSETTO:-0400
177   TZNAME:Eastern Daylight Time (US & Canada)
178   END:DAYLIGHT
179   END:VTIMEZONE
180   END:VCALENDAR
181   ]]></C:calendar-timezone>
182       </D:prop>
183     </D:set>
184   </C:mkcalendar>';
185
186        $request->setBody($body);
187        $this->server->httpRequest = $request;
188        $this->server->exec();
189
190        $this->assertEquals(403, $this->response->status);
191
192    }
193
194    function testMkCalendarNoParentNode() {
195
196        $request = HTTP\Sapi::createFromServerArray(array(
197            'REQUEST_METHOD' => 'MKCALENDAR',
198            'REQUEST_URI'    => '/doesntexist/calendar',
199        ));
200
201        $body = '<?xml version="1.0" encoding="utf-8" ?>
202   <C:mkcalendar xmlns:D="DAV:"
203                 xmlns:C="urn:ietf:params:xml:ns:caldav">
204     <D:set>
205       <D:prop>
206         <D:displayname>Lisa\'s Events</D:displayname>
207         <C:calendar-description xml:lang="en"
208   >Calendar restricted to events.</C:calendar-description>
209         <C:supported-calendar-component-set>
210           <C:comp name="VEVENT"/>
211         </C:supported-calendar-component-set>
212         <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
213   PRODID:-//Example Corp.//CalDAV Client//EN
214   VERSION:2.0
215   BEGIN:VTIMEZONE
216   TZID:US-Eastern
217   LAST-MODIFIED:19870101T000000Z
218   BEGIN:STANDARD
219   DTSTART:19671029T020000
220   RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
221   TZOFFSETFROM:-0400
222   TZOFFSETTO:-0500
223   TZNAME:Eastern Standard Time (US & Canada)
224   END:STANDARD
225   BEGIN:DAYLIGHT
226   DTSTART:19870405T020000
227   RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
228   TZOFFSETFROM:-0500
229   TZOFFSETTO:-0400
230   TZNAME:Eastern Daylight Time (US & Canada)
231   END:DAYLIGHT
232   END:VTIMEZONE
233   END:VCALENDAR
234   ]]></C:calendar-timezone>
235       </D:prop>
236     </D:set>
237   </C:mkcalendar>';
238
239        $request->setBody($body);
240        $this->server->httpRequest = $request;
241        $this->server->exec();
242
243        $this->assertEquals(409, $this->response->status);
244
245    }
246
247    function testMkCalendarExistingCalendar() {
248
249        $request = HTTP\Sapi::createFromServerArray(array(
250            'REQUEST_METHOD' => 'MKCALENDAR',
251            'REQUEST_URI'    => '/calendars/user1/UUID-123467',
252        ));
253
254        $body = '<?xml version="1.0" encoding="utf-8" ?>
255   <C:mkcalendar xmlns:D="DAV:"
256                 xmlns:C="urn:ietf:params:xml:ns:caldav">
257     <D:set>
258       <D:prop>
259         <D:displayname>Lisa\'s Events</D:displayname>
260         <C:calendar-description xml:lang="en"
261   >Calendar restricted to events.</C:calendar-description>
262         <C:supported-calendar-component-set>
263           <C:comp name="VEVENT"/>
264         </C:supported-calendar-component-set>
265         <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
266   PRODID:-//Example Corp.//CalDAV Client//EN
267   VERSION:2.0
268   BEGIN:VTIMEZONE
269   TZID:US-Eastern
270   LAST-MODIFIED:19870101T000000Z
271   BEGIN:STANDARD
272   DTSTART:19671029T020000
273   RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
274   TZOFFSETFROM:-0400
275   TZOFFSETTO:-0500
276   TZNAME:Eastern Standard Time (US & Canada)
277   END:STANDARD
278   BEGIN:DAYLIGHT
279   DTSTART:19870405T020000
280   RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
281   TZOFFSETFROM:-0500
282   TZOFFSETTO:-0400
283   TZNAME:Eastern Daylight Time (US & Canada)
284   END:DAYLIGHT
285   END:VTIMEZONE
286   END:VCALENDAR
287   ]]></C:calendar-timezone>
288       </D:prop>
289     </D:set>
290   </C:mkcalendar>';
291
292        $request->setBody($body);
293        $this->server->httpRequest = $request;
294        $this->server->exec();
295
296        $this->assertEquals(405, $this->response->status);
297
298    }
299
300    function testMkCalendarSucceed() {
301
302        $request = HTTP\Sapi::createFromServerArray(array(
303            'REQUEST_METHOD' => 'MKCALENDAR',
304            'REQUEST_URI'    => '/calendars/user1/NEWCALENDAR',
305        ));
306
307        $timezone = 'BEGIN:VCALENDAR
308PRODID:-//Example Corp.//CalDAV Client//EN
309VERSION:2.0
310BEGIN:VTIMEZONE
311TZID:US-Eastern
312LAST-MODIFIED:19870101T000000Z
313BEGIN:STANDARD
314DTSTART:19671029T020000
315RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
316TZOFFSETFROM:-0400
317TZOFFSETTO:-0500
318TZNAME:Eastern Standard Time (US & Canada)
319END:STANDARD
320BEGIN:DAYLIGHT
321DTSTART:19870405T020000
322RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
323TZOFFSETFROM:-0500
324TZOFFSETTO:-0400
325TZNAME:Eastern Daylight Time (US & Canada)
326END:DAYLIGHT
327END:VTIMEZONE
328END:VCALENDAR';
329
330        $body = '<?xml version="1.0" encoding="utf-8" ?>
331   <C:mkcalendar xmlns:D="DAV:"
332                 xmlns:C="urn:ietf:params:xml:ns:caldav">
333     <D:set>
334       <D:prop>
335         <D:displayname>Lisa\'s Events</D:displayname>
336         <C:calendar-description xml:lang="en"
337   >Calendar restricted to events.</C:calendar-description>
338         <C:supported-calendar-component-set>
339           <C:comp name="VEVENT"/>
340         </C:supported-calendar-component-set>
341         <C:calendar-timezone><![CDATA[' . $timezone . ']]></C:calendar-timezone>
342       </D:prop>
343     </D:set>
344   </C:mkcalendar>';
345
346        $request->setBody($body);
347        $this->server->httpRequest = $request;
348        $this->server->exec();
349
350        $this->assertEquals(201, $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body);
351
352        $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
353        $this->assertEquals(3, count($calendars));
354
355        $newCalendar = null;
356        foreach($calendars as $calendar) {
357           if ($calendar['uri'] === 'NEWCALENDAR') {
358                $newCalendar = $calendar;
359                break;
360           }
361        }
362
363        $this->assertInternalType('array',$newCalendar);
364
365        $keys = array(
366            'uri' => 'NEWCALENDAR',
367            'id' => null,
368            '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar restricted to events.',
369            '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => $timezone,
370            '{DAV:}displayname' => 'Lisa\'s Events',
371            '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null,
372        );
373
374        foreach($keys as $key=>$value) {
375
376            $this->assertArrayHasKey($key, $newCalendar);
377
378            if (is_null($value)) continue;
379            $this->assertEquals($value, $newCalendar[$key]);
380
381        }
382        $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
383        $this->assertTrue($newCalendar[$sccs] instanceof Xml\Property\SupportedCalendarComponentSet);
384        $this->assertEquals(array('VEVENT'),$newCalendar[$sccs]->getValue());
385
386    }
387
388    function testMkCalendarEmptyBodySucceed() {
389
390        $request = HTTP\Sapi::createFromServerArray(array(
391            'REQUEST_METHOD' => 'MKCALENDAR',
392            'REQUEST_URI'    => '/calendars/user1/NEWCALENDAR',
393        ));
394
395        $request->setBody('');
396        $this->server->httpRequest = $request;
397        $this->server->exec();
398
399        $this->assertEquals(201, $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body);
400
401        $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
402        $this->assertEquals(3, count($calendars));
403
404        $newCalendar = null;
405        foreach($calendars as $calendar) {
406           if ($calendar['uri'] === 'NEWCALENDAR') {
407                $newCalendar = $calendar;
408                break;
409           }
410        }
411
412        $this->assertInternalType('array',$newCalendar);
413
414        $keys = array(
415            'uri' => 'NEWCALENDAR',
416            'id' => null,
417            '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null,
418        );
419
420        foreach($keys as $key=>$value) {
421
422            $this->assertArrayHasKey($key, $newCalendar);
423
424            if (is_null($value)) continue;
425            $this->assertEquals($value, $newCalendar[$key]);
426
427        }
428        $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
429        $this->assertTrue($newCalendar[$sccs] instanceof Xml\Property\SupportedCalendarComponentSet);
430        $this->assertEquals(array('VEVENT','VTODO'),$newCalendar[$sccs]->getValue());
431
432    }
433
434    function testMkCalendarBadXml() {
435
436        $request = HTTP\Sapi::createFromServerArray(array(
437            'REQUEST_METHOD' => 'MKCALENDAR',
438            'REQUEST_URI'    => '/blabla',
439        ));
440
441        $body = 'This is not xml';
442
443        $request->setBody($body);
444        $this->server->httpRequest = $request;
445        $this->server->exec();
446
447        $this->assertEquals(400, $this->response->status);
448
449    }
450
451    function testPrincipalProperties() {
452
453        $httpRequest = HTTP\Sapi::createFromServerArray(array(
454            'HTTP_HOST' => 'sabredav.org',
455        ));
456        $this->server->httpRequest = $httpRequest;
457
458        $props = $this->server->getPropertiesForPath('/principals/user1',array(
459            '{' . Plugin::NS_CALDAV . '}calendar-home-set',
460            '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for',
461            '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for',
462            '{' . Plugin::NS_CALENDARSERVER . '}notification-URL',
463            '{' . Plugin::NS_CALENDARSERVER . '}email-address-set',
464        ));
465
466        $this->assertArrayHasKey(0,$props);
467        $this->assertArrayHasKey(200,$props[0]);
468
469
470        $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-home-set',$props[0][200]);
471        $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-home-set'];
472        $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop);
473        $this->assertEquals('calendars/user1/',$prop->getHref());
474
475        $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-read-for', $props[0][200]);
476        $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-read-for'];
477        $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop);
478        $this->assertEquals(array('principals/admin/'), $prop->getHrefs());
479
480        $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-write-for', $props[0][200]);
481        $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-write-for'];
482        $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop);
483        $this->assertEquals(array('principals/admin/'), $prop->getHrefs());
484
485        $this->assertArrayHasKey('{' . Plugin::NS_CALENDARSERVER . '}email-address-set',$props[0][200]);
486        $prop = $props[0][200]['{' . Plugin::NS_CALENDARSERVER . '}email-address-set'];
487        $this->assertInstanceOf('Sabre\\CalDAV\\Xml\\Property\\EmailAddressSet', $prop);
488        $this->assertEquals(['user1.sabredav@sabredav.org'],$prop->getValue());
489
490    }
491
492    function testSupportedReportSetPropertyNonCalendar() {
493
494        $props = $this->server->getPropertiesForPath('/calendars/user1',array(
495            '{DAV:}supported-report-set',
496        ));
497
498        $this->assertArrayHasKey(0,$props);
499        $this->assertArrayHasKey(200,$props[0]);
500        $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
501
502        $prop = $props[0][200]['{DAV:}supported-report-set'];
503
504        $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop);
505        $value = array(
506            '{DAV:}expand-property',
507            '{DAV:}principal-property-search',
508            '{DAV:}principal-search-property-set'
509        );
510        $this->assertEquals($value,$prop->getValue());
511
512    }
513
514    /**
515     * @depends testSupportedReportSetPropertyNonCalendar
516     */
517    function testSupportedReportSetProperty() {
518
519        $props = $this->server->getPropertiesForPath('/calendars/user1/UUID-123467',array(
520            '{DAV:}supported-report-set',
521        ));
522
523        $this->assertArrayHasKey(0,$props);
524        $this->assertArrayHasKey(200,$props[0]);
525        $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
526
527        $prop = $props[0][200]['{DAV:}supported-report-set'];
528
529        $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop);
530        $value = array(
531            '{urn:ietf:params:xml:ns:caldav}calendar-multiget',
532            '{urn:ietf:params:xml:ns:caldav}calendar-query',
533            '{urn:ietf:params:xml:ns:caldav}free-busy-query',
534            '{DAV:}expand-property',
535            '{DAV:}principal-property-search',
536            '{DAV:}principal-search-property-set'
537        );
538        $this->assertEquals($value,$prop->getValue());
539
540    }
541
542    function testSupportedReportSetUserCalendars() {
543
544        $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
545
546        $props = $this->server->getPropertiesForPath('/calendars/user1',array(
547            '{DAV:}supported-report-set',
548        ));
549
550        $this->assertArrayHasKey(0,$props);
551        $this->assertArrayHasKey(200,$props[0]);
552        $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
553
554        $prop = $props[0][200]['{DAV:}supported-report-set'];
555
556        $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop);
557        $value = array(
558            '{DAV:}sync-collection',
559            '{DAV:}expand-property',
560            '{DAV:}principal-property-search',
561            '{DAV:}principal-search-property-set',
562        );
563        $this->assertEquals($value,$prop->getValue());
564
565    }
566
567    /**
568     * @depends testSupportedReportSetProperty
569     */
570    function testCalendarMultiGetReport() {
571
572        $body =
573            '<?xml version="1.0"?>' .
574            '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
575            '<d:prop>' .
576            '  <c:calendar-data />' .
577            '  <d:getetag />' .
578            '</d:prop>' .
579            '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
580            '</c:calendar-multiget>';
581
582        $request = HTTP\Sapi::createFromServerArray(array(
583            'REQUEST_METHOD' => 'REPORT',
584            'REQUEST_URI'    => '/calendars/user1',
585            'HTTP_DEPTH'     => '1',
586        ));
587        $request->setBody($body);
588
589        $this->server->httpRequest = $request;
590        $this->server->exec();
591
592        $this->assertEquals(207, $this->response->status,'Invalid HTTP status received. Full response body');
593
594        $expectedIcal = TestUtil::getTestCalendarData();
595
596        $expected = <<<XML
597<?xml version="1.0"?>
598<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
599<d:response>
600  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
601  <d:propstat>
602    <d:prop>
603      <cal:calendar-data>$expectedIcal</cal:calendar-data>
604      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
605    </d:prop>
606    <d:status>HTTP/1.1 200 OK</d:status>
607  </d:propstat>
608</d:response>
609</d:multistatus>
610XML;
611
612        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
613
614    }
615
616    /**
617     * @depends testCalendarMultiGetReport
618     */
619    function testCalendarMultiGetReportExpand() {
620
621        $body =
622            '<?xml version="1.0"?>' .
623            '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
624            '<d:prop>' .
625            '  <c:calendar-data>' .
626            '     <c:expand start="20110101T000000Z" end="20111231T235959Z" />' .
627            '  </c:calendar-data>' .
628            '  <d:getetag />' .
629            '</d:prop>' .
630            '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
631            '</c:calendar-multiget>';
632
633        $request = HTTP\Sapi::createFromServerArray(array(
634            'REQUEST_METHOD' => 'REPORT',
635            'REQUEST_URI'    => '/calendars/user1',
636            'HTTP_DEPTH'     => '1',
637        ));
638        $request->setBody($body);
639
640        $this->server->httpRequest = $request;
641        $this->server->exec();
642
643        $this->assertEquals(207, $this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
644
645        $expectedIcal = TestUtil::getTestCalendarData();
646        $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal);
647        $expectedIcal->expand(
648            new DateTime('2011-01-01 00:00:00', new DateTimeZone('UTC')),
649            new DateTime('2011-12-31 23:59:59', new DateTimeZone('UTC'))
650        );
651        $expectedIcal = str_replace("\r\n", "&#xD;\n", $expectedIcal->serialize());
652
653        $expected = <<<XML
654<?xml version="1.0"?>
655<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
656<d:response>
657  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
658  <d:propstat>
659    <d:prop>
660      <cal:calendar-data>$expectedIcal</cal:calendar-data>
661      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
662    </d:prop>
663    <d:status>HTTP/1.1 200 OK</d:status>
664  </d:propstat>
665</d:response>
666</d:multistatus>
667XML;
668
669        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
670
671    }
672
673    /**
674     * @depends testSupportedReportSetProperty
675     * @depends testCalendarMultiGetReport
676     */
677    function testCalendarQueryReport() {
678
679        $body =
680            '<?xml version="1.0"?>' .
681            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
682            '<d:prop>' .
683            '  <c:calendar-data>' .
684            '     <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
685            '  </c:calendar-data>' .
686            '  <d:getetag />' .
687            '</d:prop>' .
688            '<c:filter>' .
689            '  <c:comp-filter name="VCALENDAR">' .
690            '    <c:comp-filter name="VEVENT" />' .
691            '  </c:comp-filter>' .
692            '</c:filter>' .
693            '</c:calendar-query>';
694
695        $request = HTTP\Sapi::createFromServerArray(array(
696            'REQUEST_METHOD' => 'REPORT',
697            'REQUEST_URI'    => '/calendars/user1/UUID-123467',
698            'HTTP_DEPTH'     => '1',
699        ));
700        $request->setBody($body);
701
702        $this->server->httpRequest = $request;
703        $this->server->exec();
704
705        $this->assertEquals(207, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
706
707        $expectedIcal = TestUtil::getTestCalendarData();
708        $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal);
709        $expectedIcal->expand(
710            new DateTime('2000-01-01 00:00:00', new DateTimeZone('UTC')),
711            new DateTime('2010-12-31 23:59:59', new DateTimeZone('UTC'))
712        );
713        $expectedIcal = str_replace("\r\n", "&#xD;\n", $expectedIcal->serialize());
714
715        $expected = <<<XML
716<?xml version="1.0"?>
717<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
718<d:response>
719  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
720  <d:propstat>
721    <d:prop>
722      <cal:calendar-data>$expectedIcal</cal:calendar-data>
723      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
724    </d:prop>
725    <d:status>HTTP/1.1 200 OK</d:status>
726  </d:propstat>
727</d:response>
728</d:multistatus>
729XML;
730
731        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
732
733    }
734
735    /**
736     * @depends testSupportedReportSetProperty
737     * @depends testCalendarMultiGetReport
738     */
739    function testCalendarQueryReportWindowsPhone() {
740
741        $body =
742            '<?xml version="1.0"?>' .
743            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
744            '<d:prop>' .
745            '  <c:calendar-data>' .
746            '     <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
747            '  </c:calendar-data>' .
748            '  <d:getetag />' .
749            '</d:prop>' .
750            '<c:filter>' .
751            '  <c:comp-filter name="VCALENDAR">' .
752            '    <c:comp-filter name="VEVENT" />' .
753            '  </c:comp-filter>' .
754            '</c:filter>' .
755            '</c:calendar-query>';
756
757        $request = HTTP\Sapi::createFromServerArray(array(
758            'REQUEST_METHOD'  => 'REPORT',
759            'REQUEST_URI'     => '/calendars/user1/UUID-123467',
760            'HTTP_USER_AGENT' => 'MSFT-WP/8.10.14219 (gzip)',
761            'HTTP_DEPTH'      => '0',
762        ));
763        $request->setBody($body);
764
765        $this->server->httpRequest = $request;
766        $this->server->exec();
767
768        $this->assertEquals(207, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
769
770        $expectedIcal = TestUtil::getTestCalendarData();
771        $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal);
772        $expectedIcal->expand(
773            new \DateTime('2000-01-01 00:00:00', new \DateTimeZone('UTC')),
774            new \DateTime('2010-12-31 23:59:59', new \DateTimeZone('UTC'))
775        );
776        $expectedIcal = str_replace("\r\n", "&#xD;\n", $expectedIcal->serialize());
777
778        $expected = <<<XML
779<?xml version="1.0"?>
780<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
781<d:response>
782  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
783  <d:propstat>
784    <d:prop>
785      <cal:calendar-data>$expectedIcal</cal:calendar-data>
786      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
787    </d:prop>
788    <d:status>HTTP/1.1 200 OK</d:status>
789  </d:propstat>
790</d:response>
791</d:multistatus>
792XML;
793
794        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
795
796    }
797
798    /**
799     * @depends testSupportedReportSetProperty
800     * @depends testCalendarMultiGetReport
801     */
802    function testCalendarQueryReportBadDepth() {
803
804        $body =
805            '<?xml version="1.0"?>' .
806            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
807            '<d:prop>' .
808            '  <c:calendar-data>' .
809            '     <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
810            '  </c:calendar-data>' .
811            '  <d:getetag />' .
812            '</d:prop>' .
813            '<c:filter>' .
814            '  <c:comp-filter name="VCALENDAR">' .
815            '    <c:comp-filter name="VEVENT" />' .
816            '  </c:comp-filter>' .
817            '</c:filter>' .
818            '</c:calendar-query>';
819
820        $request = HTTP\Sapi::createFromServerArray(array(
821            'REQUEST_METHOD' => 'REPORT',
822            'REQUEST_URI'    => '/calendars/user1/UUID-123467',
823            'HTTP_DEPTH'     => '0',
824        ));
825        $request->setBody($body);
826
827        $this->server->httpRequest = $request;
828        $this->server->exec();
829
830        $this->assertEquals(400, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
831
832    }
833
834    /**
835     * @depends testCalendarQueryReport
836     */
837    function testCalendarQueryReportNoCalData() {
838
839        $body =
840            '<?xml version="1.0"?>' .
841            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
842            '<d:prop>' .
843            '  <d:getetag />' .
844            '</d:prop>' .
845            '<c:filter>' .
846            '  <c:comp-filter name="VCALENDAR">' .
847            '    <c:comp-filter name="VEVENT" />' .
848            '  </c:comp-filter>' .
849            '</c:filter>' .
850            '</c:calendar-query>';
851
852        $request = HTTP\Sapi::createFromServerArray(array(
853            'REQUEST_METHOD' => 'REPORT',
854            'REQUEST_URI'    => '/calendars/user1//UUID-123467',
855            'HTTP_DEPTH'     => '1',
856        ));
857        $request->setBody($body);
858
859        $this->server->httpRequest = $request;
860        $this->server->exec();
861
862        $this->assertEquals(207, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
863
864        $expected = <<<XML
865<?xml version="1.0"?>
866<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
867<d:response>
868  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
869  <d:propstat>
870    <d:prop>
871      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
872    </d:prop>
873    <d:status>HTTP/1.1 200 OK</d:status>
874  </d:propstat>
875</d:response>
876</d:multistatus>
877XML;
878
879        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
880
881    }
882
883    /**
884     * @depends testCalendarQueryReport
885     */
886    function testCalendarQueryReportNoFilters() {
887
888        $body =
889            '<?xml version="1.0"?>' .
890            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
891            '<d:prop>' .
892            '  <c:calendar-data />' .
893            '  <d:getetag />' .
894            '</d:prop>' .
895            '</c:calendar-query>';
896
897        $request = HTTP\Sapi::createFromServerArray(array(
898            'REQUEST_METHOD' => 'REPORT',
899            'REQUEST_URI'    => '/calendars/user1//UUID-123467',
900        ));
901        $request->setBody($body);
902
903        $this->server->httpRequest = $request;
904        $this->server->exec();
905
906        $this->assertEquals(400, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
907
908    }
909
910    /**
911     * @depends testSupportedReportSetProperty
912     * @depends testCalendarMultiGetReport
913     */
914    function testCalendarQueryReport1Object() {
915
916        $body =
917            '<?xml version="1.0"?>' .
918            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
919            '<d:prop>' .
920            '  <c:calendar-data>' .
921            '     <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
922            '  </c:calendar-data>' .
923            '  <d:getetag />' .
924            '</d:prop>' .
925            '<c:filter>' .
926            '  <c:comp-filter name="VCALENDAR">' .
927            '    <c:comp-filter name="VEVENT" />' .
928            '  </c:comp-filter>' .
929            '</c:filter>' .
930            '</c:calendar-query>';
931
932        $request = HTTP\Sapi::createFromServerArray(array(
933            'REQUEST_METHOD' => 'REPORT',
934            'REQUEST_URI'    => '/calendars/user1/UUID-123467/UUID-2345',
935            'HTTP_DEPTH'     => '0',
936        ));
937        $request->setBody($body);
938
939        $this->server->httpRequest = $request;
940        $this->server->exec();
941
942        $this->assertEquals(207, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
943
944        $expectedIcal = TestUtil::getTestCalendarData();
945        $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal);
946        $expectedIcal->expand(
947            new DateTime('2000-01-01 00:00:00', new DateTimeZone('UTC')),
948            new DateTime('2010-12-31 23:59:59', new DateTimeZone('UTC'))
949        );
950        $expectedIcal = str_replace("\r\n", "&#xD;\n", $expectedIcal->serialize());
951
952        $expected = <<<XML
953<?xml version="1.0"?>
954<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
955<d:response>
956  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
957  <d:propstat>
958    <d:prop>
959      <cal:calendar-data>$expectedIcal</cal:calendar-data>
960      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
961    </d:prop>
962    <d:status>HTTP/1.1 200 OK</d:status>
963  </d:propstat>
964</d:response>
965</d:multistatus>
966XML;
967
968        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
969
970    }
971
972    /**
973     * @depends testSupportedReportSetProperty
974     * @depends testCalendarMultiGetReport
975     */
976    function testCalendarQueryReport1ObjectNoCalData() {
977
978        $body =
979            '<?xml version="1.0"?>' .
980            '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
981            '<d:prop>' .
982            '  <d:getetag />' .
983            '</d:prop>' .
984            '<c:filter>' .
985            '  <c:comp-filter name="VCALENDAR">' .
986            '    <c:comp-filter name="VEVENT" />' .
987            '  </c:comp-filter>' .
988            '</c:filter>' .
989            '</c:calendar-query>';
990
991        $request = HTTP\Sapi::createFromServerArray(array(
992            'REQUEST_METHOD' => 'REPORT',
993            'REQUEST_URI'    => '/calendars/user1/UUID-123467/UUID-2345',
994            'HTTP_DEPTH'     => '0',
995        ));
996        $request->setBody($body);
997
998        $this->server->httpRequest = $request;
999        $this->server->exec();
1000
1001        $this->assertEquals(207, $this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
1002
1003        $expected = <<<XML
1004<?xml version="1.0"?>
1005<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
1006<d:response>
1007  <d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>
1008  <d:propstat>
1009    <d:prop>
1010      <d:getetag>"e207e33c10e5fb9c12cfb35b5d9116e1"</d:getetag>
1011    </d:prop>
1012    <d:status>HTTP/1.1 200 OK</d:status>
1013  </d:propstat>
1014</d:response>
1015</d:multistatus>
1016XML;
1017
1018        $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString());
1019
1020    }
1021
1022    function testHTMLActionsPanel() {
1023
1024        $output = '';
1025        $r = $this->server->emit('onHTMLActionsPanel', [$this->server->tree->getNodeForPath('calendars/user1'), &$output]);
1026        $this->assertFalse($r);
1027
1028        $this->assertTrue(!!strpos($output,'Display name'));
1029
1030    }
1031
1032    /**
1033     * @depends testCalendarMultiGetReport
1034     */
1035    function testCalendarMultiGetReportNoEnd() {
1036
1037        $body =
1038            '<?xml version="1.0"?>' .
1039            '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
1040            '<d:prop>' .
1041            '  <c:calendar-data>' .
1042            '     <c:expand start="20110101T000000Z" />' .
1043            '  </c:calendar-data>' .
1044            '  <d:getetag />' .
1045            '</d:prop>' .
1046            '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
1047            '</c:calendar-multiget>';
1048
1049        $request = HTTP\Sapi::createFromServerArray(array(
1050            'REQUEST_METHOD' => 'REPORT',
1051            'REQUEST_URI'    => '/calendars/user1',
1052            'HTTP_DEPTH'     => '1',
1053        ));
1054        $request->setBody($body);
1055
1056        $this->server->httpRequest = $request;
1057        $this->server->exec();
1058
1059        $this->assertEquals(400, $this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
1060
1061    }
1062
1063    /**
1064     * @depends testCalendarMultiGetReport
1065     */
1066    function testCalendarMultiGetReportNoStart() {
1067
1068        $body =
1069            '<?xml version="1.0"?>' .
1070            '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
1071            '<d:prop>' .
1072            '  <c:calendar-data>' .
1073            '     <c:expand end="20110101T000000Z" />' .
1074            '  </c:calendar-data>' .
1075            '  <d:getetag />' .
1076            '</d:prop>' .
1077            '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
1078            '</c:calendar-multiget>';
1079
1080        $request = HTTP\Sapi::createFromServerArray(array(
1081            'REQUEST_METHOD' => 'REPORT',
1082            'REQUEST_URI'    => '/calendars/user1',
1083            'HTTP_DEPTH'     => '1',
1084        ));
1085        $request->setBody($body);
1086
1087        $this->server->httpRequest = $request;
1088        $this->server->exec();
1089
1090        $this->assertEquals(400, $this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
1091
1092    }
1093
1094    /**
1095     * @depends testCalendarMultiGetReport
1096     */
1097    function testCalendarMultiGetReportEndBeforeStart() {
1098
1099        $body =
1100            '<?xml version="1.0"?>' .
1101            '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
1102            '<d:prop>' .
1103            '  <c:calendar-data>' .
1104            '     <c:expand start="20200101T000000Z" end="20110101T000000Z" />' .
1105            '  </c:calendar-data>' .
1106            '  <d:getetag />' .
1107            '</d:prop>' .
1108            '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
1109            '</c:calendar-multiget>';
1110
1111        $request = HTTP\Sapi::createFromServerArray(array(
1112            'REQUEST_METHOD' => 'REPORT',
1113            'REQUEST_URI'    => '/calendars/user1',
1114            'HTTP_DEPTH'     => '1',
1115        ));
1116        $request->setBody($body);
1117
1118        $this->server->httpRequest = $request;
1119        $this->server->exec();
1120
1121        $this->assertEquals(400, $this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
1122
1123    }
1124
1125    /**
1126     * @depends testSupportedReportSetPropertyNonCalendar
1127     */
1128    function testCalendarProperties() {
1129
1130        $ns = '{urn:ietf:params:xml:ns:caldav}';
1131        $props = $this->server->getProperties('calendars/user1/UUID-123467', [
1132            $ns . 'max-resource-size',
1133            $ns . 'supported-calendar-data',
1134            $ns . 'supported-collation-set',
1135        ]);
1136
1137        $this->assertEquals([
1138            $ns . 'max-resource-size' => 10000000,
1139            $ns . 'supported-calendar-data' => new Xml\Property\SupportedCalendarData(),
1140            $ns . 'supported-collation-set' => new Xml\Property\SupportedCollationSet(),
1141        ], $props);
1142
1143    }
1144
1145}
1146