Skip to content

Commit

Permalink
[FEATURE] Introduce translation access features for backend user groups
Browse files Browse the repository at this point in the history
Add new Items custom_options to the be_groups table, access to deepltranslate translate option.
  • Loading branch information
NarkNiro committed Sep 13, 2024
1 parent 307b8dc commit 064ac7c
Show file tree
Hide file tree
Showing 19 changed files with 420 additions and 186 deletions.
36 changes: 36 additions & 0 deletions Classes/Access/AccessItemInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace WebVision\WvDeepltranslate\Access;

interface AccessItemInterface
{
/**
* Unique access identifier
*
* @return string
*/
public function getIdentifier(): string;

/**
* The title of the access
*
* @return string
*/
public function getTitle(): string;

/**
* A short description about the access
*
* @return string
*/
public function getDescription(): string;

/**
* The icon identifier for this access
*
* @return string
*/
public function getIconIdentifier(): string;
}
45 changes: 45 additions & 0 deletions Classes/Access/AccessRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace WebVision\WvDeepltranslate\Access;

use TYPO3\CMS\Core\SingletonInterface;

final class AccessRegistry implements SingletonInterface
{
/**
* @var AccessItemInterface[]
*/
private static $access = [];

public function addAccess(AccessItemInterface $accessItem): void
{
self::$access[] = $accessItem;
}

/**
* @return AccessItemInterface[]
*/
public function getAllAccess(): array
{
return self::$access;
}

public function getAccess(string $identifier): ?AccessItemInterface
{
foreach (self::$access as $accessItem) {
if ($accessItem->getIdentifier() === $identifier) {
return $accessItem;
}
}

return null;
}

public function hasAccess(string $identifier): bool
{
$object = $this->getAccess($identifier);
return $object !== null;
}
}
30 changes: 30 additions & 0 deletions Classes/Access/AllowedGlossarySyncAccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace WebVision\WvDeepltranslate\Access;

class AllowedGlossarySyncAccess implements AccessItemInterface
{
public const ALLOWED_GLOSSARY_SYNC = 'deepltranslate:allowedGlossarySync';

public function getIdentifier(): string
{
return 'allowedGlossarySync';
}

public function getTitle(): string
{
return 'LLL:EXT:wv_deepltranslate/Resources/Private/Language/locallang.xlf:be_groups.deepltranslate_access.items.allowedGlossarySync.title';
}

public function getDescription(): string
{
return 'LLL:EXT:wv_deepltranslate/Resources/Private/Language/locallang.xlf:be_groups.deepltranslate_access.items.allowedGlossarySync.description';
}

public function getIconIdentifier(): string
{
return 'deepl-logo';
}
}
30 changes: 30 additions & 0 deletions Classes/Access/AllowedTranslateAccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace WebVision\WvDeepltranslate\Access;

