fix(cardav): return correct card version on report

Signed-off-by: Hamza <hamzamahjoubi221@gmail.com>
This commit is contained in:
Hamza 2025-08-21 18:07:47 +01:00
parent b243fd31bd
commit 11315704b7
3 changed files with 94 additions and 0 deletions

View file

@ -66,6 +66,10 @@ class Card implements ICard, IACL {
return 'text/vcard; charset=utf-8';
}
public function getVersion(): ?string {
return '3.0';
}
/**
* @inheritDoc
*/

View file

@ -29,6 +29,11 @@ class Card extends \Sabre\CardDAV\Card {
return (int)$this->cardData['addressbookid'];
}
public function getVersion(): ?string {
preg_match('/^VERSION:([34])\.0/mi', $this->cardData['carddata'], $matches);
return isset($matches[1]) ? $matches[1] . '.0' : null;
}
public function getPrincipalUri(): string {
return $this->addressBookInfo['principaluri'];
}

View file

@ -8,6 +8,7 @@
namespace OCA\DAV\CardDAV;
use OCA\DAV\CardDAV\Xml\Groups;
use Sabre\DAV\Exception\ReportNotSupported;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\Server;
@ -55,4 +56,88 @@ class Plugin extends \Sabre\CardDAV\Plugin {
});
}
}
/**
* This function handles the addressbook-query REPORT.
*
* This report is used by the client to filter an addressbook based on a
* complex query.
*
* @param \Sabre\CardDAV\Xml\Request\AddressBookQueryReport $report
*/
protected function addressbookQueryReport($report) {
$depth = $this->server->getHTTPDepth(0);
if ($depth == 0) {
$candidateNodes = [
$this->server->tree->getNodeForPath($this->server->getRequestUri()),
];
if (!$candidateNodes[0] instanceof Card) {
throw new ReportNotSupported('The addressbook-query report is not supported on this url with Depth: 0');
}
} else {
$candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
}
$validNodes = [];
foreach ($candidateNodes as $node) {
if (!$node instanceof Card) {
continue;
}
$blob = $node->get();
if (is_resource($blob)) {
$blob = stream_get_contents($blob);
}
if (!$this->validateFilters($blob, $report->filters, $report->test)) {
continue;
}
$validNodes[] = $node;
if ($report->limit && $report->limit <= count($validNodes)) {
// We hit the maximum number of items, we can stop now.
break;
}
}
$result = [];
foreach ($validNodes as $validNode) {
$contentType = $report->contentType;
// we theoretically support versions 3.0 and 4.0 so $vcardType should be dyncamic depending on the node
if ($validNode->getVersion()) {
$contentType .= '; version=' . $validNode->getVersion();
} elseif ($report->version) {
$contentType .= '; version=' . $report->version;
}
$vcardType = $this->negotiateVCard(
$contentType
);
if ($depth == 0) {
$href = $this->server->getRequestUri();
} else {
$href = $this->server->getRequestUri() . '/' . $validNode->getName();
}
/** @psalm-suppress DeprecatedMethod */
[$props] = $this->server->getPropertiesForPath($href, $report->properties, 0);
if (isset($props[200]['{' . self::NS_CARDDAV . '}address-data'])) {
$props[200]['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
$props[200]['{' . self::NS_CARDDAV . '}address-data'],
$vcardType,
$report->addressDataProperties
);
}
$result[] = $props;
}
$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'));
}
}