예제 #1
0
 /**
  * 'beforeMethod' event handles. This event handles intercepts GET requests ending
  * with ?export
  *
  * @param string $method
  * @param string $uri
  * @return bool
  */
 public function beforeMethod($method, $uri)
 {
     if ($method != 'GET') {
         return;
     }
     if ($this->server->httpRequest->getQueryString() != 'export') {
         return;
     }
     // splitting uri
     list($uri) = explode('?', $uri, 2);
     $node = $this->server->tree->getNodeForPath($uri);
     if (!$node instanceof Calendar) {
         return;
     }
     // Checking ACL, if available.
     if ($aclPlugin = $this->server->getPlugin('acl')) {
         $aclPlugin->checkPrivileges($uri, '{DAV:}read');
     }
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->sendStatus(200);
     $nodes = $this->server->getPropertiesForPath($uri, array('{' . Plugin::NS_CALDAV . '}calendar-data'), 1);
     $this->server->httpResponse->sendBody($this->generateICS($nodes));
     // Returning false to break the event chain
     return false;
 }
예제 #2
0
 /**
  * WebDAV PROPFIND
  *
  * This WebDAV method requests information about an uri resource, or a list of resources
  * If a client wants to receive the properties for a single resource it will add an HTTP Depth: header with a 0 value
  * If the value is 1, it means that it also expects a list of sub-resources (e.g.: files in a directory)
  *
  * The request body contains an XML data structure that has a list of properties the client understands
  * The response body is also an xml document, containing information about every uri resource and the requested properties
  *
  * It has to return a HTTP 207 Multi-status status code
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return void
  */
 function httpPropfind(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     $requestedProperties = $this->server->parsePropFindRequest($request->getBodyAsString());
     $depth = $this->server->getHTTPDepth(1);
     // The only two options for the depth of a propfind is 0 or 1 - as long as depth infinity is not enabled
     if (!$this->server->enablePropfindDepthInfinity && $depth != 0) {
         $depth = 1;
     }
     $newProperties = $this->server->getPropertiesForPath($path, $requestedProperties, $depth);
     // This is a multi-status response
     $response->setStatus(207);
     $response->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $response->setHeader('Vary', 'Brief,Prefer');
     // Normally this header is only needed for OPTIONS responses, however..
     // iCal seems to also depend on these being set for PROPFIND. Since
     // this is not harmful, we'll add it.
     $features = ['1', '3', 'extended-mkcol'];
     foreach ($this->server->getPlugins() as $plugin) {
         $features = array_merge($features, $plugin->getFeatures());
     }
     $response->setHeader('DAV', implode(', ', $features));
     $prefer = $this->server->getHTTPPrefer();
     $minimal = $prefer['return-minimal'];
     $data = $this->server->generateMultiStatus($newProperties, $minimal);
     $response->setBody($data);
     // Sending back false will interupt the event chain and tell the server
     // we've handled this method.
     return false;
 }
예제 #3
0
 /**
  * REPORT operations to look for comments
  *
  * @param string $reportName
  * @param [] $report
  * @param string $uri
  * @return bool
  * @throws NotFound
  * @throws ReportNotSupported
  */
 public function onReport($reportName, $report, $uri)
 {
     $node = $this->server->tree->getNodeForPath($uri);
     if (!$node instanceof EntityCollection || $reportName !== self::REPORT_NAME) {
         throw new ReportNotSupported();
     }
     $args = ['limit' => 0, 'offset' => 0, 'datetime' => null];
     $acceptableParameters = [$this::REPORT_PARAM_LIMIT, $this::REPORT_PARAM_OFFSET, $this::REPORT_PARAM_TIMESTAMP];
     $ns = '{' . $this::NS_OWNCLOUD . '}';
     foreach ($report as $parameter) {
         if (!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) {
             continue;
         }
         $args[str_replace($ns, '', $parameter['name'])] = $parameter['value'];
     }
     if (!is_null($args['datetime'])) {
         $args['datetime'] = new \DateTime($args['datetime']);
     }
     $results = $node->findChildren($args['limit'], $args['offset'], $args['datetime']);
     $responses = [];
     foreach ($results as $node) {
         $nodePath = $this->server->getRequestUri() . '/' . $node->comment->getId();
         $resultSet = $this->server->getPropertiesForPath($nodePath, CommentNode::getPropertyNames());
         if (isset($resultSet[0]) && isset($resultSet[0][200])) {
             $responses[] = new Response($this->server->getBaseUri() . $nodePath, [200 => $resultSet[0][200]], 200);
         }
     }
     $xml = $this->server->xml->write('{DAV:}multistatus', new MultiStatus($responses));
     $this->server->httpResponse->setStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setBody($xml);
     return false;
 }
