From 0c4d471c18eaefc41453a5fad2bf9788f4e56ca2 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 30 Aug 2016 12:08:39 +0200 Subject: [PATCH 1/2] Correctly handle multi-values when converting VCards to array --- apps/dav/lib/CardDAV/AddressBookImpl.php | 42 +++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/apps/dav/lib/CardDAV/AddressBookImpl.php b/apps/dav/lib/CardDAV/AddressBookImpl.php index c83ee613d3..9de54eec33 100644 --- a/apps/dav/lib/CardDAV/AddressBookImpl.php +++ b/apps/dav/lib/CardDAV/AddressBookImpl.php @@ -28,6 +28,7 @@ use OCP\Constants; use OCP\IAddressBook; use OCP\IURLGenerator; use Sabre\VObject\Component\VCard; +use Sabre\VObject\Property; use Sabre\VObject\Property\Text; use Sabre\VObject\Reader; use Sabre\VObject\UUIDUtil; @@ -225,7 +226,7 @@ class AddressBookImpl implements IAddressBook { ]; foreach ($vCard->children as $property) { - $result[$property->name] = $property->getValue(); + /** @var \Sabre\VObject\Property\Unknown $property */ if ($property->name === 'PHOTO' && $property->getValueType() === 'BINARY') { $url = $this->urlGenerator->getAbsoluteURL( $this->urlGenerator->linkTo('', 'remote.php') . '/dav/'); @@ -237,14 +238,53 @@ class AddressBookImpl implements IAddressBook { ]) . '?photo'; $result['PHOTO'] = 'VALUE=uri:' . $url; + + } else if ($property->name === 'X-SOCIALPROFILE') { + $type = $this->getTypeFromProperty($property); + + // Type is the social network, when it's empty we don't need this. + if ($type !== null) { + if (!isset($result[$property->name])) { + $result[$property->name] = []; + } + $result[$property->name][$type] = $property->getValue(); + } + + // The following properties can be set multiple times + } else if (in_array($property->name, ['CLOUD', 'EMAIL', 'IMPP', 'TEL', 'URL'])) { + if (!isset($result[$property->name])) { + $result[$property->name] = []; + } + + $result[$property->name][] = $property->getValue(); + } else { $result[$property->name] = $property->getValue(); } } + if ($this->addressBookInfo['principaluri'] === 'principals/system/system' && $this->addressBookInfo['uri'] === 'system') { $result['isLocalSystemBook'] = true; } return $result; } + + /** + * Get the type of the current property + * + * @param Property $property + * @return null|string + */ + protected function getTypeFromProperty(Property $property) { + $parameters = $property->parameters(); + // Type is the social network, when it's empty we don't need this. + if (isset($parameters['TYPE'])) { + /** @var \Sabre\VObject\Parameter $type */ + $type = $parameters['TYPE']; + return $type->getValue(); + } + + return null; + } } From a123fe6f1812159dbb46aded519ad435f3812b9e Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 30 Aug 2016 12:24:20 +0200 Subject: [PATCH 2/2] Add a unit test for all the magic --- .../unit/CardDAV/AddressBookImplTest.php | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php b/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php index ba8527dc76..fa3cae27de 100644 --- a/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php +++ b/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php @@ -60,7 +60,9 @@ class AddressBookImplTest extends TestCase { $this->addressBookInfo = [ 'id' => 42, - '{DAV:}displayname' => 'display name' + 'uri' => 'system', + 'principaluri' => 'principals/system/system', + '{DAV:}displayname' => 'display name', ]; $this->addressBook = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBook') ->disableOriginalConstructor()->getMock(); @@ -306,4 +308,65 @@ class AddressBookImplTest extends TestCase { $this->assertSame($expectedVCardSerialized, $resultSerialized); } + public function testVCard2Array() { + $vCard = new VCard(); + + $vCard->add($vCard->createProperty('FN', 'Full Name')); + + // Multi-value properties + $vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost')); + $vCard->add($vCard->createProperty('CLOUD', 'cloud-user2@example.tld')); + $vCard->add($vCard->createProperty('EMAIL', 'email-user1@localhost')); + $vCard->add($vCard->createProperty('EMAIL', 'email-user2@example.tld')); + $vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost')); + $vCard->add($vCard->createProperty('IMPP', 'impp-user2@example.tld')); + $vCard->add($vCard->createProperty('TEL', '+49 123456789')); + $vCard->add($vCard->createProperty('TEL', '+1 555 123456789')); + $vCard->add($vCard->createProperty('URL', 'https://localhost')); + $vCard->add($vCard->createProperty('URL', 'https://example.tld')); + + // Type depending properties + $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example'); + $property->add('TYPE', 'twitter'); + $vCard->add($property); + $property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example'); + $property->add('TYPE', 'facebook'); + $vCard->add($property); + + $array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard]); + unset($array['PRODID']); + + $this->assertEquals([ + 'URI' => 'uri', + 'VERSION' => '3.0', + 'FN' => 'Full Name', + 'CLOUD' => [ + 'cloud-user1@localhost', + 'cloud-user2@example.tld', + ], + 'EMAIL' => [ + 'email-user1@localhost', + 'email-user2@example.tld', + ], + 'IMPP' => [ + 'impp-user1@localhost', + 'impp-user2@example.tld', + ], + 'TEL' => [ + '+49 123456789', + '+1 555 123456789', + ], + 'URL' => [ + 'https://localhost', + 'https://example.tld', + ], + + 'X-SOCIALPROFILE' => [ + 'twitter'=> 'tw-example', + 'facebook'=> 'fb-example', + ], + + 'isLocalSystemBook' => true, + ], $array); + } }