diff options
author | Sebastian Krupinski <165827823+SebastianKrupinski@users.noreply.github.com> | 2024-08-07 08:49:34 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-07 08:49:34 -0400 |
commit | 4c4e414036e75fc1fe248721d05041d8c7d93eb6 (patch) | |
tree | b54c24eec3ec2eea30d3f785c308ffb48dd1869d /apps/dav/lib/CalDAV | |
parent | 3ffcfb1dab2c81646d2af3518197b7f3dd3a710d (diff) | |
parent | a56d0dbf4b7ff83d36d9e0c2b0c1c115aff37f62 (diff) | |
download | nextcloud-server-4c4e414036e75fc1fe248721d05041d8c7d93eb6.tar.gz nextcloud-server-4c4e414036e75fc1fe248721d05041d8c7d93eb6.zip |
Merge pull request #46623 from nextcloud/fix/issue-44127
fix(caldav): fixed initial sync and double processing
Diffstat (limited to 'apps/dav/lib/CalDAV')
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 99 |
1 files changed, 41 insertions, 58 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 49e99201df1..8fff6902f9a 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -2410,74 +2410,57 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription ); $stmt = $qb->executeQuery(); $currentToken = $stmt->fetchOne(); + $initialSync = !is_numeric($syncToken); if ($currentToken === false) { return null; } - $result = [ - 'syncToken' => $currentToken, - 'added' => [], - 'modified' => [], - 'deleted' => [], - ]; - - if ($syncToken) { - $qb = $this->db->getQueryBuilder(); - - $qb->select('uri', 'operation') - ->from('calendarchanges') - ->where( - $qb->expr()->andX( - $qb->expr()->gte('synctoken', $qb->createNamedParameter($syncToken)), - $qb->expr()->lt('synctoken', $qb->createNamedParameter($currentToken)), - $qb->expr()->eq('calendarid', $qb->createNamedParameter($calendarId)), - $qb->expr()->eq('calendartype', $qb->createNamedParameter($calendarType)) - ) - )->orderBy('synctoken'); - if (is_int($limit) && $limit > 0) { - $qb->setMaxResults($limit); - } - - // Fetching all changes - $stmt = $qb->executeQuery(); - $changes = []; - - // This loop ensures that any duplicates are overwritten, only the - // last change on a node is relevant. - while ($row = $stmt->fetch()) { - $changes[$row['uri']] = $row['operation']; - } - $stmt->closeCursor(); - - foreach ($changes as $uri => $operation) { - switch ($operation) { - case 1: - $result['added'][] = $uri; - break; - case 2: - $result['modified'][] = $uri; - break; - case 3: - $result['deleted'][] = $uri; - break; - } - } - } else { - // No synctoken supplied, this is the initial sync. + // evaluate if this is a initial sync and construct appropriate command + if ($initialSync) { $qb = $this->db->getQueryBuilder(); $qb->select('uri') ->from('calendarobjects') - ->where( - $qb->expr()->andX( - $qb->expr()->eq('calendarid', $qb->createNamedParameter($calendarId)), - $qb->expr()->eq('calendartype', $qb->createNamedParameter($calendarType)) - ) - ); - $stmt = $qb->executeQuery(); + ->where($qb->expr()->eq('calendarid', $qb->createNamedParameter($calendarId))) + ->andWhere($qb->expr()->eq('calendartype', $qb->createNamedParameter($calendarType))) + ->andWhere($qb->expr()->isNull('deleted_at')); + } else { + $qb = $this->db->getQueryBuilder(); + $qb->select('uri', $qb->func()->max('operation')) + ->from('calendarchanges') + ->where($qb->expr()->eq('calendarid', $qb->createNamedParameter($calendarId))) + ->andWhere($qb->expr()->eq('calendartype', $qb->createNamedParameter($calendarType))) + ->andWhere($qb->expr()->gte('synctoken', $qb->createNamedParameter($syncToken))) + ->andWhere($qb->expr()->lt('synctoken', $qb->createNamedParameter($currentToken))) + ->groupBy('uri'); + } + // evaluate if limit exists + if (is_numeric($limit)) { + $qb->setMaxResults($limit); + } + // execute command + $stmt = $qb->executeQuery(); + // build results + $result = ['syncToken' => $currentToken, 'added' => [], 'modified' => [], 'deleted' => []]; + // retrieve results + if ($initialSync) { $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN); - $stmt->closeCursor(); + } else { + // \PDO::FETCH_NUM is needed due to the inconsistent field names + // produced by doctrine for MAX() with different databases + while ($entry = $stmt->fetch(\PDO::FETCH_NUM)) { + // assign uri (column 0) to appropriate mutation based on operation (column 1) + // forced (int) is needed as doctrine with OCI returns the operation field as string not integer + match ((int)$entry[1]) { + 1 => $result['added'][] = $entry[0], + 2 => $result['modified'][] = $entry[0], + 3 => $result['deleted'][] = $entry[0], + default => $this->logger->debug('Unknown calendar change operation detected') + }; + } } + $stmt->closeCursor(); + return $result; }, $this->db); } |