예제 #4
0
 /**
  * This method handler is invoked during fetching of properties.
  *
  * We use this event to add calendar-auto-schedule-specific properties.
  *
  * @param PropFind $propFind
  * @param INode $node
  * @return void
  */
 function propFind(PropFind $propFind, INode $node)
 {
     if ($node instanceof DAVACL\IPrincipal) {
         $caldavPlugin = $this->server->getPlugin('caldav');
         $principalUrl = $node->getPrincipalUrl();
         // schedule-outbox-URL property
         $propFind->handle('{' . self::NS_CALDAV . '}schedule-outbox-URL', function () use($principalUrl, $caldavPlugin) {
             $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
             if (!$calendarHomePath) {
                 return null;
             }
             $outboxPath = $calendarHomePath . '/outbox/';
             return new Href($outboxPath);
         });
         // schedule-inbox-URL property
         $propFind->handle('{' . self::NS_CALDAV . '}schedule-inbox-URL', function () use($principalUrl, $caldavPlugin) {
             $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
             if (!$calendarHomePath) {
                 return null;
             }
             $inboxPath = $calendarHomePath . '/inbox/';
             return new Href($inboxPath);
         });
         $propFind->handle('{' . self::NS_CALDAV . '}schedule-default-calendar-URL', function () use($principalUrl, $caldavPlugin) {
             // We don't support customizing this property yet, so in the
             // meantime we just grab the first calendar in the home-set.
             $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
             if (!$calendarHomePath) {
                 return null;
             }
             $sccs = '{' . self::NS_CALDAV . '}supported-calendar-component-set';
             $result = $this->server->getPropertiesForPath($calendarHomePath, ['{DAV:}resourcetype', $sccs], 1);
             foreach ($result as $child) {
                 if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar') || $child[200]['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared')) {
                     // Node is either not a calendar or a shared instance.
                     continue;
                 }
                 if (!isset($child[200][$sccs]) || in_array('VEVENT', $child[200][$sccs]->getValue())) {
                     // Either there is no supported-calendar-component-set
                     // (which is fine) or we found one that supports VEVENT.
                     return new Href($child['href']);
                 }
             }
         });
         // The server currently reports every principal to be of type
         // 'INDIVIDUAL'
         $propFind->handle('{' . self::NS_CALDAV . '}calendar-user-type', function () {
             return 'INDIVIDUAL';
         });
     }
     // Mapping the old property to the new property.
     $propFind->handle('{http://calendarserver.org/ns/}calendar-availability', function () use($propFind, $node) {
         // In case it wasn't clear, the only difference is that we map the
         // old property to a different namespace.
         $availProp = '{' . self::NS_CALDAV . '}calendar-availability';
         $subPropFind = new PropFind($propFind->getPath(), [$availProp]);
         $this->server->getPropertiesByNode($subPropFind, $node);
         $propFind->set('{http://calendarserver.org/ns/}calendar-availability', $subPropFind->get($availProp), $subPropFind->getStatus($availProp));
     });
 }
