Skip to content

Commit

Permalink
Added PermissionLimitationResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
ciastektk authored and lucasOsti committed Sep 4, 2023
1 parent 5ffc829 commit d4665de
Show file tree
Hide file tree
Showing 16 changed files with 506 additions and 125 deletions.
54 changes: 54 additions & 0 deletions src/bundle/Controller/Permission/LanguageLimitationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?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\LimitationResolverInterface;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\LocationService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

final class LanguageLimitationController extends Controller
{
private ContentService $contentService;

private LocationService $locationService;

private LimitationResolverInterface $limitationResolver;

public function __construct(
ContentService $contentService,
LocationService $locationService,
LimitationResolverInterface $limitationResolver
) {
$this->contentService = $contentService;
$this->locationService = $locationService;
$this->limitationResolver = $limitationResolver;
}

public function loadLanguageLimitationsForContentAction(
int $contentId,
?int $versionNo = null,
?int $locationId = null
): Response {
$versionInfo = $this->contentService->loadVersionInfoById($contentId, $versionNo);

if (null === $locationId) {
$locationId = $versionInfo->getContentInfo()->getMainLocationId();
}

return new JsonResponse(
$this->limitationResolver->getLanguageLimitations(
$versionInfo,
$this->locationService->loadLocation($locationId)
)
);
}
}
14 changes: 14 additions & 0 deletions src/bundle/Resources/config/routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,17 @@ ibexa.asset.upload_image:
defaults:
_controller: 'Ibexa\Bundle\AdminUi\Controller\AssetController::uploadImageAction'
methods: [POST]

#
# Permissions
#

ibexa.permission.limitation.language:
path: permission/limitation/language/{contentId}/{versionNo}/{locationId}
options:
expose: true
defaults:
versionNo: null
locationId: null
_controller: 'Ibexa\Bundle\AdminUi\Controller\Permission\LanguageLimitationController::loadLanguageLimitationsForContentAction'
methods: [GET]
7 changes: 7 additions & 0 deletions src/bundle/Resources/config/services/components.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ services:
public: false

Ibexa\Contracts\AdminUi\Component\Renderer\RendererInterface: '@Ibexa\AdminUi\Component\Renderer\DefaultRenderer'

ibexa.adminui.html.body:
parent: Ibexa\AdminUi\Component\TwigComponent
arguments:
$template: '@@ibexadesign/ui/html_body.html.twig'
tags:
- { name: ibexa.admin_ui.component, group: 'html-body' }
6 changes: 6 additions & 0 deletions src/bundle/Resources/config/services/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,9 @@ services:
autowire: true

Ibexa\Bundle\AdminUi\Controller\User\InvitationController: ~

Ibexa\Bundle\AdminUi\Controller\Permission\LanguageLimitationController:
parent: Ibexa\Contracts\AdminUi\Controller\Controller
autowire: true
tags:
- controller.service_arguments
5 changes: 5 additions & 0 deletions src/bundle/Resources/config/services/permissions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ services:
alias: Ibexa\AdminUi\Permission\PermissionChecker

Ibexa\AdminUi\Permission\LookupLimitationsTransformer: ~

Ibexa\AdminUi\Permission\LimitationResolver: ~

Ibexa\AdminUi\Permission\LimitationResolverInterface:
alias: Ibexa\AdminUi\Permission\LimitationResolver
2 changes: 2 additions & 0 deletions src/bundle/Resources/config/services/ui_config/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ services:

Ibexa\Bundle\AdminUi\Templating\Twig\ContentTypeIconExtension: ~

Ibexa\Bundle\AdminUi\Templating\Twig\EmbeddedItemEditFormExtension: ~

Ibexa\AdminUi\UI\Config\Provider\UserContentTypes:
tags:
- { name: ibexa.admin_ui.config.provider, key: 'userContentTypes' }
Expand Down
22 changes: 22 additions & 0 deletions src/bundle/Resources/views/themes/admin/ui/html_body.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="ibexa-embedded-item-edit-container">
{% set form = ibexa_render_embedded_item_edit_form() %}

