diff --git a/Classes/Access/AccessItemInterface.php b/Classes/Access/AccessItemInterface.php new file mode 100644 index 00000000..498c04a2 --- /dev/null +++ b/Classes/Access/AccessItemInterface.php @@ -0,0 +1,36 @@ +getIdentifier() === $identifier) { + return $accessItem; + } + } + + return null; + } + + public function hasAccess(string $identifier): bool + { + $object = $this->getAccess($identifier); + return $object !== null; + } +} diff --git a/Classes/Access/AllowedGlossarySyncAccess.php b/Classes/Access/AllowedGlossarySyncAccess.php new file mode 100644 index 00000000..4e113591 --- /dev/null +++ b/Classes/Access/AllowedGlossarySyncAccess.php @@ -0,0 +1,30 @@ +buildParamsArrayForListView($id); + if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedGlossarySyncAccess::ALLOWED_GLOSSARY_SYNC)) { + return; + } + + $parameters = $this->buildParamsArrayForListView((int)$id); $title = (string)LocalizationUtility::translate( 'glossary.sync.button.all', 'wv_deepltranslate' diff --git a/Classes/Event/Listener/UsageToolBarEventListener.php b/Classes/Event/Listener/UsageToolBarEventListener.php index ef0fc8c1..74c0104d 100644 --- a/Classes/Event/Listener/UsageToolBarEventListener.php +++ b/Classes/Event/Listener/UsageToolBarEventListener.php @@ -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) { diff --git a/Classes/Hooks/ButtonBarHook.php b/Classes/Hooks/ButtonBarHook.php index f46ef808..16ec5167 100644 --- a/Classes/Hooks/ButtonBarHook.php +++ b/Classes/Hooks/ButtonBarHook.php @@ -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 { @@ -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']) || $queryParams['id'] === '0') { + 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 ( + (int)$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((int)$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; } diff --git a/Classes/Hooks/TCEmainHook.php b/Classes/Hooks/TCEmainHook.php index c98a584f..ecc1ab84 100644 --- a/Classes/Hooks/TCEmainHook.php +++ b/Classes/Hooks/TCEmainHook.php @@ -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 { /** diff --git a/Classes/Override/Core11/DatabaseRecordList.php b/Classes/Override/Core11/DatabaseRecordList.php index 0ee00d72..e5034a8b 100644 --- a/Classes/Override/Core11/DatabaseRecordList.php +++ b/Classes/Override/Core11/DatabaseRecordList.php @@ -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; /** @@ -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']; + } } diff --git a/Classes/Override/Core11/DeeplRecordListController.php b/Classes/Override/Core11/DeeplRecordListController.php index fcdb404b..c3917d49 100644 --- a/Classes/Override/Core11/DeeplRecordListController.php +++ b/Classes/Override/Core11/DeeplRecordListController.php @@ -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; @@ -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, @@ -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) diff --git a/Classes/Override/Core12/DatabaseRecordList.php b/Classes/Override/Core12/DatabaseRecordList.php index c9884960..bf83352c 100644 --- a/Classes/Override/Core12/DatabaseRecordList.php +++ b/Classes/Override/Core12/DatabaseRecordList.php @@ -4,6 +4,7 @@ namespace WebVision\WvDeepltranslate\Override\Core12; +use WebVision\WvDeepltranslate\Access\AllowedTranslateAccess; use WebVision\WvDeepltranslate\Utility\DeeplBackendUtility; /** @@ -23,41 +24,43 @@ 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'] + ); } } diff --git a/Classes/Override/Core12/DeeplRecordListController.php b/Classes/Override/Core12/DeeplRecordListController.php index f5f9c0db..91e50628 100644 --- a/Classes/Override/Core12/DeeplRecordListController.php +++ b/Classes/Override/Core12/DeeplRecordListController.php @@ -16,6 +16,8 @@ use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; +use WebVision\WvDeepltranslate\Access\AllowedGlossarySyncAccess; +use WebVision\WvDeepltranslate\Access\AllowedTranslateAccess; use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; use WebVision\WvDeepltranslate\Utility\DeeplBackendUtility; @@ -44,6 +46,10 @@ protected function languageSelector(array $siteLanguages, string $requestUri): s return $originalOutput; } + if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedTranslateAccess::ALLOWED_TRANSLATE_OPTION_VALUE)) { + return $originalOutput; + } + $options = DeeplBackendUtility::buildTranslateDropdown( $siteLanguages, $this->id, @@ -78,6 +84,10 @@ private function buildGlossaryTranslationOptionDropdown(array $siteLanguages, st 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) diff --git a/Classes/Override/LocalizationController.php b/Classes/Override/LocalizationController.php index 2c2a2bdc..afcfbef9 100644 --- a/Classes/Override/LocalizationController.php +++ b/Classes/Override/LocalizationController.php @@ -182,7 +182,7 @@ public function getRecordLocalizeSummary(ServerRequestInterface $request): Respo $payloadBody = $recordLocalizeSummaryModifier->rebuildPayload($payloadBody); } // Supported TYPO3 v12 - } elseif(class_exists(\TYPO3\CMS\Backend\Controller\Event\AfterRecordSummaryForLocalizationEvent::class)) { + } elseif (class_exists(\TYPO3\CMS\Backend\Controller\Event\AfterRecordSummaryForLocalizationEvent::class)) { $event = new AfterRecordSummaryForLocalizationEvent($payloadBody['records'], $payloadBody['columns']); $this->eventDispatcher->dispatch($event); diff --git a/Classes/ViewHelpers/Be/Access/DeeplTranslateAllowedViewHelper.php b/Classes/ViewHelpers/Be/Access/DeeplTranslateAllowedViewHelper.php new file mode 100644 index 00000000..6a9c9f77 --- /dev/null +++ b/Classes/ViewHelpers/Be/Access/DeeplTranslateAllowedViewHelper.php @@ -0,0 +1,25 @@ +check('custom_options', AllowedTranslateAccess::ALLOWED_TRANSLATE_OPTION_VALUE)) { + return true; + } + return false; + } +} diff --git a/Configuration/Icons.php b/Configuration/Icons.php index 5016f6f5..ea25b28d 100644 --- a/Configuration/Icons.php +++ b/Configuration/Icons.php @@ -17,4 +17,8 @@ 'provider' => SvgIconProvider::class, 'source' => 'EXT:wv_deepltranslate/Resources/Public/Icons/deepl-grey.svg', ], + 'deepl-logo' => [ + 'provider' => SvgIconProvider::class, + 'source' => 'EXT:wv_deepltranslate/Resources/Public/Icons/deepl.svg', + ], ]; diff --git a/Documentation/Administration/Access/Index.rst b/Documentation/Administration/Access/Index.rst new file mode 100644 index 00000000..2fabea88 --- /dev/null +++ b/Documentation/Administration/Access/Index.rst @@ -0,0 +1,27 @@ +.. include:: /Includes.rst.txt + +.. _administration-access: + +Access Configuration +==================================== + +Access to the automatic translation functions with Deepl-Translate in the TYPO3 backend +can be defined via the following options in the user group settings. + +.. figure:: /Images/Administration/BackendGroupAccess.png + :alt: Backend Gruppen Access Right - Custom module options + +.. note:: + + In order to be able to use the backend group authorisations, an update to the latest version of the `wv_deepltranslate` is required. + +.. confval:: Allowed Translate + + This setting controls the visibility of the general translation function in the + translation modal of the page module, in the translation options of data records in the list module + and in the translation selection in the page header of the page and list module. + +.. confval:: Allowed Glossary Sync + + This setting allows backend users of a backend user group with corresponding authorisation to + synchronise glossary entries of a glossary SysFolder (SysFolder with activated glossary module) towards Deepl. diff --git a/Documentation/Administration/Index.rst b/Documentation/Administration/Index.rst index fd2b91c4..11927c3b 100644 --- a/Documentation/Administration/Index.rst +++ b/Documentation/Administration/Index.rst @@ -12,5 +12,6 @@ Administration Installation/Index Configuration/Index + Access/Index AutoTranslatePrefix/Index Updates/Index diff --git a/Documentation/Images/Administration/BackendGroupAccess.png b/Documentation/Images/Administration/BackendGroupAccess.png new file mode 100644 index 00000000..a67bd398 Binary files /dev/null and b/Documentation/Images/Administration/BackendGroupAccess.png differ diff --git a/Resources/Private/Backend/Partials/PageLayout/LanguageColumns.html b/Resources/Private/Backend/Partials/PageLayout/LanguageColumns.html index 2da2c48c..c88ab2e5 100644 --- a/Resources/Private/Backend/Partials/PageLayout/LanguageColumns.html +++ b/Resources/Private/Backend/Partials/PageLayout/LanguageColumns.html @@ -49,6 +49,7 @@

{languageColumn.context.siteLanguage.title}

data-has-elements="{languageColumn.translationData.hasTranslations as integer}" data-allow-copy="{languageColumn.allowTranslateCopy as integer}" data-allow-translate="{languageColumn.allowTranslate as integer}" + data-allow-deepl-translate="{deepl:be.access.deeplTranslateAllowed(then: '1', else: '0')}" data-table="tt_content" data-page-id="{context.pageId}" data-language-id="{languageColumn.context.siteLanguage.languageId}" @@ -147,40 +148,44 @@

{languageColumn.context.siteLanguage.title}

- - + + + +
+ +
+ +
+
+
+
+
+ +
+ + + + + +
-
- - -
-
-
- - - -
-
-
- -
-
-
-
+ +
+ diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index ec81330c..4ccdeb68 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -186,6 +186,23 @@ DeepL Translate Limit %s / %s + + + Deepl translate access + + + Allowed Translate + + + + + + Allowed Glossary Sync + + + + + DeepL Usage diff --git a/Resources/Public/JavaScript/Localization.js b/Resources/Public/JavaScript/Localization.js index f5a7ce9a..0a57f309 100644 --- a/Resources/Public/JavaScript/Localization.js +++ b/Resources/Public/JavaScript/Localization.js @@ -150,48 +150,51 @@ class Localization { ''); availableLocalizationModes.push('copyFromLanguage'); } - actions.push(` -
-
- -
-
- -

- ${TYPO3.lang['localize.educate.deepltranslate']} -

-
-
- `); - availableLocalizationModes.push('copyFromLanguage'); - actions.push(` -
-
- -
-
- -

- ${TYPO3.lang['localize.educate.deepltranslateAuto']} -

-
-
- `); - availableLocalizationModes.push('copyFromLanguage'); + if ($triggerButton.data('allowDeeplTranslate')) { + actions.push(` +
+
+ +
+
+ +

+ ${TYPO3.lang['localize.educate.deepltranslate']} +

+
+
+ `); + availableLocalizationModes.push('copyFromLanguage'); + actions.push(` +
+
+ +
+
+ +

+ ${TYPO3.lang['localize.educate.deepltranslateAuto']} +

+
+
+ `); + availableLocalizationModes.push('copyFromLanguage'); + + } if ($triggerButton.data('allowTranslate') === 0 && $triggerButton.data('allowCopy') === 0) { actions.push('
' + '
' + diff --git a/Resources/Public/JavaScript/Localization11.js b/Resources/Public/JavaScript/Localization11.js index 005db0ee..c53e1bd6 100644 --- a/Resources/Public/JavaScript/Localization11.js +++ b/Resources/Public/JavaScript/Localization11.js @@ -152,31 +152,33 @@ define('TYPO3/CMS/WvDeepltranslate/Localization11', [ ) } - actions.push( - '
' + + if ($triggerButton.data('allowDeeplTranslate')) { + actions.push( + '
' + '
' + - Localization.actions.deepltranslateAuto[0].outerHTML + + Localization.actions.deepltranslateAuto[0].outerHTML + '
' + '
' + - '

' + - TYPO3.lang['localize.educate.deepltranslateAuto'] + - '

' + + '

' + + TYPO3.lang['localize.educate.deepltranslateAuto'] + + '

' + '
' + - '
', - ) + '
', + ) - actions.push( - '
' + + actions.push( + '
' + '
' + - Localization.actions.deepltranslate[0].outerHTML + + Localization.actions.deepltranslate[0].outerHTML + '
' + '
' + - '

' + - TYPO3.lang['localize.educate.deepltranslate'] + - '

' + + '

' + + TYPO3.lang['localize.educate.deepltranslate'] + + '

' + '
' + - '
', - ) + '
', + ) + } } slideStep1 += diff --git a/Tests/Functional/Hooks/ButtonBarHookTest.php b/Tests/Functional/Hooks/ButtonBarHookTest.php new file mode 100644 index 00000000..de56d4bc --- /dev/null +++ b/Tests/Functional/Hooks/ButtonBarHookTest.php @@ -0,0 +1,113 @@ +configurationToUseInTestInstance = array_merge( + $this->configurationToUseInTestInstance, + require __DIR__ . '/../Fixtures/ExtensionConfig.php' + ); + + parent::setUp(); + + $this->importCSVDataSet(__DIR__ . '/Fixtures/ButtonBarHookFixtures.csv'); + + } + + /** + * @test + */ + public function showGlossarySynchronizationButton(): void + { + // User with Access + $beUser = $this->setUpBackendUser(2); + $GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->createFromUserPreferences($beUser); + + $buttons = $this->getButtonsAddsGlossarySyncButton(3); + + static::assertIsArray($buttons[ButtonBar::BUTTON_POSITION_LEFT]); + static::assertIsArray($buttons[ButtonBar::BUTTON_POSITION_LEFT][5]); + // Assertions to check if the button has been added + static::assertCount(1, $buttons[ButtonBar::BUTTON_POSITION_LEFT][5]); + + /** @var LinkButton $button */ + $button = $buttons[ButtonBar::BUTTON_POSITION_LEFT][5][0]; + static::assertInstanceOf(LinkButton::class, $button); + } + + /** + * @test + */ + public function displayGlossarySynchronizationButtonBecauseNotRightModel(): void + { + // Backend-Admin User + $beUser = $this->setUpBackendUser(2); + $GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->createFromUserPreferences($beUser); + // Create page with not correct module value + + $buttons = $this->getButtonsAddsGlossarySyncButton(4); + + static::assertIsArray($buttons); + static::assertFalse(isset($buttons[ButtonBar::BUTTON_POSITION_LEFT])); + static::assertFalse(isset($buttons[ButtonBar::BUTTON_POSITION_LEFT][5])); + } + + /** + * @test + */ + public function displayGlossarySynchronizationButtonBecauseNotAllowed(): void + { + // Backend-Admin User + $beUser = $this->setUpBackendUser(3); + $GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->createFromUserPreferences($beUser); + // Create page with correct module value + // But had no Access + $buttons = $this->getButtonsAddsGlossarySyncButton(3); + + static::assertIsArray($buttons[ButtonBar::BUTTON_POSITION_LEFT][5]); + } + + /** + * @return mixed[] + */ + private function getButtonsAddsGlossarySyncButton(int $pageId) + { + $request = (new ServerRequest('https://www.example.com/typo3', 'GET')) + ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE) + ; + $GLOBALS['TYPO3_REQUEST'] = $request = $request + ->withAttribute('normalizedParams', NormalizedParams::createFromRequest($request)) + ->withQueryParams(['id' => $pageId]) + ; + + $subject = new ButtonBarHook(); + + /** @var ButtonBar $buttonBar */ + $buttonBar = GeneralUtility::makeInstance(ButtonBar::class); + + $params = [ + 'id' => $pageId, + 'buttons' => [], + ]; + return $subject->getButtons($params, $buttonBar); + } +} diff --git a/Tests/Functional/Hooks/Fixtures/ButtonBarHookFixtures.csv b/Tests/Functional/Hooks/Fixtures/ButtonBarHookFixtures.csv new file mode 100644 index 00000000..f444382b --- /dev/null +++ b/Tests/Functional/Hooks/Fixtures/ButtonBarHookFixtures.csv @@ -0,0 +1,12 @@ +be_users,,,,, +,uid,pid,username,password,admin,description,usergroup +,2,0,"Deepl-Functional-Test BeUser","123",1,"with glossary button access","1" +,3,0,"Deepl-Functional-Test BeUser 2","123",1,"without glossary button asses","1" +be_groups +,uid,pid,title,custom_options +,1,0,"glossage_allowed","deepltranslate:allowedGlossarySync" +pages,,,,,,,, +,uid,pid,title,slug,doktype,sys_language_uid,l10n_parent,l10n_source,module +,2,0,"Default Translate Page","/",1,2,1,1,"" +,3,0,"Glossary Module Page","/",254,2,1,1,"glossary" +,4,0,"Glossary Module Page","/",254,2,1,1,"" diff --git a/Tests/Functional/Hooks/TranslateHookTest.php b/Tests/Functional/Hooks/TranslateHookTest.php index 662e2161..c9793d85 100644 --- a/Tests/Functional/Hooks/TranslateHookTest.php +++ b/Tests/Functional/Hooks/TranslateHookTest.php @@ -23,6 +23,7 @@ final class TranslateHookTest extends AbstractDeepLTestCase { use SiteBasedTestTrait; + protected const LANGUAGE_PRESETS = [ 'EN' => [ 'id' => 0, diff --git a/Tests/Unit/Access/AccessRegistryTest.php b/Tests/Unit/Access/AccessRegistryTest.php new file mode 100644 index 00000000..6a856134 --- /dev/null +++ b/Tests/Unit/Access/AccessRegistryTest.php @@ -0,0 +1,43 @@ +createMock(AccessItemInterface::class); + $accessObject->expects(static::once())->method('getIdentifier')->willReturn($identifier); + + $accessRegistry->addAccess($accessObject); + $object = $accessRegistry->getAccess($identifier); + + static::assertSame($accessObject, $object); + } + + /** + * @test + */ + public function getAccessReturnsNullForNonExistentIdentifier(): void + { + $accessRegistry = new AccessRegistry(); + + static::assertNull($accessRegistry->getAccess('nonExistentIdentifier')); + } +} diff --git a/Tests/Unit/Access/AllowedGlossarySyncAccessTest.php b/Tests/Unit/Access/AllowedGlossarySyncAccessTest.php new file mode 100644 index 00000000..d4f22f88 --- /dev/null +++ b/Tests/Unit/Access/AllowedGlossarySyncAccessTest.php @@ -0,0 +1,59 @@ +accessInstance = new AllowedGlossarySyncAccess(); + } + + /** + * @test + */ + public function hasInterfaceImplementation(): void + { + static::assertInstanceOf(AccessItemInterface::class, $this->accessInstance); + } + + /** + * @test + */ + public function getIdentifier(): void + { + static::assertSame('allowedGlossarySync', $this->accessInstance->getIdentifier()); + } + + /** + * @test + */ + public function getTitle(): void + { + static::assertIsString($this->accessInstance->getTitle()); + } + + /** + * @test + */ + public function getDescription(): void + { + static::assertIsString($this->accessInstance->getDescription()); + } + + /** + * @test + */ + public function getIconIdentifier(): void + { + static::assertSame('deepl-logo', $this->accessInstance->getIconIdentifier()); + } +} diff --git a/Tests/Unit/Access/AllowedTranslateAccessTest.php b/Tests/Unit/Access/AllowedTranslateAccessTest.php new file mode 100644 index 00000000..dab9b011 --- /dev/null +++ b/Tests/Unit/Access/AllowedTranslateAccessTest.php @@ -0,0 +1,59 @@ +accessInstance = new AllowedTranslateAccess(); + } + + /** + * @test + */ + public function hasInterfaceImplementation(): void + { + static::assertInstanceOf(AccessItemInterface::class, $this->accessInstance); + } + + /** + * @test + */ + public function getIdentifier(): void + { + static::assertSame('translateAllowed', $this->accessInstance->getIdentifier()); + } + + /** + * @test + */ + public function getTitle(): void + { + static::assertIsString($this->accessInstance->getTitle()); + } + + /** + * @test + */ + public function getDescription(): void + { + static::assertIsString($this->accessInstance->getDescription()); + } + + /** + * @test + */ + public function getIconIdentifier(): void + { + static::assertSame('deepl-logo', $this->accessInstance->getIconIdentifier()); + } +} diff --git a/ext_localconf.php b/ext_localconf.php index 61c0c871..379cc2d5 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -94,4 +94,8 @@ ??= []; $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['wvdeepltranslate']['backend'] ??= \TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend::class; + + $accessRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\WebVision\WvDeepltranslate\Access\AccessRegistry::class); + $accessRegistry->addAccess((new \WebVision\WvDeepltranslate\Access\AllowedTranslateAccess())); + $accessRegistry->addAccess((new \WebVision\WvDeepltranslate\Access\AllowedGlossarySyncAccess())); })(); diff --git a/ext_tables.php b/ext_tables.php index b05236e5..483fad68 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -1,5 +1,7 @@ getAllAccess() as $access) { + $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions']['deepltranslate']['items'][$access->getIdentifier()] = [ + $access->getTitle(), + $access->getIconIdentifier(), + $access->getDescription(), + ]; + } })();