예제 #5
0
 /**
  * This method is responsible for generating the actual, full response.
  *
  * @param string $path
  * @param DateTime|null $start
  * @param DateTime|null $end
  * @param bool $expand
  * @param string $componentType
  * @param string $format
  * @param array $properties
  * @param ResponseInterface $response
  */
 protected function generateResponse($path, $start, $end, $expand, $componentType, $format, $properties, ResponseInterface $response)
 {
     $calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data';
     $blobs = [];
     if ($start || $end || $componentType) {
         // If there was a start or end filter, we need to enlist
         // calendarQuery for speed.
         $calendarNode = $this->server->tree->getNodeForPath($path);
         $queryResult = $calendarNode->calendarQuery(['name' => 'VCALENDAR', 'comp-filters' => [['name' => $componentType, 'comp-filters' => [], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => ['start' => $start, 'end' => $end]]], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => null]);
         // queryResult is just a list of base urls. We need to prefix the
         // calendar path.
         $queryResult = array_map(function ($item) use($path) {
             return $path . '/' . $item;
         }, $queryResult);
         $nodes = $this->server->getPropertiesForMultiplePaths($queryResult, [$calDataProp]);
         unset($queryResult);
     } else {
         $nodes = $this->server->getPropertiesForPath($path, [$calDataProp], 1);
     }
     // Flattening the arrays
     foreach ($nodes as $node) {
         if (isset($node[200][$calDataProp])) {
             $blobs[$node['href']] = $node[200][$calDataProp];
         }
     }
     unset($nodes);
     $mergedCalendar = $this->mergeObjects($properties, $blobs);
     if ($expand) {
         $calendarTimeZone = null;
         // We're expanding, and for that we need to figure out the
         // calendar's timezone.
         $tzProp = '{' . Plugin::NS_CALDAV . '}calendar-timezone';
         $tzResult = $this->server->getProperties($path, [$tzProp]);
         if (isset($tzResult[$tzProp])) {
             // This property contains a VCALENDAR with a single
             // VTIMEZONE.
             $vtimezoneObj = VObject\Reader::read($tzResult[$tzProp]);
             $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
             // Destroy circular references to PHP will GC the object.
             $vtimezoneObj->destroy();
             unset($vtimezoneObj);
         } else {
             // Defaulting to UTC.
             $calendarTimeZone = new DateTimeZone('UTC');
         }
         $mergedCalendar->expand($start, $end, $calendarTimeZone);
     }
     $response->setHeader('Content-Type', $format);
     switch ($format) {
         case 'text/calendar':
             $mergedCalendar = $mergedCalendar->serialize();
             break;
         case 'application/calendar+json':
             $mergedCalendar = json_encode($mergedCalendar->jsonSerialize());
             break;
     }
     $response->setStatus(200);
     $response->setBody($mergedCalendar);
 }
예제 #6
0
 function testSupportedReportSetUserCalendars()
 {
     $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
     $props = $this->server->getPropertiesForPath('/calendars/user1', ['{DAV:}supported-report-set']);
     $this->assertArrayHasKey(0, $props);
     $this->assertArrayHasKey(200, $props[0]);
     $this->assertArrayHasKey('{DAV:}supported-report-set', $props[0][200]);
     $prop = $props[0][200]['{DAV:}supported-report-set'];
     $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop);
     $value = ['{DAV:}sync-collection', '{DAV:}expand-property', '{DAV:}principal-property-search', '{DAV:}principal-search-property-set'];
     $this->assertEquals($value, $prop->getValue());
 }
예제 #7
0
 /**
  * This method is responsible for generating the actual, full response.
  *
  * @param string $path
  * @param DateTime|null $start
  * @param DateTime|null $end
  * @param bool $expand
  * @param string $format
  * @param array $properties
  * @param ResponseInterface $response
  */
 protected function generateResponse($path, $start, $end, $expand, $format, $properties, ResponseInterface $response)
 {
     $calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data';
     $blobs = [];
     if ($start || $end) {
         // If there was a start or end filter, we need to enlist
         // calendarQuery for speed.
         $calendarNode = $this->server->tree->getNodeForPath($path);
         $queryResult = $calendarNode->calendarQuery(['name' => 'VCALENDAR', 'comp-filters' => [['name' => 'VEVENT', 'comp-filters' => [], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => ['start' => $start, 'end' => $end]]], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => null]);
         // queryResult is just a list of base urls. We need to prefix the
         // calendar path.
         $queryResult = array_map(function ($item) use($path) {
             return $path . '/' . $item;
         }, $queryResult);
         $nodes = $this->server->getPropertiesForMultiplePaths($queryResult, [$calDataProp]);
         unset($queryResult);
     } else {
         $nodes = $this->server->getPropertiesForPath($path, [$calDataProp], 1);
     }
     // Flattening the arrays
     foreach ($nodes as $node) {
         if (isset($node[200][$calDataProp])) {
             $blobs[] = $node[200][$calDataProp];
         }
     }
     unset($nodes);
     $mergedCalendar = $this->mergeObjects($properties, $blobs);
     if ($expand) {
         $mergedCalendar->expand($start, $end);
     }
     $response->setHeader('Content-Type', $format);
     switch ($format) {
         case 'text/calendar':
             $mergedCalendar = $mergedCalendar->serialize();
             break;
         case 'application/calendar+json':
             $mergedCalendar = json_encode($mergedCalendar->jsonSerialize());
             break;
     }
     $response->setStatus(200);
     $response->setBody($mergedCalendar);
 }
 /**
  * Sends the response to a sync-collection request.
  *
  * @param string $syncToken
  * @param string $collectionUrl
  * @param array $added
  * @param array $modified
  * @param array $deleted
  * @param array $properties
  * @return void
  */
 protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties)
 {
     $resolvedProperties = array();
     foreach (array_merge($added, $modified) as $item) {
         $fullPath = $collectionUrl . '/' . $item;
         try {
             $resolvedProperties[$fullPath] = $this->server->getPropertiesForPath($fullPath, $properties);
             // in case the user doesnt have access to this
         } catch (Sabre\DAV\Exception\NotFound $e) {
             unset($resolvedProperties[$fullPath]);
         }
     }
     foreach ($deleted as $item) {
         $fullPath = $collectionUrl . '/' . $item;
         $resolvedProperties[$fullPath] = array();
     }
     $data = $this->generateMultiStatus($resolvedProperties, $syncToken);
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->sendBody($data);
 }
