From 764b70d46b4ba1de8b0420197a141139fd0cbd3b Mon Sep 17 00:00:00 2001 From: nboisteault Date: Thu, 27 Jun 2024 12:17:05 +0200 Subject: [PATCH 1/3] Filter by user - Attribute filter: allow having multiple users or groups separated by comma --- lizmap/modules/lizmap/lib/Form/QgisForm.php | 39 +- lizmap/modules/lizmap/lib/Project/Project.php | 61 +- .../modules/lizmap/lib/Request/WFSRequest.php | 4 +- .../integration/requests-metadata-ghaction.js | 10 + .../playwright/maps-management.spec.js | 168 ++-- .../tests/filter_layer_by_user.qgs | 729 ++++++++++++------ .../tests/filter_layer_by_user.qgs.cfg | 26 +- .../tests/set_tests_respository_rights.sql | 13 +- tests/qgis-projects/tests/tests_dataset.sql | 203 ++--- tests/units/classes/Project/ProjectTest.php | 13 +- .../units/classes/Request/WFSRequestTest.php | 18 +- tests/units/testslib/ContextForTests.php | 1 + .../units/testslib/jDbConnectionForTests.php | 4 +- 13 files changed, 831 insertions(+), 458 deletions(-) diff --git a/lizmap/modules/lizmap/lib/Form/QgisForm.php b/lizmap/modules/lizmap/lib/Form/QgisForm.php index 84dfaef0ea..72cdd3605f 100644 --- a/lizmap/modules/lizmap/lib/Form/QgisForm.php +++ b/lizmap/modules/lizmap/lib/Form/QgisForm.php @@ -1794,41 +1794,30 @@ protected function filterDataByLogin($layername) return null; } - // Optionnaly add a filter parameter - $lproj = $this->layer->getProject(); - $loginFilteredConfig = $lproj->getLoginFilteredConfig($layername); + // Optionally add a filter parameter + $layerProject = $this->layer->getProject(); + $loginFilteredConfig = $layerProject->getLoginFilteredConfig($layername); if ($loginFilteredConfig) { + // Get filter type $type = 'groups'; - $attribute = $loginFilteredConfig->filterAttribute; - - // check filter type if (property_exists($loginFilteredConfig, 'filterPrivate') - && $loginFilteredConfig->filterPrivate == 'True') { + && $loginFilteredConfig->filterPrivate == 'True') { $type = 'login'; } - // Check if a user is authenticated - $isConnected = $this->appContext->userIsConnected(); - $cnx = $this->appContext->getDbConnection($this->layer->getId()); - if ($isConnected) { - $user = $this->appContext->getUserSession(); - $login = $user->login; - if ($type == 'login') { - $where = ' "'.$attribute."\" IN ( '".$login."' , 'all' )"; - } else { - $userGroups = $this->appContext->aclUserPublicGroupsId(); - // Set XML Filter if getFeature request - $flatGroups = implode("' , '", $userGroups); - $where = ' "'.$attribute."\" IN ( '".$flatGroups."' , 'all' )"; - } - } else { - // The user is not authenticated: only show data with attribute = 'all' - $where = ' "'.$attribute.'" = '.$cnx->quote('all'); + // Filter attribute + $attribute = $loginFilteredConfig->filterAttribute; + + // SQL filter + $layerFilter = $layerProject->getLoginFilter($layername); + if (empty($layerFilter)) { + return null; } + // Set filter when multiple layers concerned return array( - 'where' => $where, + 'where' => $layerFilter['filter'], 'type' => $type, 'attribute' => $attribute, ); diff --git a/lizmap/modules/lizmap/lib/Project/Project.php b/lizmap/modules/lizmap/lib/Project/Project.php index 7a825eedc8..60fb62ddb6 100644 --- a/lizmap/modules/lizmap/lib/Project/Project.php +++ b/lizmap/modules/lizmap/lib/Project/Project.php @@ -1223,10 +1223,19 @@ public function getLoginFilteredConfig($layerName, $edition = false) * Get login filters, get expressions for layers based on login filtered * config. * + * NOTE: We could delegate this completely to the lizmap_server plugin + * for all requests. The only request needed to have the SQL filter + * is the WFS GetFeature request, if the layer is a PostgreSQL layer. + * It this particular case, we could use a similar approach + * that the one use with qgisVectorLayer::requestPolygonFilter + * which calls the server plugin with SERVICE=Lizmap&REQUEST=GetSubsetString + * * @param string[] $layers : layers' name list * @param bool $edition : get login filters for edition * - * @return array + * @return array Array containing layers names as key and filter configuration + * and SQL filters as values. Array might be empty if no filter + * is configured for the layer. */ public function getLoginFilters($layers, $edition = false) { @@ -1258,22 +1267,64 @@ public function getLoginFilters($layers, $edition = false) // attribute to filter $attribute = $loginFilteredConfig->filterAttribute; + // Quoted attribute with double-quotes + $cnx = $this->appContext->getDbConnection(); + $quotedField = $cnx->encloseName($attribute); + // default no user connected - $filter = "\"{$attribute}\" = 'all'"; + $filter = "{$quotedField} = 'all' OR {$quotedField} LIKE 'all,%' OR {$quotedField} LIKE '%,all' OR {$quotedField} LIKE '%,all,%'"; // A user is connected if ($this->appContext->userIsConnected()) { + // Get the user $user = $this->appContext->getUserSession(); $login = $user->login; + + // List of values for expression + $values = array(); if (property_exists($loginFilteredConfig, 'filterPrivate') && $this->optionToBoolean($loginFilteredConfig->filterPrivate) ) { - $filter = "\"{$attribute}\" IN ( '".$login."' , 'all' )"; + // If filter is private use user_login + $values[] = $login; } else { + // Else use user groups $userGroups = $this->appContext->aclUserPublicGroupsId(); - $flatGroups = implode("' , '", $userGroups); - $filter = "\"{$attribute}\" IN ( '".$flatGroups."' , 'all' )"; + $values = $userGroups; + } + + // Add all to values + $values[] = 'all'; + $allValuesFilters = array(); + + // For each value (group, all, login, etc.), create a filter + // combining all the possibility: equality & LIKE + foreach ($values as $value) { + $valueFilters = array(); + // Quote the value with single quotes + $quotedValue = $cnx->quote($value); + + // equality + $valueFilters[] = "{$quotedField} = {$quotedValue}"; + + // begins with value & comma + $quotedLikeValue = $cnx->quote("{$value},%"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + + // ends with comma & value + $quotedLikeValue = $cnx->quote("%,{$value}"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + + // value between two commas + $quotedLikeValue = $cnx->quote("%,{$value},%"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + + // Build the filter for this value + $allValuesFilters[] = implode(' OR ', $valueFilters); } + + // Build filter for all values + $filter = implode(' OR ', $allValuesFilters); } $filters[$layerName] = array_merge( diff --git a/lizmap/modules/lizmap/lib/Request/WFSRequest.php b/lizmap/modules/lizmap/lib/Request/WFSRequest.php index 559df613af..7bd783ae4e 100644 --- a/lizmap/modules/lizmap/lib/Request/WFSRequest.php +++ b/lizmap/modules/lizmap/lib/Request/WFSRequest.php @@ -643,13 +643,13 @@ protected function parseExpFilter($cnx, $params) if (strpos($validFilter, '$id') !== false) { $key = $this->datasource->key; if (count(explode(',', $key)) == 1) { - return ' AND '.str_replace('$id ', $cnx->encloseName($key).' ', $validFilter); + return ' AND ( '.str_replace('$id ', $cnx->encloseName($key).' ', $validFilter).' ) '; } return false; } - return ' AND '.$validFilter; + return ' AND ( '.$validFilter.' ) '; } return ''; diff --git a/tests/end2end/cypress/integration/requests-metadata-ghaction.js b/tests/end2end/cypress/integration/requests-metadata-ghaction.js index 87a7e468a1..ddf486bb89 100644 --- a/tests/end2end/cypress/integration/requests-metadata-ghaction.js +++ b/tests/end2end/cypress/integration/requests-metadata-ghaction.js @@ -41,6 +41,7 @@ describe('Request JSON metadata', function () { "__anonymous", "admins", "group_a", + "group_b", "publishers" ].sort() ); @@ -49,6 +50,7 @@ describe('Request JSON metadata', function () { "__anonymous", "admins", "group_a", + "group_b", "publishers" ].sort() ); @@ -72,6 +74,9 @@ describe('Request JSON metadata', function () { "group_a": { "label": "group_a" }, + "group_b": { + "label": "group_b" + }, "intranet": { "label": "Intranet demos group" }, @@ -145,6 +150,7 @@ describe('Request JSON metadata', function () { "__anonymous", "admins", "group_a", + "group_b", "publishers" ].sort() ); @@ -153,6 +159,7 @@ describe('Request JSON metadata', function () { "__anonymous", "admins", "group_a", + "group_b", "publishers" ].sort() ); @@ -167,6 +174,9 @@ describe('Request JSON metadata', function () { "group_a": { "label": "group_a" }, + "group_b": { + "label": "group_b" + }, "intranet": { "label": "Intranet demos group" }, diff --git a/tests/end2end/playwright/maps-management.spec.js b/tests/end2end/playwright/maps-management.spec.js index e3218110b7..be62f96301 100644 --- a/tests/end2end/playwright/maps-management.spec.js +++ b/tests/end2end/playwright/maps-management.spec.js @@ -36,45 +36,54 @@ test.describe('Maps management', () => { // Check default rights on repository // anonymous, admins and users can view - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_0"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_5"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_6"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="__anonymous"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="publishers"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="users"]')).toBeChecked(); + // admins and users can display get capabilities links - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_0"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_5"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_6"]')).toBeChecked(); - // admins and users can use edition - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_0"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_5"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_6"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="__anonymous"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="publishers"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="users"]')).toBeChecked(); + + // admins can use edition + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="__anonymous"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="publishers"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="users"]')).not.toBeChecked(); + // admins and users can export layers - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_0"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_5"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_6"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="__anonymous"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="publishers"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="users"]')).toBeChecked(); + // no users override login filtered layers - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_0"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_1"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_5"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_6"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="__anonymous"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="admins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="publishers"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="users"]')).not.toBeChecked(); // Select a path to create a new repository await page.locator('[id=jforms_admin_config_section_path]').selectOption('/srv/lzm/tests/qgis-projects/ProJets 1982*!/'); @@ -132,46 +141,55 @@ test.describe('Maps management', () => { await expect(page.locator('[id=jforms_admin_config_section_accessControlAllowOrigin]')).toHaveValue('http://othersite.local:8130'); // Check default rights on repository - // anonymous, admins, group_a and publishers can view - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_0"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_2"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_5"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.repositories\\.view_6"]')).not.toBeChecked(); - // anonymous, admins, group_a and publishers can display get capabilities links - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_0"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_2"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_5"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.displayGetCapabilitiesLinks_6"]')).not.toBeChecked(); - // anonymous, admins, group_a and publishers can use edition - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_0"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_2"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_5"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.edition\\.use_6"]')).not.toBeChecked(); - // anonymous, admins, group_a and publishers can export layers - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_0"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_2"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_5"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.layer\\.export_6"]')).not.toBeChecked(); + // anonymous, admins, group_a, group_b and publishers can view + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="__anonymous"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="group_a"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="group_b"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="publishers"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.repositories.view[]"][value="users"]')).not.toBeChecked(); + + // anonymous, admins, group_a, group_b and publishers can display get capabilities links + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="__anonymous"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="group_a"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="group_b"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="publishers"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.displayGetCapabilitiesLinks[]"][value="users"]')).not.toBeChecked(); + + // anonymous, admins, group_a, group_b and publishers can use edition + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="__anonymous"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="group_a"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="group_b"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="publishers"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.edition.use[]"][value="users"]')).not.toBeChecked(); + + // anonymous, admins, group_a, group_b and publishers can export layers + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="__anonymous"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="group_a"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="group_b"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="publishers"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.layer.export[]"][value="users"]')).not.toBeChecked(); + // admins and publishers override login filtered layers - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_0"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_1"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_2"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_3"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_4"]')).not.toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_5"]')).toBeChecked(); - await expect(page.locator('[id="jforms_admin_config_section_lizmap\\.tools\\.loginFilteredLayers\\.override_6"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="__anonymous"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="admins"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="group_a"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="group_b"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="intranet"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="lizadmins"]')).not.toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="publishers"]')).toBeChecked(); + await expect(page.locator('input[name="lizmap.tools.loginFilteredLayers.override[]"][value="users"]')).not.toBeChecked(); await page.getByRole('link', { name: 'Back' }).click(); // Check URL diff --git a/tests/qgis-projects/tests/filter_layer_by_user.qgs b/tests/qgis-projects/tests/filter_layer_by_user.qgs index 9733c54bca..39fda2075d 100644 --- a/tests/qgis-projects/tests/filter_layer_by_user.qgs +++ b/tests/qgis-projects/tests/filter_layer_by_user.qgs @@ -1,11 +1,10 @@ - + - - - + + - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -45,8 +44,8 @@ - + @@ -61,7 +60,7 @@ 0 - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -95,7 +94,6 @@ - Annotations_1b82beaa_5a0a_445e_b2ad_d7288106e20f @@ -104,7 +102,7 @@ - + 0 @@ -127,7 +125,7 @@ - + 0 @@ -168,7 +166,7 @@ blue_filter_layer_by_user - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -200,7 +198,7 @@ - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -244,9 +242,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -276,25 +406,6 @@ - - - - - - - - - - - - - - - - - - - @@ -310,12 +421,12 @@ - + - + @@ -345,25 +456,6 @@ - - - - - - - - - - - - - - - - - - - @@ -373,7 +465,7 @@ - + @@ -395,17 +487,6 @@ - - - - - - - - - - - @@ -427,8 +508,8 @@ - - + + @@ -448,7 +529,7 @@ - + @@ -464,7 +545,9 @@ + + @@ -475,10 +558,10 @@ 1 - + - + @@ -516,33 +599,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -620,7 +676,7 @@ - + @@ -663,7 +719,11 @@ def my_form_open(dialog, layer, feature): - + + + + + "gid" @@ -690,7 +750,7 @@ def my_form_open(dialog, layer, feature): green_filter_layer_by_user_edition_only - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -722,7 +782,7 @@ def my_form_open(dialog, layer, feature): - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -766,9 +826,141 @@ def my_form_open(dialog, layer, feature): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -798,25 +990,6 @@ def my_form_open(dialog, layer, feature): - - - - - - - - - - - - - - - - - - - @@ -832,12 +1005,12 @@ def my_form_open(dialog, layer, feature): - + - + @@ -867,25 +1040,6 @@ def my_form_open(dialog, layer, feature): - - - - - - - - - - - - - - - - - - - @@ -895,7 +1049,7 @@ def my_form_open(dialog, layer, feature): - + @@ -917,17 +1071,6 @@ def my_form_open(dialog, layer, feature): - - - - - - - - - - - @@ -949,8 +1092,8 @@ def my_form_open(dialog, layer, feature): - - + + @@ -970,7 +1113,7 @@ def my_form_open(dialog, layer, feature): - + @@ -986,6 +1129,9 @@ def my_form_open(dialog, layer, feature): + @@ -996,10 +1142,10 @@ def my_form_open(dialog, layer, feature): 1 - + - + @@ -1037,33 +1183,6 @@ def my_form_open(dialog, layer, feature): - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1141,7 +1260,7 @@ def my_form_open(dialog, layer, feature): - + @@ -1211,7 +1330,7 @@ def my_form_open(dialog, layer, feature): red_layer_with_no_filter - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -1234,7 +1353,7 @@ def my_form_open(dialog, layer, feature): - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -1270,9 +1389,141 @@ def my_form_open(dialog, layer, feature): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1302,25 +1553,6 @@ def my_form_open(dialog, layer, feature): - - - - - - - - - - - - - - - - - - - @@ -1335,7 +1567,11 @@ def my_form_open(dialog, layer, feature): - + + + 0 0 @@ -1374,7 +1610,10 @@ def my_form_open(dialog, layer, feature): - + + + + @@ -1393,7 +1632,7 @@ def my_form_open(dialog, layer, feature): - + "gid" @@ -1403,14 +1642,7 @@ def my_form_open(dialog, layer, feature): - - - - - - 1 - true - + 2 @@ -1470,7 +1702,7 @@ def my_form_open(dialog, layer, feature): lizmap_user_groups - intranet + testsrepository @@ -1558,7 +1790,7 @@ def my_form_open(dialog, layer, feature): - + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -1571,7 +1803,7 @@ def my_form_open(dialog, layer, feature): - + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] +proj=longlat +datum=WGS84 +no_defs 3452 @@ -1607,11 +1839,12 @@ def my_form_open(dialog, layer, feature): + - - + + PROJCRS["RGF93 v1 / Lambert-93",BASEGEOGCRS["RGF93 v1",DATUM["Reseau Geodesique Francais 1993 v1",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4171]],CONVERSION["Lambert-93",METHOD["Lambert Conic Conformal (2SP)",ID["EPSG",9802]],PARAMETER["Latitude of false origin",46.5,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8821]],PARAMETER["Longitude of false origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8822]],PARAMETER["Latitude of 1st standard parallel",49,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Latitude of 2nd standard parallel",44,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8824]],PARAMETER["Easting at false origin",700000,LENGTHUNIT["metre",1],ID["EPSG",8826]],PARAMETER["Northing at false origin",6600000,LENGTHUNIT["metre",1],ID["EPSG",8827]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Engineering survey, topographic mapping."],AREA["France - onshore and offshore, mainland and Corsica."],BBOX[41.15,-9.86,51.56,10.38]],ID["EPSG",2154]] +proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 145 @@ -1624,19 +1857,55 @@ def my_form_open(dialog, layer, feature): + + + - + + + + + + + - + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + - + \ No newline at end of file diff --git a/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg b/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg index fafa4f2243..3b6fbf3279 100644 --- a/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg +++ b/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg @@ -1,15 +1,17 @@ { "metadata": { - "qgis_desktop_version": 32216, - "lizmap_plugin_version_str": "3.14.3-alpha", - "lizmap_plugin_version": 31403, - "lizmap_web_client_target_version": 30700, + "qgis_desktop_version": 32815, + "lizmap_plugin_version_str": "4.3.18-alpha", + "lizmap_plugin_version": 40318, + "lizmap_web_client_target_version": 30900, "lizmap_web_client_target_status": "Dev", "instance_target_url": "http://localhost:8130/", - "instance_target_repository": "intranet", - "project_valid": true + "instance_target_repository": "testsrepository" + }, + "warnings": {}, + "debug": { + "total_time": 0.379 }, - "warnings": [], "options": { "projection": { "proj4": "+proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", @@ -33,11 +35,13 @@ ], "minScale": 10000, "maxScale": 2000000, + "use_native_zoom_levels": false, + "hide_numeric_scale_value": false, "initialExtent": [ - -492657.5601093583, - 698659.0419671754, - 609116.6044059563, - 1329107.5127044579 + -492657.5601, + 698659.042, + 609116.6044, + 1329107.5127 ], "popupLocation": "dock", "pointTolerance": 25, diff --git a/tests/qgis-projects/tests/set_tests_respository_rights.sql b/tests/qgis-projects/tests/set_tests_respository_rights.sql index be17ce4360..3d0f7ee40a 100644 --- a/tests/qgis-projects/tests/set_tests_respository_rights.sql +++ b/tests/qgis-projects/tests/set_tests_respository_rights.sql @@ -5,6 +5,8 @@ INSERT INTO lizmap.jacl2_group( id_aclgrp, name, grouptype, ownerlogin) VALUES ('group_a', 'group_a', 0, null), ('__priv_user_in_group_a', 'user_in_group_a', 2, 'user_in_group_a'), + ('group_b', 'group_b', 0, null), + ('__priv_user_in_group_b', 'user_in_group_b', 2, 'user_in_group_b'), ('__priv_publisher', 'publisher', 2, 'publisher') ON CONFLICT DO NOTHING ; @@ -14,6 +16,7 @@ INSERT INTO lizmap.jlx_user( usr_login, usr_email, usr_password, status, create_date) VALUES ('user_in_group_a', 'user_in_group_a@nomail.nomail', '$2y$10$d2KZfxeYJP0l3YbNyDMZYe2vGSA3JWa8kFJSdecmSEIqInjnunTJ.', 1, NOW()), + ('user_in_group_b', 'user_in_group_b@nomail.nomail', '$2y$10$d2KZfxeYJP0l3YbNyDMZYe2vGSA3JWa8kFJSdecmSEIqInjnunTJ.', 1, NOW()), ('publisher', 'publisher@nomail.nomail', '$2y$10$d2KZfxeYJP0l3YbNyDMZYe2vGSA3JWa8kFJSdecmSEIqInjnunTJ.', 1, NOW()) ON CONFLICT DO NOTHING ; @@ -24,6 +27,9 @@ INSERT INTO lizmap.jacl2_user_group( VALUES ('user_in_group_a', 'group_a'), ('user_in_group_a', '__priv_user_in_group_a'), ('user_in_group_a', 'users'), + ('user_in_group_b', 'group_b'), + ('user_in_group_b', '__priv_user_in_group_b'), + ('user_in_group_b', 'users'), ('publisher', '__priv_publisher'), ('publisher', 'users'), ('publisher', 'publishers') @@ -54,6 +60,11 @@ VALUES ('lizmap.repositories.view', 'group_a', 'testsrepository', 0), ('lizmap.tools.displayGetCapabilitiesLinks', 'group_a', 'testsrepository', 0), ('lizmap.tools.edition.use', 'group_a', 'testsrepository', 0), -('lizmap.tools.layer.export', 'group_a', 'testsrepository', 0) +('lizmap.tools.layer.export', 'group_a', 'testsrepository', 0), +-- ...for users in group_b group +('lizmap.repositories.view', 'group_b', 'testsrepository', 0), +('lizmap.tools.displayGetCapabilitiesLinks', 'group_b', 'testsrepository', 0), +('lizmap.tools.edition.use', 'group_b', 'testsrepository', 0), +('lizmap.tools.layer.export', 'group_b', 'testsrepository', 0) ON CONFLICT DO NOTHING ; diff --git a/tests/qgis-projects/tests/tests_dataset.sql b/tests/qgis-projects/tests/tests_dataset.sql index 16f60f4a49..31bb33cc42 100644 --- a/tests/qgis-projects/tests/tests_dataset.sql +++ b/tests/qgis-projects/tests/tests_dataset.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version 14.11 (Debian 14.11-1.pgdg110+2) --- Dumped by pg_dump version 14.11 (Ubuntu 14.11-0ubuntu0.22.04.1) +-- Dumped by pg_dump version 14.12 (Ubuntu 14.12-0ubuntu0.22.04.1) SET statement_timeout = 0; SET lock_timeout = 0; @@ -404,6 +404,38 @@ CREATE SEQUENCE tests_projects.dnd_popup_id_seq ALTER SEQUENCE tests_projects.dnd_popup_id_seq OWNED BY tests_projects.dnd_popup.id; +-- +-- Name: double_geom; Type: TABLE; Schema: tests_projects; Owner: - +-- + +CREATE TABLE tests_projects.double_geom ( + id integer NOT NULL, + title text, + geom public.geometry(Polygon,4326), + geom_d public.geometry(Polygon,4326) +); + + +-- +-- Name: double_geom_id_seq; Type: SEQUENCE; Schema: tests_projects; Owner: - +-- + +CREATE SEQUENCE tests_projects.double_geom_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: double_geom_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - +-- + +ALTER SEQUENCE tests_projects.double_geom_id_seq OWNED BY tests_projects.double_geom.id; + + -- -- Name: edition_layer_embed_child; Type: TABLE; Schema: tests_projects; Owner: - -- @@ -2319,51 +2351,23 @@ ALTER SEQUENCE tests_projects.tramway_stops_id_stop_seq OWNED BY tests_projects. -- --- Name: xss; Type: TABLE; Schema: tests_projects; Owner: - --- - -CREATE TABLE tests_projects.xss ( - id integer NOT NULL, - geom public.geometry(Point,2154), - description text -); - - --- --- Name: xss_id_seq; Type: SEQUENCE; Schema: tests_projects; Owner: - --- - -CREATE SEQUENCE tests_projects.xss_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: xss_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - --- - -ALTER SEQUENCE tests_projects.xss_id_seq OWNED BY tests_projects.xss.id; - --- --- Name: double_geom; Type: TABLE; Schema: tests_projects; Owner: - +-- Name: triple_geom; Type: TABLE; Schema: tests_projects; Owner: - -- -CREATE TABLE tests_projects.double_geom ( +CREATE TABLE tests_projects.triple_geom ( id integer NOT NULL, title text, - geom public.geometry(Polygon,4326), - geom_d public.geometry(Polygon,4326) + geom public.geometry(Point,4326), + geom_l public.geometry(LineString,4326), + geom_p public.geometry(Polygon,4326) ); + -- --- Name: double_geom; Type: SEQUENCE; Schema: tests_projects; Owner: - +-- Name: triple_geom_id_seq; Type: SEQUENCE; Schema: tests_projects; Owner: - -- -CREATE SEQUENCE tests_projects.double_geom_id_seq +CREATE SEQUENCE tests_projects.triple_geom_id_seq AS integer START WITH 1 INCREMENT BY 1 @@ -2373,30 +2377,28 @@ CREATE SEQUENCE tests_projects.double_geom_id_seq -- --- Name: double_geom_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - +-- Name: triple_geom_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - -- -ALTER SEQUENCE tests_projects.double_geom_id_seq OWNED BY tests_projects.double_geom.id; +ALTER SEQUENCE tests_projects.triple_geom_id_seq OWNED BY tests_projects.triple_geom.id; -- --- Name: triple_geom; Type: TABLE; Schema: tests_projects; Owner: - +-- Name: xss; Type: TABLE; Schema: tests_projects; Owner: - -- -CREATE TABLE tests_projects.triple_geom ( +CREATE TABLE tests_projects.xss ( id integer NOT NULL, - title text, - geom public.geometry(Point,4326), - geom_l public.geometry(LineString,4326), - geom_p public.geometry(Polygon,4326) - + geom public.geometry(Point,2154), + description text ); + -- --- Name: triple_geom Type: SEQUENCE; Schema: tests_projects; Owner: - +-- Name: xss_id_seq; Type: SEQUENCE; Schema: tests_projects; Owner: - -- -CREATE SEQUENCE tests_projects.triple_geom_id_seq +CREATE SEQUENCE tests_projects.xss_id_seq AS integer START WITH 1 INCREMENT BY 1 @@ -2406,10 +2408,10 @@ CREATE SEQUENCE tests_projects.triple_geom_id_seq -- --- Name: triple_geom_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - +-- Name: xss_id_seq; Type: SEQUENCE OWNED BY; Schema: tests_projects; Owner: - -- -ALTER SEQUENCE tests_projects.triple_geom_id_seq OWNED BY tests_projects.triple_geom.id; +ALTER SEQUENCE tests_projects.xss_id_seq OWNED BY tests_projects.xss.id; -- @@ -2489,6 +2491,13 @@ ALTER TABLE ONLY tests_projects.dnd_form_geom ALTER COLUMN id SET DEFAULT nextva ALTER TABLE ONLY tests_projects.dnd_popup ALTER COLUMN id SET DEFAULT nextval('tests_projects.dnd_popup_id_seq'::regclass); +-- +-- Name: double_geom id; Type: DEFAULT; Schema: tests_projects; Owner: - +-- + +ALTER TABLE ONLY tests_projects.double_geom ALTER COLUMN id SET DEFAULT nextval('tests_projects.double_geom_id_seq'::regclass); + + -- -- Name: edition_layer_embed_child id; Type: DEFAULT; Schema: tests_projects; Owner: - -- @@ -2903,22 +2912,18 @@ ALTER TABLE ONLY tests_projects.tramway_stops ALTER COLUMN id_stop SET DEFAULT n -- --- Name: xss id; Type: DEFAULT; Schema: tests_projects; Owner: - +-- Name: triple_geom id; Type: DEFAULT; Schema: tests_projects; Owner: - -- -ALTER TABLE ONLY tests_projects.xss ALTER COLUMN id SET DEFAULT nextval('tests_projects.xss_id_seq'::regclass); - --- --- Name: double_geom id; Type: DEFAULT; Schema: tests_projects; Owner: - --- +ALTER TABLE ONLY tests_projects.triple_geom ALTER COLUMN id SET DEFAULT nextval('tests_projects.triple_geom_id_seq'::regclass); -ALTER TABLE ONLY tests_projects.double_geom ALTER COLUMN id SET DEFAULT nextval('tests_projects.double_geom_id_seq'::regclass); -- --- Name: triple_geom id; Type: DEFAULT; Schema: tests_projects; Owner: - +-- Name: xss id; Type: DEFAULT; Schema: tests_projects; Owner: - -- -ALTER TABLE ONLY tests_projects.triple_geom ALTER COLUMN id SET DEFAULT nextval('tests_projects.triple_geom_id_seq'::regclass); +ALTER TABLE ONLY tests_projects.xss ALTER COLUMN id SET DEFAULT nextval('tests_projects.xss_id_seq'::regclass); + -- -- Data for Name: attribute_table; Type: TABLE DATA; Schema: tests_projects; Owner: - @@ -3065,6 +3070,15 @@ COPY tests_projects.dnd_popup (id, field_tab1, field_tab2, geom) FROM stdin; \. +-- +-- Data for Name: double_geom; Type: TABLE DATA; Schema: tests_projects; Owner: - +-- + +COPY tests_projects.double_geom (id, title, geom, geom_d) FROM stdin; +1 F2 0103000020E610000001000000060000005520F9393F8E0E4043232852C1CD454091126D1728C40E4049F9C8EAF5CB454015E1134ED2540E40190EB02B2ECC454015E1134ED2540E40190EB02B2ECC454089C25720B0490E402CE5037573CE45405520F9393F8E0E4043232852C1CD4540 0103000020E61000000100000007000000879AE9F0C7BA0E4030327583F7D1454067325F7DA79E0E404EB50AFEA5D04540FA7B2DC3A5AF0E40CC0ED2F6E3CE45408E34CC0DD0C10E40F5B479184BCF45408E34CC0DD0C10E40F5B479184BCF4540BC614BB6D4EA0E40BE84EFBB22D04540879AE9F0C7BA0E4030327583F7D14540 +\. + + -- -- Data for Name: edition_layer_embed_child; Type: TABLE DATA; Schema: tests_projects; Owner: - -- @@ -3119,8 +3133,8 @@ COPY tests_projects.end2end_form_edition_geom (id, value, geom) FROM stdin; COPY tests_projects.filter_layer_by_user (gid, "user", "group", geom) FROM stdin; 1 admin \N 01010000206A08000000E08B6EAA0E744090DC4977C6372F41 -2 user_in_group_a \N 01010000206A08000084D3086E0FDFF3404A2C05E482472F41 3 \N \N 01010000206A08000028B76AD632CBE540B5C59180B9102E41 +2 user_in_group_a,user_in_group_b \N 01010000206A08000084D3086E0FDFF3404A2C05E482472F41 \. @@ -3731,25 +3745,20 @@ COPY tests_projects.tramway_stops (id_stop, geom) FROM stdin; -- --- Data for Name: xss; Type: TABLE DATA; Schema: tests_projects; Owner: - +-- Data for Name: triple_geom; Type: TABLE DATA; Schema: tests_projects; Owner: - -- -COPY tests_projects.xss (id, geom, description) FROM stdin; -1 01010000206A0800000D9D9921FD822741B3C56B7B4DF45741 +COPY tests_projects.triple_geom (id, title, geom, geom_l, geom_p) FROM stdin; +1 P2 0101000020E61000009BAFF31C24420F40B0F20C103ECD4540 0102000020E610000003000000F831609D15230F40B6C8ADA872CB45400D2267EAD5350F40CA0ED2F6E3CE4540CD98B4D8D86F0F40013F5C530CCE4540 0103000020E610000001000000040000008CEAFEE73F350F40CE5B430568D2454027CEAF4A464D0F40F4234A1D77D045405E04E2147F7E0F402E327583F7D145408CEAFEE73F350F40CE5B430568D24540 \. --- --- Data for Name: double_geom; Type: TABLE DATA; Schema: tests_projects; Owner: - --- -COPY tests_projects.double_geom (id, title, geom, geom_d) FROM stdin; -1 F2 010300000001000000060000005520F9393F8E0E4043232852C1CD454091126D1728C40E4049F9C8EAF5CB454015E1134ED2540E40190EB02B2ECC454015E1134ED2540E40190EB02B2ECC454089C25720B0490E402CE5037573CE45405520F9393F8E0E4043232852C1CD4540 01030000000100000007000000879AE9F0C7BA0E4030327583F7D1454067325F7DA79E0E404EB50AFEA5D04540FA7B2DC3A5AF0E40CC0ED2F6E3CE45408E34CC0DD0C10E40F5B479184BCF45408E34CC0DD0C10E40F5B479184BCF4540BC614BB6D4EA0E40BE84EFBB22D04540879AE9F0C7BA0E4030327583F7D14540 -\. -- --- Data for Name: triple_geom; Type: TABLE DATA; Schema: tests_projects; Owner: - +-- Data for Name: xss; Type: TABLE DATA; Schema: tests_projects; Owner: - -- -COPY tests_projects.triple_geom (id, title, geom, geom_l, geom_p) FROM stdin; -1 P2 01010000009BAFF31C24420F40B0F20C103ECD4540 010200000003000000F831609D15230F40B6C8ADA872CB45400D2267EAD5350F40CA0ED2F6E3CE4540CD98B4D8D86F0F40013F5C530CCE4540 010300000001000000040000008CEAFEE73F350F40CE5B430568D2454027CEAF4A464D0F40F4234A1D77D045405E04E2147F7E0F402E327583F7D145408CEAFEE73F350F40CE5B430568D24540 + +COPY tests_projects.xss (id, geom, description) FROM stdin; +1 01010000206A0800000D9D9921FD822741B3C56B7B4DF45741 \. @@ -3830,6 +3839,13 @@ SELECT pg_catalog.setval('tests_projects.dnd_form_id_seq', 1, true); SELECT pg_catalog.setval('tests_projects.dnd_popup_id_seq', 2, true); +-- +-- Name: double_geom_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - +-- + +SELECT pg_catalog.setval('tests_projects.double_geom_id_seq', 1, true); + + -- -- Name: edition_layer_embed_child_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - -- @@ -4258,23 +4274,17 @@ SELECT pg_catalog.setval('tests_projects.tramway_stops_id_stop_seq', 5, true); -- --- Name: xss_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - +-- Name: triple_geom_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - -- -SELECT pg_catalog.setval('tests_projects.xss_id_seq', 1, true); - --- --- Name: double_geom_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - --- +SELECT pg_catalog.setval('tests_projects.triple_geom_id_seq', 1, true); -SELECT pg_catalog.setval('tests_projects.double_geom_id_seq', 1, true); -- --- Name: triple_geom_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - +-- Name: xss_id_seq; Type: SEQUENCE SET; Schema: tests_projects; Owner: - -- -SELECT pg_catalog.setval('tests_projects.triple_geom_id_seq', 1, true); - +SELECT pg_catalog.setval('tests_projects.xss_id_seq', 1, true); -- @@ -4365,6 +4375,14 @@ ALTER TABLE ONLY tests_projects.dnd_popup ADD CONSTRAINT dnd_popup_pkey PRIMARY KEY (id); +-- +-- Name: double_geom double_geom_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - +-- + +ALTER TABLE ONLY tests_projects.double_geom + ADD CONSTRAINT double_geom_pkey PRIMARY KEY (id); + + -- -- Name: edition_layer_embed_child edition_layer_embed_child_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - -- @@ -4878,27 +4896,19 @@ ALTER TABLE ONLY tests_projects.tramway_stops -- --- Name: xss xss_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - +-- Name: triple_geom triple_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - -- -ALTER TABLE ONLY tests_projects.xss - ADD CONSTRAINT xss_pkey PRIMARY KEY (id); - - --- --- Name: double_geom double_geom_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - --- - -ALTER TABLE ONLY tests_projects.double_geom - ADD CONSTRAINT double_geom_pkey PRIMARY KEY (id); +ALTER TABLE ONLY tests_projects.triple_geom + ADD CONSTRAINT triple_pkey PRIMARY KEY (id); -- --- Name: triple_geom triple_geom_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - +-- Name: xss xss_pkey; Type: CONSTRAINT; Schema: tests_projects; Owner: - -- -ALTER TABLE ONLY tests_projects.triple_geom - ADD CONSTRAINT triple_pkey PRIMARY KEY (id); +ALTER TABLE ONLY tests_projects.xss + ADD CONSTRAINT xss_pkey PRIMARY KEY (id); -- @@ -4976,3 +4986,4 @@ ALTER TABLE ONLY tests_projects.tramway_pivot -- -- PostgreSQL database dump complete -- + diff --git a/tests/units/classes/Project/ProjectTest.php b/tests/units/classes/Project/ProjectTest.php index 2a3a02a34c..8bb169c8cc 100644 --- a/tests/units/classes/Project/ProjectTest.php +++ b/tests/units/classes/Project/ProjectTest.php @@ -270,8 +270,17 @@ public static function getFiltersData() $aclData2 = array( 'userIsConnected' => false, ); - $filter1 = '"Group" IN ( \'admin\' , \'groups\' , \'lizmap\' , \'all\' )'; - $filter2 = '"Group" = \'all\''; + //$filter1 = '"Group" IN ( \'admin\' , \'groups\' , \'lizmap\' , \'all\' )'; + $filter1 = '"Group" = \'admin\' OR "Group" LIKE \'admin,%\' OR "Group" LIKE \'%,admin\' OR "Group" LIKE \'%,admin,%\''; + $filter1 .= ' OR '; + $filter1 .= '"Group" = \'groups\' OR "Group" LIKE \'groups,%\' OR "Group" LIKE \'%,groups\' OR "Group" LIKE \'%,groups,%\''; + $filter1 .= ' OR '; + $filter1 .= '"Group" = \'lizmap\' OR "Group" LIKE \'lizmap,%\' OR "Group" LIKE \'%,lizmap\' OR "Group" LIKE \'%,lizmap,%\''; + $filter1 .= ' OR '; + $filter1 .= '"Group" = \'all\' OR "Group" LIKE \'all,%\' OR "Group" LIKE \'%,all\' OR "Group" LIKE \'%,all,%\''; + + //$filter2 = '"Group" = \'all\''; + $filter2 = '"Group" = \'all\' OR "Group" LIKE \'all,%\' OR "Group" LIKE \'%,all\' OR "Group" LIKE \'%,all,%\''; return array( array($aclData1, $filter1), diff --git a/tests/units/classes/Request/WFSRequestTest.php b/tests/units/classes/Request/WFSRequestTest.php index 11ec0bf838..82b8a1d572 100644 --- a/tests/units/classes/Request/WFSRequestTest.php +++ b/tests/units/classes/Request/WFSRequestTest.php @@ -138,9 +138,9 @@ public static function getBuildQueryBaseData() 'geometryname' => 'none' ); return array( - array($paramsComplete, $wfsFields, array('prop', 'name', 'key', 'geom', 'test'), ' SELECT prop, name, key, geom, test, geocol AS geosource FROM table'), - array($paramsGeom, $wfsFields, array('prop', 'name', 'notProp', 'key', 'geom', 'test'), ' SELECT prop, name, notProp, key, geom, test, geocol AS geosource FROM table'), - array($paramsProp, $wfsFields, array('prop', 'name', 'key', 'geom', 'test'), ' SELECT prop, name, key, geom, test FROM table'), + array($paramsComplete, $wfsFields, array('"prop"', '"name"', '"key"', '"geom"', '"test"'), ' SELECT "prop", "name", "key", "geom", "test", "geocol" AS "geosource" FROM table'), + array($paramsGeom, $wfsFields, array('"prop"', '"name"', '"notProp"', '"key"', '"geom"', '"test"'), ' SELECT "prop", "name", "notProp", "key", "geom", "test", "geocol" AS "geosource" FROM table'), + array($paramsProp, $wfsFields, array('"prop"', '"name"', '"key"', '"geom"', '"test"'), ' SELECT "prop", "name", "key", "geom", "test" FROM table'), ); } @@ -191,8 +191,8 @@ public static function getParseExpFilterData() return array( array(array(), '', ''), array(array('exp_filter' => 'select'), '', false), - array(array('exp_filter' => 'filter for test'), '', ' AND filter for test'), - array(array('exp_filter' => 'filter for test with $id = 5'), 'key', ' AND filter for test with key = 5'), + array(array('exp_filter' => 'filter for test'), '', ' AND ( filter for test ) '), + array(array('exp_filter' => 'filter for test with $id = 5'), 'key', ' AND ( filter for test with "key" = 5 ) '), array(array('exp_filter' => 'filter for test with $id = 5'), 'key,otherKey', false), ); } @@ -213,9 +213,9 @@ public static function getParseFeatureData() { return array( array('', '', '', ''), - array('type', 'type.test@@55', 'key,otherKey', ' AND (key = "test" AND otherKey = 55)'), - array('type', 'type.test@@55,you shall not pass,type.name@@42', 'key,otherKey', ' AND (key = "test" AND otherKey = 55) OR (key = "name" AND otherKey = 42)'), - array('', 'type.test@@55', 'key,otherKey', ' AND (key = "test" AND otherKey = 55)'), + array('type', 'type.test@@55', 'key,otherKey', ' AND ("key" = \'test\' AND "otherKey" = 55)'), + array('type', 'type.test@@55,you shall not pass,type.name@@42', 'key,otherKey', ' AND ("key" = \'test\' AND "otherKey" = 55) OR ("key" = \'name\' AND "otherKey" = 42)'), + array('', 'type.test@@55', 'key,otherKey', ' AND ("key" = \'test\' AND "otherKey" = 55)'), ); } @@ -240,7 +240,7 @@ public static function getGetQueryOrderData() array(array(), array(), ''), array(array('sortby' => ''), array(), ''), array(array('sortby' => 'id a,test d,wfs a'), array(), ''), - array(array('sortby' => 'id a,test d,wfs a'), array('test', 'field', 'wfs'), ' ORDER BY test DESC, wfs ASC'), + array(array('sortby' => 'id a,test d,wfs a'), array('test', 'field', 'wfs'), ' ORDER BY "test" DESC, "wfs" ASC'), ); } diff --git a/tests/units/testslib/ContextForTests.php b/tests/units/testslib/ContextForTests.php index 79528a4a0e..2a807da4ed 100644 --- a/tests/units/testslib/ContextForTests.php +++ b/tests/units/testslib/ContextForTests.php @@ -181,6 +181,7 @@ public function eventNotify($eventName, $params = array()) public function getDbConnection($profile = '') { + return new jDbConnectionForTests(); } public function getLocale($key, $variables = array()) diff --git a/tests/units/testslib/jDbConnectionForTests.php b/tests/units/testslib/jDbConnectionForTests.php index 83e8ff938d..273b7b9282 100644 --- a/tests/units/testslib/jDbConnectionForTests.php +++ b/tests/units/testslib/jDbConnectionForTests.php @@ -4,11 +4,11 @@ class jDbConnectionForTests { public function encloseName($name) { - return $name; + return '"'.$name.'"'; } public function quote($name) { - return '"'.$name.'"'; + return "'".str_replace("'", "\\'", $name)."'"; } } From 11799e0ef1c9b0633cfe88e8b6b3714e703227a6 Mon Sep 17 00:00:00 2001 From: Michael Douchin Date: Thu, 22 Aug 2024 12:32:22 +0200 Subject: [PATCH 2/3] PlayWright test - Filter by user: replace GetMap screenshot comparison with GetFeatureInfo JSON checks --- .../playwright/filter-layer-by-user.spec.js | 99 ++++++++++++++----- 1 file changed, 75 insertions(+), 24 deletions(-) diff --git a/tests/end2end/playwright/filter-layer-by-user.spec.js b/tests/end2end/playwright/filter-layer-by-user.spec.js index 861642f883..d0ae32b511 100644 --- a/tests/end2end/playwright/filter-layer-by-user.spec.js +++ b/tests/end2end/playwright/filter-layer-by-user.spec.js @@ -12,17 +12,34 @@ test.describe('Filter layer data by user - not connected', () => { await page.locator('#dock-close').click(); }); - test('GetMap', async ({ page }) => { - // Hide all elements but #newOlMap and its children - await page.$eval("*", el => el.style.visibility = 'hidden'); - await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + // DISABLED BECAUSE IT IS NOT RELIABLE, MAINTAINABLE AND CAUSES HEADACHE ;-) + // Instead, we use a WMS GetFeatureInfo in JSON format below + // test('GetMap', async ({ page }) => { + // // Hide all elements but #newOlMap and its children + // await page.$eval("*", el => el.style.visibility = 'hidden'); + // await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + + // expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_not_connected.png', { + // maxDiffPixels: 500 + // }); + // }); + + test('WMS GetFeatureInfo JSON', async ({ page }) => { + + const getFeatureInfo = await page.evaluate(async () => { + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + .then(r => r.ok ? r.json() : Promise.reject(r)) + }) + + // check features + expect(getFeatureInfo.features).toHaveLength(4) + // check a specific feature + const feature = getFeatureInfo.features[0] + expect(feature.id).not.toBeUndefined() - expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_not_connected.png', { - maxDiffPixels: 500 - }); }); - test('Popup', async ({ page }) => { + test('Popup with map click', async ({ page }) => { let getFeatureInfoRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData()?.includes('GetFeatureInfo') === true); // blue_filter_layer_by_user @@ -133,17 +150,34 @@ test.describe('Filter layer data by user - user in group a', () => { await page.locator('#dock-close').click(); }); - test('GetMap', async ({ page }) => { - // Hide all elements but #newOlMap and its children - await page.$eval("*", el => el.style.visibility = 'hidden'); - await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + // DISABLED BECAUSE IT IS NOT RELIABLE, MAINTAINABLE AND CAUSES HEADACHE ;-) + // Instead, we use a WMS GetFeatureInfo in JSON format below + // test('GetMap', async ({ page }) => { + // // Hide all elements but #newOlMap and its children + // await page.$eval("*", el => el.style.visibility = 'hidden'); + // await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + + // expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_connected_as_user_in_group_a.png', { + // maxDiffPixels: 500 + // }); + // }); + + test('WMS GetFeatureInfo JSON', async ({ page }) => { + + const getFeatureInfo = await page.evaluate(async () => { + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + .then(r => r.ok ? r.json() : Promise.reject(r)) + }) + + // check features + expect(getFeatureInfo.features).toHaveLength(5) + // check a specific feature + const feature = getFeatureInfo.features[0] + expect(feature.id).not.toBeUndefined() - expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_connected_as_user_in_group_a.png', { - maxDiffPixels: 500 - }); }); - test('Popup', async ({ page }) => { + test('Popup with map click', async ({ page }) => { let getFeatureInfoRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData()?.includes('GetFeatureInfo') === true); // blue_filter_layer_by_user @@ -258,17 +292,34 @@ test.describe('Filter layer data by user - admin', () => { await page.locator('#dock-close').click(); }); - test('GetMap', async ({ page }) => { - // Hide all elements but #newOlMap and its children - await page.$eval("*", el => el.style.visibility = 'hidden'); - await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + // DISABLED BECAUSE IT IS NOT RELIABLE, MAINTAINABLE AND CAUSES HEADACHE ;-) + // Instead, we use a WMS GetFeatureInfo in JSON format below + // test('GetMap', async ({ page }) => { + // // Hide all elements but #newOlMap and its children + // await page.$eval("*", el => el.style.visibility = 'hidden'); + // await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible'); + + // expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_connected_as_admin.png', { + // maxDiffPixels: 500 + // }); + // }); + + test('WMS GetFeatureInfo JSON', async ({ page }) => { + + const getFeatureInfo = await page.evaluate(async () => { + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + .then(r => r.ok ? r.json() : Promise.reject(r)) + }) + + // check features + expect(getFeatureInfo.features).toHaveLength(7) + // check a specific feature + const feature = getFeatureInfo.features[0] + expect(feature.id).not.toBeUndefined() - expect(await page.locator('#newOlMap').screenshot()).toMatchSnapshot('map_connected_as_admin.png', { - maxDiffPixels: 500 - }); }); - test('Popup', async ({ page }) => { + test('Popup with map click', async ({ page }) => { let getFeatureInfoRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData()?.includes('GetFeatureInfo') === true); // blue_filter_layer_by_user From af9156b76d0e77668a2c7e46889b0f291d9bf43c Mon Sep 17 00:00:00 2001 From: Michael Douchin Date: Fri, 23 Aug 2024 12:35:07 +0200 Subject: [PATCH 3/3] Attribute filter - activate multiple values capability only for PostgreSQL layers & if allow_multiple_acl_values is true --- lizmap/modules/lizmap/lib/Project/Project.php | 46 ++- .../playwright/filter-layer-by-user.spec.js | 6 +- .../tests/filter_layer_by_user.qgs.cfg | 2 + tests/units/classes/Project/ProjectTest.php | 97 +++++- .../edition_embed_parent_filtered.qgs.cfg | 285 ++++++++++++++++++ 5 files changed, 411 insertions(+), 25 deletions(-) create mode 100644 tests/units/classes/Project/Ressources/edition_embed_parent_filtered.qgs.cfg diff --git a/lizmap/modules/lizmap/lib/Project/Project.php b/lizmap/modules/lizmap/lib/Project/Project.php index 60fb62ddb6..f75b8b357b 100644 --- a/lizmap/modules/lizmap/lib/Project/Project.php +++ b/lizmap/modules/lizmap/lib/Project/Project.php @@ -1271,8 +1271,27 @@ public function getLoginFilters($layers, $edition = false) $cnx = $this->appContext->getDbConnection(); $quotedField = $cnx->encloseName($attribute); + // Get QGIS vector layer provider + /** @var null|\qgisVectorLayer $qgisLayer The QGIS vector layer instance */ + $qgisLayer = $this->qgis->getLayer($layerByTypeName->id, $this); + $provider = 'unknown'; + if ($qgisLayer) { + $provider = $qgisLayer->getProvider(); + } + // default no user connected - $filter = "{$quotedField} = 'all' OR {$quotedField} LIKE 'all,%' OR {$quotedField} LIKE '%,all' OR {$quotedField} LIKE '%,all,%'"; + $filter = "{$quotedField} = 'all'"; + + // For PostgreSQL layers, allow multiple values in the filter field + // E.g. "groupe_a,other_group" + if ($provider == 'postgres' + && property_exists($loginFilteredConfig, 'allow_multiple_acl_values') + && $loginFilteredConfig->allow_multiple_acl_values + ) { + $filter .= " OR {$quotedField} LIKE 'all,%'"; + $filter .= " OR {$quotedField} LIKE '%,all'"; + $filter .= " OR {$quotedField} LIKE '%,all,%'"; + } // A user is connected if ($this->appContext->userIsConnected()) { @@ -1307,17 +1326,24 @@ public function getLoginFilters($layers, $edition = false) // equality $valueFilters[] = "{$quotedField} = {$quotedValue}"; - // begins with value & comma - $quotedLikeValue = $cnx->quote("{$value},%"); - $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + // For PostgreSQL layers, allow multiple values in the filter field + // E.g. "groupe_a,other_group" + if ($provider == 'postgres' + && property_exists($loginFilteredConfig, 'allow_multiple_acl_values') + && $loginFilteredConfig->allow_multiple_acl_values + ) { + // begins with value & comma + $quotedLikeValue = $cnx->quote("{$value},%"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; - // ends with comma & value - $quotedLikeValue = $cnx->quote("%,{$value}"); - $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + // ends with comma & value + $quotedLikeValue = $cnx->quote("%,{$value}"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; - // value between two commas - $quotedLikeValue = $cnx->quote("%,{$value},%"); - $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + // value between two commas + $quotedLikeValue = $cnx->quote("%,{$value},%"); + $valueFilters[] = "{$quotedField} LIKE {$quotedLikeValue}"; + } // Build the filter for this value $allValuesFilters[] = implode(' OR ', $valueFilters); diff --git a/tests/end2end/playwright/filter-layer-by-user.spec.js b/tests/end2end/playwright/filter-layer-by-user.spec.js index d0ae32b511..d33c45f9fc 100644 --- a/tests/end2end/playwright/filter-layer-by-user.spec.js +++ b/tests/end2end/playwright/filter-layer-by-user.spec.js @@ -27,7 +27,7 @@ test.describe('Filter layer data by user - not connected', () => { test('WMS GetFeatureInfo JSON', async ({ page }) => { const getFeatureInfo = await page.evaluate(async () => { - return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") .then(r => r.ok ? r.json() : Promise.reject(r)) }) @@ -165,7 +165,7 @@ test.describe('Filter layer data by user - user in group a', () => { test('WMS GetFeatureInfo JSON', async ({ page }) => { const getFeatureInfo = await page.evaluate(async () => { - return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") .then(r => r.ok ? r.json() : Promise.reject(r)) }) @@ -307,7 +307,7 @@ test.describe('Filter layer data by user - admin', () => { test('WMS GetFeatureInfo JSON', async ({ page }) => { const getFeatureInfo = await page.evaluate(async () => { - return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&BBOX=-310600.3821764754%2C726545.2026738503%2C364617.6349262256%2C1244071.2377259205&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") + return await fetch("/index.php/lizmap/service?repository=testsrepository&project=filter_layer_by_user&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.3.0&CRS=EPSG%3A2154&INFO_FORMAT=application%2Fjson&QUERY_LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&LAYERS=green_filter_layer_by_user_edition_only%2Cblue_filter_layer_by_user%2Cred_layer_with_no_filter&STYLE=default%2Cdefault%2Cdefault&FEATURE_COUNT=10&FILTER=green_filter_layer_by_user_edition_only:\"gid\" > 0") .then(r => r.ok ? r.json() : Promise.reject(r)) }) diff --git a/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg b/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg index 3b6fbf3279..4a10893b09 100644 --- a/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg +++ b/tests/qgis-projects/tests/filter_layer_by_user.qgs.cfg @@ -236,6 +236,7 @@ "filterAttribute": "user", "filterPrivate": "True", "edition_only": "False", + "allow_multiple_acl_values": true, "order": 0 }, "green_filter_layer_by_user_edition_only": { @@ -243,6 +244,7 @@ "filterAttribute": "user", "filterPrivate": "True", "edition_only": "True", + "allow_multiple_acl_values": true, "order": 1 } }, diff --git a/tests/units/classes/Project/ProjectTest.php b/tests/units/classes/Project/ProjectTest.php index 8bb169c8cc..5d550ed2ae 100644 --- a/tests/units/classes/Project/ProjectTest.php +++ b/tests/units/classes/Project/ProjectTest.php @@ -270,17 +270,17 @@ public static function getFiltersData() $aclData2 = array( 'userIsConnected' => false, ); - //$filter1 = '"Group" IN ( \'admin\' , \'groups\' , \'lizmap\' , \'all\' )'; - $filter1 = '"Group" = \'admin\' OR "Group" LIKE \'admin,%\' OR "Group" LIKE \'%,admin\' OR "Group" LIKE \'%,admin,%\''; + //$filter1 = '"descr" IN ( \'admin\' , \'groups\' , \'lizmap\' , \'all\' )'; + $filter1 = '"descr" = \'admin\' OR "descr" LIKE \'admin,%\' OR "descr" LIKE \'%,admin\' OR "descr" LIKE \'%,admin,%\''; $filter1 .= ' OR '; - $filter1 .= '"Group" = \'groups\' OR "Group" LIKE \'groups,%\' OR "Group" LIKE \'%,groups\' OR "Group" LIKE \'%,groups,%\''; + $filter1 .= '"descr" = \'groups\' OR "descr" LIKE \'groups,%\' OR "descr" LIKE \'%,groups\' OR "descr" LIKE \'%,groups,%\''; $filter1 .= ' OR '; - $filter1 .= '"Group" = \'lizmap\' OR "Group" LIKE \'lizmap,%\' OR "Group" LIKE \'%,lizmap\' OR "Group" LIKE \'%,lizmap,%\''; + $filter1 .= '"descr" = \'lizmap\' OR "descr" LIKE \'lizmap,%\' OR "descr" LIKE \'%,lizmap\' OR "descr" LIKE \'%,lizmap,%\''; $filter1 .= ' OR '; - $filter1 .= '"Group" = \'all\' OR "Group" LIKE \'all,%\' OR "Group" LIKE \'%,all\' OR "Group" LIKE \'%,all,%\''; + $filter1 .= '"descr" = \'all\' OR "descr" LIKE \'all,%\' OR "descr" LIKE \'%,all\' OR "descr" LIKE \'%,all,%\''; //$filter2 = '"Group" = \'all\''; - $filter2 = '"Group" = \'all\' OR "Group" LIKE \'all,%\' OR "Group" LIKE \'%,all\' OR "Group" LIKE \'%,all,%\''; + $filter2 = '"descr" = \'all\' OR "descr" LIKE \'all,%\' OR "descr" LIKE \'%,all\' OR "descr" LIKE \'%,all,%\''; return array( array($aclData1, $filter1), @@ -296,20 +296,93 @@ public static function getFiltersData() */ public function testGetLoginFilters($aclData, $expectedFilters) { - $file = __DIR__.'/Ressources/montpellier_filtered.qgs.cfg'; - $json = json_decode(file_get_contents($file)); + $data = array( + 'WMSInformation' => array(), + 'layers' => array(), + ); + $file = __DIR__.'/Ressources/edition_embed_parent.qgs'; + $context = new ContextForTests(); + $context->setResult($aclData); + $proj = new ProjectForTests($context); + $testQgis = new QgisProjectForTests($data); + $rep = new Project\Repository('key', array(), null, null, null); + $testQgis->setPath($file); + $testQgis->readXMLProjectTest($file); + + $cfg = json_decode(file_get_contents( __DIR__.'/Ressources/edition_embed_parent_filtered.qgs.cfg')); + $config = new Project\ProjectConfig($cfg); + $proj->setCfg($config); + $proj->setQgis($testQgis); + $proj->setRepo($rep); + $proj->setKey('test'); + + // Test $expectedFilters = array( - 'edition_line' => array_merge((array)$json->loginFilteredLayers->edition_line, - array('layername' => 'edition_line', + 'edition_layer_embed_point' => array_merge((array)$cfg->loginFilteredLayers->edition_layer_embed_point, + array('layername' => 'edition_layer_embed_point', 'filter' => $expectedFilters)), ); - $config = new Project\ProjectConfig($json); + $filters = $proj->getLoginFilters(array('edition_layer_embed_point')); + $this->assertEquals($expectedFilters, $filters); + + } + + public static function getFiltersDataNotMultiple() + { + $aclData1 = array( + 'userIsConnected' => true, + 'userSession' => (object) array('login' => 'admin'), + 'groups' => array('admin', 'groups', 'lizmap'), + ); + $aclData2 = array( + 'userIsConnected' => false, + ); + $filter1 = '"descr" = \'admin\' OR "descr" = \'groups\' OR "descr" = \'lizmap\' OR "descr" = \'all\''; + $filter2 = '"descr" = \'all\''; + + return array( + array($aclData1, $filter1), + array($aclData2, $filter2), + ); + } + + /** + * @dataProvider getFiltersDataNotMultiple + * + * @param mixed $aclData + * @param mixed $expectedFilters + */ + public function testGetLoginFiltersNotMultiple($aclData, $expectedFilters) + { + $data = array( + 'WMSInformation' => array(), + 'layers' => array(), + ); + $file = __DIR__.'/Ressources/edition_embed_parent.qgs'; $context = new ContextForTests(); $context->setResult($aclData); $proj = new ProjectForTests($context); + $testQgis = new QgisProjectForTests($data); + $rep = new Project\Repository('key', array(), null, null, null); + $testQgis->setPath($file); + $testQgis->readXMLProjectTest($file); + + $cfg = json_decode(file_get_contents( __DIR__.'/Ressources/edition_embed_parent_filtered.qgs.cfg')); + $config = new Project\ProjectConfig($cfg); $proj->setCfg($config); - $filters = $proj->getLoginFilters(array('edition_line')); + $proj->setQgis($testQgis); + $proj->setRepo($rep); + $proj->setKey('test'); + + // test + $expectedFilters = array( + 'edition_layer_embed_line' => array_merge((array)$cfg->loginFilteredLayers->edition_layer_embed_line, + array('layername' => 'edition_layer_embed_line', + 'filter' => $expectedFilters)), + ); + $filters = $proj->getLoginFilters(array('edition_layer_embed_line')); $this->assertEquals($expectedFilters, $filters); + } public static function getGoogleData() diff --git a/tests/units/classes/Project/Ressources/edition_embed_parent_filtered.qgs.cfg b/tests/units/classes/Project/Ressources/edition_embed_parent_filtered.qgs.cfg new file mode 100644 index 0000000000..0073af8415 --- /dev/null +++ b/tests/units/classes/Project/Ressources/edition_embed_parent_filtered.qgs.cfg @@ -0,0 +1,285 @@ +{ + "metadata": { + "qgis_desktop_version": 32815, + "lizmap_plugin_version_str": "4.1.8", + "lizmap_plugin_version": 40108, + "lizmap_web_client_target_version": 30800, + "lizmap_web_client_target_status": "Dev", + "instance_target_url": "http://localhost:8130/", + "instance_target_repository": "intranet" + }, + "warnings": {}, + "options": { + "projection": { + "proj4": "+proj=longlat +datum=WGS84 +no_defs", + "ref": "EPSG:4326" + }, + "bbox": [ + "3.72495035999999979", + "43.54176487699999853", + "4.03651796000000029", + "43.68444261700000197" + ], + "mapScales": [ + 10000, + 25000, + 50000, + 100000, + 250000, + 500000 + ], + "minScale": 1, + "maxScale": 1000000000, + "use_native_zoom_levels": false, + "hide_numeric_scale_value": false, + "initialExtent": [ + 3.72495036, + 43.541764877, + 4.03651796, + 43.684442617 + ], + "popupLocation": "dock", + "pointTolerance": 25, + "lineTolerance": 10, + "polygonTolerance": 5, + "tmTimeFrameSize": 10, + "tmTimeFrameType": "seconds", + "tmAnimationFrameLength": 1000, + "datavizLocation": "dock", + "theme": "dark", + "fixed_scale_overview_map": true, + "dataviz_drag_drop": [] + }, + "layers": { + "edition_layer_embed_point": { + "id": "edition_layer_embed_point_7794e305_0e9b_40d0_bf0b_2494790d4eb3", + "name": "edition_layer_embed_point", + "type": "layer", + "geometryType": "point", + "extent": [ + 3.859641575782584, + 43.61140074084927, + 3.887664580431485, + 43.63103265725464 + ], + "crs": "EPSG:4326", + "title": "Embedded Point", + "abstract": "", + "link": "", + "minScale": 1, + "maxScale": 1000000000000, + "toggled": "True", + "popup": "True", + "popupSource": "form", + "popupTemplate": "", + "popupMaxFeatures": 10, + "popupDisplayChildren": "False", + "popup_allow_download": true, + "legend_image_option": "hide_at_startup", + "groupAsLayer": "False", + "baseLayer": "False", + "displayInLegend": "True", + "group_visibility": [], + "singleTile": "True", + "imageFormat": "image/png", + "cached": "False", + "clientCacheExpiration": 300 + }, + "edition_layer_embed_line": { + "id": "edition_layer_embed_line_e74301b9_95ae_4b72_81cc_71fafb80082f", + "name": "edition_layer_embed_line", + "type": "layer", + "geometryType": "line", + "extent": [ + 3.827400054304815, + 43.58412355578639, + 3.916290230341653, + 43.62405315475053 + ], + "crs": "EPSG:4326", + "title": "Embedded Line", + "abstract": "", + "link": "", + "minScale": 1, + "maxScale": 1000000000000, + "toggled": "True", + "popup": "True", + "popupSource": "auto", + "popupTemplate": "", + "popupMaxFeatures": 10, + "popupDisplayChildren": "False", + "popup_allow_download": true, + "legend_image_option": "hide_at_startup", + "groupAsLayer": "False", + "baseLayer": "False", + "displayInLegend": "True", + "group_visibility": [], + "singleTile": "True", + "imageFormat": "image/png", + "cached": "False", + "clientCacheExpiration": 300 + }, + "edition_layer_embed_child": { + "id": "edition_layer_embed_child_d87f81cd_26d2_4c40_820d_676ba03ff6ab", + "name": "edition_layer_embed_child", + "type": "layer", + "geometryType": "none", + "extent": [ + 1.7976931348623157e+308, + 1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308 + ], + "crs": "", + "title": "Relation_table_id", + "abstract": "", + "link": "", + "minScale": 1, + "maxScale": 1000000000000, + "toggled": "False", + "popup": "False", + "popupSource": "auto", + "popupTemplate": "", + "popupMaxFeatures": 10, + "popupDisplayChildren": "False", + "popup_allow_download": true, + "legend_image_option": "hide_at_startup", + "groupAsLayer": "False", + "baseLayer": "False", + "displayInLegend": "True", + "group_visibility": [], + "singleTile": "True", + "imageFormat": "image/png", + "cached": "False", + "clientCacheExpiration": 300 + } + }, + "atlas": { + "layers": [] + }, + "locateByLayer": {}, + "attributeLayers": { + "edition_layer_embed_line": { + "layerId": "edition_layer_embed_line_e74301b9_95ae_4b72_81cc_71fafb80082f", + "primaryKey": "id", + "pivot": "False", + "hideAsChild": "False", + "hideLayer": "False", + "custom_config": "False", + "order": 0 + }, + "edition_layer_embed_child": { + "layerId": "edition_layer_embed_child_d87f81cd_26d2_4c40_820d_676ba03ff6ab", + "primaryKey": "id", + "pivot": "False", + "hideAsChild": "False", + "hideLayer": "False", + "custom_config": "False", + "order": 1 + }, + "edition_layer_embed_point": { + "layerId": "edition_layer_embed_point_7794e305_0e9b_40d0_bf0b_2494790d4eb3", + "primaryKey": "id", + "pivot": "False", + "hideAsChild": "False", + "hideLayer": "False", + "custom_config": "False", + "order": 2 + } + }, + "tooltipLayers": {}, + "editionLayers": { + "edition_layer_embed_line": { + "layerId": "edition_layer_embed_line_e74301b9_95ae_4b72_81cc_71fafb80082f", + "snap_vertices": "False", + "snap_segments": "False", + "snap_intersections": "False", + "snap_vertices_tolerance": 10, + "snap_segments_tolerance": 10, + "snap_intersections_tolerance": 10, + "provider": "postgres", + "capabilities": { + "createFeature": "True", + "allow_without_geom": "False", + "modifyAttribute": "True", + "modifyGeometry": "True", + "deleteFeature": "True" + }, + "geometryType": "line", + "order": 0 + }, + "edition_layer_embed_point": { + "layerId": "edition_layer_embed_point_7794e305_0e9b_40d0_bf0b_2494790d4eb3", + "snap_vertices": "False", + "snap_segments": "False", + "snap_intersections": "False", + "snap_vertices_tolerance": 10, + "snap_segments_tolerance": 10, + "snap_intersections_tolerance": 10, + "provider": "postgres", + "capabilities": { + "createFeature": "True", + "allow_without_geom": "False", + "modifyAttribute": "True", + "modifyGeometry": "True", + "deleteFeature": "True" + }, + "geometryType": "point", + "order": 1 + }, + "edition_layer_embed_child": { + "layerId": "edition_layer_embed_child_d87f81cd_26d2_4c40_820d_676ba03ff6ab", + "snap_layers": [], + "snap_vertices": "False", + "snap_segments": "False", + "snap_intersections": "False", + "snap_vertices_tolerance": 10, + "snap_segments_tolerance": 10, + "snap_intersections_tolerance": 10, + "provider": "postgres", + "capabilities": { + "createFeature": "True", + "allow_without_geom": "False", + "modifyAttribute": "True", + "modifyGeometry": "False", + "deleteFeature": "True" + }, + "geometryType": "none", + "order": 2 + } + }, + "layouts": { + "config": { + "default_popup_print": false + }, + "list": [] + }, + "loginFilteredLayers": {}, + "timemanagerLayers": {}, + "loginFilteredLayers": { + "edition_layer_embed_point": { + "layerId": "edition_layer_embed_point_7794e305_0e9b_40d0_bf0b_2494790d4eb3", + "filterAttribute": "descr", + "filterPrivate": "False", + "allow_multiple_acl_values": true, + "order": 0 + }, + "edition_layer_embed_line": { + "layerId": "edition_layer_embed_line_e74301b9_95ae_4b72_81cc_71fafb80082f", + "filterAttribute": "descr", + "filterPrivate": "False", + "allow_multiple_acl_values": false, + "order": 0 + } + }, + "datavizLayers": {}, + "filter_by_polygon": { + "config": { + "polygon_layer_id": null, + "group_field": "", + "filter_by_user": false + }, + "layers": [] + }, + "formFilterLayers": {} +}