{{ form_start(form) }}
{{ form_widget(form.content_info, { 'attr': {
'hidden': 'hidden',
'class': 'ibexa-embedded-item-edit__form-field ibexa-embedded-item-edit__form-field--content-info'
} }) }}
{{ form_widget(form.version_info, { 'attr': {
'hidden': 'hidden',
'class': 'ibexa-embedded-item-edit__form-field ibexa-embedded-item-edit__form-field--version-info'
} }) }}
{{ form_widget(form.language, { 'attr': {
'hidden': 'hidden',
'class': 'ibexa-embedded-item-edit__form-field ibexa-embedded-item-edit__form-field--language'
} }) }}
{{ form_widget(form.location, { 'attr': {
'hidden': 'hidden',
'class': 'ibexa-embedded-item-edit__form-field ibexa-embedded-item-edit__form-field--location'
} }) }}
{{ form_end(form) }}
</div>
2 changes: 2 additions & 0 deletions src/bundle/Resources/views/themes/admin/ui/layout.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@
{% endblock %}
{% endif %}

{{ ibexa_render_component_group('html-body') }}

{{ encore_entry_script_tags('ibexa-admin-ui-layout-js', null, 'ibexa') }}
{{ encore_entry_script_tags('ibexa-admin-ui-udw-tabs-js', null, 'ibexa') }}
{{ encore_entry_script_tags('ibexa-admin-ui-udw-extras-js', null, 'ibexa') }}
Expand Down
52 changes: 52 additions & 0 deletions src/bundle/Templating/Twig/EmbeddedItemEditFormExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?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\Templating\Twig;

use Ibexa\AdminUi\Form\Data\Content\Draft\ContentEditData;
use Ibexa\AdminUi\Form\Factory\FormFactory;
use Symfony\Component\Form\FormView;
use Symfony\Component\Routing\RouterInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class EmbeddedItemEditFormExtension extends AbstractExtension
{
private FormFactory $formFactory;

private RouterInterface $router;

public function __construct(
FormFactory $formFactory,
RouterInterface $router
) {
$this->formFactory = $formFactory;
$this->router = $router;
}

public function getFunctions(): array
{
return [
new TwigFunction(
'ibexa_render_embedded_item_edit_form',
[$this, 'renderEmbeddedItemEditForm']
),
];
}

public function renderEmbeddedItemEditForm(): FormView
{
return $this->formFactory->contentEdit(
new ContentEditData(),
'embedded_item_edit',
[
'action' => $this->router->generate('ibexa.content.edit'),
]
)->createView();
}
}
14 changes: 10 additions & 4 deletions src/contracts/Permission/PermissionCheckerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,26 @@ public function getRestrictions(array $hasAccess, string $class): array;
public function canCreateInLocation(Location $location, $hasAccess): bool;

/**
* @internal
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
*
* @internal
*
* @deprecated 4.6.0 The "\Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface::getContentCreateLimitations()" method is deprecated, will be removed in 5.0.
* Use { @see \Ibexa\AdminUi\Permission\LimitationResolverInterface::getContentCreateLimitations } instead.
*/
public function getContentCreateLimitations(Location $parentLocation): LookupLimitationResult;

/**
* @internal
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
*
* @internal
*
* @deprecated 4.6.0 The "\Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface::getContentUpdateLimitations()" method is deprecated, will be removed in 5.0.
* Use { @see \Ibexa\AdminUi\Permission\LimitationResolverInterface::getContentUpdateLimitations } instead.
*/
public function getContentUpdateLimitations(Location $parentLocation): LookupLimitationResult;
}
Expand Down
154 changes: 154 additions & 0 deletions src/lib/Permission/LimitationResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?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;

use Ibexa\Contracts\Core\Limitation\Target\Builder\VersionBuilder;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Contracts\Core\Repository\LanguageService;
use Ibexa\Contracts\Core\Repository\LocationService;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\Values\Content\Language;
use Ibexa\Contracts\Core\Repository\Values\Content\Location;
use Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo;
use Ibexa\Contracts\Core\Repository\Values\User\Limitation;
use Ibexa\Contracts\Core\Repository\Values\User\LookupLimitationResult;

