Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-9002: Added endpoint for list users with permission info #1372

Open
wants to merge 26 commits into
base: 4.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6c0d054
Added UsersWithPermissionInfoToContentItemController
ciastektk Oct 17, 2024
d244b37
Added route
ciastektk Oct 17, 2024
34eb334
Added UserQueryType
ciastektk Oct 17, 2024
7615895
Added UsersWithPermissionInfoToContentItemMapper
ciastektk Oct 17, 2024
adfbf14
[DI] Added services definitions
ciastektk Oct 17, 2024
55c2b8b
[Tests] Added integration test
ciastektk Oct 17, 2024
cabdfe7
Renamed method getUserRegistrationGroupId to getUserRegistrationGroup…
ciastektk Oct 18, 2024
6d016f1
Fixed phpstan-type TUserData
ciastektk Oct 18, 2024
ac8e35b
Reworked UserQueryType
ciastektk Oct 31, 2024
8784413
Added PermissionCheckContextResolver
ciastektk Oct 31, 2024
0cfc9af
Added PermissionCheckContextProviderInterface
ciastektk Oct 31, 2024
142ed55
Added ContentItemContextProvider
ciastektk Oct 31, 2024
53f57fd
Reworked UsersWithPermissionInfoController
ciastektk Oct 31, 2024
d41001b
Reworked UsersWithPermissionInfoMapper
ciastektk Oct 31, 2024
a948b73
[Tests] Reworked GetUsersWithPermissionInfoTest
ciastektk Oct 31, 2024
47a2af3
[DI] Added services definitions
ciastektk Oct 31, 2024
0abf8b8
Added strict types declaration
ciastektk Oct 31, 2024
59d0982
Moved PermissionCheckContext to contracts
ciastektk Oct 31, 2024
6b9bb59
Reoreder variables in UsersWithPermissionInforMapper::groupByPermissions
ciastektk Oct 31, 2024
997ccf9
Update src/lib/QueryType/UserQueryType.php
ciastektk Nov 27, 2024
6b19882
Dropped UserQueryType::excludeSystemUsers method
ciastektk Nov 27, 2024
7e0576e
[Tests] Fixed test
ciastektk Nov 27, 2024
bb77f85
[Routing] Set option expose
ciastektk Dec 9, 2024
6eec554
Moved user search phrase pattern to const
ciastektk Dec 9, 2024
5675b8b
Fixed UsersWithPermissionInfoMapper
ciastektk Dec 9, 2024
c4fc802
Renamed no_access key to noAccess
ciastektk Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\AdminUi\Controller\Permission;

use Ibexa\AdminUi\Permission\Mapper\UsersWithPermissionInfoMapper;
use Ibexa\AdminUi\Permission\PermissionCheckContextResolverInterface;
use Ibexa\Contracts\Core\Repository\SearchService;
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
use Ibexa\Core\QueryType\QueryType;
use Ibexa\Rest\Server\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;

