Skip to content

Commit b916a6a

Browse files
fix(provisioning_api): filter users by enabled state on the server
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
1 parent 2511528 commit b916a6a

14 files changed

Lines changed: 704 additions & 30 deletions

File tree

‎apps/provisioning_api/lib/Controller/AUserDataOCSController.php‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,35 @@ protected function getUserSubAdminGroupsData(string $userId): array {
252252
return $groups;
253253
}
254254

255+
/**
256+
* Collect up to $limit users matching the filters from a paginated source, skipping missing ones.
257+
*
258+
* @param \Closure(?int, int): iterable<?IUser> $search Returns the source page for a limit and offset
259+
* @param bool $enabled Only collect users with this enabled state
260+
* @return array{list<IUser>, int, bool} The matching users, the source offset of the next page,
261+
* and whether the source may have more users
262+
*/
263+
protected function searchFilteredUsers(\Closure $search, ?int $limit, int $offset, bool $enabled): array {
264+
$users = [];
265+
while (true) {
266+
$count = 0;
267+
foreach ($search($limit, $offset) as $user) {
268+
$count++;
269+
$offset++;
270+
if ($user === null || $user->isEnabled() !== $enabled) {
271+
continue;
272+
}
273+
$users[] = $user;
274+
if ($limit !== null && $limit > 0 && count($users) >= $limit) {
275+
return [$users, $offset, true];
276+
}
277+
}
278+
if ($limit === null || $limit <= 0 || $count < $limit) {
279+
return [$users, $offset, false];
280+
}
281+
}
282+
}
283+
255284
/**
256285
* A full group has id, name, usercount, disabled, canAdd and canRemove. Only
257286
* the displayname is cached; usercount/disabled are not cached. So this only

‎apps/provisioning_api/lib/Controller/GroupsController.php‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,15 @@ public function getGroupUsers(string $groupId): DataResponse {
200200
* @param string $search Text to search for
201201
* @param int|null $limit Limit the amount of groups returned
202202
* @param int $offset Offset for searching for groups
203+
* @param bool|null $enabled Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset
203204
*
204205
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>, groups: list<Provisioning_APIUserDetailsGroupDisplayname>}, array{Link?: string}>
205206
* @throws OCSException
206207
*
207208
* 200: Group users details returned
208209
*/
209210
#[NoAdminRequired]
210-
public function getGroupUsersDetails(string $groupId, string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
211+
public function getGroupUsersDetails(string $groupId, string $search = '', ?int $limit = null, int $offset = 0, ?bool $enabled = null): DataResponse {
211212
$groupId = urldecode($groupId);
212213
$currentUser = $this->userSession->getUser();
213214

@@ -223,7 +224,18 @@ public function getGroupUsersDetails(string $groupId, string $search = '', ?int
223224
$isAdmin = $this->groupManager->isAdmin($currentUser->getUID());
224225
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentUser->getUID());
225226
if ($isAdmin || $isDelegatedAdmin || $isSubadminOfGroup) {
226-
$users = $group->searchUsers($search, $limit, $offset);
227+
$hasMore = null;
228+
$nextOffset = null;
229+
if ($enabled !== null) {
230+
[$users, $nextOffset, $hasMore] = $this->searchFilteredUsers(
231+
fn (?int $limit, int $offset): array => $group->searchUsers($search, $limit, $offset),
232+
$limit,
233+
$offset,
234+
enabled: $enabled,
235+
);
236+
} else {
237+
$users = $group->searchUsers($search, $limit, $offset);
238+
}
227239

228240
// Extract required number
229241
$usersDetails = [];
@@ -244,9 +256,11 @@ public function getGroupUsersDetails(string $groupId, string $search = '', ?int
244256
// continue if a users ceased to exist.
245257
}
246258
}
247-
$headers = $this->buildOffsetNextPageLinkHeader($users, [
259+
$params = [
248260
'search' => $search,
249-
], $limit, $offset);
261+
'enabled' => $enabled
262+
];
263+
$headers = $this->buildOffsetNextPageLinkHeader($hasMore ?? $users, $params, $limit, $offset, $nextOffset);
250264
return new DataResponse([
251265
'users' => $usersDetails,
252266
'groups' => $this->findGroupsWithDisplayname($usersDetails),

‎apps/provisioning_api/lib/Controller/UsersController.php‎

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -158,34 +158,65 @@ public function getUsers(string $search = '', ?int $limit = null, int $offset =
158158
* @param string $search Text to search for
159159
* @param int|null $limit Limit the amount of groups returned
160160
* @param int $offset Offset for searching for groups
161+
* @param bool|null $enabled Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset
161162
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>, groups: list<Provisioning_APIUserDetailsGroupDisplayname>}, array{Link?: string}>
162163
*
163164
* 200: Users details returned
164165
*/
165166
#[NoAdminRequired]
166-
public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
167+
public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0, ?bool $enabled = null): DataResponse {
167168
$currentUser = $this->userSession->getUser();
168169
$users = [];
170+
$hasMore = null;
171+
$nextOffset = null;
169172

170173
// Admin? Or SubAdmin?
171174
$uid = $currentUser->getUID();
172175
$subAdminManager = $this->groupManager->getSubAdmin();
173176
$isAdmin = $this->groupManager->isAdmin($uid);
174177
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
175178
if ($isAdmin || $isDelegatedAdmin) {
176-
$users = $this->userManager->search($search, $limit, $offset);
177-
$users = array_keys($users);
178-
} elseif ($subAdminManager->isSubAdmin($currentUser)) {
179-
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
180-
foreach ($subAdminOfGroups as $key => $group) {
181-
$subAdminOfGroups[$key] = $group->getGID();
179+
$searchUsers = fn (?int $limit, int $offset): array => $this->userManager->search($search, $limit, $offset);
180+
if ($enabled !== null) {
181+
[$users, $nextOffset, $hasMore] = $this->searchFilteredUsers(
182+
$searchUsers,
183+
$limit,
184+
$offset,
185+
enabled: $enabled,
186+
);
187+
$users = array_map(fn (IUser $user): string => $user->getUID(), $users);
188+
} else {
189+
$users = $searchUsers($limit, $offset);
190+
$users = array_keys($users);
182191
}
192+
} elseif ($subAdminManager->isSubAdmin($currentUser)) {
193+
if ($enabled !== null) {
194+
$users = [];
195+
/* The groups are searched together, so offset and limit are applied to the combined list */
196+
$tempLimit = ($limit === null ? null : $limit + $offset);
197+
foreach ($subAdminManager->getSubAdminsGroups($currentUser) as $group) {
198+
foreach ($group->searchUsers($search) as $user) {
199+
if ($user->isEnabled() === $enabled) {
200+
$users[$user->getUID()] = $user->getUID();
201+
}
202+
}
203+
if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
204+
break;
205+
}
206+
}
207+
$users = array_slice(array_values($users), $offset, $limit);
208+
} else {
209+
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
210+
foreach ($subAdminOfGroups as $key => $group) {
211+
$subAdminOfGroups[$key] = $group->getGID();
212+
}
183213

184-
$users = [];
185-
foreach ($subAdminOfGroups as $group) {
186-
$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
214+
$users = [];
215+
foreach ($subAdminOfGroups as $group) {
216+
$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
217+
}
218+
$users = array_merge(...$users);
187219
}
188-
$users = array_merge(...$users);
189220
}
190221

191222
$usersDetails = [];
@@ -209,9 +240,11 @@ public function getUsersDetails(string $search = '', ?int $limit = null, int $of
209240
}
210241
}
211242

212-
$headers = $this->buildOffsetNextPageLinkHeader($users, [
243+
$params = [
213244
'search' => $search,
214-
], $limit, $offset);
245+
'enabled' => $enabled
246+
];
247+
$headers = $this->buildOffsetNextPageLinkHeader($hasMore ?? $users, $params, $limit, $offset, $nextOffset);
215248
return new DataResponse([
216249
'users' => $usersDetails,
217250
'groups' => $this->findGroupsWithDisplayname($usersDetails),
@@ -309,6 +342,7 @@ public function getDisabledUsersDetails(string $search = '', ?int $limit = null,
309342
* @param string $search Text to search for
310343
* @param ?int $limit Limit the amount of users returned
311344
* @param int $offset Offset
345+
* @param bool|null $enabled Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset
312346
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{Link?: string}>
313347
*
314348
* 200: Users details returned based on last logged in information
@@ -318,6 +352,7 @@ public function getLastLoggedInUsers(
318352
string $search = '',
319353
?int $limit = null,
320354
int $offset = 0,
355+
?bool $enabled = null,
321356
): DataResponse {
322357
$currentUser = $this->userSession->getUser();
323358
if ($currentUser === null) {
@@ -331,9 +366,24 @@ public function getLastLoggedInUsers(
331366
}
332367

333368
$users = [];
369+
$hasMore = null;
370+
$nextOffset = null;
334371

335372
// For Admin alone user sorting based on lastLogin. For sub admin and groups this is not supported
336-
$users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
373+
if ($enabled !== null) {
374+
[$users, $nextOffset, $hasMore] = $this->searchFilteredUsers(
375+
fn (?int $limit, int $offset): array => array_map(
376+
fn (string $userId): ?IUser => $this->userManager->get($userId),
377+
$this->userManager->getLastLoggedInUsers($limit, $offset, $search),
378+
),
379+
$limit,
380+
$offset,
381+
enabled: $enabled,
382+
);
383+
$users = array_map(fn (IUser $user): string => $user->getUID(), $users);
384+
} else {
385+
$users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
386+
}
337387

338388
$usersDetails = [];
339389
foreach ($users as $userId) {
@@ -355,9 +405,11 @@ public function getLastLoggedInUsers(
355405
}
356406
}
357407

358-
$headers = $this->buildOffsetNextPageLinkHeader($users, [
408+
$params = [
359409
'search' => $search,
360-
], $limit, $offset);
410+
'enabled' => $enabled
411+
];
412+
$headers = $this->buildOffsetNextPageLinkHeader($hasMore ?? $users, $params, $limit, $offset, $nextOffset);
361413
return new DataResponse([
362414
'users' => $usersDetails
363415
], headers: $headers);

‎apps/provisioning_api/openapi-administration.json‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,16 @@
14781478
"default": 0
14791479
}
14801480
},
1481+
{
1482+
"name": "enabled",
1483+
"in": "query",
1484+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
1485+
"schema": {
1486+
"type": "boolean",
1487+
"nullable": true,
1488+
"default": null
1489+
}
1490+
},
14811491
{
14821492
"name": "OCS-APIRequest",
14831493
"in": "header",

‎apps/provisioning_api/openapi-full.json‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,16 @@
17841784
"default": 0
17851785
}
17861786
},
1787+
{
1788+
"name": "enabled",
1789+
"in": "query",
1790+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
1791+
"schema": {
1792+
"type": "boolean",
1793+
"nullable": true,
1794+
"default": null
1795+
}
1796+
},
17871797
{
17881798
"name": "OCS-APIRequest",
17891799
"in": "header",
@@ -3531,6 +3541,16 @@
35313541
"default": 0
35323542
}
35333543
},
3544+
{
3545+
"name": "enabled",
3546+
"in": "query",
3547+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
3548+
"schema": {
3549+
"type": "boolean",
3550+
"nullable": true,
3551+
"default": null
3552+
}
3553+
},
35343554
{
35353555
"name": "OCS-APIRequest",
35363556
"in": "header",
@@ -4017,6 +4037,16 @@
40174037
"default": 0
40184038
}
40194039
},
4040+
{
4041+
"name": "enabled",
4042+
"in": "query",
4043+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
4044+
"schema": {
4045+
"type": "boolean",
4046+
"nullable": true,
4047+
"default": null
4048+
}
4049+
},
40204050
{
40214051
"name": "OCS-APIRequest",
40224052
"in": "header",

‎apps/provisioning_api/openapi.json‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,16 @@
924924
"default": 0
925925
}
926926
},
927+
{
928+
"name": "enabled",
929+
"in": "query",
930+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
931+
"schema": {
932+
"type": "boolean",
933+
"nullable": true,
934+
"default": null
935+
}
936+
},
927937
{
928938
"name": "OCS-APIRequest",
929939
"in": "header",
@@ -1521,6 +1531,16 @@
15211531
"default": 0
15221532
}
15231533
},
1534+
{
1535+
"name": "enabled",
1536+
"in": "query",
1537+
"description": "Only return users with this enabled state, or all users if null. Use the `Link` header for the next page offset",
1538+
"schema": {
1539+
"type": "boolean",
1540+
"nullable": true,
1541+
"default": null
1542+
}
1543+
},
15241544
{
15251545
"name": "OCS-APIRequest",
15261546
"in": "header",

0 commit comments

Comments
 (0)