Skip to content

Commit a61d561

Browse files
authored
Merge pull request #51782 from nextcloud/backport/51336/stable30
[stable30] fix(settings): Fix infinitely loading account management page with pagination of groups
2 parents b05a608 + fcd5da1 commit a61d561

27 files changed

Lines changed: 1034 additions & 271 deletions

apps/provisioning_api/appinfo/routes.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@
4242
['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
4343
['root' => '/cloud', 'name' => 'Users#disableUser', 'url' => '/users/{userId}/disable', 'verb' => 'PUT'],
4444
['root' => '/cloud', 'name' => 'Users#getUsersGroups', 'url' => '/users/{userId}/groups', 'verb' => 'GET'],
45+
['root' => '/cloud', 'name' => 'Users#getUsersGroupsDetails', 'url' => '/users/{userId}/groups/details', 'verb' => 'GET'],
4546
['root' => '/cloud', 'name' => 'Users#addToGroup', 'url' => '/users/{userId}/groups', 'verb' => 'POST'],
4647
['root' => '/cloud', 'name' => 'Users#removeFromGroup', 'url' => '/users/{userId}/groups', 'verb' => 'DELETE'],
4748
['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroups', 'url' => '/users/{userId}/subadmins', 'verb' => 'GET'],
49+
['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroupsDetails', 'url' => '/users/{userId}/subadmins/details', 'verb' => 'GET'],
4850
['root' => '/cloud', 'name' => 'Users#addSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'POST'],
4951
['root' => '/cloud', 'name' => 'Users#removeSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'DELETE'],
5052
['root' => '/cloud', 'name' => 'Users#resendWelcomeMessage', 'url' => '/users/{userId}/welcome', 'verb' => 'POST'],

apps/provisioning_api/lib/Controller/UsersController.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use InvalidArgumentException;
1414
use OC\Authentication\Token\RemoteWipe;
15+
use OC\Group\Group;
1516
use OC\KnownUser\KnownUserService;
1617
use OC\User\Backend;
1718
use OCA\Provisioning_API\ResponseDefinitions;
@@ -50,6 +51,7 @@
5051
use Psr\Log\LoggerInterface;
5152

5253
/**
54+
* @psalm-import-type Provisioning_APIGroupDetails from ResponseDefinitions
5355
* @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
5456
*/
5557
class UsersController extends AUserData {
@@ -1398,6 +1400,127 @@ public function getUsersGroups(string $userId): DataResponse {
13981400
}
13991401
}
14001402

1403+
/**
1404+
* @NoSubAdminRequired
1405+
*
1406+
* Get a list of groups with details
1407+
*
1408+
* @param string $userId ID of the user
1409+
* @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1410+
* @throws OCSException
1411+
*
1412+
* 200: Users groups returned
1413+
*/
1414+
#[NoAdminRequired]
1415+
public function getUsersGroupsDetails(string $userId): DataResponse {
1416+
$loggedInUser = $this->userSession->getUser();
1417+
1418+
$targetUser = $this->userManager->get($userId);
1419+
if ($targetUser === null) {
1420+
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1421+
}
1422+
1423+
$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1424+
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1425+
if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1426+
// Self lookup or admin lookup
1427+
$groups = array_map(
1428+
function (Group $group) {
1429+
return [
1430+
'id' => $group->getGID(),
1431+
'displayname' => $group->getDisplayName(),
1432+
'usercount' => $group->count(),
1433+
'disabled' => $group->countDisabled(),
1434+
'canAdd' => $group->canAddUser(),
1435+
'canRemove' => $group->canRemoveUser(),
1436+
];
1437+
},
1438+
array_values($this->groupManager->getUserGroups($targetUser)),
1439+
);
1440+
return new DataResponse([
1441+
'groups' => $groups,
1442+
]);
1443+
} else {
1444+
$subAdminManager = $this->groupManager->getSubAdmin();
1445+
1446+
// Looking up someone else
1447+
if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1448+
// Return the group that the method caller is subadmin of for the user in question
1449+
$gids = array_values(array_intersect(
1450+
array_map(
1451+
static fn (IGroup $group) => $group->getGID(),
1452+
$subAdminManager->getSubAdminsGroups($loggedInUser),
1453+
),
1454+
$this->groupManager->getUserGroupIds($targetUser)
1455+
));
1456+
$groups = array_map(
1457+
function (string $gid) {
1458+
$group = $this->groupManager->get($gid);
1459+
return [
1460+
'id' => $group->getGID(),
1461+
'displayname' => $group->getDisplayName(),
1462+
'usercount' => $group->count(),
1463+
'disabled' => $group->countDisabled(),
1464+
'canAdd' => $group->canAddUser(),
1465+
'canRemove' => $group->canRemoveUser(),
1466+
];
1467+
},
1468+
$gids,
1469+
);
1470+
return new DataResponse([
1471+
'groups' => $groups,
1472+
]);
1473+
} else {
1474+
// Not permitted
1475+
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1476+
}
1477+
}
1478+
}
1479+
1480+
/**
1481+
* @NoSubAdminRequired
1482+
*
1483+
* Get a list of the groups the user is a subadmin of, with details
1484+
*
1485+
* @param string $userId ID of the user
1486+
* @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1487+
* @throws OCSException
1488+
*
1489+
* 200: Users subadmin groups returned
1490+
*/
1491+
#[NoAdminRequired]
1492+
public function getUserSubAdminGroupsDetails(string $userId): DataResponse {
1493+
$loggedInUser = $this->userSession->getUser();
1494+
1495+
$targetUser = $this->userManager->get($userId);
1496+
if ($targetUser === null) {
1497+
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1498+
}
1499+
1500+
$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1501+
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1502+
if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1503+
$subAdminManager = $this->groupManager->getSubAdmin();
1504+
$groups = array_map(
1505+
function (IGroup $group) {
1506+
return [
1507+
'id' => $group->getGID(),
1508+
'displayname' => $group->getDisplayName(),
1509+
'usercount' => $group->count(),
1510+
'disabled' => $group->countDisabled(),
1511+
'canAdd' => $group->canAddUser(),
1512+
'canRemove' => $group->canRemoveUser(),
1513+
];
1514+
},
1515+
array_values($subAdminManager->getSubAdminsGroups($targetUser)),
1516+
);
1517+
return new DataResponse([
1518+
'groups' => $groups,
1519+
]);
1520+
}
1521+
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1522+
}
1523+
14011524
/**
14021525
* Add a user to a group
14031526
*

apps/provisioning_api/openapi-full.json

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,6 +3593,168 @@
35933593
}
35943594
}
35953595
},
3596+
"/ocs/v2.php/cloud/users/{userId}/groups/details": {
3597+
"get": {
3598+
"operationId": "users-get-users-groups-details",
3599+
"summary": "Get a list of groups with details",
3600+
"tags": [
3601+
"users"
3602+
],
3603+
"security": [
3604+
{
3605+
"bearer_auth": []
3606+
},
3607+
{
3608+
"basic_auth": []
3609+
}
3610+
],
3611+
"parameters": [
3612+
{
3613+
"name": "userId",
3614+
"in": "path",
3615+
"description": "ID of the user",
3616+
"required": true,
3617+
"schema": {
3618+
"type": "string"
3619+
}
3620+
},
3621+
{
3622+
"name": "OCS-APIRequest",
3623+
"in": "header",
3624+
"description": "Required to be true for the API request to pass",
3625+
"required": true,
3626+
"schema": {
3627+
"type": "boolean",
3628+
"default": true
3629+
}
3630+
}
3631+
],
3632+
"responses": {
3633+
"200": {
3634+
"description": "Users groups returned",
3635+
"content": {
3636+
"application/json": {
3637+
"schema": {
3638+
"type": "object",
3639+
"required": [
3640+
"ocs"
3641+
],
3642+
"properties": {
3643+
"ocs": {
3644+
"type": "object",
3645+
"required": [
3646+
"meta",
3647+
"data"
3648+
],
3649+
"properties": {
3650+
"meta": {
3651+
"$ref": "#/components/schemas/OCSMeta"
3652+
},
3653+
"data": {
3654+
"type": "object",
3655+
"required": [
3656+
"groups"
3657+
],
3658+
"properties": {
3659+
"groups": {
3660+
"type": "array",
3661+
"items": {
3662+
"$ref": "#/components/schemas/GroupDetails"
3663+
}
3664+
}
3665+
}
3666+
}
3667+
}
3668+
}
3669+
}
3670+
}
3671+
}
3672+
}
3673+
}
3674+
}
3675+
}
3676+
},
3677+
"/ocs/v2.php/cloud/users/{userId}/subadmins/details": {
3678+
"get": {
3679+
"operationId": "users-get-user-sub-admin-groups-details",
3680+
"summary": "Get a list of the groups the user is a subadmin of, with details",
3681+
"tags": [
3682+
"users"
3683+
],
3684+
"security": [
3685+
{
3686+
"bearer_auth": []
3687+
},
3688+
{
3689+
"basic_auth": []
3690+
}
3691+
],
3692+
"parameters": [
3693+
{
3694+
"name": "userId",
3695+
"in": "path",
3696+
"description": "ID of the user",
3697+
"required": true,
3698+
"schema": {
3699+
"type": "string"
3700+
}
3701+
},
3702+
{
3703+
"name": "OCS-APIRequest",
3704+
"in": "header",
3705+
"description": "Required to be true for the API request to pass",
3706+
"required": true,
3707+
"schema": {
3708+
"type": "boolean",
3709+
"default": true
3710+
}
3711+
}
3712+
],
3713+
"responses": {
3714+
"200": {
3715+
"description": "Users subadmin groups returned",
3716+
"content": {
3717+
"application/json": {
3718+
"schema": {
3719+
"type": "object",
3720+
"required": [
3721+
"ocs"
3722+
],
3723+
"properties": {
3724+
"ocs": {
3725+
"type": "object",
3726+
"required": [
3727+
"meta",
3728+
"data"
3729+
],
3730+
"properties": {
3731+
"meta": {
3732+
"$ref": "#/components/schemas/OCSMeta"
3733+
},
3734+
"data": {
3735+
"type": "object",
3736+
"required": [
3737+
"groups"
3738+
],
3739+
"properties": {
3740+
"groups": {
3741+
"type": "array",
3742+
"items": {
3743+
"$ref": "#/components/schemas/GroupDetails"
3744+
}
3745+
}
3746+
}
3747+
}
3748+
}
3749+
}
3750+
}
3751+
}
3752+
}
3753+
}
3754+
}
3755+
}
3756+
}
3757+
},
35963758
"/ocs/v2.php/cloud/users/{userId}/welcome": {
35973759
"post": {
35983760
"operationId": "users-resend-welcome-message",

0 commit comments

Comments
 (0)