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
mdouchin committed Aug 21, 2024
1 parent 6c0c124 commit 01a8330
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 36 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
62 changes: 57 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,65 @@ public function getLoginFilters($layers, $edition = false)
// attribute to filter
$attribute = $loginFilteredConfig->filterAttribute;

// Quoted attribute with double-quotes
// $cnx = $this->appContext->getDbConnection();
$cnx = \jDb::getConnection();
$quotedField = $cnx->encloseName($attribute);

// default no user connected
$filter = "\"{$attribute}\" = 'all'";
$filter = "{$quotedField} = '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
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 Down
13 changes: 11 additions & 2 deletions tests/units/classes/Project/ProjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions tests/units/classes/Request/WFSRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
}
Expand Down

0 comments on commit 01a8330

Please sign in to comment.