/**
* @internal
*/
final class LimitationResolver implements LimitationResolverInterface
{
private ContentService $contentService;

private ContentTypeService $contentTypeService;

private LanguageService $languageService;

private LocationService $locationService;

private LookupLimitationsTransformer $lookupLimitationsTransformer;

private PermissionResolver $permissionResolver;

public function __construct(
ContentService $contentService,
ContentTypeService $contentTypeService,
LanguageService $languageService,
LocationService $locationService,
LookupLimitationsTransformer $lookupLimitationsTransformer,
PermissionResolver $permissionResolver
) {
$this->contentService = $contentService;
$this->contentTypeService = $contentTypeService;
$this->languageService = $languageService;
$this->locationService = $locationService;
$this->lookupLimitationsTransformer = $lookupLimitationsTransformer;
$this->permissionResolver = $permissionResolver;
}

public function getContentCreateLimitations(Location $parentLocation): LookupLimitationResult
{
$contentInfo = $parentLocation->getContentInfo();
$contentType = $this->contentTypeService->loadContentType($contentInfo->getContentType()->id);
$contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, $contentInfo->getMainLanguageCode());
$contentCreateStruct->sectionId = $contentInfo->getSection();
$locationCreateStruct = $this->locationService->newLocationCreateStruct($parentLocation->id);

$versionBuilder = new VersionBuilder();
$versionBuilder->translateToAnyLanguageOf($this->getActiveLanguageCodes());
$versionBuilder->createFromAnyContentTypeOf($this->getContentTypeIds());

return $this->permissionResolver->lookupLimitations(
'content',
'create',
$contentCreateStruct,
[$versionBuilder->build(), $locationCreateStruct],
[Limitation::CONTENTTYPE, Limitation::LANGUAGE]
);
}

public function getContentUpdateLimitations(Location $parentLocation): LookupLimitationResult
{
$versionBuilder = new VersionBuilder();
$versionBuilder->translateToAnyLanguageOf($this->getActiveLanguageCodes());
$versionBuilder->createFromAnyContentTypeOf($this->getContentTypeIds());

return $this->permissionResolver->lookupLimitations(
'content',
'edit',
$parentLocation->getContentInfo(),
[$versionBuilder->build(), $parentLocation],
[Limitation::CONTENTTYPE, Limitation::LANGUAGE]
);
}

public function getLanguageLimitations(
VersionInfo $versionInfo,
Location $location
): array {
$languages = $versionInfo->getLanguages();
$lookupLimitations = $this->permissionResolver->lookupLimitations(
'content',
'edit',
$versionInfo->getContentInfo(),
[
(new VersionBuilder())->translateToAnyLanguageOf($this->getActiveLanguageCodes($languages))->build(),
$location,
],
[Limitation::LANGUAGE]
);

$limitationLanguageCodes = $this->lookupLimitationsTransformer->getFlattenedLimitationsValues($lookupLimitations);

return array_map(
static function (Language $language) use ($limitationLanguageCodes): array {
return [
'languageCode' => $language->getLanguageCode(),
'name' => $language->getName(),
'hasAccess' => empty($limitationLanguageCodes) || in_array($language->getLanguageCode(), $limitationLanguageCodes, true),
];
},
$languages
);
}

/**
* @return array<string>
*/
private function getContentTypeIds(): array
{
$contentTypeIds = [];

$contentTypeGroups = $this->contentTypeService->loadContentTypeGroups();
foreach ($contentTypeGroups as $contentTypeGroup) {
$contentTypes = $this->contentTypeService->loadContentTypes($contentTypeGroup);
foreach ($contentTypes as $contentType) {
$contentTypeIds[] = $contentType->id;
}
}

return $contentTypeIds;
}

/**
* @return array<string>
*/
private function getActiveLanguageCodes(?array $languageCodes = null): array
{
$filter = array_filter(
$languageCodes ?? $this->languageService->loadLanguages(),
static function (Language $language) {
return $language->enabled;
}
);

return array_column($filter, 'languageCode');
}
}
Loading

0 comments on commit d4665de

Please sign in to comment.