예제 #9
0
파일: Plugin.php 프로젝트: sebbie42/casebox
 /**
  * This function handles the calendar-query REPORT
  *
  * This report is used by clients to request calendar objects based on
  * complex conditions.
  *
  * @param Xml\Request\CalendarQueryReport $report
  * @return void
  */
 function calendarQueryReport($report)
 {
     $path = $this->server->getRequestUri();
     $needsJson = $report->contentType === 'application/calendar+json';
     $node = $this->server->tree->getNodeForPath($this->server->getRequestUri());
     $depth = $this->server->getHTTPDepth(0);
     // The default result is an empty array
     $result = [];
     $calendarTimeZone = null;
     if ($report->expand) {
         // We're expanding, and for that we need to figure out the
         // calendar's timezone.
         $tzProp = '{' . self::NS_CALDAV . '}calendar-timezone';
         $tzResult = $this->server->getProperties($path, [$tzProp]);
         if (isset($tzResult[$tzProp])) {
             // This property contains a VCALENDAR with a single
             // VTIMEZONE.
             $vtimezoneObj = VObject\Reader::read($tzResult[$tzProp]);
             $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
             unset($vtimezoneObj);
         } else {
             // Defaulting to UTC.
             $calendarTimeZone = new DateTimeZone('UTC');
         }
     }
     // The calendarobject was requested directly. In this case we handle
     // this locally.
     if ($depth == 0 && $node instanceof ICalendarObject) {
         $requestedCalendarData = true;
         $requestedProperties = $report->properties;
         if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
             // We always retrieve calendar-data, as we need it for filtering.
             $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
             // If calendar-data wasn't explicitly requested, we need to remove
             // it after processing.
             $requestedCalendarData = false;
         }
         $properties = $this->server->getPropertiesForPath($path, $requestedProperties, 0);
         // This array should have only 1 element, the first calendar
         // object.
         $properties = current($properties);
         // If there wasn't any calendar-data returned somehow, we ignore
         // this.
         if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
             $validator = new CalendarQueryValidator();
             $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
             if ($validator->validate($vObject, $report->filters)) {
                 // If the client didn't require the calendar-data property,
                 // we won't give it back.
                 if (!$requestedCalendarData) {
                     unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
                 } else {
                     if ($report->expand) {
                         $vObject->expand($report->expand['start'], $report->expand['end'], $calendarTimeZone);
                     }
                     if ($needsJson) {
                         $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = json_encode($vObject->jsonSerialize());
                     } elseif ($report->expand) {
                         $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
                     }
                 }
                 $result = [$properties];
             }
         }
     }
     if ($node instanceof ICalendarObjectContainer && $depth === 0) {
         if (strpos($this->server->httpRequest->getHeader('User-Agent'), 'MSFT-WP/') === 0) {
             // Windows phone incorrectly supplied depth as 0, when it actually
             // should have set depth to 1. We're implementing a workaround here
             // to deal with this.
             $depth = 1;
         } else {
             throw new BadRequest('A calendar-query REPORT on a calendar with a Depth: 0 is undefined. Set Depth to 1');
         }
     }
     // If we're dealing with a calendar, the calendar itself is responsible
     // for the calendar-query.
     if ($node instanceof ICalendarObjectContainer && $depth == 1) {
         $nodePaths = $node->calendarQuery($report->filters);
         foreach ($nodePaths as $path) {
             list($properties) = $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $report->properties);
             if ($needsJson || $report->expand) {
                 $vObject = VObject\Reader::read($properties[200]['{' . self::NS_CALDAV . '}calendar-data']);
                 if ($report->expand) {
                     $vObject->expand($report->expand['start'], $report->expand['end'], $calendarTimeZone);
                 }
                 if ($needsJson) {
                     $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = json_encode($vObject->jsonSerialize());
                 } else {
                     $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
                 }
             }
             $result[] = $properties;
         }
     }
     $prefer = $this->server->getHTTPPrefer();
     $this->server->httpResponse->setStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
     $this->server->httpResponse->setBody($this->server->generateMultiStatus($result, $prefer['return'] === 'minimal'));
 }
 function testGetDisplayName()
 {
     $tree = [new DAV\SimpleCollection('principals', [$principal = new MockPrincipal('user', 'principals/user')])];
     $fakeServer = new DAV\Server($tree);
     $plugin = new Plugin();
     $fakeServer->addPlugin($plugin);
     $requestedProperties = ['{DAV:}displayname'];
     $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties);
     $result = $result[0];
     $this->assertTrue(isset($result[200]));
     $this->assertTrue(isset($result[200]['{DAV:}displayname']));
     $this->assertEquals('user', $result[200]['{DAV:}displayname']);
 }
