diff --git a/lingotek.permissions.yml b/lingotek.permissions.yml index 914157c..449c8b3 100644 --- a/lingotek.permissions.yml +++ b/lingotek.permissions.yml @@ -5,3 +5,6 @@ administer lingotek: assign lingotek translation profiles: title: 'Assign Lingotek translation profiles to content' description: 'Assign Lingotek translation profiles to content. Defaults will be used if users cannot select a profile.' +manage lingotek translations: + title: 'Manage Lingotek translations' + description: 'Allow users to send content for translations and download translations when they are ready.' diff --git a/lingotek.post_update.php b/lingotek.post_update.php index 5a62669..b9bfd43 100644 --- a/lingotek.post_update.php +++ b/lingotek.post_update.php @@ -1,11 +1,21 @@ hasPermission('administer lingotek')) { + $role->grantPermission('manage lingotek translations'); + $role->save(); + } + } +} /** * Fix lingotek metadata entities with dependencies on config entities which diff --git a/lingotek.routing.yml b/lingotek.routing.yml index 63ec6a8..9d70df5 100644 --- a/lingotek.routing.yml +++ b/lingotek.routing.yml @@ -4,7 +4,7 @@ lingotek.dashboard: _controller: '\Drupal\lingotek\Controller\LingotekDashboardController::dashboardPage' _title: 'Lingotek Translation Dashboard' requirements: - _permission: 'administer lingotek' + _permission: 'administer lingotek+manage lingotek translations' lingotek.dashboard_endpoint: path: '/admin/lingotek/dashboard_endpoint' @@ -13,7 +13,7 @@ lingotek.dashboard_endpoint: _controller: '\Drupal\lingotek\Controller\LingotekDashboardController::endpoint' _title: 'Lingotek Dashboard Endpoint' requirements: - _permission: 'administer lingotek' + _permission: 'administer lingotek+manage lingotek translations' lingotek.notify: path: '/lingotek/notify' @@ -93,7 +93,7 @@ lingotek.manage: _controller: '\Drupal\lingotek\Controller\LingotekManagementController::content' _title: 'Manage Translations' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.manage_config: path: '/admin/lingotek/config/manage' @@ -101,7 +101,7 @@ lingotek.manage_config: _form: '\Drupal\lingotek\Form\LingotekConfigManagementForm' _title: 'Manage Configuration Translation' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.import: path: '/admin/lingotek/import' @@ -125,7 +125,7 @@ lingotek.entity.check_upload: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::checkUpload' _title: 'Check Upload' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.entity.check_target: path: '/admin/lingotek/entity/check_target/{doc_id}/{locale}' @@ -133,7 +133,7 @@ lingotek.entity.check_target: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::checkTarget' _title: 'Check Targets' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.entity.request_translation: path: '/admin/lingotek/entity/add_target/{doc_id}/{locale}' @@ -141,7 +141,7 @@ lingotek.entity.request_translation: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::addTarget' _title: 'Add Target' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.entity.upload: path: '/admin/lingotek/entity/upload/{entity_type}/{entity_id}' @@ -149,7 +149,7 @@ lingotek.entity.upload: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::upload' _title: 'Upload Source' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.entity.update: path: '/admin/lingotek/entity/update/{doc_id}' @@ -157,7 +157,7 @@ lingotek.entity.update: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::update' _title: 'Update Source' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.entity.download: path: '/admin/lingotek/entity/download/{doc_id}/{locale}' @@ -165,7 +165,7 @@ lingotek.entity.download: _controller: '\Drupal\lingotek\Controller\LingotekEntityController::download' _title: 'Check Upload' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' lingotek.config.upload: path: '/admin/lingotek/config/upload/{entity_type}/{entity_id}' @@ -173,7 +173,7 @@ lingotek.config.upload: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::upload' _title: 'Upload Source' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.config.update: path: '/admin/lingotek/config/update/{entity_type}/{entity_id}' @@ -181,7 +181,7 @@ lingotek.config.update: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::update' _title: 'Update Source' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.config.check_upload: path: '/admin/lingotek/config/check_upload/{entity_type}/{entity_id}' @@ -189,7 +189,7 @@ lingotek.config.check_upload: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::checkUpload' _title: 'Check Source Status' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.config.request: path: '/admin/lingotek/config/request/{entity_type}/{entity_id}/{locale}' @@ -197,7 +197,7 @@ lingotek.config.request: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::request' _title: 'Request translation' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.config.check_download: path: '/admin/lingotek/config/check_download/{entity_type}/{entity_id}/{locale}' @@ -205,7 +205,7 @@ lingotek.config.check_download: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::checkDownload' _title: 'Check Target Status' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.config.download: path: '/admin/lingotek/config/download/{entity_type}/{entity_id}/{locale}' @@ -213,7 +213,7 @@ lingotek.config.download: _controller: '\Drupal\lingotek\Controller\LingotekConfigTranslationController::download' _title: 'Download translation' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations,translate configuration' lingotek.workbench: path: '/admin/lingotek/workbench/{doc_id}/{locale}' @@ -221,7 +221,7 @@ lingotek.workbench: _controller: '\Drupal\lingotek\Controller\LingotekWorkbenchController::loadDocument' _title: 'Use Lingotek Workbench' requirements: - _permission: 'administer lingotek' + _permission: 'manage lingotek translations' entity.lingotek_profile.add_form: path: '/admin/lingotek/settings/profile/add' diff --git a/src/Controller/LingotekConfigTranslationController.php b/src/Controller/LingotekConfigTranslationController.php index f802da5..60583c4 100644 --- a/src/Controller/LingotekConfigTranslationController.php +++ b/src/Controller/LingotekConfigTranslationController.php @@ -99,6 +99,12 @@ class LingotekConfigTranslationController extends ConfigTranslationController { public function itemPage(Request $request, RouteMatchInterface $route_match, $plugin_id) { $page = parent::itemPage($request, $route_match, $plugin_id); + + // If the user cannot manage translations, we don't add any actions. + if (!\Drupal::currentUser()->hasPermission('manage lingotek translations')) { + return $page; + } + $entity = NULL; $entity_id = NULL; /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */ diff --git a/src/Form/LingotekContentTranslationForm.php b/src/Form/LingotekContentTranslationForm.php index 223e6d2..6339c2f 100644 --- a/src/Form/LingotekContentTranslationForm.php +++ b/src/Form/LingotekContentTranslationForm.php @@ -105,7 +105,7 @@ class LingotekContentTranslationForm extends LingotekConfigFormBase { $option = array_shift($overview['#rows']); $configLanguage = ConfigurableLanguage::load($langcode); - $enabled = $this->lingotekConfiguration->isLanguageEnabled($configLanguage); + $enabled = $this->lingotekConfiguration->isLanguageEnabled($configLanguage) && \Drupal::currentUser()->hasPermission('manage lingotek translations'); // Buttons for the ENTITY SOURCE LANGUAGE // We disable the checkbox for this row. @@ -163,23 +163,26 @@ class LingotekContentTranslationForm extends LingotekConfigFormBase { $form['languages']['#options'][$langcode] = $option; } - $form['actions']['#type'] = 'actions'; - - if ($status_check_needed) { - $form['actions']['request'] = array( - '#type' => 'submit', - '#value' => $this->t('Check Progress'), - '#submit' => array('::submitForm'), - '#button_type' => 'primary', - ); - } - elseif ($targets_ready) { - $form['actions']['request'] = array( - '#type' => 'submit', - '#value' => $this->t('Download selected translations'), - '#submit' => array('::submitForm'), - '#button_type' => 'primary', - ); + + if (\Drupal::currentUser()->hasPermission('manage lingotek translations')) { + $form['actions']['#type'] = 'actions'; + + if ($status_check_needed) { + $form['actions']['request'] = array( + '#type' => 'submit', + '#value' => $this->t('Check Progress'), + '#submit' => array('::submitForm'), + '#button_type' => 'primary', + ); + } + elseif ($targets_ready) { + $form['actions']['request'] = array( + '#type' => 'submit', + '#value' => $this->t('Download selected translations'), + '#submit' => array('::submitForm'), + '#button_type' => 'primary', + ); + } } $form['fieldset']['entity'] = array( '#type' => 'value', diff --git a/src/Routing/LingotekRouteSubscriber.php b/src/Routing/LingotekRouteSubscriber.php index be7c7ee..e461f97 100644 --- a/src/Routing/LingotekRouteSubscriber.php +++ b/src/Routing/LingotekRouteSubscriber.php @@ -67,7 +67,7 @@ class LingotekRouteSubscriber extends RouteSubscriberBase { '_form' => 'Drupal\lingotek\Form\LingotekManagementForm', '_title' => 'Manage Translations', ) + $defaults, - array('_permission' => 'administer lingotek'), + array('_permission' => 'manage lingotek translations'), $options ); $collection->add("lingotek.manage.{$entity_type_id}", $route); @@ -91,7 +91,7 @@ class LingotekRouteSubscriber extends RouteSubscriberBase { '_form' => 'Drupal\lingotek\Form\LingotekMetadataEditForm', '_title' => 'Edit translation metadata', ] + $defaults, - ['_permission' => 'administer lingotek'], + ['_permission' => 'manage lingotek translations'], $options ); $collection->add("lingotek.metadata.{$entity_type_id}", $route); diff --git a/src/Tests/LingotekDashboardTest.php b/src/Tests/LingotekDashboardTest.php index a6776d3..71a9bca 100644 --- a/src/Tests/LingotekDashboardTest.php +++ b/src/Tests/LingotekDashboardTest.php @@ -229,6 +229,10 @@ class LingotekDashboardTest extends LingotekTestBase { $response = json_decode($request, TRUE); $this->verbose(var_export($response, TRUE)); + // Rebuild the container so that the new languages are picked up by services + // that hold a list of languages. + $this->rebuildContainer(); + /** @var \Drupal\Core\Language\LanguageManagerInterface $language_manager */ $language_manager = \Drupal::service('language_manager'); $languages = $language_manager->getLanguages(); @@ -270,13 +274,13 @@ class LingotekDashboardTest extends LingotekTestBase { $this->assertIdentical('es', $response['language']); $this->assertIdentical('Language disabled: es_ES', $response['message']); - $languages = $language_manager->getLanguages(); - $this->assertIdentical(2, count($languages), 'Spanish language is disabled, but not deleted.'); - // Rebuild the container so that the new languages are picked up by services // that hold a list of languages. $this->rebuildContainer(); + $languages = $language_manager->getLanguages(); + $this->assertIdentical(2, count($languages), 'Spanish language is disabled, but not deleted.'); + $language = ConfigurableLanguage::load('es'); $this->assertIdentical($language->getThirdPartySetting('lingotek', 'disabled', NULL), TRUE, 'The Spanish language is disabled'); @@ -361,6 +365,10 @@ class LingotekDashboardTest extends LingotekTestBase { $response = json_decode($request, TRUE); $this->verbose(var_export($response, TRUE)); + // Rebuild the container so that the new languages are picked up by services + // that hold a list of languages. + $this->rebuildContainer(); + /** @var LanguageManagerInterface $language_manager */ $language_manager = \Drupal::service('language_manager'); $languages = $language_manager->getLanguages(); @@ -404,6 +412,10 @@ class LingotekDashboardTest extends LingotekTestBase { $this->assertIdentical('es', $response['language']); $this->assertIdentical('Language disabled: es_ES', $response['message']); + // Rebuild the container so that the new languages are picked up by services + // that hold a list of languages. + $this->rebuildContainer(); + // Check the stats. $request = $this->curlExec(array( CURLOPT_URL => \Drupal::url('lingotek.dashboard_endpoint', [], ['absolute' => TRUE]), diff --git a/src/Tests/LingotekManageLingotekTranslationsPermissionTest.php b/src/Tests/LingotekManageLingotekTranslationsPermissionTest.php new file mode 100755 index 0000000..0a6c5e6 --- /dev/null +++ b/src/Tests/LingotekManageLingotekTranslationsPermissionTest.php @@ -0,0 +1,252 @@ +translationManagerUser->getRoles(TRUE); + /** @var \Drupal\user\RoleInterface $role */ + $role = Role::load($roles[0]); + $role->grantPermission('access toolbar')->save(); + + // Place the actions and title block. + $this->drupalPlaceBlock('page_title_block', ['region' => 'content', 'weight' => -5]); + $this->drupalPlaceBlock('local_tasks_block', ['region' => 'content', 'weight' => -10]); + + // Create Article node types. + $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']); + + // Add a language. + ConfigurableLanguage::createFromLangcode('es')->setThirdPartySetting('lingotek', 'locale', 'es_ES')->save(); + + // Enable translation for the current entity type and ensure the change is + // picked up. + ContentLanguageSettings::loadByEntityTypeBundle('node', 'article')->setLanguageAlterable(TRUE)->save(); + \Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE); + + drupal_static_reset(); + \Drupal::entityManager()->clearCachedDefinitions(); + \Drupal::service('entity.definition_update_manager')->applyUpdates(); + // Rebuild the container so that the new languages are picked up by services + // that hold a list of languages. + $this->rebuildContainer(); + + $edit = [ + 'node[article][enabled]' => 1, + 'node[article][profiles]' => 'automatic', + 'node[article][fields][title]' => 1, + 'node[article][fields][body]' => 1, + ]; + $this->drupalPostForm('admin/lingotek/settings', $edit, 'Save', [], [], 'lingoteksettings-tab-content-form'); + } + + /** + * Test that if user can see settings tab without right permissions + */ + public function testCannotSeeSettingsTabWithoutRightPermission() { + $user = $this->drupalCreateUser([ + 'administer lingotek', + 'assign lingotek translation profiles', + 'manage lingotek translations' + ]); + // Login as user. + $this->drupalLogin($user); + // Get the settings form. + $this->drupalGet('admin/lingotek/settings'); + // Assert translation profile can be assigned. + $this->assertNoText('You are not authorized to access this page.'); + + $user = $this->drupalCreateUser([ + 'assign lingotek translation profiles', + 'manage lingotek translations' + ]); + // Login as user. + $this->drupalLogin($user); + // Get the settings form. + $this->drupalGet('admin/lingotek/settings'); + // Assert translation profile cannot be assigned. + $this->assertText('You are not authorized to access this page.'); + } + + /** + * Tests that a user can navigate to the content bulk translation pages. + */ + public function testNavigationThroughSiteForBulkContentTranslationAsTranslationsManager() { + // Login as translations manager. + $this->drupalLogin($this->translationManagerUser); + + $this->drupalGet('/user'); + + // Assert the toolbar has the proper links for configuration and translation. + $this->assertLink('Configuration'); + $this->assertLink('Translation'); + + // Assert in the configuration panes we have access to Lingotek Translation. + $this->clickLink('Configuration'); + + $this->assertText('Regional and language'); + $this->clickLink('Lingotek Translation'); + + // Assert we see the dashboard and can navigate to content. + $this->assertLink('Content'); + $this->clickLink('Content'); + $this->assertText('Manage Translations'); + } + + /** + * Tests that a user can navigate to the config bulk translation pages. + */ + public function testNavigationThroughSiteForBulkConfigTranslationAsTranslationsManager() { + // Login as translations manager. + $this->drupalLogin($this->translationManagerUser); + + $this->drupalGet('/user'); + + // Assert the toolbar has the proper links for configuration and translation. + $this->assertLink('Configuration'); + $this->assertLink('Translation'); + + // Assert in the configuration panes we have access to Lingotek Translation. + $this->clickLink('Configuration'); + + $this->assertText('Regional and language'); + $this->clickLink('Lingotek Translation'); + + // Config shouldn't be visible unless we can translate settings too. + $this->assertNoLink('Config'); + } + + /** + * Tests that a user can navigate to the config bulk translation pages. + */ + public function testNavigationThroughSiteForBulkConfigTranslationAsTranslationsManagerWithTranslateConfigPermission() { + // Login as translations manager, but including the 'translate configuration' + // permission. + $roles = $this->translationManagerUser->getRoles(TRUE); + /** @var \Drupal\user\RoleInterface $role */ + $role = Role::load($roles[0]); + $role->grantPermission('translate configuration')->save(); + $this->drupalLogin($this->translationManagerUser); + + $this->drupalGet('/user'); + + // Assert the toolbar has the proper links for configuration and translation. + $this->assertLink('Configuration'); + $this->assertLink('Translation'); + + // Assert in the configuration panes we have access to Lingotek Translation. + $this->clickLink('Configuration'); + + $this->assertText('Regional and language'); + $this->clickLink('Lingotek Translation'); + + // Assert we see the dashboard and can navigate to config. + $this->assertLink('Config'); + $this->clickLink('Config'); + $this->assertText('Manage Configuration Translation'); + } + + /** + * Tests dashboard works as a translations manager. + */ + public function testDashboardAsTranslationsManager() { + // Login as translations manager. + $this->drupalLogin($this->translationManagerUser); + + // Check the stats. + $request = $this->curlExec(array( + CURLOPT_URL => \Drupal::url('lingotek.dashboard_endpoint', [], ['absolute' => TRUE]), + CURLOPT_HTTPGET => TRUE, + CURLOPT_CUSTOMREQUEST => NULL, + CURLOPT_NOBODY => FALSE, + CURLOPT_HTTPHEADER => array( + 'Accept: application/json', + ), + )); + $response = json_decode($request, TRUE); + $this->verbose(var_export($response, TRUE)); + $this->assertIdentical('GET', $response['method']); + $this->assertIdentical(2, $response['count']); + $this->assertIdentical('en', $response['languages']['en_US']['xcode']); + $this->assertIdentical(1, $response['languages']['en_US']['active']); + $this->assertIdentical(1, $response['languages']['en_US']['enabled']); + $this->assertIdentical('es', $response['languages']['es_ES']['xcode']); + $this->assertIdentical(1, $response['languages']['es_ES']['active']); + $this->assertIdentical(1, $response['languages']['es_ES']['enabled']); + } + + /** + * The node translation form doesn't contain any operations if the current + * user is not a translation manager. + */ + public function testNodeTranslateDoesntContainBulkActions() { + // Create a user that can create content and translate it, but not with the + // Lingotek module. + $contentManager = $this->createUser([ + 'access toolbar', + 'access content overview', + 'administer nodes', + 'assign lingotek translation profiles', + 'create article content', + 'translate any entity', + ]); + $this->drupalLogin($contentManager); + + $edit = array(); + $edit['title[0][value]'] = 'Llamas are cool'; + $edit['body[0][value]'] = 'Llamas are very cool'; + $edit['langcode[0][value]'] = 'en'; + $edit['lingotek_translation_profile'] = 'manual'; + $this->saveAndPublishNodeForm($edit); + + $this->clickLink('Translate'); + + // We don't have any operations or actions available. + $this->assertNoLink('Upload'); + $this->assertNoFieldByName('op'); + } + + /** + * The node translation form doesn't contain any operations if the current + * user is not a translation manager. + */ + public function testConfigTranslateDoesntContainBulkActions() { + // Login as a user that can translate configuration, but cannot manage + // Lingotek translations. + $contentManager = $this->createUser([ + 'access toolbar', + 'access administration pages', + 'administer site configuration', + 'translate configuration', + ]); + $this->drupalLogin($contentManager); + + // Check that the translate tab is in the site information. + $this->drupalGet('/admin/config/system/site-information'); + $this->clickLink('Translate system information'); + + // We don't have any operations available. + $this->assertNoLink('Upload'); + } + +} diff --git a/src/Tests/LingotekNodeBulkTranslationTest.php b/src/Tests/LingotekNodeBulkTranslationTest.php index d527d2c..6d5debe 100644 --- a/src/Tests/LingotekNodeBulkTranslationTest.php +++ b/src/Tests/LingotekNodeBulkTranslationTest.php @@ -74,6 +74,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { $edit['lingotek_translation_profile'] = 'manual'; $this->saveAndPublishNodeForm($edit); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + $this->goToContentBulkManagementForm(); $basepath = \Drupal::request()->getBasePath(); @@ -135,6 +138,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { $edit['lingotek_translation_profile'] = 'manual'; $this->saveAndPublishNodeForm($edit); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + $this->goToContentBulkManagementForm(); $basepath = \Drupal::request()->getBasePath(); @@ -452,6 +458,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { // We need a node with translations first. $this->testNodeTranslationUsingLinks(); + // Login as admin. + $this->drupalLogin($this->rootUser); + // Add a language so we can check that it's not marked as dirty if there are // no translations. ConfigurableLanguage::createFromLangcode('eu')->setThirdPartySetting('lingotek', 'locale', 'eu_ES')->save(); @@ -468,6 +477,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { $edit['lingotek_translation_profile'] = 'manual'; $this->saveAndKeepPublishedThisTranslationNodeForm($edit, 1); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + $this->goToContentBulkManagementForm(); // Check the status is edited for Spanish. @@ -521,6 +533,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { // We need a node with translations first. $this->testNodeTranslationUsingLinks(); + // Login as admin. + $this->drupalLogin($this->rootUser); + // Add a language so we can check that it's not marked as dirty if there are // no translations. ConfigurableLanguage::createFromLangcode('eu')->setThirdPartySetting('lingotek', 'locale', 'eu_ES')->save(); @@ -533,6 +548,9 @@ class LingotekNodeBulkTranslationTest extends LingotekTestBase { $edit['lingotek_translation_profile'] = 'automatic'; $this->saveAndKeepPublishedThisTranslationNodeForm($edit, 1); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + $this->goToContentBulkManagementForm(); // Check the status is edited for Spanish. diff --git a/src/Tests/LingotekSystemSiteBulkTranslationTest.php b/src/Tests/LingotekSystemSiteBulkTranslationTest.php index d8e81ee..88989f2 100644 --- a/src/Tests/LingotekSystemSiteBulkTranslationTest.php +++ b/src/Tests/LingotekSystemSiteBulkTranslationTest.php @@ -6,6 +6,7 @@ use Drupal\config_translation\ConfigMapperManagerInterface; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\lingotek\Lingotek; use Drupal\lingotek\LingotekConfigTranslationServiceInterface; +use Drupal\user\Entity\Role; /** * Tests translating a config object using the bulk management form. @@ -20,6 +21,13 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { protected function setUp() { parent::setUp(); + // Login as translations manager, but including the 'translate configuration' + // permission. + $roles = $this->translationManagerUser->getRoles(TRUE); + /** @var \Drupal\user\RoleInterface $role */ + $role = Role::load($roles[0]); + $role->grantPermission('translate configuration')->save(); + // Add a language. ConfigurableLanguage::createFromLangcode('es')->setThirdPartySetting('lingotek', 'locale', 'es_MX')->save(); @@ -31,8 +39,8 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { * Tests that a config can be translated using the links on the management page. */ public function testSystemSiteTranslationUsingLinks() { - // Login as admin. - $this->drupalLogin($this->rootUser); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); // Go to the bulk config management page. $this->goToConfigBulkManagementForm(); @@ -82,8 +90,8 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { * Tests that a config can be translated using the actions on the management page. */ public function testSystemSiteTranslationUsingActions() { - // Login as admin. - $this->drupalLogin($this->rootUser); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); // Add a language. ConfigurableLanguage::createFromLangcode('de')->setThirdPartySetting('lingotek', 'locale', 'de_AT')->save(); @@ -150,6 +158,9 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { // We need a config object with translations first. $this->testSystemSiteTranslationUsingLinks(); + // Login as translation manager. + $this->drupalLogin($this->rootUser); + // Add a language so we can check that it's not marked as dirty if there are // no translations. ConfigurableLanguage::createFromLangcode('eu')->setThirdPartySetting('lingotek', 'locale', 'eu_ES')->save(); @@ -161,6 +172,9 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { // Edit the object $this->drupalPostForm('/admin/config/system/site-information', ['site_name' => 'My site'], t('Save configuration')); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + // Go to the bulk config management page. $this->goToConfigBulkManagementForm(); @@ -209,12 +223,12 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { * Tests that a config object can be translated using the actions on the management page. */ public function testSystemSiteMultipleLanguageTranslationUsingActions() { - // Login as admin. - $this->drupalLogin($this->rootUser); - // Add a language. ConfigurableLanguage::createFromLangcode('de')->setThirdPartySetting('lingotek', 'locale', 'de_AT')->save(); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + // Go to the bulk config management page. $this->goToConfigBulkManagementForm(); @@ -464,6 +478,9 @@ class LingotekSystemSiteBulkTranslationTest extends LingotekTestBase { ConfigurableLanguage::createFromLangcode('ca')->setThirdPartySetting('lingotek', 'locale', 'ca_ES')->save(); ConfigurableLanguage::createFromLangcode('it')->setThirdPartySetting('lingotek', 'locale', 'it_IT')->save(); + // Login as translation manager. + $this->drupalLogin($this->translationManagerUser); + $this->goToConfigBulkManagementForm(); $basepath = \Drupal::request()->getBasePath(); diff --git a/src/Tests/LingotekTestBase.php b/src/Tests/LingotekTestBase.php index 2885a54..98c8095 100644 --- a/src/Tests/LingotekTestBase.php +++ b/src/Tests/LingotekTestBase.php @@ -18,12 +18,32 @@ abstract class LingotekTestBase extends WebTestBase { */ public static $modules = ['lingotek', 'lingotek_test']; + /** + * @var \Drupal\Core\Session\AccountInterface + * Minimal Lingotek translation manager user. + */ + protected $translationManagerUser; + protected function setUp() { parent::setUp(); // Login as admin. $this->drupalLogin($this->rootUser); $this->connectToLingotek(); + + $this->createTranslationManagerUser(); + } + + /** + * Creates a translation manager role and a user with the minimal + * Lingotek translation management permissions. + */ + protected function createTranslationManagerUser() { + $this->translationManagerUser = $this->drupalCreateUser([ + 'assign lingotek translation profiles', + 'manage lingotek translations', + 'access administration pages', + ]); } /** diff --git a/src/Tests/Update/LingotekManageTranslationsPostUpdateTest.php b/src/Tests/Update/LingotekManageTranslationsPostUpdateTest.php new file mode 100644 index 0000000..faeb778 --- /dev/null +++ b/src/Tests/Update/LingotekManageTranslationsPostUpdateTest.php @@ -0,0 +1,43 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../tests/fixtures/update/drupal-8.lingotek.manage-lingotek-translations-permission.php.gz', + ]; + } + + /** + * Tests that the Lingotek role has the new permission. + */ + public function testLingotekManageTranslationsPermissionPostUpdate() { + // The role doesn't have the permission. + $role = Role::load('translation_manager'); + $this->assertFalse($role->hasPermission('manage lingotek translations'), "The Translation Manager role doesn't have the 'Manage Lingotek Translations' permission."); + $this->assertTrue($role->hasPermission('administer lingotek'), "The Translation Manager role has the 'Administer Lingotek' permission."); + + $this->runUpdates(); + + // The role now has the permission. + $role = Role::load('translation_manager'); + $this->assertTrue($role->hasPermission('manage lingotek translations'), "The Translation Manager role has the 'Manage Lingotek Translations' permission."); + $this->assertTrue($role->hasPermission('administer lingotek'), "The Translation Manager role has the 'Administer Lingotek' permission."); + } + +} diff --git a/tests/fixtures/update/drupal-8.lingotek.manage-lingotek-translations-permission.php.gz b/tests/fixtures/update/drupal-8.lingotek.manage-lingotek-translations-permission.php.gz new file mode 100644 index 0000000..f21de01 Binary files /dev/null and b/tests/fixtures/update/drupal-8.lingotek.manage-lingotek-translations-permission.php.gz differ