PdoAddressBook::Sync should work (in theory)

This commit is contained in:
the-djmaze 2022-05-29 23:36:03 +02:00
parent a71874a8c4
commit c39d89258a
2 changed files with 59 additions and 44 deletions

View file

@ -19,6 +19,11 @@ class Contact implements \JsonSerializable
*/ */
public $IdContactStr = ''; public $IdContactStr = '';
/**
* @var string
*/
// public $Display;
/** /**
* @var int * @var int
*/ */
@ -29,6 +34,12 @@ class Contact implements \JsonSerializable
*/ */
public $ReadOnly = false; public $ReadOnly = false;
/**
* @var string
* Used for CardDAV synchronization
*/
public $Etag = '';
/** /**
* @var \Sabre\VObject\Component\VCard * @var \Sabre\VObject\Component\VCard
*/ */

View file

@ -110,14 +110,12 @@ class PdoAddressBook
$sKeyID = $aItem['id_contact_str']; $sKeyID = $aItem['id_contact_str'];
$aResult[$sKeyID] = array( $aResult[$sKeyID] = array(
'deleted' => '1' === (string) $aItem['deleted'], 'deleted' => !empty($aItem['deleted']),
'id_contact' => $aItem['id_contact'], 'id_contact' => $aItem['id_contact'],
'uid' => $sKeyID, 'uid' => $sKeyID,
'etag' => $aItem['etag'], 'etag' => $aItem['etag'],
'changed' => (int) $aItem['changed'], 'changed' => (int) $aItem['changed']
); );
$aResult[$sKeyID]['changed_'] = \gmdate('c', $aResult[$sKeyID]['changed']);
} }
} }
} }
@ -128,10 +126,6 @@ class PdoAddressBook
public function Sync() : bool public function Sync() : bool
{ {
/* TODO: broken
$this->SyncDatabase();
if (1 > $this->iUserID) { if (1 > $this->iUserID) {
\SnappyMail\Log::warning('PdoAddressBook', 'Sync() invalid $iUserID'); \SnappyMail\Log::warning('PdoAddressBook', 'Sync() invalid $iUserID');
return false; return false;
@ -162,31 +156,34 @@ class PdoAddressBook
// Delete remote when Mode = read + write // Delete remote when Mode = read + write
if ($this->isDAVReadWrite()) { if ($this->isDAVReadWrite()) {
foreach ($aDatabaseSyncData as $sKey => $aData) { foreach ($aDatabaseSyncData as $sKey => $aData) {
if ($aData['deleted'] && isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf'])) { if ($aData['deleted']) {
unset($aDatabaseSyncData[$sKey]);
if (isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf'])) {
\SnappyMail\HTTP\Stream::JSON(['messsage'=>"Delete remote {$sKey}"]); \SnappyMail\HTTP\Stream::JSON(['messsage'=>"Delete remote {$sKey}"]);
$this->davClientRequest($oClient, 'DELETE', $sPath.$aRemoteSyncData[$sKey]['vcf']); $this->davClientRequest($oClient, 'DELETE', $sPath.$aRemoteSyncData[$sKey]['vcf']);
} }
} }
} }
}
// Delete from db // Delete from db
$aIdsForDeletedion = array(); $aIdsForDeletion = array();
foreach ($aDatabaseSyncData as $sKey => $aData) { foreach ($aDatabaseSyncData as $sKey => $aData) {
if (!$aData['deleted'] && !empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) { if (!empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) {
$aIdsForDeletedion[] = $aData['id_contact']; $aIdsForDeletion[] = $aData['id_contact'];
} }
} }
if (\count($aIdsForDeletedion)) { if (\count($aIdsForDeletion)) {
\SnappyMail\HTTP\Stream::JSON(['messsage'=>'Delete local ' . \implode(', ', $aIdsForDeletedion)]); \SnappyMail\HTTP\Stream::JSON(['messsage'=>'Delete local ' . \implode(', ', $aIdsForDeletion)]);
$this->DeleteContacts($aIdsForDeletedion, false); $this->DeleteContacts($aIdsForDeletion);
unset($aIdsForDeletion);
} }
$this->flushDeletedContacts(); $this->flushDeletedContacts();
//+++new or newer (from db) //+++new or newer (from db)
foreach ($aDatabaseSyncData as $sKey => $aData) { foreach ($aDatabaseSyncData as $sKey => $aData) {
if (!$aData['deleted'] && if ((empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new
(empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new
|| ||
(!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer (!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer
$aRemoteSyncData[$sKey]['etag'] !== $aData['etag'] && $aRemoteSyncData[$sKey]['etag'] !== $aData['etag'] &&
@ -244,7 +241,7 @@ class PdoAddressBook
$aDatabaseSyncData[$sKey]['changed'] < $aData['changed']) $aDatabaseSyncData[$sKey]['changed'] < $aData['changed'])
) { ) {
\SnappyMail\HTTP\Stream::JSON(['messsage'=>"Update local {$sKey}"]); \SnappyMail\HTTP\Stream::JSON(['messsage'=>"Update local {$sKey}"]);
$mExsistenContactID = isset($aDatabaseSyncData[$sKey]['id_contact']) ? $mExistingContactID = isset($aDatabaseSyncData[$sKey]['id_contact']) ?
$aDatabaseSyncData[$sKey]['id_contact'] : ''; $aDatabaseSyncData[$sKey]['id_contact'] : '';
$oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$aData['vcf']); $oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$aData['vcf']);
@ -272,8 +269,8 @@ class PdoAddressBook
$oVCard->UID = $aData['uid']; $oVCard->UID = $aData['uid'];
$oContact = null; $oContact = null;
if ($mExsistenContactID) { if ($mExistingContactID) {
$oContact = $this->GetContactByID($mExsistenContactID); $oContact = $this->GetContactByID($mExistingContactID);
} }
if (!$oContact) { if (!$oContact) {
$oContact = new Classes\Contact(); $oContact = new Classes\Contact();
@ -281,7 +278,7 @@ class PdoAddressBook
$oContact->setVCard($oVCard); $oContact->setVCard($oVCard);
$sEtag = \trim(\trim($oResponse->getHeader('etag')), '"\''); $sEtag = \trim($oResponse->getHeader('etag'), " \n\r\t\v\x00\"'");
if (!empty($sEtag)) { if (!empty($sEtag)) {
$oContact->Etag = $sEtag; $oContact->Etag = $sEtag;
} }
@ -295,14 +292,12 @@ class PdoAddressBook
} }
} }
} }
*/
return true; return true;
} }
public function Export(string $sType = 'vcf') : bool public function Export(string $sType = 'vcf') : bool
{ {
$this->SyncDatabase();
if (1 > $this->iUserID) { if (1 > $this->iUserID) {
return false; return false;
} }
@ -332,13 +327,17 @@ class PdoAddressBook
public function ContactSave(Classes\Contact $oContact) : bool public function ContactSave(Classes\Contact $oContact) : bool
{ {
$this->SyncDatabase(); if (1 > $this->iUserID) {
return false;
}
$iIdContact = \strlen($oContact->id) && \is_numeric($oContact->id) ? (int) $oContact->id : 0; $iIdContact = \strlen($oContact->id) && \is_numeric($oContact->id) ? (int) $oContact->id : 0;
$bUpdate = 0 < $iIdContact; $bUpdate = 0 < $iIdContact;
$oContact->Changed = \time(); $oContact->Changed = \time();
// $oContact->vCard->REV = \gmdate('Ymd\\THis\\Z', $oContact->Changed);
// $oContact->REV = \time();
try { try {
$sFullName = (string) $oContact->vCard->FN; $sFullName = (string) $oContact->vCard->FN;
@ -356,7 +355,7 @@ class PdoAddressBook
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR), ':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
':display' => array($sFullName, \PDO::PARAM_STR), ':display' => array($sFullName, \PDO::PARAM_STR),
':changed' => array($oContact->Changed, \PDO::PARAM_INT), ':changed' => array($oContact->Changed, \PDO::PARAM_INT),
':etag' => array(''/*$oContact->Etag*/, \PDO::PARAM_STR) ':etag' => array($oContact->Etag, \PDO::PARAM_STR)
) )
); );
@ -378,7 +377,7 @@ class PdoAddressBook
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR), ':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
':display' => array($sFullName, \PDO::PARAM_STR), ':display' => array($sFullName, \PDO::PARAM_STR),
':changed' => array($oContact->Changed, \PDO::PARAM_INT), ':changed' => array($oContact->Changed, \PDO::PARAM_INT),
':etag' => array(''/*$oContact->Etag*/, \PDO::PARAM_STR) ':etag' => array($oContact->Etag, \PDO::PARAM_STR)
) )
); );
@ -425,10 +424,10 @@ class PdoAddressBook
return 0 < $iIdContact; return 0 < $iIdContact;
} }
public function DeleteContacts(array $aContactIds, bool $bSyncDb = true) : bool public function DeleteContacts(array $aContactIds) : bool
{ {
if ($bSyncDb) { if (1 > $this->iUserID) {
$this->SyncDatabase(); return false;
} }
$aContactIds = \array_filter(\array_map('intval', $aContactIds)); $aContactIds = \array_filter(\array_map('intval', $aContactIds));
@ -455,8 +454,6 @@ class PdoAddressBook
public function DeleteAllContacts(string $sEmail) : bool public function DeleteAllContacts(string $sEmail) : bool
{ {
$this->SyncDatabase();
$iUserID = $this->getUserId($sEmail); $iUserID = $this->getUserId($sEmail);
$aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT)); $aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
@ -481,18 +478,17 @@ class PdoAddressBook
$oContact = new Classes\Contact(); $oContact = new Classes\Contact();
$oContact->id = (string) $iIdContact; $oContact->id = (string) $iIdContact;
$oContact->IdContactStr = (string) $aItem['id_contact_str']; $oContact->IdContactStr = (string) $aItem['id_contact_str'];
// $oContact->Display = (string) $aItem['display'];
$oContact->Changed = (int) $aItem['changed']; $oContact->Changed = (int) $aItem['changed'];
$oContact->Etag = (int) $aItem['etag'];
if (!empty($aItem['jcard'])) { if (!empty($aItem['jcard'])) {
$oContact->FN = (string) $aItem['display'];
$oContact->setVCard( $oContact->setVCard(
\Sabre\VObject\Reader::readJson($aItem['jcard']) \Sabre\VObject\Reader::readJson($aItem['jcard'])
); );
// $oContact->vCard->FN = (string) $aItem['display'];
// $oContact->vCard->REV = \gmdate('Ymd\\THis\\Z', $oContact->Changed); // $oContact->vCard->REV = \gmdate('Ymd\\THis\\Z', $oContact->Changed);
} else { } else {
$aIdContacts[] = $iIdContact; $aIdContacts[] = $iIdContact;
if (!empty($aItem['display'])) {
// $oContact->vCard->FN = (string) $aItem['display'];
}
} }
$aContacts[$iIdContact] = $oContact; $aContacts[$iIdContact] = $oContact;
} }
@ -608,7 +604,9 @@ class PdoAddressBook
public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array
{ {
$this->SyncDatabase(); if (1 > $this->iUserID) {
return [];
}
$aSearchIds = array(); $aSearchIds = array();
@ -658,6 +656,7 @@ class PdoAddressBook
c.id_contact_str, c.id_contact_str,
c.display, c.display,
c.changed, c.changed,
c.etag,
p.prop_value as jcard p.prop_value as jcard
FROM rainloop_ab_contacts AS c FROM rainloop_ab_contacts AS c
LEFT JOIN rainloop_ab_properties AS p ON (p.id_contact = c.id_contact AND p.prop_type = :prop_type) LEFT JOIN rainloop_ab_properties AS p ON (p.id_contact = c.id_contact AND p.prop_type = :prop_type)
@ -694,6 +693,7 @@ class PdoAddressBook
c.id_contact_str, c.id_contact_str,
c.display, c.display,
c.changed, c.changed,
c.etag,
p.prop_value as jcard p.prop_value as jcard
FROM rainloop_ab_contacts AS c FROM rainloop_ab_contacts AS c
LEFT JOIN rainloop_ab_properties AS p ON (p.id_contact = c.id_contact AND p.prop_type = :prop_type) LEFT JOIN rainloop_ab_properties AS p ON (p.id_contact = c.id_contact AND p.prop_type = :prop_type)
@ -729,13 +729,15 @@ class PdoAddressBook
*/ */
public function GetSuggestions(string $sSearch, int $iLimit = 20) : array public function GetSuggestions(string $sSearch, int $iLimit = 20) : array
{ {
if (1 > $this->iUserID) {
return [];
}
$sSearch = \trim($sSearch); $sSearch = \trim($sSearch);
if (!\strlen($sSearch)) { if (!\strlen($sSearch)) {
throw new \InvalidArgumentException('Empty Search argument'); throw new \InvalidArgumentException('Empty Search argument');
} }
$this->SyncDatabase();
$sTypes = \implode(',', static::$aSearchInFields); $sTypes = \implode(',', static::$aSearchInFields);
$sLowerSearch = $this->specialConvertSearchValueLower($sSearch); $sLowerSearch = $this->specialConvertSearchValueLower($sSearch);
@ -889,6 +891,10 @@ class PdoAddressBook
public function IncFrec(array $aEmails, bool $bCreateAuto = true) : bool public function IncFrec(array $aEmails, bool $bCreateAuto = true) : bool
{ {
if (1 > $this->iUserID) {
return false;
}
$self = $this; $self = $this;
$aEmailsObjects = \array_map(function ($mItem) { $aEmailsObjects = \array_map(function ($mItem) {
$oResult = null; $oResult = null;
@ -909,8 +915,6 @@ class PdoAddressBook
throw new \InvalidArgumentException('Empty Emails argument'); throw new \InvalidArgumentException('Empty Emails argument');
} }
$this->SyncDatabase();
$aExists = array(); $aExists = array();
$aEmailsToCreate = array(); $aEmailsToCreate = array();
$aEmailsToUpdate = array(); $aEmailsToUpdate = array();