예제 #11
0
 /**
  * This function handles the calendar-query REPORT
  *
  * This report is used by clients to request calendar objects based on
  * complex conditions.
  *
  * @param \DOMNode $dom
  * @return void
  */
 function calendarQueryReport($dom)
 {
     $parser = new CalendarQueryParser($dom);
     $parser->parse();
     $path = $this->server->getRequestUri();
     // TODO: move this into CalendarQueryParser
     $xpath = new \DOMXPath($dom);
     $xpath->registerNameSpace('cal', Plugin::NS_CALDAV);
     $xpath->registerNameSpace('dav', 'urn:DAV');
     $needsJson = $xpath->evaluate("boolean(/cal:calendar-query/dav:prop/cal:calendar-data[@content-type='application/calendar+json'])");
     $node = $this->server->tree->getNodeForPath($this->server->getRequestUri());
     $depth = $this->server->getHTTPDepth(0);
     // The default result is an empty array
     $result = [];
     $calendarTimeZone = null;
     if ($parser->expand) {
         // We're expanding, and for that we need to figure out the
         // calendar's timezone.
         $tzProp = '{' . self::NS_CALDAV . '}calendar-timezone';
         $tzResult = $this->server->getProperties($path, [$tzProp]);
         if (isset($tzResult[$tzProp])) {
             // This property contains a VCALENDAR with a single
             // VTIMEZONE.
             $vtimezoneObj = VObject\Reader::read($tzResult[$tzProp]);
             $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
             unset($vtimezoneObj);
         } else {
             // Defaulting to UTC.
             $calendarTimeZone = new DateTimeZone('UTC');
         }
     }
     // The calendarobject was requested directly. In this case we handle
     // this locally.
     if ($depth == 0 && $node instanceof ICalendarObject) {
         $requestedCalendarData = true;
         $requestedProperties = $parser->requestedProperties;
         if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
             // We always retrieve calendar-data, as we need it for filtering.
             $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
             // If calendar-data wasn't explicitly requested, we need to remove
             // it after processing.
             $requestedCalendarData = false;
         }
         $properties = $this->server->getPropertiesForPath($path, $requestedProperties, 0);
         // This array should have only 1 element, the first calendar
         // object.
         $properties = current($properties);
         // If there wasn't any calendar-data returned somehow, we ignore
         // this.
         if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
             $validator = new CalendarQueryValidator();
             $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
             if ($validator->validate($vObject, $parser->filters)) {
                 // If the client didn't require the calendar-data property,
                 // we won't give it back.
                 if (!$requestedCalendarData) {
                     unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
                 } else {
                     if ($parser->expand) {
                         $vObject->expand($parser->expand['start'], $parser->expand['end'], $calendarTimeZone);
                     }
                     if ($needsJson) {
                         $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = json_encode($vObject->jsonSerialize());
                     } elseif ($parser->expand) {
                         $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
                     }
                 }
                 $result = [$properties];
             }
         }
     }
     // If we're dealing with a calendar, the calendar itself is responsible
     // for the calendar-query.
     if ($node instanceof ICalendarObjectContainer && $depth == 1) {
         $nodePaths = $node->calendarQuery($parser->filters);
         $timeZones = [];
         foreach ($nodePaths as $path) {
             list($properties) = $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $parser->requestedProperties);
             if ($needsJson || $parser->expand) {
                 $vObject = VObject\Reader::read($properties[200]['{' . self::NS_CALDAV . '}calendar-data']);
                 if ($parser->expand) {
                     $vObject->expand($parser->expand['start'], $parser->expand['end'], $calendarTimeZone);
                 }
                 if ($needsJson) {
                     $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = json_encode($vObject->jsonSerialize());
                 } else {
                     $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
                 }
             }
             $result[] = $properties;
         }
     }
     $prefer = $this->server->getHTTPPRefer();
     $this->server->httpResponse->setStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
     $this->server->httpResponse->setBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
 }
