Skip to content

Commit

Permalink
EZP-29223: Implement permissions for "Content/Translate"
Browse files Browse the repository at this point in the history
  • Loading branch information
mikadamczyk committed Oct 19, 2018
1 parent 8bc715c commit f7a6a48
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 47 deletions.
15 changes: 11 additions & 4 deletions src/bundle/Resources/views/content/tab/translations/tab.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
'action': path('ezplatform.translation.remove'),
'attr': { 'class': 'ez-toggle-btn-state', 'data-toggle-button-id': '#delete-translations' }
}) }}
{% include '@ezdesign/parts/table_header.html.twig' with { headerText: 'tab.translations.translation_manger'|trans|desc('Translation manager'), tools: tab.table_header_tools(form_translation_remove) } %}
{% include '@ezdesign/parts/table_header.html.twig' with {
headerText: 'tab.translations.translation_manger'|trans|desc('Translation manager'),
tools: tab.table_header_tools(form_translation_remove, can_translate)
} %}
<table class="ez-table table">
<thead>
<tr>
Expand All @@ -32,9 +35,13 @@
{% include '@ezdesign/content/tab/translations/modal_add_translation.html.twig' with {'form': form_translation_add} only %}
</section>

{% macro table_header_tools(form_translation_remove) %}
<button class="btn btn-primary ez-btn--prevented ez-btn--add-translation" data-toggle="modal" data-target="#add-translation-modal"
title="{{ 'tab.translations.action.add'|trans|desc('Add Translation') }}">
{% macro table_header_tools(form_translation_remove, can_translate) %}
<button
class="btn btn-primary ez-btn--prevented ez-btn--add-translation"
data-toggle="modal"
data-target="#add-translation-modal"
{% if not can_translate %} disabled {% endif %}
title="{{ 'tab.translations.action.add'|trans|desc('Add Translation') }}">
<svg class="ez-icon ez-icon-create">
<use xlink:href="{{ asset('bundles/ezplatformadminui/img/ez-icons.svg') }}#create"></use>
</svg>
Expand Down
98 changes: 67 additions & 31 deletions src/lib/Form/Type/Content/Translation/TranslationAddType.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,55 @@

use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
use eZ\Publish\API\Repository\LanguageService;
use eZ\Publish\API\Repository\LocationService;
use eZ\Publish\API\Repository\Values\Content\Language;
use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation;
use EzSystems\EzPlatformAdminUi\Form\Data\Content\Translation\TranslationAddData;
use EzSystems\EzPlatformAdminUi\Form\Type\Content\LocationType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
use Symfony\Component\Form\Exception\AlreadySubmittedException;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use eZ\Publish\API\Repository\PermissionResolver;
use function is_array;
use in_array;

