diff --git a/src/lib/Server/Controller/User/UserBaseController.php b/src/lib/Server/Controller/User/UserBaseController.php index 22f813c8..e8d6a373 100644 --- a/src/lib/Server/Controller/User/UserBaseController.php +++ b/src/lib/Server/Controller/User/UserBaseController.php @@ -82,9 +82,8 @@ public function loadUsers(Request $request): Values\UserList|Values\UserRefList try { if ($request->query->has('roleId')) { - $restUsers = $this->loadUsersAssignedToRole( - (int) $this->uriParser->getAttributeFromUri($request->query->getString('roleId'), 'roleId') - ); + $roleId = is_numeric($request->query->get('roleId')) ? $request->query->getInt('roleId') : (int)$this->uriParser->getAttributeFromUri($request->query->getString('roleId'), 'roleId'); + $restUsers = $this->loadUsersAssignedToRole($roleId); } elseif ($request->query->has('remoteId')) { $restUsers = [ $this->buildRestUserObject( diff --git a/src/lib/Server/Controller/User/UserGroupListController.php b/src/lib/Server/Controller/User/UserGroupListController.php index 90086c5c..7c72e81b 100644 --- a/src/lib/Server/Controller/User/UserGroupListController.php +++ b/src/lib/Server/Controller/User/UserGroupListController.php @@ -25,10 +25,52 @@ openapi: new Model\Operation( operationId: 'ibexa.rest.load_user_groups', summary: 'Load User Groups', - description: 'Loads User Groups for either an an ID or a remote ID or a Role.', + description: 'Loads User Groups for either an ID, a remote ID, or a Role ID. Filters can\'t be combined.', tags: [ 'User Group', ], + parameters: [ + new Model\Parameter( + name: 'id', + in: 'query', + description: 'Content ID of the User Group to load.', + required: false, + schema: [ + 'type' => 'integer', + 'description' => 'Numeral ID of the User Group', + 'example' => '12', + ], + ), + new Model\Parameter( + name: 'roleId', + in: 'query', + description: 'Role ID or Role Href of the User Groups to load.', + required: false, + schema: [ + 'type' => ['integer', 'string'], + 'description' => 'Role ID or Role Href', + ], + examples: new \ArrayObject([ + 'id' => [ + 'value' => 2, + 'summary' => 'Role ID', + ], + 'href' => [ + 'value' => '/api/ibexa/v2/user/roles/2', + 'summary' => 'Role Href', + ], + ]), + ), + new Model\Parameter( + name: 'remoteId', + in: 'query', + description: 'Remote ID of the User Group to load.', + required: false, + schema: [ + 'type' => 'string', + ], + ), + ], responses: [ Response::HTTP_OK => [ 'description' => 'UserGroupList - If set, the User Group List is returned in XML or JSON format. UserGroupRefList - If set, the link list of User Group is returned in XML or JSON format.', @@ -62,6 +104,9 @@ Response::HTTP_UNAUTHORIZED => [ 'description' => 'Error - the user has no permission to read User Groups.', ], + Response::HTTP_NOT_FOUND => [ + 'description' => 'Error - the id or remoteId doesn\'t match an existing User Group, or the roleId doesn\'t match an existing Role.', + ], ], ), )] @@ -73,7 +118,8 @@ final class UserGroupListController extends UserBaseController public function loadUserGroups(Request $request): RestValue { $restUserGroups = []; - if ($request->query->has('id') && is_int($id = $request->query->get('id'))) { + if ($request->query->has('id') && is_numeric($request->query->get('id'))) { + $id = $request->query->getInt('id'); $userGroup = $this->userService->loadUserGroup($id, Language::ALL); $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo(); @@ -94,7 +140,8 @@ public function loadUserGroups(Request $request): RestValue ), ]; } elseif ($request->query->has('roleId')) { - $restUserGroups = $this->loadUserGroupsAssignedToRole((int) $request->query->get('roleId')); + $roleId = is_numeric($request->query->get('roleId')) ? $request->query->getInt('roleId') : (int)$this->uriParser->getAttributeFromUri($request->query->getString('roleId'), 'roleId'); + $restUserGroups = $this->loadUserGroupsAssignedToRole($roleId); } elseif ($request->query->has('remoteId')) { $restUserGroups = [ $this->loadUserGroupByRemoteId($request), diff --git a/src/lib/Server/Controller/User/UserGroupLoadByPathController.php b/src/lib/Server/Controller/User/UserGroupLoadByPathController.php index 6cb7a50d..4b37074a 100644 --- a/src/lib/Server/Controller/User/UserGroupLoadByPathController.php +++ b/src/lib/Server/Controller/User/UserGroupLoadByPathController.php @@ -41,6 +41,8 @@ required: true, schema: [ 'type' => 'string', + 'description' => 'The Location path to the user\'s group.', + 'example' => '1/5/13', ], ), ], diff --git a/src/lib/Server/Controller/User/UserListController.php b/src/lib/Server/Controller/User/UserListController.php index 2e1ec4c4..7173dd64 100644 --- a/src/lib/Server/Controller/User/UserListController.php +++ b/src/lib/Server/Controller/User/UserListController.php @@ -17,10 +17,61 @@ openapi: new Model\Operation( operationId: 'ibexa.rest.load_users', summary: 'List Users', - description: 'Load Users either for a given remote ID or Role.', + description: 'Load Users either for a given role ID, remote ID, login, or email. To use one of the available filter is mandatory. Filters can\'t be combined.', tags: [ 'User', ], + parameters: [ + new Model\Parameter( + name: 'roleId', + in: 'query', + description: 'Role directly assigned to the Users to load. (If the role is assigned to a user group, its users won\'t be returned. See GET /user/groups roleId filter.)', + required: false, + schema: [ + 'type' => ['integer', 'string'], + 'description' => 'Role ID or Role Href', + ], + examples: new \ArrayObject([ + 'id' => [ + 'value' => 2, + 'summary' => 'Role ID', + ], + 'href' => [ + 'value' => '/api/ibexa/v2/user/roles/2', + 'summary' => 'Role Href', + ], + ]), + ), + new Model\Parameter( + name: 'remoteId', + in: 'query', + description: 'Remote ID of the User to load.', + required: false, + schema: [ + 'type' => 'string', + ], + ), + new Model\Parameter( + name: 'login', + in: 'query', + description: 'Username of the User to load.', + required: false, + schema: [ + 'type' => 'string', + 'example' => 'admin', + ], + ), + new Model\Parameter( + name: 'email', + in: 'query', + description: 'Email address of the User to load.', + required: false, + schema: [ + 'type' => 'string', + 'example' => 'admin@link.invalid', + ], + ), + ], responses: [ Response::HTTP_OK => [ 'description' => 'OK - Loads Users either for a given remote ID or Role.', @@ -51,7 +102,10 @@ ], ], Response::HTTP_NOT_FOUND => [ - 'description' => 'If there are no visible Users matching the filter.', + 'description' => 'If there are no visible Users matching the filter or the filter is missing.', + ], + Response::HTTP_NOT_ACCEPTABLE => [ + 'description' => 'The filter value is not acceptable.', ], ], ), diff --git a/tests/bundle/Functional/UserTest.php b/tests/bundle/Functional/UserTest.php index 7a1ff5a1..9e03be86 100644 --- a/tests/bundle/Functional/UserTest.php +++ b/tests/bundle/Functional/UserTest.php @@ -305,6 +305,33 @@ public function testLoadUserByRemoteId(): void self::assertHttpResponseCodeEquals($response, 200); } + /** + * @dataProvider provideDataForTestLoadUsersByRoleId + * + * Covers GET /user/users?roleId={roleId} + */ + public function testLoadUsersByRoleId(int|string $roleId, int $expectedCode, ?string $expectedContent): void + { + $response = $this->sendHttpRequest( + $this->createHttpRequest('GET', "/api/ibexa/v2/user/users?roleId=$roleId") + ); + + self::assertHttpResponseCodeEquals($response, $expectedCode); + if (null !== $expectedContent) { + self::assertStringContainsString($expectedContent, $response->getBody()->getContents()); + } + } + + /** + * @return iterable + */ + public function provideDataForTestLoadUsersByRoleId(): iterable + { + yield 'Administrator by ID' => [2, 404, null]; + yield 'Administrator by Href' => ['/api/ibexa/v2/user/roles/2', 404, null]; + yield 'Not Acceptable' => ['/api/ibexa/v2/something/wrong', 406, "None of the routers in the chain matched url '/api/ibexa/v2/something/wrong'"]; + } + /** * Covers GET /user/groups. */ @@ -317,6 +344,21 @@ public function testLoadUserGroups(): void self::assertHttpResponseCodeEquals($response, 200); } + /** + * Covers GET /user/groups?id={userGroupContentID}. + */ + public function testLoadUserGroupById(): void + { + $groupId = 12; // "Administrator users" + $response = $this->sendHttpRequest( + $this->createHttpRequest('GET', "/api/ibexa/v2/user/groups?id=$groupId") + ); + + self::assertHttpResponseCodeEquals($response, 200); + // 1/5/13 = "Administrator users" + self::assertStringContainsString('', $response->getBody()->getContents()); + } + /** * @depends testCreateUserGroup * @@ -332,6 +374,33 @@ public function testLoadUserGroupByRemoteId(): void self::assertHttpResponseCodeEquals($response, 200); } + /** + * @dataProvider provideDataForTestLoadGroupsByRoleId + * + * Covers GET /user/groups?roleId={roleId} + */ + public function testLoadUserGroupsByRoleId(int|string $roleId, int $expectedCode, ?string $expectedContent): void + { + $response = $this->sendHttpRequest( + $this->createHttpRequest('GET', "/api/ibexa/v2/user/groups?roleId=$roleId") + ); + + self::assertHttpResponseCodeEquals($response, $expectedCode); + if (null !== $expectedContent) { + self::assertStringContainsString($expectedContent, $response->getBody()->getContents()); + } + } + + /** + * @return iterable + */ + public function provideDataForTestLoadGroupsByRoleId(): iterable + { + yield 'Administrator by ID' => [2, 200, '']; + yield 'Administrator by Href' => ['/api/ibexa/v2/user/roles/2', 200, '']; + yield 'Not Acceptable' => ['/api/ibexa/v2/something/wrong', 406, "None of the routers in the chain matched url '/api/ibexa/v2/something/wrong'"]; + } + /** * Covers GET /user/users/{userId}/drafts. *