Skip to content

Commit

Permalink
Filter by user - Attribute filter: allow having multiple users or gro…
Browse files Browse the repository at this point in the history
…ups separated by comma
  • Loading branch information
nboisteault authored and mdouchin committed Aug 22, 2024
1 parent f7c0c7d commit 4fc54e4
Show file tree
Hide file tree
Showing 13 changed files with 831 additions and 458 deletions.
39 changes: 14 additions & 25 deletions lizmap/modules/lizmap/lib/Form/QgisForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
Expand Down
61 changes: 56 additions & 5 deletions lizmap/modules/lizmap/lib/Project/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions lizmap/modules/lizmap/lib/Request/WFSRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 '';
Expand Down
10 changes: 10 additions & 0 deletions tests/end2end/cypress/integration/requests-metadata-ghaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe('Request JSON metadata', function () {
"__anonymous",
"admins",
"group_a",
"group_b",
"publishers"
].sort()
);
Expand All @@ -49,6 +50,7 @@ describe('Request JSON metadata', function () {
"__anonymous",
"admins",
"group_a",
"group_b",
"publishers"
].sort()
);
Expand All @@ -72,6 +74,9 @@ describe('Request JSON metadata', function () {
"group_a": {
"label": "group_a"
},
"group_b": {
"label": "group_b"
},
"intranet": {
"label": "Intranet demos group"
},
Expand Down Expand Up @@ -145,6 +150,7 @@ describe('Request JSON metadata', function () {
"__anonymous",
"admins",
"group_a",
"group_b",
"publishers"
].sort()
);
Expand All @@ -153,6 +159,7 @@ describe('Request JSON metadata', function () {
"__anonymous",
"admins",
"group_a",
"group_b",
"publishers"
].sort()
);
Expand All @@ -167,6 +174,9 @@ describe('Request JSON metadata', function () {
"group_a": {
"label": "group_a"
},
"group_b": {
"label": "group_b"
},
"intranet": {
"label": "Intranet demos group"
},
Expand Down
Loading

0 comments on commit 4fc54e4

Please sign in to comment.