예제 #12
0
 /**
  * This function handles the calendar-query REPORT
  *
  * This report is used by clients to request calendar objects based on
  * complex conditions.
  *
  * @param \DOMNode $dom
  * @return void
  */
 public function calendarQueryReport($dom)
 {
     $parser = new CalendarQueryParser($dom);
     $parser->parse();
     $node = $this->server->tree->getNodeForPath($this->server->getRequestUri());
     $depth = $this->server->getHTTPDepth(0);
     // The default result is an empty array
     $result = array();
     // The calendarobject was requested directly. In this case we handle
     // this locally.
     if ($depth == 0 && $node instanceof ICalendarObject) {
         $requestedCalendarData = true;
         $requestedProperties = $parser->requestedProperties;
         if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
             // We always retrieve calendar-data, as we need it for filtering.
             $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
             // If calendar-data wasn't explicitly requested, we need to remove
             // it after processing.
             $requestedCalendarData = false;
         }
         $properties = $this->server->getPropertiesForPath($this->server->getRequestUri(), $requestedProperties, 0);
         // This array should have only 1 element, the first calendar
         // object.
         $properties = current($properties);
         // If there wasn't any calendar-data returned somehow, we ignore
         // this.
         if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
             $validator = new CalendarQueryValidator();
             $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
             if ($validator->validate($vObject, $parser->filters)) {
                 // If the client didn't require the calendar-data property,
                 // we won't give it back.
                 if (!$requestedCalendarData) {
                     unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
                 } else {
                     if ($parser->expand) {
                         $vObject->expand($parser->expand['start'], $parser->expand['end']);
                         $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
                     }
                 }
                 $result = array($properties);
             }
         }
     }
     // If we're dealing with a calendar, the calendar itself is responsible
     // for the calendar-query.
     if ($node instanceof ICalendar && ($depth = 1)) {
         $nodePaths = $node->calendarQuery($parser->filters);
         foreach ($nodePaths as $path) {
             list($properties) = $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $parser->requestedProperties);
             if ($parser->expand) {
                 // We need to do some post-processing
                 $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
                 $vObject->expand($parser->expand['start'], $parser->expand['end']);
                 $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
             }
             $result[] = $properties;
         }
     }
     $prefer = $this->server->getHTTPPRefer();
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
     $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
 }
예제 #13
0
 function testGetDisplayName()
 {
     $tree = [new DAV\SimpleCollection('principals', [$principal = new MockPrincipal('user', 'principals/user')])];
     $fakeServer = new DAV\Server($tree);
     $plugin = new Plugin();
     $plugin->allowUnauthenticatedAccess = false;
     $fakeServer->addPlugin($plugin);
     $plugin->setDefaultACL([['principal' => '{DAV:}all', 'privilege' => '{DAV:}all']]);
     $requestedProperties = ['{DAV:}displayname'];
     $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties);
     $result = $result[0];
     $this->assertTrue(isset($result[200]));
     $this->assertTrue(isset($result[200]['{DAV:}displayname']));
     $this->assertEquals('user', $result[200]['{DAV:}displayname']);
 }