From a4671204048ff08524046f515090a7ebd930adae Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Fri, 10 Jan 2025 14:38:02 +0100 Subject: [PATCH] test: Add test cases for admin settings possibly influencing the API Signed-off-by: Ferdinand Thiessen --- .../Api/RespectAdminSettingsTest.php | 323 ++++++++++++++++++ tests/Integration/DB/SharedFormsTest.php | 84 +++++ tests/Integration/IntegrationBase.php | 17 +- 3 files changed, 421 insertions(+), 3 deletions(-) create mode 100644 tests/Integration/Api/RespectAdminSettingsTest.php diff --git a/tests/Integration/Api/RespectAdminSettingsTest.php b/tests/Integration/Api/RespectAdminSettingsTest.php new file mode 100644 index 000000000..622fe2a38 --- /dev/null +++ b/tests/Integration/Api/RespectAdminSettingsTest.php @@ -0,0 +1,323 @@ + 'Test user', + ]; + + /** + * Store Test Forms Array. + * Necessary as function due to object type-casting. + */ + private function setTestForms() { + $this->testForms = [ + [ + 'hash' => 'abcdefghij123456', + 'title' => 'Title of owned Form', + 'description' => '', + 'owner_id' => 'test', + 'access_enum' => 0, + 'created' => 12345, + 'expires' => 0, + 'state' => 0, + 'is_anonymous' => false, + 'submit_multiple' => false, + 'show_expiration' => false, + 'last_updated' => 123456789, + 'submission_message' => '', + 'file_id' => null, + 'file_format' => null, + 'questions' => [], + 'shares' => [], + 'submissions' => [], + ], + [ + 'hash' => '1234567890abcdef', + 'title' => 'Title of a globally shared Form', + 'description' => '', + 'owner_id' => 'test1', + 'access_enum' => 2, + 'created' => 12345, + 'expires' => 0, + 'state' => 0, + 'is_anonymous' => false, + 'submit_multiple' => false, + 'show_expiration' => false, + 'last_updated' => 123456789, + 'submission_message' => '', + 'file_id' => null, + 'file_format' => null, + 'questions' => [], + 'shares' => [], + 'submissions' => [], + ], + [ + 'hash' => 'bcdf011899881', + 'title' => 'Title of a directly shared Form', + 'description' => '', + 'owner_id' => 'test1', + 'access_enum' => 0, + 'created' => 12345, + 'expires' => 0, + 'state' => 0, + 'is_anonymous' => false, + 'submit_multiple' => false, + 'show_expiration' => false, + 'last_updated' => 123456789, + 'submission_message' => '', + 'file_id' => null, + 'file_format' => null, + 'questions' => [], + 'shares' => [ + [ + 'shareType' => 0, + 'shareWith' => 'test', + 'permissions' => ['submit'], + ], + ], + 'submissions' => [], + ], + ]; + } + + private static function sharedTestForms(): array { + return [ + [ + 'hash' => 'abcdefghij123456', + 'title' => 'Title of owned Form', + 'description' => '', + 'created' => 12345, + 'expires' => 0, + 'state' => 0, + 'questions' => [], + 'shares' => [], + 'ownerId' => 'test', + 'fileId' => null, + 'fileFormat' => null, + 'access' => [ + 'permitAllUsers' => false, + 'showToAllUsers' => false, + ], + 'isAnonymous' => false, + 'submitMultiple' => false, + 'showExpiration' => false, + 'submissionMessage' => '', + 'permissions' => [ + 'edit', + 'results', + 'results_delete', + 'submit', + 'embed', + ], + 'canSubmit' => true, + 'submissionCount' => 0, + ], + ]; + } + + /** + * Set up test environment. + * Writing testforms into db, preparing http request + */ + public function setUp(): void { + $this->setTestForms(); + $this->users = [ + 'test' => 'Test Displayname', + 'user1' => 'User No. 1', + ]; + + parent::setUp(); + + // Set up http Client + $this->http = new Client([ + 'base_uri' => 'http://localhost:8080/ocs/v2.php/apps/forms/', + 'auth' => ['test', 'test'], + 'headers' => [ + 'OCS-ApiRequest' => 'true', + 'Accept' => 'application/json' + ], + ]); + } + + public function tearDown(): void { + parent::tearDown(); + } + + // Small Wrapper for OCS-Response + private function OcsResponse2Data($resp) { + $arr = json_decode($resp->getBody()->getContents(), true); + return $arr['ocs']['data']; + } + + /** + * Allow to update form if there are no admin settings + */ + public function testAllowUpdate(): void { + $resp = $this->http->request( + 'PATCH', + "api/v3/forms/{$this->testForms[0]['id']}", + [ + 'json' => [ + 'keyValuePairs' => ['access' => ['permitAllUsers' => true, 'showToAllUsers' => true]], + ], + ], + ); + $this->assertEquals(200, $resp->getStatusCode()); + + $resp = $this->http->request( + 'GET', + "api/v3/forms/{$this->testForms[0]['id']}", + ); + $data = $this->OcsResponse2Data($resp); + // we do not know the ID and the update time is flaky + unset($data['id']); + unset($data['lastUpdated']); + + $expected = self::sharedTestForms()[0]; + $expected['access'] = ['permitAllUsers' => true, 'showToAllUsers' => true]; + + $this->assertEquals(200, $resp->getStatusCode()); + $this->assertEquals($expected, $data); + } + + /** + * Forbid to update form if there are admin settings + * @dataProvider forbidUpdateAdminSettingsData + */ + public function testForbidUpdate(array $accessValue, array $adminConfigKeys): void { + $config = \OCP\Server::get(IConfig::class); + foreach ($adminConfigKeys as $key => $value) { + $config->setAppValue(Application::APP_ID, $key, $value); + } + + $resp = $this->http->request( + 'PATCH', + "api/v3/forms/{$this->testForms[0]['id']}", + [ + 'json' => [ + 'keyValuePairs' => ['access' => $accessValue], + ], + // do not throw on 403 + 'http_errors' => false, + ], + ); + $this->assertEquals(403, $resp->getStatusCode()); + + $resp = $this->http->request( + 'GET', + "api/v3/forms/{$this->testForms[0]['id']}", + ); + $data = $this->OcsResponse2Data($resp); + // we do not know the ID or the update + unset($data['id']); + unset($data['lastUpdated']); + + $this->assertEquals(200, $resp->getStatusCode()); + $this->assertEquals(self::sharedTestForms()[0], $data); + } + + public static function forbidUpdateAdminSettingsData(): array { + return [ + 'set both without show-to-all permission' => [ + [ + 'permitAllUsers' => true, + 'showToAllUsers' => true, + ], + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => 'false', + Constants::CONFIG_KEY_ALLOWPERMITALL => 'true', + ], + ], + 'set both without permit-all permission' => [ + [ + 'permitAllUsers' => true, + 'showToAllUsers' => true, + ], + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => 'true', + Constants::CONFIG_KEY_ALLOWPERMITALL => 'false', + ], + ], + 'set show-to-all without permission' => [ + [ + 'showToAllUsers' => true, + ], + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => 'false', + Constants::CONFIG_KEY_ALLOWPERMITALL => 'true', + ], + ], + 'set permit-all without permission' => [ + [ + 'permitAllUsers' => true, + ], + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => 'true', + Constants::CONFIG_KEY_ALLOWPERMITALL => 'false', + ], + ], + ]; + } + + /** + * Test that forms with public access are listed + */ + public function testListFormsAllowed(): void { + $resp = $this->http->request( + 'GET', + 'api/v3/forms?type=shared', + ); + $this->assertEquals(200, $resp->getStatusCode()); + + $data = $this->OcsResponse2Data($resp); + $this->assertEqualsCanonicalizing( + [ + 'Title of a globally shared Form', + 'Title of a directly shared Form', + ], + array_map(fn ($form) => $form['title'], $data), + ); + } + + /** + * Test that only forms directly shared are listed if the admin setting forbid access to the form. + * Equivalent to creating form with "show to all" permission, but then the admin deactivates the "show all" globally. + */ + public function testListFormsNoAdminPermission(): void { + // Disable global access + \OCP\Server::get(IConfig::class)->setAppValue(Application::APP_ID, Constants::CONFIG_KEY_ALLOWPERMITALL, 'false'); + + $resp = $this->http->request( + 'GET', + 'api/v3/forms?type=shared', + ); + $this->assertEquals(200, $resp->getStatusCode()); + + $data = $this->OcsResponse2Data($resp); + $this->assertEqualsCanonicalizing( + ['Title of a directly shared Form'], + array_map(fn ($form) => $form['title'], $data), + ); + } + +}; diff --git a/tests/Integration/DB/SharedFormsTest.php b/tests/Integration/DB/SharedFormsTest.php index f1d3d8782..2998cbd4e 100644 --- a/tests/Integration/DB/SharedFormsTest.php +++ b/tests/Integration/DB/SharedFormsTest.php @@ -8,9 +8,11 @@ */ namespace OCA\Forms\Tests\Integration\Api; +use OCA\Forms\AppInfo\Application; use OCA\Forms\Constants; use OCA\Forms\Db\FormMapper; use OCA\Forms\Tests\Integration\IntegrationBase; +use OCP\IConfig; /** * @group DB @@ -172,4 +174,86 @@ public function testPublicSharedForms() { array_map(fn ($form) => $form->read()['hash'], $forms), ); } + + /** + * Test that no public shared forms are shown to user if admin disabled it + * @dataProvider dataForbidPublicShowAccess + */ + public function testShowNoSharedFormsIfDisabled(array $configValues) { + $config = \OCP\Server::get(IConfig::class); + foreach ($configValues as $key => $value) { + $config->setAppValue(Application::APP_ID, $key, json_encode($value)); + } + + $formMapper = \OCP\Server::get(FormMapper::class); + $forms = $formMapper->findSharedForms('user1'); + + $this->assertEquals(2, count($forms)); + $this->assertEqualsCanonicalizing( + ['aaaa', 'dddd'], + array_map(fn ($form) => $form->read()['hash'], $forms), + ); + } + + /** + * Test that a form with public access can be accessed even if show permissions are not granted (can fill out but not see in sidebar) + */ + public function testAllowPublicAccessOnDeniedPublicVisibility(): void { + $config = \OCP\Server::get(IConfig::class); + $config->setAppValue(Application::APP_ID, Constants::CONFIG_KEY_ALLOWSHOWTOALL, json_encode(false)); + + $formMapper = \OCP\Server::get(FormMapper::class); + $forms = $formMapper->findSharedForms('user1', filterShown: false); + + $this->assertEqualsCanonicalizing( + ['aaaa', 'bbbb', 'cccc', 'dddd'], + array_map(fn ($form) => $form->read()['hash'], $forms), + ); + } + + /** + * Test that no public shared forms are available to user if admin disabled it + * @dataProvider dataForbidPublicAccess + */ + public function testShowNoSharedFormsAccessIfDisabled(array $configValues): void { + $config = \OCP\Server::get(IConfig::class); + foreach ($configValues as $key => $value) { + $config->setAppValue(Application::APP_ID, $key, json_encode($value)); + } + + $formMapper = \OCP\Server::get(FormMapper::class); + $forms = $formMapper->findSharedForms('user1', filterShown: false); + + $this->assertEquals(2, count($forms)); + $this->assertEqualsCanonicalizing( + ['aaaa', 'dddd'], + array_map(fn ($form) => $form->read()['hash'], $forms), + ); + } + + public static function dataForbidPublicAccess(): array { + return [ + 'no-permit' => [ + [ + Constants::CONFIG_KEY_ALLOWPERMITALL => false, + ], + ], + 'non-at-all' => [ + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => false, + Constants::CONFIG_KEY_ALLOWPERMITALL => false, + ], + ], + ]; + } + + public static function dataForbidPublicShowAccess(): array { + return array_merge(self::dataForbidPublicAccess(), [ + 'no-show-to-all' => [ + [ + Constants::CONFIG_KEY_ALLOWSHOWTOALL => false, + ], + ], + ]); + } } diff --git a/tests/Integration/IntegrationBase.php b/tests/Integration/IntegrationBase.php index 13fce6917..7b2fc271d 100644 --- a/tests/Integration/IntegrationBase.php +++ b/tests/Integration/IntegrationBase.php @@ -7,7 +7,12 @@ */ namespace OCA\Forms\Tests\Integration; +use OCA\Forms\AppInfo\Application; +use OCA\Forms\Constants; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\IUserManager; use Test\TestCase; /** @@ -30,7 +35,12 @@ class IntegrationBase extends TestCase { public function setUp(): void { parent::setUp(); - $userManager = \OC::$server->getUserManager(); + $config = \OCP\Server::get(IConfig::class); + foreach (Constants::CONFIG_KEYS as $key) { + $config->deleteAppValue(Application::APP_ID, $key); + } + + $userManager = \OCP\Server::get(IUserManager::class); foreach ($this->users as $userId => $displayName) { $user = $userManager->get($userId); if ($user === null) { @@ -39,7 +49,7 @@ public function setUp(): void { $user->setDisplayName($displayName); } - $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + $qb = \OCP\Server::get(IDBConnection::class)->getQueryBuilder(); // Write our test forms into db foreach ($this->testForms as $index => $form) { @@ -136,7 +146,8 @@ public function setUp(): void { /** Clean up database from testforms */ public function tearDown(): void { - $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + $db = \OCP\Server::get(IDBConnection::class); + $qb = $db->getQueryBuilder(); foreach ($this->testForms as $form) { $qb->delete('forms_v2_forms')