final class UsersWithPermissionInfoController extends Controller
{
private QueryType $userQueryType;

private PermissionCheckContextResolverInterface $permissionCheckContextResolver;

private SearchService $searchService;

private UsersWithPermissionInfoMapper $userWithPermissionsMapper;

private int $limit;

public function __construct(
QueryType $userQueryType,
PermissionCheckContextResolverInterface $permissionCheckContextResolver,
SearchService $searchService,
UsersWithPermissionInfoMapper $userWithPermissionsMapper,
int $limit
) {
$this->userQueryType = $userQueryType;
$this->permissionCheckContextResolver = $permissionCheckContextResolver;
$this->searchService = $searchService;
$this->userWithPermissionsMapper = $userWithPermissionsMapper;
$this->limit = $limit;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
*/
public function listAction(
Request $request,
string $module,
string $function
): JsonResponse {
$context = $this->permissionCheckContextResolver->resolve($module, $function, $request);
$searchQuery = $this->getQuery(
$request->query,
$context->getCriteria()
);
$users = $this->searchService->findContentInfo($searchQuery, [], false);

$response = $this->userWithPermissionsMapper->mapSearchResults(
$users,
$context,
$module,
$function
);

return new JsonResponse($response);
}

private function getQuery(
ParameterBag $query,
?Query\Criterion $criteria
): Query {
$parameters = [
'limit' => $query->getInt('limit', $this->limit),
'offset' => $query->getInt('offset'),
'phrase' => $query->get('phrase'),
'extra_criteria' => $criteria,
];

return $this->userQueryType->getQuery($parameters);
}
}
13 changes: 13 additions & 0 deletions src/bundle/Resources/config/routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -971,3 +971,16 @@ ibexa.focus_mode.change:
path: /user/focus-mode
controller: 'Ibexa\Bundle\AdminUi\Controller\User\FocusModeController::changeAction'
methods: [GET, POST]

#
# Users
#
ibexa.permission.users_with_permission_info:
path: /permission/users-with-permission-info/{module}/{function}
controller: 'Ibexa\Bundle\AdminUi\Controller\Permission\UsersWithPermissionInfoController::listAction'
methods: [GET]
options:
expose: true
requirements:
module: \w+
function: \w+
6 changes: 6 additions & 0 deletions src/bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ imports:
- { resource: services/role_form_mappers.yaml }
- { resource: services/security.yaml }

parameters:
ibexa.admin_ui.load_users_with_permission_info.limit: 10
ibexa.admin_ui.permission_check_context.content.user_content_type_identifiers: [editor]

services:
_defaults:
autowire: true
Expand Down Expand Up @@ -162,3 +166,5 @@ services:
$siteAccessGroups: '%ibexa.site_access.groups%'
tags:
- {name: kernel.event_subscriber}

Ibexa\AdminUi\Permission\Mapper\UsersWithPermissionInfoMapper: ~
8 changes: 8 additions & 0 deletions src/bundle/Resources/config/services/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,11 @@ services:
$imageMappings: '%ibexa.dam_widget.image.mappings%'
tags:
- controller.service_arguments

Ibexa\Bundle\AdminUi\Controller\Permission\UsersWithPermissionInfoController:
parent: Ibexa\Rest\Server\Controller
arguments:
$userQueryType: '@Ibexa\AdminUi\QueryType\UserQueryType'
$limit: '%ibexa.admin_ui.load_users_with_permission_info.limit%'
tags:
- controller.service_arguments
17 changes: 17 additions & 0 deletions src/bundle/Resources/config/services/permissions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,20 @@ services:

Ibexa\AdminUi\Permission\LimitationResolverInterface:
alias: Ibexa\AdminUi\Permission\LimitationResolver

Ibexa\AdminUi\Permission\PermissionCheckContextResolver:
arguments:
$permissionContextProviders: !tagged_iterator ibexa.admin_ui.permission_check_context.provider

Ibexa\AdminUi\Permission\PermissionCheckContextResolverInterface:
alias: Ibexa\AdminUi\Permission\PermissionCheckContextResolver

Ibexa\Contracts\AdminUi\Permission\PermissionCheckContextProviderInterface: ~

Ibexa\AdminUi\Permission\ContextProvider\ContentItemContextProvider:
arguments:
$userContentTypeIdentifiers: '%ibexa.admin_ui.permission_check_context.content.user_content_type_identifiers%'
tags:
-
name: ibexa.admin_ui.permission_check_context.provider
priority: -100
2 changes: 2 additions & 0 deletions src/bundle/Resources/config/services/query_types.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ services:
Ibexa\AdminUi\QueryType\MediaLocationSubtreeQueryType: ~

Ibexa\AdminUi\QueryType\TrashSearchQueryType: ~

Ibexa\AdminUi\QueryType\UserQueryType: ~
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\AdminUi\Permission;

use Ibexa\Contracts\AdminUi\Values\PermissionCheckContext;
use Symfony\Component\HttpFoundation\Request;

interface PermissionCheckContextProviderInterface
{
public function supports(string $module, string $function): bool;

public function getPermissionCheckContext(string $module, string $function, Request $request): PermissionCheckContext;
}
53 changes: 53 additions & 0 deletions src/contracts/Values/PermissionCheckContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\AdminUi\Values;

use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Contracts\Core\Repository\Values\ValueObject;

final class PermissionCheckContext
{
private ValueObject $subject;

/** @var array<\Ibexa\Contracts\Core\Repository\Values\ValueObject> */
private array $targets;

private ?Criterion $criteria;

/**
* @param array<\Ibexa\Contracts\Core\Repository\Values\ValueObject> $targets
*/
public function __construct(
ValueObject $subject,
array $targets,
?Criterion $criteria = null
) {
$this->subject = $subject;
$this->targets = $targets;
$this->criteria = $criteria;
}

public function getSubject(): ValueObject
{
return $this->subject;
}

/**
* @return array<\Ibexa\Contracts\Core\Repository\Values\ValueObject>
*/
public function getTargets(): array
{
return $this->targets;
}

public function getCriteria(): ?Criterion
{
return $this->criteria;
}
}
111 changes: 111 additions & 0 deletions src/lib/Permission/ContextProvider/ContentItemContextProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\AdminUi\Permission\ContextProvider;

use Ibexa\Contracts\AdminUi\Permission\PermissionCheckContextProviderInterface;
use Ibexa\Contracts\AdminUi\Values\PermissionCheckContext;
use Ibexa\Contracts\Core\Exception\InvalidArgumentException;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\LocationService;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;

final class ContentItemContextProvider implements PermissionCheckContextProviderInterface
{
private const POLICY_MODULE_CONTENT = 'content';

private ContentService $contentService;

private LocationService $locationService;

/** @var array<string> */
private array $userContentTypeIdentifiers;

/**
* @param array<string> $userContentTypeIdentifiers
*/
public function __construct(
ContentService $contentService,
LocationService $locationService,
array $userContentTypeIdentifiers
) {
$this->contentService = $contentService;
$this->locationService = $locationService;
$this->userContentTypeIdentifiers = $userContentTypeIdentifiers;
}

public function supports(string $module, string $function): bool
{
return self::POLICY_MODULE_CONTENT === $module;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
*/
public function getPermissionCheckContext(
string $module,
string $function,
Request $request
): PermissionCheckContext {
$query = $request->query;

$contentInfo = $this->getContentInfo($query);
$targets = $this->getTargets($query);
$criteria = $this->createCriteria();

return new PermissionCheckContext($contentInfo, $targets, $criteria);
}

private function getContentInfo(ParameterBag $query): ContentInfo
{
$contentId = $query->getInt('contentId');

return $this->contentService->loadContentInfo($contentId);
}

/**
* @return array<\Ibexa\Contracts\Core\Repository\Values\ValueObject>
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
* @throws \Ibexa\Contracts\Core\Exception\InvalidArgumentException
*/
private function getTargets(ParameterBag $query): array
{
if (!$query->has('locationId')) {
return [];
}

$locationId = $query->getInt('locationId');
if ($locationId <= 0) {
throw new InvalidArgumentException(
'locationId',
'Expected value should be greater than 0.'
);
}

$location = $this->locationService->loadLocation($locationId);

return [$location];
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
*/
private function createCriteria(): Criterion
{
$criteria = [new Criterion\ContentTypeIdentifier($this->userContentTypeIdentifiers)];

return new Criterion\LogicalAnd($criteria);
}
}
Loading
Loading