Skip to content
5 changes: 2 additions & 3 deletions src/lib/Server/Controller/User/UserBaseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
53 changes: 50 additions & 3 deletions src/lib/Server/Controller/User/UserGroupListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down Expand Up @@ -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.',
],
],
),
)]
Expand All @@ -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'))) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This couldn't work as $request->query->get('id')is always a string with an integer in it, not an integer.

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();

Expand All @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
required: true,
schema: [
'type' => 'string',
'description' => 'The Location path to the user\'s group.',
'example' => '1/5/13',
],
),
],
Expand Down
58 changes: 56 additions & 2 deletions src/lib/Server/Controller/User/UserListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down Expand Up @@ -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.',
],
],
),
Expand Down
69 changes: 69 additions & 0 deletions tests/bundle/Functional/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, array{0: int|string, 1: int, 2: string|null}>
*/
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.
*/
Expand All @@ -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('<UserGroup media-type="application/vnd.ibexa.api.UserGroup+xml" href="/api/ibexa/v2/user/groups/1/5/13"/>', $response->getBody()->getContents());
}

/**
* @depends testCreateUserGroup
*
Expand All @@ -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<string, array{0: int|string, 1: int, 2: string|null}>
*/
public function provideDataForTestLoadGroupsByRoleId(): iterable
{
yield 'Administrator by ID' => [2, 200, '<UserGroup media-type="application/vnd.ibexa.api.UserGroup+xml" href="/api/ibexa/v2/user/groups/1/5/13"/>'];
yield 'Administrator by Href' => ['/api/ibexa/v2/user/roles/2', 200, '<UserGroup media-type="application/vnd.ibexa.api.UserGroup+xml" href="/api/ibexa/v2/user/groups/1/5/13"/>'];
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.
*
Expand Down
Loading