From 3728c88521413c62ee7260085ea276148192b14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 10 Aug 2026 11:33:07 +0200 Subject: [PATCH 1/6] fix(32bits): Store timestamp in ms in a string to avoid int overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same strategy as for snowflake ids. Signed-off-by: Côme Chilliet --- apps/sharing/lib/ResponseDefinitions.php | 2 +- lib/private/Sharing/SharingBackend.php | 24 +++++++++---------- lib/private/Sharing/SharingManager.php | 13 +++++----- lib/unstable/Sharing/Share.php | 2 +- .../Sharing/AbstractSharingManagerTests.php | 1 - 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/sharing/lib/ResponseDefinitions.php b/apps/sharing/lib/ResponseDefinitions.php index 34bd1e4ab44..6a0b7b48d7a 100644 --- a/apps/sharing/lib/ResponseDefinitions.php +++ b/apps/sharing/lib/ResponseDefinitions.php @@ -123,7 +123,7 @@ use NCU\Sharing\Source\IShareSourceType; * id: non-empty-string, * owner: SharingUser, * // Unix time in milliseconds - * last_updated: non-negative-int, + * last_updated: numeric-string, * state: SharingState, * sources: list, * recipients: list, diff --git a/lib/private/Sharing/SharingBackend.php b/lib/private/Sharing/SharingBackend.php index 35abf383155..c57ffbdd6bc 100644 --- a/lib/private/Sharing/SharingBackend.php +++ b/lib/private/Sharing/SharingBackend.php @@ -543,8 +543,8 @@ final readonly class SharingBackend implements ISharingBackend { $rowCount = $qb ->update('sharing_share') - ->set('last_updated', $qb->createNamedParameter(SharingManager::timeToMs($lastUpdated), IQueryBuilder::PARAM_INT)) - ->where($qb->expr()->in('id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))) + ->set('last_updated', $qb->createNamedParameter(SharingManager::timeToMs($lastUpdated))) + ->where($qb->expr()->in('id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))) ->executeStatement(); if ($rowCount !== count($chunk)) { throw new ShareNotFoundException(); @@ -618,7 +618,7 @@ final readonly class SharingBackend implements ISharingBackend { } // The key type is array-key, because PHP will automatically cast the value. We can't type it as integer though, because we need to also support 32 bit systems and there the autocasting doesn't happen, if the value is too large. - /** @var array, recipients: list, properties: array, ShareProperty>, permissions: array, SharePermission>}> $shares */ + /** @var array, recipients: list, properties: array, ShareProperty>, permissions: array, SharePermission>}> $shares */ $shares = []; foreach ($queries as $qb) { $qb @@ -672,8 +672,8 @@ final readonly class SharingBackend implements ISharingBackend { /** @var non-empty-string $id */ $id = (string)$row['id']; - /** @var non-negative-int $lastUpdated */ - $lastUpdated = (int)$row['last_updated']; + /** @var numeric-string $lastUpdated */ + $lastUpdated = (string)$row['last_updated']; /** @var string $state */ $state = $row['state']; $shares[$id] ??= [ @@ -718,10 +718,10 @@ final readonly class SharingBackend implements ISharingBackend { 'ss.source_value', ) ->from('sharing_share_sources', 'ss') - ->where($qb->expr()->in('ss.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + ->where($qb->expr()->in('ss.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))); $result = $qb->executeQuery(); - /** @var array{source_class_id: mixed, source_value: non-empty-string, share_id: int}[] $rows */ + /** @var array{source_class_id: mixed, source_value: non-empty-string, share_id: string}[] $rows */ $rows = $result->fetchAll(); foreach ($rows as $row) { @@ -749,7 +749,7 @@ final readonly class SharingBackend implements ISharingBackend { } $value = $row['source_value']; - $id = (string)$row['share_id']; + $id = $row['share_id']; $shares[$id]['sources'][] = new ShareSource( $typeClass, $value, @@ -777,7 +777,7 @@ final readonly class SharingBackend implements ISharingBackend { 'sr.initiator_instance', ) ->from('sharing_share_recipients', 'sr') - ->where($qb->expr()->in('sr.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + ->where($qb->expr()->in('sr.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))); foreach ($qb->executeQuery()->fetchAll() as $row) { /** @var class-string $typeClass */ @@ -890,7 +890,7 @@ final readonly class SharingBackend implements ISharingBackend { 'sp.property_value', ) ->from('sharing_share_properties', 'sp') - ->where($qb->expr()->in('sp.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + ->where($qb->expr()->in('sp.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))); $result = $qb->executeQuery(); foreach ($result->fetchAll() as $row) { @@ -961,7 +961,7 @@ final readonly class SharingBackend implements ISharingBackend { 'sp.permission_enabled', ) ->from('sharing_share_permissions', 'sp') - ->where($qb->expr()->in('sp.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + ->where($qb->expr()->in('sp.share_id', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))); $result = $qb->executeQuery(); foreach ($result->fetchAll() as $row) { @@ -1110,7 +1110,7 @@ final readonly class SharingBackend implements ISharingBackend { return $share; } - private static function parseTimestamp(int $timestampMs): \DateTimeImmutable { + private static function parseTimestamp(string $timestampMs): \DateTimeImmutable { if (method_exists(\DateTimeImmutable::class, 'createFromTimestamp')) { // with php 8.3 the method doesn't exist and psalm doesn't know the return type /** @psalm-suppress MixedReturnStatement */ diff --git a/lib/private/Sharing/SharingManager.php b/lib/private/Sharing/SharingManager.php index 51b8dc18b0e..4c2b0f2ee11 100644 --- a/lib/private/Sharing/SharingManager.php +++ b/lib/private/Sharing/SharingManager.php @@ -753,18 +753,17 @@ final readonly class SharingManager implements ISharingManager, IEventListener { } /** - * @return non-negative-int + * @return numeric-string */ - public static function timeToMs(\DateTimeImmutable $time): int { + public static function timeToMs(\DateTimeImmutable $time): string { if (method_exists($time, 'getMicrosecond')) { - /** @var int $micros */ - $micros = $time->getMicrosecond(); + $micros = (float)$time->getMicrosecond(); } else { - $micros = (int)$time->format('u'); + $micros = (float)$time->format('u'); } - $time = $time->getTimestamp() * 1000 + (int)floor($micros / 1000); - if ($time > 0) { + $time = (string)floor((float)$time->getTimestamp() * 1000.0 + $micros / 1000.0); + if ((float)$time > 0) { return $time; } diff --git a/lib/unstable/Sharing/Share.php b/lib/unstable/Sharing/Share.php index feed3031aa3..004313e724d 100644 --- a/lib/unstable/Sharing/Share.php +++ b/lib/unstable/Sharing/Share.php @@ -132,7 +132,7 @@ use OCP\L10N\IFactory; * id: non-empty-string, * owner: SharingUser, * // Unix time in milliseconds - * last_updated: non-negative-int, + * last_updated: numeric-string, * state: SharingState, * sources: list, * recipients: list, diff --git a/tests/lib/Sharing/AbstractSharingManagerTests.php b/tests/lib/Sharing/AbstractSharingManagerTests.php index 3ab9d5e15c3..a79dc5d501b 100644 --- a/tests/lib/Sharing/AbstractSharingManagerTests.php +++ b/tests/lib/Sharing/AbstractSharingManagerTests.php @@ -87,7 +87,6 @@ abstract class AbstractSharingManagerTests extends TestCase { protected IUser $user2; private function parseTime(mixed $timestampMs): \DateTimeImmutable { - $timestampMs = (int)$timestampMs; $time = \DateTimeImmutable::createFromFormat('U.u', number_format((float)$timestampMs / 1000.0, 3, '.', '')); if ($time === false) { throw new \RuntimeException('invalid timestamp: ' . $timestampMs); From 387288d6561880d148ad626e880e780f08a6d8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 10 Aug 2026 13:05:17 +0200 Subject: [PATCH 2/6] chore: Remove useless matrix from phpunit-32bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only PHP 8.4 is tested because we use our own image Signed-off-by: Côme Chilliet --- .github/workflows/phpunit-32bits.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/phpunit-32bits.yml b/.github/workflows/phpunit-32bits.yml index 0bcbb786e25..105b174342b 100644 --- a/.github/workflows/phpunit-32bits.yml +++ b/.github/workflows/phpunit-32bits.yml @@ -29,8 +29,6 @@ jobs: strategy: fail-fast: false - matrix: - php-versions: ['8.3', '8,5'] steps: - name: Checkout server From a46f0bc3d10648a4738fdaefe0199590f8f1c66e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 10 Aug 2026 16:33:26 +0200 Subject: [PATCH 3/6] chore(ci): use ${GITHUB_WORKSPACE} instead of hardcoded value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That helps when testing locally with nektos/act Signed-off-by: Côme Chilliet --- .github/workflows/phpunit-32bits.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit-32bits.yml b/.github/workflows/phpunit-32bits.yml index 105b174342b..f1d8da06fd0 100644 --- a/.github/workflows/phpunit-32bits.yml +++ b/.github/workflows/phpunit-32bits.yml @@ -41,7 +41,7 @@ jobs: uses: docker://ghcr.io/nextcloud/continuous-integration-php8.4-32bit:latest with: args: /bin/sh -c " - git config --global --add safe.directory /github/workspace && + git config --global --add safe.directory ${GITHUB_WORKSPACE} && composer install --no-interaction" - name: Set up Nextcloud From 376a64c4aebf9ae5afba0042454422e12abc3bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 10 Aug 2026 17:19:53 +0200 Subject: [PATCH 4/6] fix: PHP_INT_SIZE is 8 on 64bits, not 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ternary was reversed because of this typo. Signed-off-by: Côme Chilliet --- lib/private/ServerInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/ServerInfo.php b/lib/private/ServerInfo.php index bf5dec468f2..05da80bae04 100644 --- a/lib/private/ServerInfo.php +++ b/lib/private/ServerInfo.php @@ -25,7 +25,7 @@ readonly class ServerInfo implements IServerInfo { if ($serverid < 1) { // Fallback: generates a server ID based on hostname /** @var int<0,max> */ - $serverid = PHP_INT_SIZE === 4 + $serverid = PHP_INT_SIZE === 8 ? hexdec(hash('xxh32', $this->getHostname())) // Makes sure it doesn't overflow 32 bits int : hexdec(substr(hash('xxh32', $this->getHostname()), -3)); From fe96dd99c6301b544b38c5d6a9a1d20604d4efee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 11 Aug 2026 09:22:00 +0200 Subject: [PATCH 5/6] chore(sharing): Rebuild openapi.json files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/sharing/openapi.json | 6 ++---- openapi.json | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/sharing/openapi.json b/apps/sharing/openapi.json index 191435bf86c..98beb6864c1 100644 --- a/apps/sharing/openapi.json +++ b/apps/sharing/openapi.json @@ -465,10 +465,8 @@ "$ref": "#/components/schemas/User" }, "last_updated": { - "type": "integer", - "format": "int64", - "description": "Unix time in milliseconds", - "minimum": 0 + "type": "string", + "description": "Unix time in milliseconds" }, "state": { "$ref": "#/components/schemas/State" diff --git a/openapi.json b/openapi.json index 3aaf8b5a32b..a0d248d466c 100644 --- a/openapi.json +++ b/openapi.json @@ -4653,10 +4653,8 @@ "$ref": "#/components/schemas/SharingUser" }, "last_updated": { - "type": "integer", - "format": "int64", - "description": "Unix time in milliseconds", - "minimum": 0 + "type": "string", + "description": "Unix time in milliseconds" }, "state": { "$ref": "#/components/schemas/SharingState" From d9867d73b235cb91d0988d243daa2abee9bbbb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 11 Aug 2026 10:41:44 +0200 Subject: [PATCH 6/6] chore(sharing): Improve typing in tests to please psalm:strict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/sharing/tests/Command/CommandTest.php | 44 +++++++++---------- .../tests/Controller/ApiV1ControllerTest.php | 14 ++++-- .../Sharing/AbstractSharingManagerTests.php | 32 +++++++++++++- 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/apps/sharing/tests/Command/CommandTest.php b/apps/sharing/tests/Command/CommandTest.php index fae0f6717c1..19b1ca1b271 100644 --- a/apps/sharing/tests/Command/CommandTest.php +++ b/apps/sharing/tests/Command/CommandTest.php @@ -164,7 +164,7 @@ final class CommandTest extends AbstractSharingManagerTests { } /** - * @return array + * @return SharingShare */ #[Override] protected function createShare(ShareAccessContext $accessContext): array { @@ -177,12 +177,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function updateShareState(ShareAccessContext $accessContext, string $id, ShareState $state): array { @@ -195,12 +195,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function addShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array { @@ -214,12 +214,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function removeShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array { @@ -233,12 +233,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function addShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array { @@ -253,12 +253,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function removeShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array { @@ -273,12 +273,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function updateShareRecipientSecret(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient, string $secret): array { @@ -294,12 +294,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function updateShareProperty(ShareAccessContext $accessContext, string $id, ShareProperty $property): array { @@ -313,12 +313,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function updateSharePermission(ShareAccessContext $accessContext, string $id, SharePermission $permission): array { @@ -332,12 +332,12 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } /** - * @return array + * @return SharingShare */ #[Override] protected function selectSharePermissionPreset(ShareAccessContext $accessContext, string $id, string $permissionPresetClass): array { @@ -350,7 +350,7 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } @@ -379,7 +379,7 @@ final class CommandTest extends AbstractSharingManagerTests { ], [], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } @@ -399,7 +399,7 @@ final class CommandTest extends AbstractSharingManagerTests { ['limit', $limit], ], ); - /** @psalm-suppress MixedReturnStatement */ + /** @var SharingShare[] */ return json_decode($stdout, true, 512, JSON_THROW_ON_ERROR); } } diff --git a/apps/sharing/tests/Controller/ApiV1ControllerTest.php b/apps/sharing/tests/Controller/ApiV1ControllerTest.php index eaf057a8f4a..05395007891 100644 --- a/apps/sharing/tests/Controller/ApiV1ControllerTest.php +++ b/apps/sharing/tests/Controller/ApiV1ControllerTest.php @@ -95,53 +95,63 @@ final class ApiV1ControllerTest extends AbstractSharingManagerTests { #[Override] protected function createShare(ShareAccessContext $accessContext): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->createShare()); } #[Override] protected function updateShareState(ShareAccessContext $accessContext, string $id, ShareState $state): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->updateShareState($id, $state->value)); } #[Override] protected function addShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->addShareSource($id, $source->class, $source->value)); } #[Override] protected function removeShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->removeShareSource($id, $source->class, $source->value)); } #[Override] protected function addShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->addShareRecipient($id, $recipient->class, $recipient->value, $recipient->instance)); } #[Override] protected function removeShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->removeShareRecipient($id, $recipient->class, $recipient->value, $recipient->instance)); } #[Override] protected function updateShareRecipientSecret(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient, string $secret): array { /** @psalm-suppress ArgumentTypeCoercion */ + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->updateShareRecipientSecret($id, $recipient->class, $recipient->value, $recipient->instance, $secret)); } #[Override] protected function updateShareProperty(ShareAccessContext $accessContext, string $id, ShareProperty $property): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->updateShareProperty($id, $property->class, $property->value)); } #[Override] protected function updateSharePermission(ShareAccessContext $accessContext, string $id, SharePermission $permission): array { + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->updateSharePermission($id, $permission->class, $permission->enabled)); } #[Override] protected function selectSharePermissionPreset(ShareAccessContext $accessContext, string $id, string $permissionPresetClass): array { /** @psalm-suppress ArgumentTypeCoercion */ + /** @var SharingShare */ return $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->selectSharePermissionPreset($id, $permissionPresetClass)); } @@ -150,11 +160,9 @@ final class ApiV1ControllerTest extends AbstractSharingManagerTests { $this->executeRequest($accessContext, fn (ApiV1Controller $controller): DataResponse => $controller->deleteShare($id)); } - /** - * @psalm-suppress MixedReturnTypeCoercion - */ #[Override] protected function getShare(ShareAccessContext $accessContext, string $id): array { + /** @var SharingShare */ return $this->executeRequest(new ShareAccessContext($accessContext->currentUser, null, [], $accessContext->overrideChecks), fn (ApiV1Controller $controller): DataResponse => $controller->getShare($id, $accessContext->secret, $accessContext->arguments)); } diff --git a/tests/lib/Sharing/AbstractSharingManagerTests.php b/tests/lib/Sharing/AbstractSharingManagerTests.php index a79dc5d501b..ee248397d8c 100644 --- a/tests/lib/Sharing/AbstractSharingManagerTests.php +++ b/tests/lib/Sharing/AbstractSharingManagerTests.php @@ -42,24 +42,54 @@ use Test\TestCase; abstract class AbstractSharingManagerTests extends TestCase { abstract protected function searchRecipients(ShareAccessContext $accessContext, ?array $filterRecipientTypeClasses, string $query, int $limit, int $offset, ?string $id = null): array; + /** + * @return SharingShare + */ abstract protected function createShare(ShareAccessContext $accessContext): array; + /** + * @return SharingShare + */ abstract protected function updateShareState(ShareAccessContext $accessContext, string $id, ShareState $state): array; + /** + * @return SharingShare + */ abstract protected function addShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array; + /** + * @return SharingShare + */ abstract protected function removeShareSource(ShareAccessContext $accessContext, string $id, ShareSource $source): array; + /** + * @return SharingShare + */ abstract protected function addShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array; + /** + * @return SharingShare + */ abstract protected function removeShareRecipient(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient): array; + /** + * @return SharingShare + */ abstract protected function updateShareRecipientSecret(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient, string $secret): array; + /** + * @return SharingShare + */ abstract protected function updateShareProperty(ShareAccessContext $accessContext, string $id, ShareProperty $property): array; + /** + * @return SharingShare + */ abstract protected function updateSharePermission(ShareAccessContext $accessContext, string $id, SharePermission $permission): array; + /** + * @return SharingShare + */ abstract protected function selectSharePermissionPreset(ShareAccessContext $accessContext, string $id, string $permissionPresetClass): array; abstract protected function deleteShare(ShareAccessContext $accessContext, string $id): void; @@ -86,7 +116,7 @@ abstract class AbstractSharingManagerTests extends TestCase { protected IUser $user2; - private function parseTime(mixed $timestampMs): \DateTimeImmutable { + private function parseTime(string $timestampMs): \DateTimeImmutable { $time = \DateTimeImmutable::createFromFormat('U.u', number_format((float)$timestampMs / 1000.0, 3, '.', '')); if ($time === false) { throw new \RuntimeException('invalid timestamp: ' . $timestampMs);