Skip to content

Commit f0e99b2

Browse files
authored
Merge pull request #909 from DeepDiver1975/3.2-vcard-filter-for-addressbook-query
[3.2] Enhance CardDAV query report to return a selective list of vcard prop…
2 parents 172d164 + 7c12f3a commit f0e99b2

File tree

8 files changed

+133
-7
lines changed

8 files changed

+133
-7
lines changed

lib/CardDAV/Plugin.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,8 @@ protected function addressbookQueryReport($report) {
490490

491491
$props[200]['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
492492
$props[200]['{' . self::NS_CARDDAV . '}address-data'],
493-
$vcardType
493+
$vcardType,
494+
$report->addressDataProperties
494495
);
495496

496497
}
@@ -845,14 +846,26 @@ protected function negotiateVCard($input, &$mimeType = null) {
845846
*
846847
* @param string|resource $data
847848
* @param string $target
849+
* @param array $propertiesFilter
848850
* @return string
849851
*/
850-
protected function convertVCard($data, $target) {
852+
protected function convertVCard($data, $target, array $propertiesFilter = null) {
851853

852854
if (is_resource($data)) {
853855
$data = stream_get_contents($data);
854856
}
855857
$input = VObject\Reader::read($data);
858+
if (!empty($propertiesFilter)) {
859+
$propertiesFilter = array_merge(['UID', 'VERSION', 'FN'], $propertiesFilter);
860+
$keys = array_unique(array_map(function($child) {
861+
return $child->name;
862+
}, $input->children()));
863+
$keys = array_diff($keys, $propertiesFilter);
864+
foreach ($keys as $key) {
865+
unset($input->$key);
866+
}
867+
$data = $input->serialize();
868+
}
856869
$output = null;
857870
try {
858871

lib/CardDAV/Xml/Filter/AddressData.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ static function xmlDeserialize(Reader $reader) {
5151
'version' => $reader->getAttribute('version') ?: '3.0',
5252
];
5353

54+
$elems = (array)$reader->parseInnerTree();
55+
$result['addressDataProperties'] = array_map(function($element) {
56+
return $element['attributes']['name'];
57+
}, $elems);
58+
5459
$reader->next();
5560
return $result;
5661

lib/CardDAV/Xml/Request/AddressBookQueryReport.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class AddressBookQueryReport implements XmlDeserializable {
2828
*/
2929
public $properties;
3030

31+
/**
32+
* An array with requested vcard properties.
33+
*
34+
* @var array
35+
*/
36+
public $addressDataProperties = [];
37+
3138
/**
3239
* List of property/component filters.
3340
*

tests/Sabre/CardDAV/AddressBookHomeTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ function testGetChild404() {
9090
function testGetChildren() {
9191

9292
$children = $this->s->getChildren();
93-
$this->assertEquals(1, count($children));
93+
$this->assertEquals(2, count($children));
9494
$this->assertInstanceOf('Sabre\\CardDAV\\AddressBook', $children[0]);
9595
$this->assertEquals('book1', $children[0]->getName());
9696

@@ -109,7 +109,7 @@ function testCreateExtendedCollection() {
109109
'uri' => 'book2',
110110
'{DAV:}displayname' => 'a-book 2',
111111
'principaluri' => 'principals/user1',
112-
], $this->backend->addressBooks[1]);
112+
], $this->backend->addressBooks[2]);
113113

114114
}
115115

tests/Sabre/CardDAV/AddressBookQueryTest.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,14 @@ function testAddressBookDepth0() {
288288
);
289289

290290
$request->setBody(
291-
'<?xml version="1.0"?>
291+
'<?xml version="1.0"?>
292292
<c:addressbook-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
293293
<d:prop>
294294
<c:address-data content-type="application/vcard+json" />
295295
<d:getetag />
296296
</d:prop>
297297
</c:addressbook-query>'
298-
);
298+
);
299299

300300
$response = new HTTP\ResponseMock();
301301

@@ -305,6 +305,51 @@ function testAddressBookDepth0() {
305305
$this->server->exec();
306306

307307
$this->assertEquals(415, $response->status, 'Incorrect status code. Full response body:' . $response->body);
308+
}
309+
310+
function testAddressBookProperties() {
311+
312+
$request = new HTTP\Request(
313+
'REPORT',
314+
'/addressbooks/user1/book3',
315+
['Depth' => '1']
316+
);
317+
318+
$request->setBody(
319+
'<?xml version="1.0"?>
320+
<c:addressbook-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
321+
<d:prop>
322+
<c:address-data>
323+
<c:prop name="FN"/>
324+
<c:prop name="BDAY"/>
325+
</c:address-data>
326+
<d:getetag />
327+
</d:prop>
328+
</c:addressbook-query>'
329+
);
330+
331+
$response = new HTTP\ResponseMock();
332+
333+
$this->server->httpRequest = $request;
334+
$this->server->httpResponse = $response;
335+
336+
$this->server->exec();
337+
338+
$this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body);
339+
340+
// using the client for parsing
341+
$client = new DAV\Client(['baseUri' => '/']);
342+
343+
$result = $client->parseMultiStatus($response->body);
344+
345+
$this->assertEquals([
346+
'/addressbooks/user1/book3/card3' => [
347+
200 => [
348+
'{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD") . '"',
349+
'{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\r\nVERSION:3.0\r\nUID:12345\r\nFN:Test-Card\r\nEND:VCARD\r\n",
350+
],
351+
],
352+
], $result);
308353

309354
}
310355
}

tests/Sabre/CardDAV/AddressBookTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function testCreateFile() {
8585
function testDelete() {
8686

8787
$this->ab->delete();
88-
$this->assertEquals([], $this->backend->addressBooks);
88+
$this->assertEquals(1, count($this->backend->addressBooks));
8989

9090
}
9191

tests/Sabre/CardDAV/Backend/Mock.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ function __construct($addressBooks = null, $cards = null) {
2020
'principaluri' => 'principals/user1',
2121
'{DAV:}displayname' => 'd-name',
2222
],
23+
[
24+
'id' => 'bar',
25+
'uri' => 'book3',
26+
'principaluri' => 'principals/user1',
27+
'{DAV:}displayname' => 'd-name',
28+
],
2329
];
2430

2531
$card2 = fopen('php://memory', 'r+');
@@ -30,6 +36,9 @@ function __construct($addressBooks = null, $cards = null) {
3036
'card1' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD",
3137
'card2' => $card2,
3238
],
39+
'bar' => [
40+
'card3' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD",
41+
],
3342
];
3443
}
3544

tests/Sabre/CardDAV/Xml/Request/AddressBookQueryReportTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,4 +300,51 @@ function testDeserializeDoubleFilter() {
300300
$this->parse($xml);
301301

302302
}
303+
304+
function testDeserializeAddressbookElements() {
305+
306+
$xml = <<<XML
307+
<?xml version="1.0"?>
308+
<c:addressbook-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
309+
<d:prop>
310+
<d:getetag />
311+
<c:address-data>
312+
<c:prop name="VERSION"/>
313+
<c:prop name="UID"/>
314+
<c:prop name="NICKNAME"/>
315+
<c:prop name="EMAIL"/>
316+
<c:prop name="FN"/>
317+
<c:prop name="TEL"/>
318+
</c:address-data>
319+
</d:prop>
320+
</c:addressbook-query>
321+
XML;
322+
323+
$result = $this->parse($xml);
324+
$addressBookQueryReport = new AddressBookQueryReport();
325+
$addressBookQueryReport->properties = [
326+
'{DAV:}getetag',
327+
'{urn:ietf:params:xml:ns:carddav}address-data'
328+
];
329+
$addressBookQueryReport->filters = [];
330+
$addressBookQueryReport->test = 'anyof';
331+
$addressBookQueryReport->contentType = 'text/vcard';
332+
$addressBookQueryReport->version = '3.0';
333+
$addressBookQueryReport->addressDataProperties = [
334+
'VERSION',
335+
'UID',
336+
'NICKNAME',
337+
'EMAIL',
338+
'FN',
339+
'TEL',
340+
];
341+
342+
$this->assertEquals(
343+
$addressBookQueryReport,
344+
$result['value']
345+
);
346+
347+
}
348+
349+
303350
}

0 commit comments

Comments
 (0)