class TranslationAddType extends AbstractType
{
/** @var LanguageService */
/** @var \eZ\Publish\API\Repository\LanguageService */
protected $languageService;

/** @var ContentService */
/** @var \eZ\Publish\API\Repository\ContentService */
protected $contentService;

/** @var LocationService */
/** @var \eZ\Publish\API\Repository\LocationService */
protected $locationService;

/** @var \eZ\Publish\API\Repository\PermissionResolver */
private $permissionResolver;

/**
* @param LanguageService $langaugeService
* @param ContentService $contentService
* @param LocationService $locationService
* @param \eZ\Publish\API\Repository\LanguageService $languageService
* @param \eZ\Publish\API\Repository\ContentService $contentService
* @param \eZ\Publish\API\Repository\LocationService $locationService
* @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
*/
public function __construct(LanguageService $langaugeService, ContentService $contentService, LocationService $locationService)
{
$this->languageService = $langaugeService;
public function __construct(
LanguageService $languageService,
ContentService $contentService,
LocationService $locationService,
PermissionResolver $permissionResolver
) {
$this->languageService = $languageService;
$this->contentService = $contentService;
$this->locationService = $locationService;
$this->permissionResolver = $permissionResolver;
}

public function buildForm(FormBuilderInterface $builder, array $options)
Expand Down Expand Up @@ -84,17 +93,16 @@ public function configureOptions(OptionsResolver $resolver)
*
* @param FormEvent $event
*
* @throws UnauthorizedException
* @throws NotFoundException
* @throws AlreadySubmittedException
* @throws LogicException
* @throws UnexpectedTypeException
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
*/
public function onPreSetData(FormEvent $event)
public function onPreSetData(FormEvent $event): void
{
$contentLanguages = [];
$form = $event->getForm();
$data = $event->getData();
/** @var \eZ\Publish\API\Repository\Values\Content\Location $location */
$location = $data->getLocation();

if (null !== $location) {
Expand All @@ -111,13 +119,11 @@ public function onPreSetData(FormEvent $event)
*
* @param FormEvent $event
*
* @throws UnauthorizedException
* @throws NotFoundException
* @throws AlreadySubmittedException
* @throws LogicException
* @throws UnexpectedTypeException
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
*/
public function onPreSubmit(FormEvent $event)
public function onPreSubmit(FormEvent $event): void
{
$contentLanguages = [];
$form = $event->getForm();
Expand Down Expand Up @@ -161,12 +167,17 @@ public function loadLanguages(callable $filter): array
* @param FormInterface $form
* @param string[] $contentLanguages
*
* @throws AlreadySubmittedException
* @throws LogicException
* @throws UnexpectedTypeException
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function addLanguageFields(FormInterface $form, array $contentLanguages): void
{
$languagesLimitations = [];

$hasAccess = $this->permissionResolver->hasAccess('content', 'translate');
if (is_array($hasAccess)) {
$languagesLimitations = $this->getLanguagesLimitations($hasAccess);
}

$form
->add(
'language',
Expand All @@ -175,10 +186,12 @@ public function addLanguageFields(FormInterface $form, array $contentLanguages):
'required' => true,
'multiple' => false,
'expanded' => true,
'choice_loader' => new CallbackChoiceLoader(function () use ($contentLanguages) {
'choice_loader' => new CallbackChoiceLoader(function () use ($contentLanguages, $languagesLimitations) {
return $this->loadLanguages(
function (Language $language) use ($contentLanguages) {
return $language->enabled && !in_array($language->languageCode, $contentLanguages, true);
function (Language $language) use ($contentLanguages, $languagesLimitations) {
return $language->enabled
&& !in_array($language->languageCode, $contentLanguages, true)
&& (empty($languagesLimitations) || in_array($language->languageCode, $languagesLimitations, true));
}
);
}),
Expand Down Expand Up @@ -206,4 +219,27 @@ function (Language $language) use ($contentLanguages) {
]
);
}

/**
* @param $limitations
*
* @return string[]
*/
private function getLanguagesLimitations($limitations): array
{
$languages = [];

foreach ($limitations as $limitation) {
/** @var \eZ\Publish\Core\Repository\Values\User\Policy $policy */
foreach ($limitation['policies'] as $policy) {
foreach ($policy->getLimitations() as $limitationObject) {
if ($limitationObject instanceof LanguageLimitation) {
$languages[] = $limitationObject->limitationValues;
}
}
}
}

return !empty($languages) ? array_merge(...$languages) : $languages;
}
}
73 changes: 61 additions & 12 deletions src/lib/Tab/LocationView/TranslationsTab.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\PermissionResolver;
use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation;
use EzSystems\EzPlatformAdminUi\Form\Data\Content\Translation\TranslationAddData;
use EzSystems\EzPlatformAdminUi\Form\Data\Content\Translation\TranslationDeleteData;
use EzSystems\EzPlatformAdminUi\Form\Factory\FormFactory;
Expand All @@ -21,39 +23,46 @@
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Twig\Environment;
use function is_array;

class TranslationsTab extends AbstractTab implements OrderedTabInterface
{
const URI_FRAGMENT = 'ez-tab-location-view-translations';

/** @var DatasetFactory */
/** @var \EzSystems\EzPlatformAdminUi\UI\Dataset\DatasetFactory */
protected $datasetFactory;

/** @var FormFactory */
/** @var \EzSystems\EzPlatformAdminUi\Form\Factory\FormFactory */
protected $formFactory;

/** @var UrlGeneratorInterface */
/** @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface */
protected $urlGenerator;

/** @var \eZ\Publish\API\Repository\PermissionResolver */
protected $permissionResolver;

/**
* @param Environment $twig
* @param TranslatorInterface $translator
* @param DatasetFactory $datasetFactory
* @param FormFactory $formFactory
* @param UrlGeneratorInterface $urlGenerator
* @param \Twig\Environment $twig
* @param \Symfony\Component\Translation\TranslatorInterface $translator
* @param \EzSystems\EzPlatformAdminUi\UI\Dataset\DatasetFactory $datasetFactory
* @param \EzSystems\EzPlatformAdminUi\Form\Factory\FormFactory $formFactory
* @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $urlGenerator
* @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
*/
public function __construct(
Environment $twig,
TranslatorInterface $translator,
DatasetFactory $datasetFactory,
FormFactory $formFactory,
UrlGeneratorInterface $urlGenerator
UrlGeneratorInterface $urlGenerator,
PermissionResolver $permissionResolver
) {
parent::__construct($twig, $translator);

$this->datasetFactory = $datasetFactory;
$this->formFactory = $formFactory;
$this->urlGenerator = $urlGenerator;
$this->permissionResolver = $permissionResolver;
}

public function getIdentifier(): string
Expand All @@ -72,6 +81,16 @@ public function getOrder(): int
return 600;
}

/**
* @param array $parameters
*
* @return string
*
* @throws \Twig_Error_Loader
* @throws \Twig_Error_Runtime
* @throws \Twig_Error_Syntax
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function renderView(array $parameters): string
{
/** @var Location $location */
Expand All @@ -82,6 +101,13 @@ public function renderView(array $parameters): string
$translationsDataset = $this->datasetFactory->translations();
$translationsDataset->load($versionInfo);

$canTranslate = $this->permissionResolver->hasAccess('content', 'translate');

if (is_array($canTranslate)) {
$limitationLanguageCodes = $this->getLimitationLanguageCodes($canTranslate);
$canTranslate = empty($limitationLanguageCodes) ? true : array_diff($limitationLanguageCodes, $translationsDataset->getLanguageCodes());
}

$translationAddForm = $this->createTranslationAddForm($location);

$translationDeleteForm = $this->createTranslationDeleteForm(
Expand All @@ -93,6 +119,7 @@ public function renderView(array $parameters): string
'translations' => $translationsDataset->getTranslations(),
'form_translation_add' => $translationAddForm->createView(),
'form_translation_remove' => $translationDeleteForm->createView(),
'can_translate' => $canTranslate,
];

return $this->twig->render(
Expand All @@ -103,16 +130,15 @@ public function renderView(array $parameters): string

/**
* @param Location $location
* @param string[]
*
* @return FormInterface
*
* @throws InvalidOptionsException
*/
private function createTranslationAddForm(Location $location): FormInterface
{
$translationAddData = new TranslationAddData($location);

return $this->formFactory->addTranslation($translationAddData);
return $this->formFactory->addTranslation($translationAddData, null);
}

/**
Expand All @@ -132,4 +158,27 @@ private function createTranslationDeleteForm(Location $location, array $language

return $this->formFactory->deleteTranslation($translationDeleteData);
}

/**
* @param $limitations
*
* @return string[]
*/
private function getLimitationLanguageCodes($limitations): array
{
$languages = [];

foreach ($limitations as $limitation) {
/** @var \eZ\Publish\Core\Repository\Values\User\Policy $policy */
foreach ($limitation['policies'] as $policy) {
foreach ($policy->getLimitations() as $limitationObject) {
if ($limitationObject instanceof LanguageLimitation) {
$languages[] = $limitationObject->limitationValues;
}
}
}
}

return !empty($languages) ? array_merge(...$languages) : $languages;
}
}

0 comments on commit f7a6a48

Please sign in to comment.