diff options
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 13 | ||||
-rw-r--r-- | apps/dav/lib/CardDAV/CardDavBackend.php | 13 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/CalDavBackendTest.php | 74 | ||||
-rw-r--r-- | apps/dav/tests/unit/CardDAV/CardDavBackendTest.php | 41 | ||||
-rw-r--r-- | core/Command/Config/App/DeleteConfig.php | 10 | ||||
-rw-r--r-- | core/Command/Config/App/GetConfig.php | 7 | ||||
-rw-r--r-- | core/Command/Config/App/SetConfig.php | 7 | ||||
-rw-r--r-- | core/Command/Config/Import.php | 6 | ||||
-rw-r--r-- | core/Command/Config/ListConfigs.php | 9 | ||||
-rw-r--r-- | core/Command/Config/System/Base.php | 7 | ||||
-rw-r--r-- | core/Command/Config/System/DeleteConfig.php | 4 | ||||
-rw-r--r-- | core/Command/Config/System/GetConfig.php | 4 | ||||
-rw-r--r-- | core/Command/Config/System/SetConfig.php | 4 | ||||
-rw-r--r-- | core/Command/Group/Add.php | 7 | ||||
-rw-r--r-- | core/Command/Group/AddUser.php | 10 | ||||
-rw-r--r-- | core/Command/Group/Delete.php | 7 | ||||
-rw-r--r-- | core/Command/Group/Info.php | 7 | ||||
-rw-r--r-- | core/Command/Group/ListCommand.php | 7 | ||||
-rw-r--r-- | core/Command/Group/RemoveUser.php | 10 |
19 files changed, 183 insertions, 64 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 1cdb705ac92..94fe9acf356 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -3134,10 +3134,19 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription if ($keep < 0) { throw new \InvalidArgumentException(); } + + $query = $this->db->getQueryBuilder(); + $query->select($query->func()->max('id')) + ->from('calendarchanges'); + + $maxId = $query->executeQuery()->fetchOne(); + if (!$maxId || $maxId < $keep) { + return 0; + } + $query = $this->db->getQueryBuilder(); $query->delete('calendarchanges') - ->orderBy('id', 'DESC') - ->setFirstResult($keep); + ->where($query->expr()->lte('id', $query->createNamedParameter($maxId - $keep, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)); return $query->executeStatement(); } diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 4e4d64f6f72..1be1ce3f18f 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -1399,10 +1399,19 @@ class CardDavBackend implements BackendInterface, SyncSupport { if ($keep < 0) { throw new \InvalidArgumentException(); } + + $query = $this->db->getQueryBuilder(); + $query->select($query->func()->max('id')) + ->from('addressbookchanges'); + + $maxId = $query->executeQuery()->fetchOne(); + if (!$maxId || $maxId < $keep) { + return 0; + } + $query = $this->db->getQueryBuilder(); $query->delete('addressbookchanges') - ->orderBy('id', 'DESC') - ->setFirstResult($keep); + ->where($query->expr()->lte('id', $query->createNamedParameter($maxId - $keep, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)); return $query->executeStatement(); } diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index 69096d0cfbb..0fdd617943b 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -1291,6 +1291,8 @@ EOD; */ public function testPruneOutdatedSyncTokens(): void { $calendarId = $this->createTestCalendar(); + $changes = $this->backend->getChangesForCalendar($calendarId, '', 1); + $syncToken = $changes['syncToken']; $uri = static::getUniqueID('calobj'); $calData = <<<EOD @@ -1333,9 +1335,79 @@ EOD; $deleted = $this->backend->pruneOutdatedSyncTokens(0); // At least one from the object creation and one from the object update $this->assertGreaterThanOrEqual(2, $deleted); - $changes = $this->backend->getChangesForCalendar($calendarId, '5', 1); + $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 1); $this->assertEmpty($changes['added']); $this->assertEmpty($changes['modified']); $this->assertEmpty($changes['deleted']); + + // Test that objects remain + + // Currently changes are empty + $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 100); + $this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted'])); + + // Create card + $uri = static::getUniqueID('calobj'); +$calData = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:Nextcloud Calendar +BEGIN:VEVENT +CREATED;VALUE=DATE-TIME:20230910T125139Z +UID:47d15e3ec9 +LAST-MODIFIED;VALUE=DATE-TIME:20230910T125139Z +DTSTAMP;VALUE=DATE-TIME:20230910T125139Z +SUMMARY:Test Event +DTSTART;VALUE=DATE-TIME:20230912T130000Z +DTEND;VALUE=DATE-TIME:20230912T140000Z +CLASS:PUBLIC +END:VEVENT +END:VCALENDAR +EOD; + $this->backend->createCalendarObject($calendarId, $uri, $calData); + + // We now have one add + $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 100); + $this->assertEquals(1, count($changes['added'])); + $this->assertEmpty($changes['modified']); + $this->assertEmpty($changes['deleted']); + + // update the card + $calData = <<<'EOD' +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:Nextcloud Calendar +BEGIN:VEVENT +CREATED;VALUE=DATE-TIME:20230910T125139Z +UID:47d15e3ec9 +LAST-MODIFIED;VALUE=DATE-TIME:20230910T125139Z +DTSTAMP;VALUE=DATE-TIME:20230910T125139Z +SUMMARY:123 Event 🙈 +DTSTART;VALUE=DATE-TIME:20230912T130000Z +DTEND;VALUE=DATE-TIME:20230912T140000Z +ATTENDEE;CN=test:mailto:foo@bar.com +END:VEVENT +END:VCALENDAR +EOD; + $this->backend->updateCalendarObject($calendarId, $uri, $calData); + + // One add, one modify, but shortened to modify + $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 100); + $this->assertEmpty($changes['added']); + $this->assertEquals(1, count($changes['modified'])); + $this->assertEmpty($changes['deleted']); + + // Delete all but last change + $deleted = $this->backend->pruneOutdatedSyncTokens(1); + $this->assertEquals(1, $deleted); // We had two changes before, now one + + // Only update should remain + $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 100); + $this->assertEmpty($changes['added']); + $this->assertEquals(1, count($changes['modified'])); + $this->assertEmpty($changes['deleted']); + + // Check that no crash occurs when prune is called without current changes + $deleted = $this->backend->pruneOutdatedSyncTokens(1); } } diff --git a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php index adf64ef82b0..425e7c44ba7 100644 --- a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php +++ b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php @@ -853,15 +853,54 @@ class CardDavBackendTest extends TestCase { */ public function testPruneOutdatedSyncTokens(): void { $addressBookId = $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []); + $changes = $this->backend->getChangesForAddressBook($addressBookId, '', 1); + $syncToken = $changes['syncToken']; + $uri = $this->getUniqueID('card'); $this->backend->createCard($addressBookId, $uri, $this->vcardTest0); $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1); $deleted = $this->backend->pruneOutdatedSyncTokens(0); // At least one from the object creation and one from the object update $this->assertGreaterThanOrEqual(2, $deleted); - $changes = $this->backend->getChangesForAddressBook($addressBookId, '5', 1); + $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 1); $this->assertEmpty($changes['added']); $this->assertEmpty($changes['modified']); $this->assertEmpty($changes['deleted']); + + // Test that objects remain + + // Currently changes are empty + $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100); + $this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted'])); + + // Create card + $uri = $this->getUniqueID('card'); + $this->backend->createCard($addressBookId, $uri, $this->vcardTest0); + // We now have one add + $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100); + $this->assertEquals(1, count($changes['added'])); + $this->assertEmpty($changes['modified']); + $this->assertEmpty($changes['deleted']); + + // Update card + $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1); + // One add, one modify, but shortened to modify + $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100); + $this->assertEmpty($changes['added']); + $this->assertEquals(1, count($changes['modified'])); + $this->assertEmpty($changes['deleted']); + + // Delete all but last change + $deleted = $this->backend->pruneOutdatedSyncTokens(1); + $this->assertEquals(1, $deleted); // We had two changes before, now one + + // Only update should remain + $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100); + $this->assertEmpty($changes['added']); + $this->assertEquals(1, count($changes['modified'])); + $this->assertEmpty($changes['deleted']); + + // Check that no crash occurs when prune is called without current changes + $deleted = $this->backend->pruneOutdatedSyncTokens(1); } } diff --git a/core/Command/Config/App/DeleteConfig.php b/core/Command/Config/App/DeleteConfig.php index 0da1e965bd0..b77f27ccd07 100644 --- a/core/Command/Config/App/DeleteConfig.php +++ b/core/Command/Config/App/DeleteConfig.php @@ -28,14 +28,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class DeleteConfig extends Base { - protected IConfig $config; - - /** - * @param IConfig $config - */ - public function __construct(IConfig $config) { + public function __construct( + protected IConfig $config, + ) { parent::__construct(); - $this->config = $config; } protected function configure() { diff --git a/core/Command/Config/App/GetConfig.php b/core/Command/Config/App/GetConfig.php index 7fdff2be732..96078b63e90 100644 --- a/core/Command/Config/App/GetConfig.php +++ b/core/Command/Config/App/GetConfig.php @@ -28,11 +28,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class GetConfig extends Base { - protected IConfig $config; - - public function __construct(IConfig $config) { + public function __construct( + protected IConfig $config, + ) { parent::__construct(); - $this->config = $config; } protected function configure() { diff --git a/core/Command/Config/App/SetConfig.php b/core/Command/Config/App/SetConfig.php index 89a5f6ba5d1..99746246b85 100644 --- a/core/Command/Config/App/SetConfig.php +++ b/core/Command/Config/App/SetConfig.php @@ -28,11 +28,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SetConfig extends Base { - protected IConfig $config; - - public function __construct(IConfig $config) { + public function __construct( + protected IConfig $config, + ) { parent::__construct(); - $this->config = $config; } protected function configure() { diff --git a/core/Command/Config/Import.php b/core/Command/Config/Import.php index 227c909038c..b8431c8c295 100644 --- a/core/Command/Config/Import.php +++ b/core/Command/Config/Import.php @@ -35,11 +35,11 @@ use Symfony\Component\Console\Output\OutputInterface; class Import extends Command implements CompletionAwareInterface { protected array $validRootKeys = ['system', 'apps']; - protected IConfig $config; - public function __construct(IConfig $config) { + public function __construct( + protected IConfig $config, + ) { parent::__construct(); - $this->config = $config; } protected function configure() { diff --git a/core/Command/Config/ListConfigs.php b/core/Command/Config/ListConfigs.php index dd8fad72d7c..4adb0a9df5b 100644 --- a/core/Command/Config/ListConfigs.php +++ b/core/Command/Config/ListConfigs.php @@ -33,13 +33,12 @@ use Symfony\Component\Console\Output\OutputInterface; class ListConfigs extends Base { protected string $defaultOutputFormat = self::OUTPUT_FORMAT_JSON_PRETTY; - protected SystemConfig $systemConfig; - protected IAppConfig $appConfig; - public function __construct(SystemConfig $systemConfig, IAppConfig $appConfig) { + public function __construct( + protected SystemConfig $systemConfig, + protected IAppConfig $appConfig, + ) { parent::__construct(); - $this->systemConfig = $systemConfig; - $this->appConfig = $appConfig; } protected function configure() { diff --git a/core/Command/Config/System/Base.php b/core/Command/Config/System/Base.php index 18bc9cb7ca0..09ec456f6a4 100644 --- a/core/Command/Config/System/Base.php +++ b/core/Command/Config/System/Base.php @@ -26,11 +26,10 @@ use OC\SystemConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; abstract class Base extends \OC\Core\Command\Base { - protected SystemConfig $systemConfig; - - public function __construct(SystemConfig $systemConfig) { + public function __construct( + protected SystemConfig $systemConfig, + ) { parent::__construct(); - $this->systemConfig = $systemConfig; } /** diff --git a/core/Command/Config/System/DeleteConfig.php b/core/Command/Config/System/DeleteConfig.php index f4d49ba8f51..f6650e7d6d3 100644 --- a/core/Command/Config/System/DeleteConfig.php +++ b/core/Command/Config/System/DeleteConfig.php @@ -30,7 +30,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class DeleteConfig extends Base { - public function __construct(SystemConfig $systemConfig) { + public function __construct( + SystemConfig $systemConfig, + ) { parent::__construct($systemConfig); } diff --git a/core/Command/Config/System/GetConfig.php b/core/Command/Config/System/GetConfig.php index 01bbf82d5d1..ab5b884fda4 100644 --- a/core/Command/Config/System/GetConfig.php +++ b/core/Command/Config/System/GetConfig.php @@ -29,7 +29,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class GetConfig extends Base { - public function __construct(SystemConfig $systemConfig) { + public function __construct( + SystemConfig $systemConfig, + ) { parent::__construct($systemConfig); } diff --git a/core/Command/Config/System/SetConfig.php b/core/Command/Config/System/SetConfig.php index 01a1999bcf9..ba5265a84d7 100644 --- a/core/Command/Config/System/SetConfig.php +++ b/core/Command/Config/System/SetConfig.php @@ -32,7 +32,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SetConfig extends Base { - public function __construct(SystemConfig $systemConfig) { + public function __construct( + SystemConfig $systemConfig, + ) { parent::__construct($systemConfig); } diff --git a/core/Command/Group/Add.php b/core/Command/Group/Add.php index d205cef0696..40502762e95 100644 --- a/core/Command/Group/Add.php +++ b/core/Command/Group/Add.php @@ -36,10 +36,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Add extends Base { - protected IGroupManager $groupManager; - - public function __construct(IGroupManager $groupManager) { - $this->groupManager = $groupManager; + public function __construct( + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/Group/AddUser.php b/core/Command/Group/AddUser.php index 6638bcd4c6d..a66d2898ef9 100644 --- a/core/Command/Group/AddUser.php +++ b/core/Command/Group/AddUser.php @@ -34,12 +34,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class AddUser extends Base { - protected IUserManager $userManager; - protected IGroupManager $groupManager; - - public function __construct(IUserManager $userManager, IGroupManager $groupManager) { - $this->userManager = $userManager; - $this->groupManager = $groupManager; + public function __construct( + protected IUserManager $userManager, + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/Group/Delete.php b/core/Command/Group/Delete.php index fd1074d6f61..c7cbf0aa0f6 100644 --- a/core/Command/Group/Delete.php +++ b/core/Command/Group/Delete.php @@ -35,10 +35,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Delete extends Base { - protected IGroupManager $groupManager; - - public function __construct(IGroupManager $groupManager) { - $this->groupManager = $groupManager; + public function __construct( + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/Group/Info.php b/core/Command/Group/Info.php index dc475581ac5..1dab56e1a89 100644 --- a/core/Command/Group/Info.php +++ b/core/Command/Group/Info.php @@ -35,10 +35,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Info extends Base { - protected IGroupManager $groupManager; - - public function __construct(IGroupManager $groupManager) { - $this->groupManager = $groupManager; + public function __construct( + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/Group/ListCommand.php b/core/Command/Group/ListCommand.php index 0285cc05dcd..22ce4cb0317 100644 --- a/core/Command/Group/ListCommand.php +++ b/core/Command/Group/ListCommand.php @@ -32,10 +32,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListCommand extends Base { - protected IGroupManager $groupManager; - - public function __construct(IGroupManager $groupManager) { - $this->groupManager = $groupManager; + public function __construct( + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/Group/RemoveUser.php b/core/Command/Group/RemoveUser.php index c7b3a2d84e7..6c7d4ce4d84 100644 --- a/core/Command/Group/RemoveUser.php +++ b/core/Command/Group/RemoveUser.php @@ -34,12 +34,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class RemoveUser extends Base { - protected IUserManager $userManager; - protected IGroupManager $groupManager; - - public function __construct(IUserManager $userManager, IGroupManager $groupManager) { - $this->userManager = $userManager; - $this->groupManager = $groupManager; + public function __construct( + protected IUserManager $userManager, + protected IGroupManager $groupManager, + ) { parent::__construct(); } |