final class AllowedTranslateAccess implements AccessItemInterface
{
public const ALLOWED_TRANSLATE_OPTION_VALUE = 'deepltranslate:translateAllowed';

public function getIdentifier(): string
{
return 'translateAllowed';
}

public function getTitle(): string
{
return 'LLL:EXT:wv_deepltranslate/Resources/Private/Language/locallang.xlf:be_groups.deepltranslate_access.items.translateAllowed.title';
}

public function getDescription(): string
{
return 'LLL:EXT:wv_deepltranslate/Resources/Private/Language/locallang.xlf:be_groups.deepltranslate_access.items.translateAllowed.description';
}

public function getIconIdentifier(): string
{
return 'deepl-logo';
}
}
2 changes: 1 addition & 1 deletion Classes/Event/Listener/UsageToolBarEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function __invoke(SystemInformationToolbarCollectorEvent $systemInformati
$usage = $this->usageService->getCurrentUsage();
// @todo Decide to handle empty UsageDetail later and add systeminformation with a default
// (no limit retrieved) instead of simply omitting it here now.
if($usage === null || $usage->character === null) {
if ($usage === null || $usage->character === null) {
return;
}
} catch (ApiKeyNotSetException $exception) {
Expand Down
79 changes: 44 additions & 35 deletions Classes/Hooks/ButtonBarHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use WebVision\WvDeepltranslate\Access\AllowedGlossarySyncAccess;

class ButtonBarHook
{
Expand All @@ -28,46 +30,53 @@ public function getButtons(array $params, ButtonBar $buttonBar): array
$buttons = $params['buttons'];
$queryParams = $GLOBALS['TYPO3_REQUEST']->getQueryParams();

// we're inside a page
if (isset($queryParams['id'])) {
$page = BackendUtility::getRecord(
'pages',
$queryParams['id'],
'uid,module'
);
if (!isset($queryParams['id'])) {
return $buttons;
}

if (
isset($page['module']) && $page['module'] === 'glossary'
&& $this->getBackendUserAuthentication()
->check('tables_modify', 'tx_wvdeepltranslate_glossaryentry')
) {
$parameters = $this->buildParamsArrayForListView($page['uid']);
$title = (string)LocalizationUtility::translate(
'glossary.sync.button.all',
'wv_deepltranslate'
);
// Style button
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
$button = $buttonBar->makeLinkButton();
$button->setIcon($iconFactory->getIcon(
'apps-pagetree-folder-contains-glossary',
Icon::SIZE_SMALL
));
$button->setTitle($title);
$button->setShowLabelText(true);
/** @var array{uid: int, doktype: int, module: string} $page */
$page = BackendUtility::getRecord(
'pages',
$queryParams['id'],
'uid,module,doktype'
);

$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$uri = $uriBuilder->buildUriFromRoute(
'glossaryupdate',
$parameters
);
$button->setHref($uri);
if (
$page['doktype'] !== PageRepository::DOKTYPE_SYSFOLDER
&& $page['module'] !== 'glossary'
) {
return $buttons;
}

// Register Button and position it
$buttons[ButtonBar::BUTTON_POSITION_LEFT][5][] = $button;
}
if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedGlossarySyncAccess::ALLOWED_GLOSSARY_SYNC)) {
return $buttons;
}

$parameters = $this->buildParamsArrayForListView($page['uid']);
$title = (string)LocalizationUtility::translate(
'glossary.sync.button.all',
'wv_deepltranslate'
);
// Style button
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
$button = $buttonBar->makeLinkButton();
$button->setIcon($iconFactory->getIcon(
'apps-pagetree-folder-contains-glossary',
Icon::SIZE_SMALL
));
$button->setTitle($title);
$button->setShowLabelText(true);

$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$uri = $uriBuilder->buildUriFromRoute(
'glossaryupdate',
$parameters
);
$button->setHref($uri);

// Register Button and position it
$buttons[ButtonBar::BUTTON_POSITION_LEFT][5][] = $button;

return $buttons;
}

Expand Down
3 changes: 3 additions & 0 deletions Classes/Hooks/TCEmainHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\DataHandling\DataHandlerCheckModifyAccessListHookInterface;

/**
* ToDo: Rename this class to "AllowedTableForCommandHandler"
*/
class TCEmainHook implements DataHandlerCheckModifyAccessListHookInterface
{
/**
Expand Down
75 changes: 42 additions & 33 deletions Classes/Override/Core11/DatabaseRecordList.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace WebVision\WvDeepltranslate\Override\Core11;

use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use WebVision\WvDeepltranslate\Access\AllowedTranslateAccess;
use WebVision\WvDeepltranslate\Utility\DeeplBackendUtility;

/**
Expand All @@ -23,44 +25,51 @@ public function makeLocalizationPanel($table, $row, array $translations): string
{
$out = parent::makeLocalizationPanel($table, $row, $translations);

if ($out) {
if (!DeeplBackendUtility::isDeeplApiKeySet()) {
return $out;
}
if (!DeeplBackendUtility::isDeeplApiKeySet()) {
return $out;
}

// glossaries should not be auto translated by DeepL
if ($table === 'tx_wvdeepltranslate_glossaryentry') {
return $out;
}
// glossaries should not be auto translated by DeepL
if ($table === 'tx_wvdeepltranslate_glossaryentry') {
return $out;
}

$pageId = (int)($table === 'pages' ? $row['uid'] : $row['pid']);
// All records excluding pages
$possibleTranslations = $this->possibleTranslations;
if ($table === 'pages') {
// Calculate possible translations for pages
$possibleTranslations = array_map(static fn ($siteLanguage) => $siteLanguage->getLanguageId(), $this->languagesAllowedForUser);
$possibleTranslations = array_filter($possibleTranslations, static fn ($languageUid) => $languageUid > 0);
}
$languageInformation = $this->translateTools->getSystemLanguages($pageId);
foreach ($possibleTranslations as $lUid_OnPage) {
if ($this->isEditable($table)
&& !$this->isRecordDeletePlaceholder($row)
&& !isset($translations[$lUid_OnPage])
&& $this->getBackendUserAuthentication()->checkLanguageAccess($lUid_OnPage)
&& DeeplBackendUtility::checkCanBeTranslated($pageId, $lUid_OnPage)
) {
$out .= DeeplBackendUtility::buildTranslateButton(
$table,
$row['uid'],
$lUid_OnPage,
$this->listURL(),
$languageInformation[$lUid_OnPage]['title'],
$languageInformation[$lUid_OnPage]['flagIcon']
);
}
if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedTranslateAccess::ALLOWED_TRANSLATE_OPTION_VALUE)) {
return $out;
}

$pageId = (int)($table === 'pages' ? $row['uid'] : $row['pid']);
// All records excluding pages
$possibleTranslations = $this->possibleTranslations;
if ($table === 'pages') {
// Calculate possible translations for pages
$possibleTranslations = array_map(static fn ($siteLanguage) => $siteLanguage->getLanguageId(), $this->languagesAllowedForUser);
$possibleTranslations = array_filter($possibleTranslations, static fn ($languageUid) => $languageUid > 0);
}
$languageInformation = $this->translateTools->getSystemLanguages($pageId);
foreach ($possibleTranslations as $lUid_OnPage) {
if ($this->isEditable($table)
&& !$this->isRecordDeletePlaceholder($row)
&& !isset($translations[$lUid_OnPage])
&& $this->getBackendUserAuthentication()->checkLanguageAccess($lUid_OnPage)
&& DeeplBackendUtility::checkCanBeTranslated($pageId, $lUid_OnPage)
) {
$out .= DeeplBackendUtility::buildTranslateButton(
$table,
$row['uid'],
$lUid_OnPage,
$this->listURL(),
$languageInformation[$lUid_OnPage]['title'],
$languageInformation[$lUid_OnPage]['flagIcon']
);
}
}

return $out;
}

protected function getBackendUserAuthentication(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}
10 changes: 10 additions & 0 deletions Classes/Override/Core11/DeeplRecordListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Recordlist\Controller\RecordListController;
use WebVision\WvDeepltranslate\Access\AllowedGlossarySyncAccess;
use WebVision\WvDeepltranslate\Access\AllowedTranslateAccess;
use WebVision\WvDeepltranslate\Service\DeeplGlossaryService;
use WebVision\WvDeepltranslate\Utility\DeeplBackendUtility;

Expand All @@ -40,6 +42,10 @@ protected function languageSelector(string $requestUri, $_forwardCore12CombatAnd
return $originalOutput;
}

if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedTranslateAccess::ALLOWED_TRANSLATE_OPTION_VALUE)) {
return $originalOutput;
}

$options = DeeplBackendUtility::buildTranslateDropdown(
$this->siteLanguages,
$this->id,
Expand Down Expand Up @@ -75,6 +81,10 @@ private function buildGlossaryTranslationOptionDropdown(string $requestUri): str
return '';
}

if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedGlossarySyncAccess::ALLOWED_GLOSSARY_SYNC)) {
return '';
}

$glossaryService = GeneralUtility::makeInstance(DeeplGlossaryService::class);
$possiblePairs = $glossaryService->getPossibleGlossaryLanguageConfig();
$site = GeneralUtility::makeInstance(SiteFinder::class)
Expand Down
Loading

0 comments on commit 064ac7c

Please sign in to comment.