Merge pull request #19901 from nextcloud/bugfix/noid/vcard-photo-handling
Improved vcard photo handling
This commit is contained in:
commit
ed56619a20
|
@ -449,7 +449,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
*/
|
*/
|
||||||
public function deleteAddressBook($addressBookId) {
|
public function deleteAddressBook($addressBookId) {
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->delete('cards')
|
$query->delete($this->dbCardsTable)
|
||||||
->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
|
->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
|
||||||
->setParameter('addressbookid', $addressBookId)
|
->setParameter('addressbookid', $addressBookId)
|
||||||
->execute();
|
->execute();
|
||||||
|
@ -493,7 +493,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
public function getCards($addressBookId) {
|
public function getCards($addressBookId) {
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
||||||
->from('cards')
|
->from($this->dbCardsTable)
|
||||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
|
||||||
|
|
||||||
$cards = [];
|
$cards = [];
|
||||||
|
@ -501,7 +501,13 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$result = $query->execute();
|
$result = $query->execute();
|
||||||
while ($row = $result->fetch()) {
|
while ($row = $result->fetch()) {
|
||||||
$row['etag'] = '"' . $row['etag'] . '"';
|
$row['etag'] = '"' . $row['etag'] . '"';
|
||||||
$row['carddata'] = $this->readBlob($row['carddata']);
|
|
||||||
|
$modified = false;
|
||||||
|
$row['carddata'] = $this->readBlob($row['carddata'], $modified);
|
||||||
|
if ($modified) {
|
||||||
|
$row['size'] = strlen($row['carddata']);
|
||||||
|
}
|
||||||
|
|
||||||
$cards[] = $row;
|
$cards[] = $row;
|
||||||
}
|
}
|
||||||
$result->closeCursor();
|
$result->closeCursor();
|
||||||
|
@ -524,7 +530,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
public function getCard($addressBookId, $cardUri) {
|
public function getCard($addressBookId, $cardUri) {
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
||||||
->from('cards')
|
->from($this->dbCardsTable)
|
||||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
|
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
|
||||||
->setMaxResults(1);
|
->setMaxResults(1);
|
||||||
|
@ -535,7 +541,12 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$row['etag'] = '"' . $row['etag'] . '"';
|
$row['etag'] = '"' . $row['etag'] . '"';
|
||||||
$row['carddata'] = $this->readBlob($row['carddata']);
|
|
||||||
|
$modified = false;
|
||||||
|
$row['carddata'] = $this->readBlob($row['carddata'], $modified);
|
||||||
|
if ($modified) {
|
||||||
|
$row['size'] = strlen($row['carddata']);
|
||||||
|
}
|
||||||
|
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
|
@ -562,7 +573,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
$query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata', 'uid'])
|
||||||
->from('cards')
|
->from($this->dbCardsTable)
|
||||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||||
->andWhere($query->expr()->in('uri', $query->createParameter('uri')));
|
->andWhere($query->expr()->in('uri', $query->createParameter('uri')));
|
||||||
|
|
||||||
|
@ -572,7 +583,13 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
while ($row = $result->fetch()) {
|
while ($row = $result->fetch()) {
|
||||||
$row['etag'] = '"' . $row['etag'] . '"';
|
$row['etag'] = '"' . $row['etag'] . '"';
|
||||||
$row['carddata'] = $this->readBlob($row['carddata']);
|
|
||||||
|
$modified = false;
|
||||||
|
$row['carddata'] = $this->readBlob($row['carddata'], $modified);
|
||||||
|
if ($modified) {
|
||||||
|
$row['size'] = strlen($row['carddata']);
|
||||||
|
}
|
||||||
|
|
||||||
$cards[] = $row;
|
$cards[] = $row;
|
||||||
}
|
}
|
||||||
$result->closeCursor();
|
$result->closeCursor();
|
||||||
|
@ -611,7 +628,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
$q = $this->db->getQueryBuilder();
|
$q = $this->db->getQueryBuilder();
|
||||||
$q->select('uid')
|
$q->select('uid')
|
||||||
->from('cards')
|
->from($this->dbCardsTable)
|
||||||
->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
|
->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
|
||||||
->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
|
->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
|
||||||
->setMaxResults(1);
|
->setMaxResults(1);
|
||||||
|
@ -676,7 +693,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$uid = $this->getUID($cardData);
|
$uid = $this->getUID($cardData);
|
||||||
$etag = md5($cardData);
|
$etag = md5($cardData);
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->update('cards')
|
$query->update($this->dbCardsTable)
|
||||||
->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
|
->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
|
||||||
->set('lastmodified', $query->createNamedParameter(time()))
|
->set('lastmodified', $query->createNamedParameter(time()))
|
||||||
->set('size', $query->createNamedParameter(strlen($cardData)))
|
->set('size', $query->createNamedParameter(strlen($cardData)))
|
||||||
|
@ -712,7 +729,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$cardId = null;
|
$cardId = null;
|
||||||
}
|
}
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$ret = $query->delete('cards')
|
$ret = $query->delete($this->dbCardsTable)
|
||||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
|
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
|
||||||
->execute();
|
->execute();
|
||||||
|
@ -872,12 +889,41 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function readBlob($cardData) {
|
/**
|
||||||
|
* @param resource|string $cardData
|
||||||
|
* @param bool $modified
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function readBlob($cardData, &$modified=false) {
|
||||||
if (is_resource($cardData)) {
|
if (is_resource($cardData)) {
|
||||||
return stream_get_contents($cardData);
|
$cardData = stream_get_contents($cardData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cardData;
|
$cardDataArray = explode("\r\n", $cardData);
|
||||||
|
|
||||||
|
$cardDataFiltered = [];
|
||||||
|
$removingPhoto = false;
|
||||||
|
foreach ($cardDataArray as $line) {
|
||||||
|
if (strpos($line, 'PHOTO:data:') === 0
|
||||||
|
&& strpos($line, 'PHOTO:data:image/') !== 0) {
|
||||||
|
// Filter out PHOTO data of non-images
|
||||||
|
$removingPhoto = true;
|
||||||
|
$modified = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($removingPhoto) {
|
||||||
|
if (strpos($line, ' ') === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// No leading space means this is a new property
|
||||||
|
$removingPhoto = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cardDataFiltered[] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\r\n", $cardDataFiltered);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -929,7 +975,11 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$result->closeCursor();
|
$result->closeCursor();
|
||||||
|
|
||||||
return array_map(function ($array) {
|
return array_map(function ($array) {
|
||||||
$array['carddata'] = $this->readBlob($array['carddata']);
|
$modified = false;
|
||||||
|
$array['carddata'] = $this->readBlob($array['carddata'], $modified);
|
||||||
|
if ($modified) {
|
||||||
|
$array['size'] = strlen($array['carddata']);
|
||||||
|
}
|
||||||
return $array;
|
return $array;
|
||||||
}, $cards);
|
}, $cards);
|
||||||
}
|
}
|
||||||
|
@ -994,6 +1044,13 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$queryResult->closeCursor();
|
$queryResult->closeCursor();
|
||||||
|
|
||||||
if (is_array($contact)) {
|
if (is_array($contact)) {
|
||||||
|
$modified = false;
|
||||||
|
$contact['etag'] = '"' . $contact['etag'] . '"';
|
||||||
|
$contact['carddata'] = $this->readBlob($contact['carddata'], $modified);
|
||||||
|
if ($modified) {
|
||||||
|
$contact['size'] = strlen($contact['carddata']);
|
||||||
|
}
|
||||||
|
|
||||||
$result = $contact;
|
$result = $contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,12 @@ class HasPhotoPlugin extends ServerPlugin {
|
||||||
if ($node instanceof Card) {
|
if ($node instanceof Card) {
|
||||||
$propFind->handle($ns . 'has-photo', function () use ($node) {
|
$propFind->handle($ns . 'has-photo', function () use ($node) {
|
||||||
$vcard = Reader::read($node->get());
|
$vcard = Reader::read($node->get());
|
||||||
return ($vcard instanceof VCard && $vcard->PHOTO);
|
return $vcard instanceof VCard
|
||||||
|
&& $vcard->PHOTO
|
||||||
|
// Either the PHOTO is a url (doesn't start with data:) or the mimetype has to start with image/
|
||||||
|
&& (strpos($vcard->PHOTO->getValue(), 'data:') !== 0
|
||||||
|
|| strpos($vcard->PHOTO->getValue(), 'data:image/') === 0)
|
||||||
|
;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -812,7 +812,7 @@ class CardDavBackendTest extends TestCase {
|
||||||
$this->assertSame(0, (int)$result['addressbookid']);
|
$this->assertSame(0, (int)$result['addressbookid']);
|
||||||
$this->assertSame('uri0', $result['uri']);
|
$this->assertSame('uri0', $result['uri']);
|
||||||
$this->assertSame(5489543, (int)$result['lastmodified']);
|
$this->assertSame(5489543, (int)$result['lastmodified']);
|
||||||
$this->assertSame('etag0', $result['etag']);
|
$this->assertSame('"etag0"', $result['etag']);
|
||||||
$this->assertSame(120, (int)$result['size']);
|
$this->assertSame(120, (int)$result['size']);
|
||||||
|
|
||||||
// this shouldn't return any result because 'uri1' is in address book 1
|
// this shouldn't return any result because 'uri1' is in address book 1
|
||||||
|
|
Loading…
Reference in New Issue