assertGreaterThanOrEqual(SharingManager::timeToMs($before), SharingManager::timeToMs($time)); $this->assertLessThanOrEqual(SharingManager::timeToMs($after), SharingManager::timeToMs($time)); } #[\Override] public function setUp(): void { parent::setUp(); $this->dbConnection = Server::get(IDBConnection::class); $this->manager = Server::get(ISharingManager::class); $this->l10nFactory = Server::get(IFactory::class); $userManager = Server::get(IUserManager::class); $owner = $userManager->createUser('owner', 'password'); $this->assertNotFalse($owner); $this->owner = $owner; $this->owner->setDisplayName('Owner'); $user1 = $userManager->createUser('user1', 'password'); $this->assertNotFalse($user1); $this->user1 = $user1; $this->user1->setDisplayName('User 1'); $user2 = $userManager->createUser('user2', 'password'); $this->assertNotFalse($user2); $this->user2 = $user2; $this->user2->setDisplayName('User 2'); $this->registry = Server::get(ISharingRegistry::class); $this->registry->clear(); $this->registry->registerSourceType(new TestShareSourceType1(['source1' => 'Source 1'])); $this->registry->registerSourceType(new TestShareSourceType2(['source2' => 'Source 2'])); $this->registry->registerRecipientType(new TestShareRecipientType1( [ 'recipient1' => 'Recipient 1', ], [ $this->user1->getUID() => ['recipient1'], ], [ new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null), ], )); $this->registry->registerRecipientType(new TestShareRecipientType2( [ 'recipient2' => 'Recipient 2', ], [ $this->user2->getUID() => ['recipient2'], ], [ new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null), ], )); $this->registry->registerPropertyType(new TestSharePropertyType1(['valid1'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyType1::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyType1::class, TestShareRecipientType1::class); $this->registry->registerPropertyType(new TestSharePropertyType2(['valid2'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyType2::class, TestShareSourceType2::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyType2::class, TestShareRecipientType2::class); $this->registry->registerPermissionPreset(new TestSharePermissionPreset1()); $this->registry->registerPermissionPreset(new TestSharePermissionPreset2()); $this->registry->registerPermissionType(TestShareSourceType1::class, new TestSharePermissionType1()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset1::class); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset2::class); $this->registry->registerPermissionType(TestShareSourceType2::class, new TestSharePermissionType2()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType2::class, TestSharePermissionPreset2::class); $this->registry->registerPermissionType(null, Server::get(ReshareSharePermissionType::class)); } #[\Override] protected function tearDown(): void { if ($this->dbConnection->inTransaction()) { $this->dbConnection->rollBack(); $this->fail('Open transaction was not committed.'); } $accessContext = new ShareAccessContext(overrideChecks: true); $this->dbConnection->beginTransaction(); foreach ($this->manager->getShares($accessContext, null, null, null, null) as $share) { $this->manager->deleteShare($accessContext, $share); } $this->owner->delete(); $this->user1->delete(); $this->user2->delete(); $this->dbConnection->commit(); foreach ([ 'sharing_share', 'sharing_share_permissions', 'sharing_share_properties', 'sharing_share_recipients', 'sharing_share_sources', ] as $table) { $qb = $this->dbConnection->getQueryBuilder(); $qb ->select($qb->func()->count('*')) ->from($table); $this->assertEquals(0, $qb->executeQuery()->fetchOne(), $table); } $this->registry->clear(); parent::tearDown(); } private function reloadShare(ShareAccessContext $accessContext, Share $share): Share { $this->dbConnection->beginTransaction(); $share = $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); return $share; } public function testSearchRecipients(): void { $this->registry->clear(); $this->registry->registerRecipientType(new TestShareRecipientType1( [ 'recipient1a' => 'Recipient 1A', 'recipient1b' => 'Recipient 1B', 'recipient1c' => 'Recipient 1C', ], [], [ new ShareRecipient(TestShareRecipientType1::class, 'recipient1a', null), new ShareRecipient(TestShareRecipientType1::class, 'recipient1b', null), new ShareRecipient(TestShareRecipientType1::class, 'recipient1c', null), ], )); $this->registry->registerRecipientType(new TestShareRecipientType2( [ 'recipient2a' => 'Recipient 2A', 'recipient2b' => 'Recipient 2B', 'recipient2c' => 'Recipient 2C', ], [], [ new ShareRecipient(TestShareRecipientType2::class, 'recipient2a', null), new ShareRecipient(TestShareRecipientType2::class, 'recipient2b', null), new ShareRecipient(TestShareRecipientType2::class, 'recipient2c', null), ], )); $accessContext = new ShareAccessContext($this->owner); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1a', 'instance' => null, 'display_name' => 'Recipient 1A', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1b', 'instance' => null, 'display_name' => 'Recipient 1B', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1c', 'instance' => null, 'display_name' => 'Recipient 1C', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2a', 'instance' => null, 'display_name' => 'Recipient 2A', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2b', 'instance' => null, 'display_name' => 'Recipient 2B', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2c', 'instance' => null, 'display_name' => 'Recipient 2C', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, null, 'recipient', 10, 0)); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1a', 'instance' => null, 'display_name' => 'Recipient 1A', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1b', 'instance' => null, 'display_name' => 'Recipient 1B', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1c', 'instance' => null, 'display_name' => 'Recipient 1C', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, [TestShareRecipientType1::class], 'recipient', 10, 0)); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1a', 'instance' => null, 'display_name' => 'Recipient 1A', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, [TestShareRecipientType1::class], 'recipient', 1, 0)); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1b', 'instance' => null, 'display_name' => 'Recipient 1B', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1c', 'instance' => null, 'display_name' => 'Recipient 1C', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, [TestShareRecipientType1::class], 'recipient', 10, 1)); } public function testSearchRecipientsUniqueDisplayNames(): void { $this->registry->clear(); $this->registry->registerRecipientType(new TestShareRecipientType1( [ 'recipient1' => 'Recipient', ], [], [ new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null), ], )); $this->registry->registerRecipientType(new TestShareRecipientType2( [ 'recipient2' => 'Recipient', 'recipient3' => 'Other', ], [], [ new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null), new ShareRecipient(TestShareRecipientType2::class, 'recipient3', null), ], )); $accessContext = new ShareAccessContext($this->owner); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient (TestShareRecipientType1: recipient1)', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient (TestShareRecipientType2: recipient2)', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient3', 'instance' => null, 'display_name' => 'Other', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, null, 'recipient', 10, 0)); } public function testSearchRecipientsIcons(): void { $this->registry->clear(); $this->registry->registerRecipientType(new TestShareRecipientType1( [ 'svg' => 'SVG', 'url' => 'URL', ], [], [ new ShareRecipient(TestShareRecipientType1::class, 'svg', null), new ShareRecipient(TestShareRecipientType1::class, 'url', null), ], )); $accessContext = new ShareAccessContext($this->owner); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'svg', 'instance' => null, 'display_name' => 'SVG', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType1::class, 'value' => 'url', 'instance' => null, 'display_name' => 'URL', 'icon' => [ 'light' => 'https://example.com/light.png', 'dark' => 'https://example.com/dark.png', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, null, 'icon', 10, 0)); } public function testSearchRecipientsOmitExisting(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->dbConnection->commit(); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, null, 'recipient', 3, 0, $share)); $this->dbConnection->beginTransaction(); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->dbConnection->commit(); $this->assertEquals([ [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => null, ], ], $this->searchRecipients($accessContext, null, 'recipient', 3, 0, $share)); } public function testCreateShare(): void { $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $share = $this->createShare($accessContext); $after = $this->manager->getTime(); unset($share['id']); $this->assertDateBetween($before, $after, $this->parseTime($share['last_updated'])); unset($share['last_updated']); $this->assertEquals([ 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [], 'recipients' => [], 'properties' => [], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], ], 'permission_preset' => null, ], $share); } /** * @return list, list, list, list, ?string}> */ public static function dataProviderUpdateShareState(): array { return [ [ [new ShareSource(TestShareSourceType1::class, 'source1')], [new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)], [new ShareProperty(TestSharePropertyTypeRequired::class, 'valid1')], [new SharePermission(ReshareSharePermissionType::class, true)], null, ], [ [], [new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)], [], [new SharePermission(ReshareSharePermissionType::class, true)], 'You need to add at least one source to make the share available.', ], [ [new ShareSource(TestShareSourceType1::class, 'source1')], [], [], [new SharePermission(ReshareSharePermissionType::class, true)], 'You need to add at least one recipient to make the share available.', ], [ [new ShareSource(TestShareSourceType1::class, 'source1')], [new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)], [new ShareProperty(TestSharePropertyTypeRequired::class, null)], [new SharePermission(ReshareSharePermissionType::class, true)], 'You need to set a value for the TestSharePropertyTypeRequired', ], [ [new ShareSource(TestShareSourceType1::class, 'source1')], [new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)], [new ShareProperty(TestSharePropertyTypeRequired::class, 'valid1')], [new SharePermission(ReshareSharePermissionType::class, false)], 'You need to allow at least one permission to make the share available.', ], ]; } /** * @param list $sources * @param list $recipients * @param list $properties * @param list $permissions */ #[DataProvider('dataProviderUpdateShareState')] public function testUpdateShareState(array $sources, array $recipients, array $properties, array $permissions, ?string $errorMessage): void { $this->registry->registerPropertyType(new TestSharePropertyTypeRequired(['valid1'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyTypeRequired::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyTypeRequired::class, TestShareRecipientType1::class); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); foreach ($sources as $source) { $share = $this->manager->addShareSource($accessContext, $share, $source); } foreach ($recipients as $recipient) { $share = $this->manager->addShareRecipient($accessContext, $share, $recipient); } foreach ($properties as $property) { $share = $this->manager->updateShareProperty($accessContext, $share, $property); } foreach ($permissions as $permission) { $share = $this->manager->updateSharePermission($accessContext, $share, $permission); } $this->dbConnection->commit(); if ($errorMessage !== null) { try { $this->updateShareState($accessContext, $share, ShareState::Active); $this->fail('Allowed to set share state active.'); } catch (HintException $exception) { $this->assertEquals($errorMessage, $exception->getHint()); } } else { $before = $this->manager->getTime(); $formatted = $this->updateShareState($accessContext, $share, ShareState::Active); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Active->value, $formatted['state']); } } public function testAddShareSource(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], $formatted['sources']); } public function testAddShareSourceInteractionRestricted(): void { $listener = function (RestrictInteractionEvent $event): void { foreach ($event->resources as $resource) { if ($resource instanceof TestInteractionResource && $resource->getID() === 'source1') { throw new InteractionRestrictedException('Source not allowed.', 'You are not allowed to add this source.'); } } }; $eventDispatcher = Server::get(IEventDispatcher::class); $eventDispatcher->addListener(RestrictInteractionEvent::class, $listener); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->reloadShare($accessContext, $share); $this->dbConnection->commit(); try { $this->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->fail('Not restricted.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to add this source.', $hintException->getHint()); } $eventDispatcher->removeListener(RestrictInteractionEvent::class, $listener); } public function testRemoveShareSource(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType2::class, 'source2')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType2::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->removeShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Active->value, $formatted['state']); $this->assertEquals([ [ 'class' => TestShareSourceType2::class, 'value' => 'source2', 'display_name' => 'Source 2', 'icon' => [ 'svg' => '', ], ], ], $formatted['sources']); $before = $this->manager->getTime(); $formatted = $this->removeShareSource($accessContext, $share, new ShareSource(TestShareSourceType2::class, 'source2')); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([], $formatted['sources']); } public function testAddShareRecipient(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); } public function testAddShareRecipientInteractionRestricted(): void { $listener = function (RestrictInteractionEvent $event): void { foreach ($event->receivers as $receiver) { if ($receiver instanceof TestInteractionReceiver && $receiver->getID() === 'recipient1') { throw new InteractionRestrictedException('Recipient not allowed.', 'You are not allowed to add this recipient.'); } } }; $eventDispatcher = Server::get(IEventDispatcher::class); $eventDispatcher->addListener(RestrictInteractionEvent::class, $listener); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->dbConnection->commit(); try { $this->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->fail('Interaction not restricted.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to add this recipient.', $hintException->getHint()); } $eventDispatcher->removeListener(RestrictInteractionEvent::class, $listener); } public function testAddChildShareRecipientWithoutResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->fail('Able to add child recipient without reshare permission.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testAddChildShareRecipientWithResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'user1', 'instance' => null, 'display_name' => 'User 1', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/user1/64', 'dark' => 'http://localhost/index.php/avatar/user1/64/dark', ], ], ], ], $formatted['recipients']); } public function testRemoveShareRecipient(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->removeShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Active->value, $formatted['state']); $this->assertEquals([ [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); $before = $this->manager->getTime(); $formatted = $this->removeShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([], $formatted['recipients']); } public function testRemoveSelfShareRecipientWithoutResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->fail('Able to remove self recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveSelfShareRecipientWithResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->fail('Able to remove self recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveChildShareRecipientWithoutResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, false)); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->fail('Able to remove child recipient without reshare permission.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveChildShareRecipientWithResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); } public function testRemoveSiblingShareRecipientWithoutResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->fail('Able to remove sibling recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveSiblingShareRecipientWithResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->fail('Able to remove sibling recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveParentShareRecipientWithoutResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, false)); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user2), $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->fail('Able to remove parent recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } public function testRemoveParentShareRecipientWithResharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->dbConnection->commit(); try { $this->removeShareRecipient(new ShareAccessContext($this->user2), $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->fail('Able to remove parent recipient.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to edit this share.', $hintException->getHint()); } } /** * @return list */ public static function dataUpdateShareRecipientSecret(): array { return [ [true], [false], ]; } #[DataProvider('dataUpdateShareRecipientSecret')] public function testUpdateShareRecipientSecret(bool $isSecretUpdatable): void { $this->registry->registerRecipientType(new TestShareRecipientTypePublicSecret( [ 'recipient1' => 'Recipient 1', ], [], true, $isSecretUpdatable, )); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $recipient = new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient1', null); $share = $this->manager->addShareRecipient($accessContext, $share, $recipient); $this->dbConnection->commit(); if (!$isSecretUpdatable) { try { $this->updateShareRecipientSecret($accessContext, $share, $recipient, 'mysecret'); $this->fail('Able to update recipient secret.'); } catch (HintException $exception) { $this->assertEquals('You are not allowed to edit this share.', $exception->getHint()); } } else { $before = $this->manager->getTime(); $formatted = $this->updateShareRecipientSecret($accessContext, $share, $recipient, 'mysecret'); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ [ 'class' => TestShareRecipientTypePublicSecret::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '' ], 'secret' => [ 'updatable' => true, 'value' => 'mysecret', 'url' => 'http://localhost/index.php/s/mysecret', ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); } } /** * @return list}> */ public static function dataProviderUpdateShareProperty(): array { return [ [[null, 'valid1']], [['valid1', null]], ]; } /** * @param list $values */ #[DataProvider('dataProviderUpdateShareProperty')] public function testUpdateShareProperty(array $values): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); foreach ($values as $value) { $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyType1::class, $value)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => $value, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], $formatted['properties']); } } public function testUpdateSharePropertyRequired(): void { $this->registry->registerPropertyType(new TestSharePropertyTypeRequired(['valid1', 'valid2'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyTypeRequired::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyTypeRequired::class, TestShareRecipientType1::class); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->manager->getShare($accessContext, $share->id); $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeRequired::class, 'valid1')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeRequired::class, 'display_name' => 'TestSharePropertyTypeRequired', 'hint' => 'hint TestSharePropertyTypeRequired', 'priority' => 1, 'advanced' => false, 'required' => true, 'value' => 'valid1', 'type' => 'enum', 'valid_values' => ['valid1', 'valid2'], ], ], $formatted['properties']); $this->dbConnection->beginTransaction(); $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeRequired::class, 'valid2')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Active->value, $formatted['state']); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeRequired::class, 'display_name' => 'TestSharePropertyTypeRequired', 'hint' => 'hint TestSharePropertyTypeRequired', 'priority' => 1, 'advanced' => false, 'required' => true, 'value' => 'valid2', 'type' => 'enum', 'valid_values' => ['valid1', 'valid2'], ], ], $formatted['properties']); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeRequired::class, null)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeRequired::class, 'display_name' => 'TestSharePropertyTypeRequired', 'hint' => 'hint TestSharePropertyTypeRequired', 'priority' => 1, 'advanced' => false, 'required' => true, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1', 'valid2'], ], ], $formatted['properties']); } public function testUpdateSharePropertyModifyProperties(): void { $this->registry->registerPropertyType(new TestSharePropertyTypeModifyValue(['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyTypeModifyValue::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyTypeModifyValue::class, TestShareRecipientType1::class); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->dbConnection->commit(); $formatted = $this->getShare($accessContext, $share->id); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeModifyValue::class, 'display_name' => 'TestSharePropertyTypeModifyValue', 'hint' => 'hint TestSharePropertyTypeModifyValue', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'modify-on-save', 'type' => 'enum', 'valid_values' => ['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'], ], ], $formatted['properties']); $formatted = $this->getShare($accessContext, $share->id); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeModifyValue::class, 'display_name' => 'TestSharePropertyTypeModifyValue', 'hint' => 'hint TestSharePropertyTypeModifyValue', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'modified-on-save', 'type' => 'enum', 'valid_values' => ['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'], ], ], $formatted['properties']); $this->dbConnection->beginTransaction(); $this->manager->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeModifyValue::class, 'old-value')); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeModifyValue::class, 'modify-on-save-old-value')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeModifyValue::class, 'display_name' => 'TestSharePropertyTypeModifyValue', 'hint' => 'hint TestSharePropertyTypeModifyValue', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'old-value', 'type' => 'enum', 'valid_values' => ['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'], ], ], $formatted['properties']); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeModifyValue::class, 'modify-on-save')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeModifyValue::class, 'display_name' => 'TestSharePropertyTypeModifyValue', 'hint' => 'hint TestSharePropertyTypeModifyValue', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'modified-on-save', 'type' => 'enum', 'valid_values' => ['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'], ], ], $formatted['properties']); $before = $this->manager->getTime(); $formatted = $this->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeModifyValue::class, 'modify-on-load')); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeModifyValue::class, 'display_name' => 'TestSharePropertyTypeModifyValue', 'hint' => 'hint TestSharePropertyTypeModifyValue', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'modified-on-load', 'type' => 'enum', 'valid_values' => ['old-value', 'modify-on-save-old-value', 'modify-on-save', 'modify-on-load'], ], ], $formatted['properties']); } public function testUpdateSharePermission(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); $before = $this->manager->getTime(); $this->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->reloadShare($accessContext, $share); $formatted = $this->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => true, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); $this->dbConnection->beginTransaction(); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $before = $this->manager->getTime(); $formatted = $this->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, false)); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Active->value, $formatted['state']); $this->assertEquals([ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, false)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(ShareState::Draft->value, $formatted['state']); $this->assertEquals([ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); } public function testUpdateSharePermissionInteractionRestricted(): void { $listener = function (RestrictInteractionEvent $event): void { if ($event->action instanceof ShareAction && $event->action->unifiedSharingPermissions !== null && in_array(TestSharePermissionType1::class, $event->action->unifiedSharingPermissions, true)) { throw new InteractionRestrictedException('Permission not allowed.', 'You are not allowed to enable this permission.'); } }; $eventDispatcher = Server::get(IEventDispatcher::class); $eventDispatcher->addListener(RestrictInteractionEvent::class, $listener); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->dbConnection->commit(); try { $this->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $this->fail('Not restricted.'); } catch (HintException $hintException) { $this->assertEquals('You are not allowed to enable this permission.', $hintException->getHint()); } $eventDispatcher->removeListener(RestrictInteractionEvent::class, $listener); } public function testSelectSharePermissionPreset(): void { $this->registry->clear(); $this->registry->registerPermissionPreset(new TestSharePermissionPreset1()); $this->registry->registerPermissionPreset(new TestSharePermissionPreset2()); $this->registry->registerPermissionType(null, new TestSharePermissionType1()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset1::class); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset2::class); $this->registry->registerPermissionType(null, new TestSharePermissionType2()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType2::class, TestSharePermissionPreset2::class); $this->registry->registerPermissionType(null, new TestSharePermissionType3()); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare($accessContext, $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertNull($formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType3::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType3', 'hint' => 'hint TestSharePermissionType3', 'presets' => [], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->selectSharePermissionPreset($accessContext, $share, TestSharePermissionPreset2::class); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(TestSharePermissionPreset2::class, $formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType3::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType3', 'hint' => 'hint TestSharePermissionType3', 'presets' => [], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType3::class, true)); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertNull($formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType3::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType3', 'hint' => 'hint TestSharePermissionType3', 'presets' => [], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->selectSharePermissionPreset($accessContext, $share, TestSharePermissionPreset1::class); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(TestSharePermissionPreset1::class, $formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType3::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType3', 'hint' => 'hint TestSharePermissionType3', 'presets' => [], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, false)); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertNull($formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType3::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType3', 'hint' => 'hint TestSharePermissionType3', 'presets' => [], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); } public function testSelectSharePermissionPresetCompatible(): void { $this->registry->clear(); $this->registry->registerSourceType(new TestShareSourceType1(['source1' => 'Source 1'])); $this->registry->registerPermissionPreset(new TestSharePermissionPreset1()); $this->registry->registerPermissionPreset(new TestSharePermissionPreset2()); $this->registry->registerPermissionType(TestShareSourceType1::class, new TestSharePermissionType1()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset1::class); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType1::class, TestSharePermissionPreset2::class); $this->registry->registerPermissionType(null, new TestSharePermissionType2()); $this->registry->markPermissionTypeCompatibleWithPermissionPreset(TestSharePermissionType2::class, TestSharePermissionPreset2::class); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare($accessContext, $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertNull($formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->selectSharePermissionPreset($accessContext, $share, TestSharePermissionPreset2::class); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(TestSharePermissionPreset2::class, $formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->reloadShare($accessContext, $share); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertNull($formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); $before = $this->manager->getTime(); $formatted = $this->selectSharePermissionPreset($accessContext, $share, TestSharePermissionPreset2::class); $after = $this->manager->getTime(); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals(TestSharePermissionPreset2::class, $formatted['permission_preset']); $this->assertEquals([ [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => null, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], $formatted['permissions']); } public function testDeleteShare(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->deleteShare($accessContext, $share); try { $this->manager->getShare(new ShareAccessContext(overrideChecks: true), $share->id); $this->fail('Share not deleted.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } finally { $this->dbConnection->commit(); } } public function testGetShare(): void { $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->manager->getShare($accessContext, $share->id); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare($accessContext, $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], $formatted); } public function testGetShareAsRecipientNotActive(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->dbConnection->commit(); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->fail('Draft share visible.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareAsRecipientActive(): void { $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); } public function testGetShareAsRecipientWithArguments(): void { $this->registry->registerRecipientType(new TestShareRecipientTypeArguments()); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientTypeArguments::class, 'secret', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->user1, arguments: [TestShareRecipientTypeArguments::class => 'secret']), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientTypeArguments::class, 'value' => 'secret', 'instance' => null, 'display_name' => 'secret', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/guest/secret/64', 'dark' => 'http://localhost/index.php/avatar/guest/secret/64?darkTheme=1', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->fail('Share visible without arguments.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareWithSecretNotActive(): void { $this->registry->registerRecipientType(new TestShareRecipientTypeArguments()); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientTypeArguments::class, 'secret', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $this->dbConnection->commit(); $secret = $share->recipients[0]->secret; $this->assertNotNull($secret); try { $this->getShare(new ShareAccessContext(secret: $secret), $share->id); $this->fail('Draft share visible with secret.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareWithSecretActive(): void { $this->registry->registerRecipientType(new TestShareRecipientTypeArguments()); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientTypeArguments::class, 'secret', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $after = $this->manager->getTime(); $this->dbConnection->commit(); $secret = $share->recipients[0]->secret; $this->assertNotNull($secret); $formatted = $this->getShare(new ShareAccessContext(secret: $secret), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientTypeArguments::class, 'value' => 'secret', 'instance' => null, 'display_name' => 'secret', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/guest/secret/64', 'dark' => 'http://localhost/index.php/avatar/guest/secret/64?darkTheme=1', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); try { $this->getShare(new ShareAccessContext(), $share->id); $this->fail('Share visible without secret.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareAsNonRecipient(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->fail('Share visible as non-recipient.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareAsRecipientFilteredProperties(): void { $this->registry->registerPropertyType(new TestSharePropertyTypeFilter(['visible', 'filtered'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyTypeFilter::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyTypeFilter::class, TestShareRecipientType1::class); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeFilter::class, 'visible')); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeFilter::class, 'display_name' => 'TestSharePropertyTypeFilter', 'hint' => 'hint TestSharePropertyTypeFilter', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'visible', 'type' => 'enum', 'valid_values' => ['visible', 'filtered'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $this->manager->updateShareProperty($accessContext, $share, new ShareProperty(TestSharePropertyTypeFilter::class, 'filtered')); $share = $this->reloadShare($accessContext, $share); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->owner), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeFilter::class, 'display_name' => 'TestSharePropertyTypeFilter', 'hint' => 'hint TestSharePropertyTypeFilter', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => 'filtered', 'type' => 'enum', 'valid_values' => ['visible', 'filtered'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->fail('Share visible with active filter property.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testGetShareAsRecipientFilteredArguments(): void { $this->registry->registerPropertyType(new TestSharePropertyTypeFilter(['visible', 'filtered'])); $this->registry->markPropertyTypeCompatibleWithSourceType(TestSharePropertyTypeFilter::class, TestShareSourceType1::class); $this->registry->markPropertyTypeCompatibleWithRecipientType(TestSharePropertyTypeFilter::class, TestShareRecipientType1::class); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeFilter::class, 'display_name' => 'TestSharePropertyTypeFilter', 'hint' => 'hint TestSharePropertyTypeFilter', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['visible', 'filtered'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); $formatted = $this->getShare(new ShareAccessContext(currentUser: $this->owner, arguments: [TestSharePropertyTypeFilter::class => 'filtered']), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertEquals([ 'id' => $share->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Active->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], [ 'class' => TestSharePropertyTypeFilter::class, 'display_name' => 'TestSharePropertyTypeFilter', 'hint' => 'hint TestSharePropertyTypeFilter', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['visible', 'filtered'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => true, 'priority' => 1, ], ], 'permission_preset' => TestSharePermissionPreset1::class, ], $formatted); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1, arguments: [TestSharePropertyTypeFilter::class => 'filtered']), $share->id); $this->fail('Share visible with filtered value as recipient.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } /** * @return list */ public static function dataGetShareWithPublicSecret(): array { return [ [true], [false], ]; } #[DataProvider('dataGetShareWithPublicSecret')] public function testGetShareWithPublicSecret(bool $isSecretPublic): void { $this->registry->clear(); $this->registry->registerRecipientType(new TestShareRecipientType1( [ 'recipient1' => 'Recipient 1', ], [], [], )); $this->registry->registerRecipientType(new TestShareRecipientTypePublicSecret( [ 'recipient2' => 'Recipient 2', ], [], $isSecretPublic, false, )); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient2', null)); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare($accessContext, $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); unset($formatted['last_updated']); $this->assertIsList($formatted['recipients']); $this->assertCount(2, $formatted['recipients']); // Sort because database order is not guaranteed usort($formatted['recipients'], fn (array $a, array $b): int => $a['value'] <=> $b['value']); $this->assertEquals([ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], $formatted['recipients'][0]); $this->assertIsArray($formatted['recipients'][1]); if ($isSecretPublic) { $this->assertArrayHasKey('secret', $formatted['recipients'][1]); $this->assertIsArray($formatted['recipients'][1]['secret']); $this->assertArrayHasKey('updatable', $formatted['recipients'][1]['secret']); $this->assertFalse($formatted['recipients'][1]['secret']['updatable']); $this->assertArrayHasKey('value', $formatted['recipients'][1]['secret']); $this->assertIsString($formatted['recipients'][1]['secret']['value']); $this->assertNotEmpty($formatted['recipients'][1]['secret']['value']); $this->assertArrayHasKey('url', $formatted['recipients'][1]['secret']); $this->assertIsString($formatted['recipients'][1]['secret']['url']); $this->assertMatchesRegularExpression('/http:\/\/localhost\/index\.php\/s\/.+/', $formatted['recipients'][1]['secret']['url']); } else { $this->assertArrayNotHasKey('url', $formatted['recipients'][1]); } } public function testGetShareWithSecret(): void { $this->registry->clear(); $this->registry->registerSourceType(new TestShareSourceType1(['source1' => 'Source'])); $this->registry->registerRecipientType(new TestShareRecipientTypePublicSecret( [ 'recipient1' => 'Recipient 1', 'recipient2' => 'Recipient 2', 'recipient3' => 'Recipient 3', 'recipient4' => 'Recipient 4', ], [ $this->user1->getUID() => ['recipient1'], $this->user2->getUID() => ['recipient2'], ], true, false, )); $this->registry->registerPermissionType(null, Server::get(ReshareSharePermissionType::class)); $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient2', null)); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user1), $share, new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient3', null)); $share = $this->manager->addShareRecipient(new ShareAccessContext($this->user2), $share, new ShareRecipient(TestShareRecipientTypePublicSecret::class, 'recipient4', null)); $this->dbConnection->commit(); $after = $this->manager->getTime(); $formatted = $this->getShare(new ShareAccessContext($this->user2), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); usort($formatted['recipients'], fn (array $a, array $b): int => $a['value'] <=> $b['value']); $this->assertArrayHasKey('recipients', $formatted); $this->assertIsArray($formatted['recipients']); $this->assertCount(4, $formatted['recipients']); // Parent - secret not visible $this->assertIsArray($formatted['recipients'][0]); $this->assertArrayHasKey('value', $formatted['recipients'][0]); $this->assertEquals('recipient1', $formatted['recipients'][0]['value']); $this->assertArrayHasKey('secret', $formatted['recipients'][0]); $this->assertIsArray($formatted['recipients'][0]['secret']); $this->assertArrayNotHasKey('value', $formatted['recipients'][0]['secret']); // Self - secret visible $this->assertIsArray($formatted['recipients'][1]); $this->assertArrayHasKey('value', $formatted['recipients'][1]); $this->assertEquals('recipient2', $formatted['recipients'][1]['value']); $this->assertArrayHasKey('secret', $formatted['recipients'][1]); $this->assertIsArray($formatted['recipients'][1]['secret']); $this->assertNotEmpty($formatted['recipients'][1]['secret']['value']); // Sibling - secret not visible $this->assertIsArray($formatted['recipients'][2]); $this->assertArrayHasKey('value', $formatted['recipients'][2]); $this->assertEquals('recipient3', $formatted['recipients'][2]['value']); $this->assertArrayHasKey('secret', $formatted['recipients'][2]); $this->assertIsArray($formatted['recipients'][2]['secret']); $this->assertArrayNotHasKey('value', $formatted['recipients'][2]['secret']); // Child - secret visible $this->assertIsArray($formatted['recipients'][3]); $this->assertArrayHasKey('value', $formatted['recipients'][3]); $this->assertEquals('recipient4', $formatted['recipients'][3]['value']); $this->assertArrayHasKey('secret', $formatted['recipients'][3]); $this->assertIsArray($formatted['recipients'][3]['secret']); $this->assertNotEmpty($formatted['recipients'][3]['secret']['value']); } public function testGetShareUniqueDisplayNames(): void { $this->registry->clear(); $this->registry->registerSourceType(new TestShareSourceType1(['source1' => 'Source'])); $this->registry->registerSourceType(new TestShareSourceType2(['source2' => 'Source', 'source3' => 'Other'])); $this->registry->registerRecipientType(new TestShareRecipientType1(['recipient1' => 'Recipient'], [], [])); $this->registry->registerRecipientType(new TestShareRecipientType2(['recipient2' => 'Recipient', 'recipient3' => 'Other'], [], [])); $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType2::class, 'source2')); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType2::class, 'source3')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient3', null)); $this->dbConnection->commit(); $formatted = $this->getShare($accessContext, $share->id); // Sort because database order is not guaranteed usort($formatted['sources'], fn (array $a, array $b): int => $a['value'] <=> $b['value']); usort($formatted['recipients'], fn (array $a, array $b): int => $a['value'] <=> $b['value']); $this->assertEquals([ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source (TestShareSourceType1: source1)', 'icon' => [ 'svg' => '', ], ], [ 'class' => TestShareSourceType2::class, 'value' => 'source2', 'display_name' => 'Source (TestShareSourceType2: source2)', 'icon' => [ 'svg' => '', ], ], [ 'class' => TestShareSourceType2::class, 'value' => 'source3', 'display_name' => 'Other', 'icon' => [ 'svg' => '', ], ], ], $formatted['sources']); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient (TestShareRecipientType1: recipient1)', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient (TestShareRecipientType2: recipient2)', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient3', 'instance' => null, 'display_name' => 'Other', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); } public function testGetShareDisabledOwner(): void { $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(TestSharePermissionType1::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $this->dbConnection->commit(); $after = $this->manager->getTime(); $this->owner->setEnabled(false); try { $this->getShare(new ShareAccessContext(currentUser: $this->user1), $share->id); $this->fail('Share still visible.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } $formatted = $this->getShare(new ShareAccessContext(overrideChecks: true), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], $formatted['owner']); } public function testGetShareDisabledInitiator(): void { $accessContext = new ShareAccessContext($this->owner); $before = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext(currentUser: $this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->dbConnection->commit(); $after = $this->manager->getTime(); $this->user1->setEnabled(false); try { $this->getShare(new ShareAccessContext(currentUser: $this->user2), $share->id); $this->fail('Share still visible.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } $formatted = $this->getShare($accessContext, $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'user1', 'instance' => null, 'display_name' => 'User 1', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/user1/64', 'dark' => 'http://localhost/index.php/avatar/user1/64/dark', ], ], ], ], $formatted['recipients']); } public function testGetShares(): void { $accessContext = new ShareAccessContext($this->owner); $before1 = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share1 = $this->manager->createShare($accessContext); $share1 = $this->manager->addShareSource($accessContext, $share1, new ShareSource(TestShareSourceType1::class, 'source1')); $share1 = $this->manager->addShareRecipient($accessContext, $share1, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $this->dbConnection->commit(); $after1 = $this->manager->getTime(); $before2 = $this->manager->getTime(); $this->dbConnection->beginTransaction(); $share2 = $this->manager->createShare($accessContext); $share2 = $this->manager->addShareSource($accessContext, $share2, new ShareSource(TestShareSourceType2::class, 'source2')); $share2 = $this->manager->addShareRecipient($accessContext, $share2, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $this->dbConnection->commit(); $after2 = $this->manager->getTime(); $formatted = $this->getShares($accessContext, null, null, null, null); $this->assertCount(2, $formatted); $this->assertIsArray($formatted[0]); $this->assertDateBetween($before1, $after1, $this->parseTime($formatted[0]['last_updated'])); $this->assertIsArray($formatted[1]); $this->assertDateBetween($before2, $after2, $this->parseTime($formatted[1]['last_updated'])); unset($formatted[0]['last_updated'], $formatted[1]['last_updated']); $this->assertEquals([ [ 'id' => $share1->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], [ 'id' => $share2->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType2::class, 'value' => 'source2', 'display_name' => 'Source 2', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType2::class, 'display_name' => 'TestSharePropertyType2', 'hint' => 'hint TestSharePropertyType2', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid2'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => TestShareSourceType2::class, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], ], $formatted); $formatted = $this->getShares($accessContext, TestShareSourceType1::class, null, null, null); $this->assertCount(1, $formatted); $this->assertIsArray($formatted[0]); $this->assertDateBetween($before1, $after1, $this->parseTime($formatted[0]['last_updated'])); unset($formatted[0]['last_updated']); $this->assertEquals([ [ 'id' => $share1->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], ], $formatted); $formatted = $this->getShares($accessContext, TestShareSourceType1::class, 'source1', null, null); $this->assertCount(1, $formatted); $this->assertIsArray($formatted[0]); $this->assertDateBetween($before1, $after1, $this->parseTime($formatted[0]['last_updated'])); unset($formatted[0]['last_updated']); $this->assertEquals([ [ 'id' => $share1->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], ], $formatted); $formatted = $this->getShares($accessContext, TestShareSourceType1::class, 'non-existent', null, null); $this->assertCount(0, $formatted); $formatted = $this->getShares($accessContext, null, null, $share1->id, null); $this->assertCount(1, $formatted); $this->assertIsArray($formatted[0]); $this->assertDateBetween($before2, $after2, $this->parseTime($formatted[0]['last_updated'])); unset($formatted[0]['last_updated']); $this->assertEquals([ [ 'id' => $share2->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType2::class, 'value' => 'source2', 'display_name' => 'Source 2', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType2::class, 'display_name' => 'TestSharePropertyType2', 'hint' => 'hint TestSharePropertyType2', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid2'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType2::class, 'source_class' => TestShareSourceType2::class, 'display_name' => 'TestSharePermissionType2', 'hint' => 'hint TestSharePermissionType2', 'presets' => [TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], ], $formatted); $formatted = $this->getShares($accessContext, null, null, null, 1); $this->assertCount(1, $formatted); $this->assertIsArray($formatted[0]); $this->assertDateBetween($before1, $after1, $this->parseTime($formatted[0]['last_updated'])); unset($formatted[0]['last_updated']); $this->assertEquals([ [ 'id' => $share1->id, 'owner' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], 'state' => ShareState::Draft->value, 'sources' => [ [ 'class' => TestShareSourceType1::class, 'value' => 'source1', 'display_name' => 'Source 1', 'icon' => [ 'svg' => '', ], ], ], 'recipients' => [ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], 'properties' => [ [ 'class' => TestSharePropertyType1::class, 'display_name' => 'TestSharePropertyType1', 'hint' => 'hint TestSharePropertyType1', 'priority' => 1, 'advanced' => false, 'required' => false, 'value' => null, 'type' => 'enum', 'valid_values' => ['valid1'], ], ], 'permissions' => [ [ 'class' => ReshareSharePermissionType::class, 'source_class' => null, 'display_name' => 'Share with others', 'hint' => null, 'presets' => [], 'enabled' => false, 'priority' => 90, ], [ 'class' => TestSharePermissionType1::class, 'source_class' => TestShareSourceType1::class, 'display_name' => 'TestSharePermissionType1', 'hint' => 'hint TestSharePermissionType1', 'presets' => [TestSharePermissionPreset1::class, TestSharePermissionPreset2::class], 'enabled' => false, 'priority' => 1, ], ], 'permission_preset' => null, ], ], $formatted); } public function testGetSharesSorted(): void { $accessContext = new ShareAccessContext(currentUser: $this->owner); $this->dbConnection->beginTransaction(); $share1 = $this->manager->createShare($accessContext); $share2 = $this->manager->createShare($accessContext); $this->dbConnection->commit(); $shares = $this->getShares($accessContext, null, null, null, null); $this->assertIsArray($shares[0]); $this->assertArrayHasKey('id', $shares[0]); $this->assertIsArray($shares[1]); $this->assertArrayHasKey('id', $shares[1]); $this->assertEquals($share1->id, $shares[0]['id']); $this->assertEquals($share2->id, $shares[1]['id']); $this->dbConnection->beginTransaction(); $this->manager->addShareSource($accessContext, $share2, new ShareSource(TestShareSourceType2::class, 'source2')); $this->manager->getShare($accessContext, $share2->id); $this->manager->updateSharePermission($accessContext, $share2, new SharePermission(TestSharePermissionType2::class, true)); $this->dbConnection->commit(); $formatted = $this->getShares($accessContext, null, null, null, null); $this->assertIsArray($formatted[0]); $this->assertArrayHasKey('id', $formatted[0]); $this->assertIsArray($formatted[1]); $this->assertArrayHasKey('id', $formatted[1]); $this->assertEquals($share2->id, $formatted[0]['id']); $this->assertEquals($share1->id, $formatted[1]['id']); } public function testOwnerDeleted(): void { $accessContext = new ShareAccessContext(currentUser: $this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $this->owner->delete(); $this->dbConnection->commit(); try { $this->getShare(new ShareAccessContext(overrideChecks: true), $share->id); $this->fail('Share still exists.'); } catch (HintException $hintException) { $this->assertEquals('Share not found.', $hintException->getHint()); } } public function testInitiatorDeleted(): void { $accessContext = new ShareAccessContext($this->owner); $this->dbConnection->beginTransaction(); $share = $this->manager->createShare($accessContext); $share = $this->manager->addShareSource($accessContext, $share, new ShareSource(TestShareSourceType1::class, 'source1')); $share = $this->manager->addShareRecipient($accessContext, $share, new ShareRecipient(TestShareRecipientType1::class, 'recipient1', null)); $share = $this->manager->updateSharePermission($accessContext, $share, new SharePermission(ReshareSharePermissionType::class, true)); $share = $this->manager->updateShareState($accessContext, $share, ShareState::Active); $share = $this->manager->addShareRecipient(new ShareAccessContext(currentUser: $this->user1), $share, new ShareRecipient(TestShareRecipientType2::class, 'recipient2', null)); $before = $this->manager->getTime(); $this->user1->delete(); $after = $this->manager->getTime(); $this->dbConnection->commit(); $formatted = $this->getShare(new ShareAccessContext(overrideChecks: true), $share->id); $this->assertDateBetween($before, $after, $this->parseTime($formatted['last_updated'])); $this->assertEquals([ [ 'class' => TestShareRecipientType1::class, 'value' => 'recipient1', 'instance' => null, 'display_name' => 'Recipient 1', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], [ 'class' => TestShareRecipientType2::class, 'value' => 'recipient2', 'instance' => null, 'display_name' => 'Recipient 2', 'icon' => [ 'svg' => '', ], 'secret' => [ 'updatable' => false, ], 'initiator' => [ 'user_id' => 'owner', 'instance' => null, 'display_name' => 'Owner', 'icon' => [ 'light' => 'http://localhost/index.php/avatar/owner/64', 'dark' => 'http://localhost/index.php/avatar/owner/64/dark', ], ], ], ], $formatted['recipients']); } }