From a6466dacea160ad2af63ba4895aa0518ba8b959c Mon Sep 17 00:00:00 2001 From: upchuk Date: Mon, 20 Feb 2023 13:56:48 +0100 Subject: [PATCH 1/2] EWPP-3037: Handling failed requests. --- composer.json | 4 +- .../oe_translation_corporate_workflow.module | 21 ++ .../src/Form/RemoteTranslationNewForm.php | 3 + .../oe_translation_epoetry_mock.schema.yml | 19 ++ .../createLinguisticRequestResponse.xml | 99 ------ .../fixtures/epoetry.wsdl | 227 -------------- .../fixtures/error_wrapper.xml | 9 + .../fixtures/request.wsdl | 226 -------------- .../oe_translation_epoetry_mock.info.yml | 1 - ...oe_translation_epoetry_mock.links.menu.yml | 5 + .../oe_translation_epoetry_mock.module | 2 +- .../oe_translation_epoetry_mock.routing.yml | 8 + .../src/Controller/MockController.php | 25 +- .../src/EpoetryTranslationMockHelper.php | 50 ++- .../src/Form/MockSettings.php | 85 ++++++ .../src/MockRequestFactory.php | 32 ++ ...eTranslationEpoetryMockServiceProvider.php | 25 ++ .../oe_translation_epoetry.routing.yml | 11 + .../oe_translation_epoetry.services.yml | 4 + .../src/Controller/EpoetryController.php | 54 ++++ ...ionRequestOperationsProviderSubscriber.php | 53 ++++ .../src/MockAuthentication.php | 35 +++ .../RemoteTranslationProvider/Epoetry.php | 102 ++++++- .../src/RequestFactory.php | 30 +- .../EpoetryTranslationTest.php | 288 +++++++++++++++++- .../oe_translation_remote.module | 8 +- .../TranslationDashboardAlterSubscriber.php | 2 + ...ionRequestOperationsProviderSubscriber.php | 2 +- .../src/Form/RemoteTranslationNewForm.php | 3 +- .../src/Form/RemoteTranslatorProviderForm.php | 1 + .../RemoteTranslationProviderManager.php | 1 + .../src/TranslationRequestRemoteInterface.php | 3 + 32 files changed, 838 insertions(+), 600 deletions(-) create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/config/schema/oe_translation_epoetry_mock.schema.yml delete mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/createLinguisticRequestResponse.xml delete mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/epoetry.wsdl create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/error_wrapper.xml delete mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/request.wsdl create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.links.menu.yml create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Form/MockSettings.php create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/MockRequestFactory.php create mode 100644 modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/OeTranslationEpoetryMockServiceProvider.php create mode 100644 modules/oe_translation_epoetry/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php create mode 100644 modules/oe_translation_epoetry/src/MockAuthentication.php diff --git a/composer.json b/composer.json index 1614a48b..9acdfc15 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "mikey179/vfsstream": "^1.6.10", "openeuropa/behat-transformation-context": "dev-master", "openeuropa/code-review": "2.x-dev", - "openeuropa/epoetry-client": "dev-master", + "openeuropa/epoetry-client": "1.x-dev", "openeuropa/oe_multilingual": "dev-master", "openeuropa/oe_editorial": "dev-master", "openeuropa/task-runner-drupal-project-symlink": "1.x-dev", @@ -58,7 +58,6 @@ }, "_readme": [ "Patching TMGMT to ensure that when a new translation is saved onto the entity, it doesn't create a new revision", - "Autoload for OpenEuropa\\EPoetry\\Tests\\ temporarily until we stop using the Mock authentication.", "Patching core event dispatcher for 9.4.x to prevent indiscriminate calls to stopPropagation. Can be removed when we go to D10. See https://www.drupal.org/project/drupal/issues/3319791.", "Requireding symfony propery-access and propery-info for the ePoetry mock for the serializer that uses them.", "Requiring minimum versions of php-soap/psr18-transport and symfony/serializer for the epoetry client which needs them for lowest dependencies.", @@ -87,7 +86,6 @@ "autoload": { "psr-4": { "Drupal\\oe_translation\\": "./src/", - "OpenEuropa\\EPoetry\\Tests\\": "./vendor/openeuropa/epoetry-client/tests/", "Symfony\\Component\\PropertyInfo\\": "./vendor/symfony/property-info/", "Symfony\\Component\\PropertyAccess\\": "./vendor/symfony/property-access/" } diff --git a/modules/oe_translation_corporate_workflow/oe_translation_corporate_workflow.module b/modules/oe_translation_corporate_workflow/oe_translation_corporate_workflow.module index 4f823390..5c99e4d5 100755 --- a/modules/oe_translation_corporate_workflow/oe_translation_corporate_workflow.module +++ b/modules/oe_translation_corporate_workflow/oe_translation_corporate_workflow.module @@ -29,6 +29,13 @@ function oe_translation_corporate_workflow_theme($existing, $type, $theme, $path * Implements hook_ENTITY_TYPE_presave(). */ function oe_translation_corporate_workflow_node_presave(EntityInterface $entity): void { + /** @var \Drupal\workflows\WorkflowInterface $workflow */ + $workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($entity); + if (!$workflow || $workflow->id() !== 'oe_corporate_workflow') { + // We only care about content using the corporate workflow. + return; + } + if (isset($entity->translation_drop) && $entity->translation_drop === TRUE && $entity->moderation_state->value === 'validated') { foreach ($entity->getTranslationLanguages(FALSE) as $langcode => $language) { $entity->removeTranslation($langcode); @@ -73,6 +80,13 @@ function oe_translation_corporate_workflow_node_presave(EntityInterface $entity) * Implements hook_ENTITY_TYPE_view_alter() for the Node entity. */ function oe_translation_corporate_workflow_node_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display): void { + /** @var \Drupal\workflows\WorkflowInterface $workflow */ + $workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($entity); + if (!$workflow || $workflow->id() !== 'oe_corporate_workflow') { + // We only care about content using the corporate workflow. + return; + } + // If we are rendering a translation, we should hide the content moderation // block because the workflow needs to be controlled from the source entity. if ($entity->isDefaultTranslation()) { @@ -189,6 +203,13 @@ function oe_translation_corporate_workflow_form_content_moderation_entity_modera return; } + /** @var \Drupal\workflows\WorkflowInterface $workflow */ + $workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($entity); + if (!$workflow || $workflow->id() !== 'oe_corporate_workflow') { + // We only care about content using the corporate workflow. + return; + } + $current_state = $entity->moderation_state->value; $form['translation_drop_wrapper'] = [ '#type' => 'container', diff --git a/modules/oe_translation_corporate_workflow/src/Form/RemoteTranslationNewForm.php b/modules/oe_translation_corporate_workflow/src/Form/RemoteTranslationNewForm.php index 5a7477f3..69fc3e80 100644 --- a/modules/oe_translation_corporate_workflow/src/Form/RemoteTranslationNewForm.php +++ b/modules/oe_translation_corporate_workflow/src/Form/RemoteTranslationNewForm.php @@ -97,6 +97,7 @@ protected function createNewRequestAccess(ContentEntityInterface $entity): Acces $statuses = [ TranslationRequestRemoteInterface::STATUS_REQUEST_TRANSLATED, TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, ]; $requests = $this->providerManager->getExistingTranslationRequests($entity, FALSE, $statuses); if ($requests) { @@ -129,6 +130,7 @@ protected function createNewRequestAccess(ContentEntityInterface $entity): Acces $statuses = [ TranslationRequestRemoteInterface::STATUS_REQUEST_TRANSLATED, TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, ]; $requests = $this->providerManager->getExistingTranslationRequests($entity, FALSE, $statuses); if ($requests) { @@ -296,6 +298,7 @@ protected function createNewRequestAccessForPublished(ContentEntityInterface $en $statuses = [ TranslationRequestRemoteInterface::STATUS_REQUEST_TRANSLATED, TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, ]; $requests = $this->providerManager->getExistingTranslationRequests($entity, TRUE, $statuses); if (!$requests) { diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/config/schema/oe_translation_epoetry_mock.schema.yml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/config/schema/oe_translation_epoetry_mock.schema.yml new file mode 100644 index 00000000..050c590e --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/config/schema/oe_translation_epoetry_mock.schema.yml @@ -0,0 +1,19 @@ +oe_translation_epoetry_mock.settings: + type: config_object + label: 'OpenEuropa Translation ePoetry Mock settings' + mapping: + endpoint: + type: string + label: 'Endpoint' + notifications_endpoint: + type: string + label: 'Notifications endpoint' + notifications_username: + type: string + label: 'Notifications username' + notifications_password: + type: string + label: 'Notifications password' + application_name: + type: string + label: 'Application name' diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/createLinguisticRequestResponse.xml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/createLinguisticRequestResponse.xml deleted file mode 100644 index f45ba8e1..00000000 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/createLinguisticRequestResponse.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - DGT - 487 - 2021 - - TRA - 0 - 0 - - - test for DOC - success - - 2022-07-01T12:51:00+02:00 - false - false - false - PUBLIC - DEGHP - ANNEX8A - my request - CONTACTS - keyw1 - key2 - aaaaaaaaaaaaaaa - SenttoDGT - application1 - - - Jochen - LIEKENS - Jochen.LIEKENS@ec.europa.eu - liekejo - AUTHOR - - - Jochen - LIEKENS - Jochen.LIEKENS@ec.europa.eu - liekejo - RECIPIENT - - - Jochen - LIEKENS - Jochen.LIEKENS@ec.europa.eu - liekejo - REQUESTER - - - - false - DOCX - TEST_FILE_ORIGINALP.docx - 0.0 - - - EN - - - - - - FR - 2021-07-06T12:51:00+02:00 - false - SenttoDGT - DOCX - - - - - test.docx - EN - REF - test - DOCX - - - test2222SRC.docx - EN - SRC - srcFile - DOCX - - - - - The decide reference will be ignored because the request is not legislative! - - - - - diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/epoetry.wsdl b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/epoetry.wsdl deleted file mode 100644 index ec942f92..00000000 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/epoetry.wsdl +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/error_wrapper.xml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/error_wrapper.xml new file mode 100644 index 00000000..67e390f1 --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/error_wrapper.xml @@ -0,0 +1,9 @@ + + + + + @code + @string + + + diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/request.wsdl b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/request.wsdl deleted file mode 100644 index 3b163aca..00000000 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/fixtures/request.wsdl +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.info.yml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.info.yml index 6b5054af..9ac8e42e 100644 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.info.yml +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.info.yml @@ -6,4 +6,3 @@ type: module core_version_requirement: ^9.2 dependencies: - oe_translation_epoetry:oe_translation_epoetry - - oe_translation_remote_test:oe_translation_remote_test diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.links.menu.yml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.links.menu.yml new file mode 100644 index 00000000..0637926f --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.links.menu.yml @@ -0,0 +1,5 @@ +oe_translation_epoetry_mock.mock_settings: + title: ePoetry mock settings + parent: system.admin_config_system + route_name: oe_translation_epoetry_mock.mock_settings + weight: 10 diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.module b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.module index 73b03395..2c8a0f2d 100644 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.module +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.module @@ -61,7 +61,7 @@ function oe_translation_epoetry_mock_preprocess_table__remote_language_list(arra throw new NotFoundHttpException(); } - if ($request->bundle() !== 'epoetry') { + if ($request->bundle() !== 'epoetry' || $request->getRequestStatus() === TranslationRequestEpoetryInterface::STATUS_REQUEST_FAILED) { return; } diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.routing.yml b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.routing.yml index f6672254..4ee3bee1 100644 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.routing.yml +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/oe_translation_epoetry_mock.routing.yml @@ -15,3 +15,11 @@ oe_translation_epoetry_mock.notify: parameters: oe_translation_request: type: entity:oe_translation_request + +oe_translation_epoetry_mock.mock_settings: + path: '/admin/config/system/epoetry-mock-settings' + defaults: + _title: 'ePoetry mock settings' + _form: 'Drupal\oe_translation_epoetry_mock\Form\MockSettings' + requirements: + _permission: 'administer site configuration' diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Controller/MockController.php b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Controller/MockController.php index 29ff4ca4..b3fc1b7a 100644 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Controller/MockController.php +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Controller/MockController.php @@ -8,6 +8,7 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\State\StateInterface; use Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface; use Drupal\oe_translation_epoetry_mock\EpoetryTranslationMockHelper; use Drupal\oe_translation_epoetry_mock\MockServer; @@ -37,6 +38,13 @@ class MockController extends ControllerBase { */ protected $classResolver; + /** + * The state service. + * + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + /** * The controller constructor. * @@ -44,10 +52,13 @@ class MockController extends ControllerBase { * The entity type manager. * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $classResolver * The class resolver. + * @param \Drupal\Core\State\StateInterface $state + * The state service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, ClassResolverInterface $classResolver) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, ClassResolverInterface $classResolver, StateInterface $state) { $this->entityTypeManager = $entity_type_manager; $this->classResolver = $classResolver; + $this->state = $state; } /** @@ -56,7 +67,8 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Cla public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.manager'), - $container->get('class_resolver') + $container->get('class_resolver'), + $container->get('state') ); } @@ -77,6 +89,15 @@ public function server(Request $request): Response { throw new NotFoundHttpException(); } + $error_response = $this->state->get('oe_translation_epoetry_mock_response_error', []); + if ($error_response) { + $wrapper = file_get_contents(drupal_get_path('module', 'oe_translation_epoetry_mock') . '/fixtures/error_wrapper.xml'); + $wrapper = str_replace(['@code', '@string'], $error_response, $wrapper); + $response = new Response($wrapper); + $response->headers->set('Content-type', 'application/xml; charset=utf-8'); + return $response; + } + $xml = str_ireplace([ 'SOAPENV:', 'SOAP:', diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/EpoetryTranslationMockHelper.php b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/EpoetryTranslationMockHelper.php index 850e1f53..c3676d57 100644 --- a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/EpoetryTranslationMockHelper.php +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/EpoetryTranslationMockHelper.php @@ -10,12 +10,11 @@ use Drupal\oe_translation_epoetry\TranslationRequestEpoetry; use Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface; use Drupal\oe_translation_remote\TranslationRequestRemoteInterface; -use Drupal\oe_translation_remote_test\TestRemoteTranslationMockHelper; /** * Helper class to deal with requests until we have notifications set up. */ -class EpoetryTranslationMockHelper extends TestRemoteTranslationMockHelper { +class EpoetryTranslationMockHelper { /** * The PHPUnit test database prefix. @@ -77,15 +76,42 @@ public static function translateRequest(TranslationRequestRemoteInterface $reque /** * Recursively sets translated data to field values. * + * @todo refactor to reuse the logic from TestRemoteTranslationMockHelper. + * * @param array $data * The data. * @param string $langcode * The langcode. * @param string|null $suffix * An extra suffix to append to the translation. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected static function translateFieldData(array &$data, string $langcode, ?string $suffix = NULL): void { - parent::translateFieldData($data, $langcode, $suffix); + if (!isset($data['#text'])) { + foreach ($data as $field => &$info) { + if (!is_array($info)) { + continue; + } + static::translateFieldData($info, $langcode, $suffix); + } + + return; + } + + if (isset($data['#translate']) && $data['#translate'] === FALSE) { + return; + } + + // Check whether this is a new translation or not by checking for a + // stored translation for the field. + if (isset($data['#translation'])) { + $data['#translation']['#text'] = $data['#translation']['#text'] . ' OVERRIDDEN'; + return; + } + + $append = $suffix ? $langcode . ' - ' . $suffix : $langcode; + $data['#translation']['#text'] = $data['#text'] . ' - ' . $append; // Set the translation value onto the original. if (isset($data['#translation']['#text']) && $data['#translation']['#text'] != "") { @@ -169,14 +195,28 @@ public static function notifyRequest(TranslationRequestEpoetry $request, array $ */ protected static function performNotification(string $notification): void { $url = Url::fromRoute('oe_translation_epoetry.notifications_endpoint')->setAbsolute()->toString(); + $config = \Drupal::config('oe_translation_epoetry_mock.settings'); + $notifications_endpoint = $config->get('notifications_endpoint'); + if ($notifications_endpoint && $notifications_endpoint !== '') { + $url = $notifications_endpoint; + } if (Settings::get('epoetry_notifications_endpoint')) { $url = Settings::get('epoetry_notifications_endpoint'); } - $client = new \SoapClient(NULL, [ + + $options = [ 'cache_wsdl' => WSDL_CACHE_NONE, 'location' => $url, 'uri' => 'http://eu.europa.ec.dgt.epoetry', - ]); + ]; + $username = $config->get('notifications_username'); + $password = $config->get('notifications_password'); + if ($username && $password && $username != "" && $password != "") { + $options['login'] = $username; + $options['password'] = $password; + } + + $client = new \SoapClient(NULL, $options); if (static::$databasePrefix) { $client->__setCookie('SIMPLETEST_USER_AGENT', drupal_generate_test_ua(static::$databasePrefix)); diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Form/MockSettings.php b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Form/MockSettings.php new file mode 100644 index 00000000..ccef4215 --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/Form/MockSettings.php @@ -0,0 +1,85 @@ + 'textfield', + '#maxlength' => 1000, + '#title' => $this->t('Endpoint'), + '#default_value' => $this->config('oe_translation_epoetry_mock.settings')->get('endpoint'), + ]; + + $form['notifications_endpoint'] = [ + '#type' => 'textfield', + '#maxlength' => 1000, + '#title' => $this->t('Notifications endpoint'), + '#default_value' => $this->config('oe_translation_epoetry_mock.settings')->get('notifications_endpoint'), + ]; + + $form['notifications_username'] = [ + '#type' => 'textfield', + '#title' => $this->t('Notifications username'), + '#default_value' => $this->config('oe_translation_epoetry_mock.settings')->get('notifications_username'), + ]; + + $form['notifications_password'] = [ + '#type' => 'textfield', + '#title' => $this->t('Notifications password'), + '#default_value' => $this->config('oe_translation_epoetry_mock.settings')->get('notifications_password'), + ]; + + $form['application_name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Application'), + '#default_value' => $this->config('oe_translation_epoetry_mock.settings')->get('application_name'), + ]; + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->config('oe_translation_epoetry_mock.settings') + ->set('endpoint', $form_state->getValue('endpoint')) + ->set('application_name', $form_state->getValue('application_name')) + ->set('notifications_endpoint', $form_state->getValue('notifications_endpoint')) + ->set('notifications_username', $form_state->getValue('notifications_username')) + ->set('notifications_password', $form_state->getValue('notifications_password')) + ->save(); + parent::submitForm($form, $form_state); + } + +} diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/MockRequestFactory.php b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/MockRequestFactory.php new file mode 100644 index 00000000..6985e81d --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/MockRequestFactory.php @@ -0,0 +1,32 @@ +get('endpoint'); + return $endpoint && $endpoint !== '' ? $endpoint : parent::getEpoetryServiceUrl(); + } + + /** + * {@inheritdoc} + */ + public static function getEpoetryApplicationName(): ?string { + $config = \Drupal::config('oe_translation_epoetry_mock.settings'); + $application_name = $config->get('application_name'); + return $application_name && $application_name !== '' ? $application_name : parent::getEpoetryApplicationName(); + } + +} diff --git a/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/OeTranslationEpoetryMockServiceProvider.php b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/OeTranslationEpoetryMockServiceProvider.php new file mode 100644 index 00000000..0e5fab9c --- /dev/null +++ b/modules/oe_translation_epoetry/modules/oe_translation_epoetry_mock/src/OeTranslationEpoetryMockServiceProvider.php @@ -0,0 +1,25 @@ +hasDefinition('oe_translation_epoetry.request_factory')) { + $definition = $container->getDefinition('oe_translation_epoetry.request_factory'); + $definition->setClass(MockRequestFactory::class); + } + } + +} diff --git a/modules/oe_translation_epoetry/oe_translation_epoetry.routing.yml b/modules/oe_translation_epoetry/oe_translation_epoetry.routing.yml index eb117ffa..fc94c3c6 100644 --- a/modules/oe_translation_epoetry/oe_translation_epoetry.routing.yml +++ b/modules/oe_translation_epoetry/oe_translation_epoetry.routing.yml @@ -30,3 +30,14 @@ oe_translation_epoetry.notifications_endpoint: _controller: Drupal\oe_translation_epoetry\Controller\EpoetryController::notifications requirements: _permission: 'access content' + +oe_translation_epoetry.failed_to_finished: + path: '/translation-request/epoetry/failed-to-finish/{translation_request}' + defaults: + _controller: Drupal\oe_translation_epoetry\Controller\EpoetryController::finishFailedRequest + requirements: + _custom_access: Drupal\oe_translation_epoetry\Controller\EpoetryController::finishFailedRequestAccess + options: + parameters: + translation_request: + type: entity:oe_translation_request diff --git a/modules/oe_translation_epoetry/oe_translation_epoetry.services.yml b/modules/oe_translation_epoetry/oe_translation_epoetry.services.yml index 1cf07e13..c3ca1243 100644 --- a/modules/oe_translation_epoetry/oe_translation_epoetry.services.yml +++ b/modules/oe_translation_epoetry/oe_translation_epoetry.services.yml @@ -13,3 +13,7 @@ services: arguments: ['@entity_type.manager', '@oe_translation_epoetry.html_formatter', '@language_manager', '@logger.factory'] tags: - { name: event_subscriber } + oe_translation_epoetry.event_subscriber.operations_provider: + class: Drupal\oe_translation_epoetry\EventSubscriber\TranslationRequestOperationsProviderSubscriber + tags: + - { name: event_subscriber } diff --git a/modules/oe_translation_epoetry/src/Controller/EpoetryController.php b/modules/oe_translation_epoetry/src/Controller/EpoetryController.php index 13df2145..0de7e4f0 100644 --- a/modules/oe_translation_epoetry/src/Controller/EpoetryController.php +++ b/modules/oe_translation_epoetry/src/Controller/EpoetryController.php @@ -13,13 +13,16 @@ use Drupal\oe_translation_epoetry\EpoetryOngoingNewVersionRequestHandlerInterface; use Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface; use Http\Discovery\Psr17Factory; +use Drupal\oe_translation_remote\TranslationRequestRemoteInterface; use OpenEuropa\EPoetry\NotificationServerFactory; use OpenEuropa\EPoetry\Serializer\Serializer; use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Controller for ePoetry routes. @@ -74,6 +77,57 @@ public function notifications(Request $request): Response { return $http_foundation_factory->createResponse($response); } + /** + * Route for marking a failed request as finished. + * + * @param \Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface $translation_request + * The translation request. + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request. + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse + * A redirect response. + */ + public function finishFailedRequest(TranslationRequestEpoetryInterface $translation_request, Request $request): RedirectResponse { + $translation_request->setRequestStatus(TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED); + $translation_request->save(); + + $destination = $request->query->get('destination'); + if (!$destination) { + throw new NotFoundHttpException(); + } + + return new RedirectResponse($destination); + } + + /** + * Checks access to the finishFailedRequest route. + * + * @param \Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface $translation_request + * The translation request. + * @param \Drupal\Core\Session\AccountInterface $account + * The user account. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function finishFailedRequestAccess(TranslationRequestEpoetryInterface $translation_request, AccountInterface $account): AccessResultInterface { + $cache = new CacheableMetadata(); + $cache->addCacheContexts(['user.permissions']); + $cache->addCacheableDependency($translation_request); + + if (!$account->hasPermission('translate any entity')) { + return AccessResult::forbidden()->addCacheableDependency($cache); + } + + // Only failed requests can be marked. + if ($translation_request->getRequestStatus() !== TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED) { + return AccessResult::forbidden()->addCacheableDependency($cache); + } + + return AccessResult::allowed(); + } + /** * Access callback for the createNewVersion request. * diff --git a/modules/oe_translation_epoetry/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php b/modules/oe_translation_epoetry/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php new file mode 100644 index 00000000..15bf7853 --- /dev/null +++ b/modules/oe_translation_epoetry/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php @@ -0,0 +1,53 @@ + 'addOperations']; + } + + /** + * Adds the local translations operations. + * + * @param \Drupal\oe_translation\Event\TranslationRequestOperationsProviderEvent $event + * The event. + */ + public function addOperations(TranslationRequestOperationsProviderEvent $event) { + $request = $event->getRequest(); + if ($request->bundle() !== 'epoetry') { + return; + } + + $links = $event->getOperations(); + + $cache = CacheableMetadata::createFromRenderArray($links); + $url = Url::fromRoute('oe_translation_epoetry.failed_to_finished', ['translation_request' => $request->id()], ['query' => ['destination' => Url::fromRoute('')->toString()]]); + $access = $url->access(NULL, TRUE); + $cache->addCacheableDependency($access); + if ($access->isAllowed()) { + $links['#links']['edit'] = [ + 'title' => t('Mark as finished'), + 'url' => $url, + ]; + } + + $cache->applyTo($links); + $event->setOperations($links); + } + +} diff --git a/modules/oe_translation_epoetry/src/MockAuthentication.php b/modules/oe_translation_epoetry/src/MockAuthentication.php new file mode 100644 index 00000000..9cd6d7f5 --- /dev/null +++ b/modules/oe_translation_epoetry/src/MockAuthentication.php @@ -0,0 +1,35 @@ +ticket = $ticket; + } + + /** + * {@inheritdoc} + */ + public function getTicket(): string { + return $this->ticket; + } + +} diff --git a/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php b/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php index 4be49c20..751c79c7 100644 --- a/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php +++ b/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php @@ -11,6 +11,7 @@ use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\State\StateInterface; +use Drupal\oe_translation\Entity\TranslationRequestLogInterface; use Drupal\oe_translation\TranslationSourceManagerInterface; use Drupal\oe_translation_epoetry\Plugin\Field\FieldType\ContactItem; use Drupal\oe_translation_epoetry\Plugin\Field\FieldType\ContactItemInterface; @@ -89,6 +90,19 @@ public function defaultConfiguration() { ] + parent::defaultConfiguration(); } + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + $default_configuration = $this->defaultConfiguration(); + // Only include configuration that is defined in the default configuration + // array. + $configuration = array_filter($configuration, function ($value, $key) use ($default_configuration) { + return isset($default_configuration[$key]); + }, ARRAY_FILTER_USE_BOTH); + $this->configuration = $configuration + $default_configuration; + } + /** * {@inheritdoc} */ @@ -132,6 +146,36 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#default_value' => $this->configuration['auto_accept'], ]; + $form['dossiers_wrapper'] = [ + '#type' => 'fieldset', + '#title' => $this->t('ePoetry dossiers'), + ]; + $form['dossiers_wrapper']['dossiers'] = [ + '#theme' => 'item_list', + '#items' => [], + ]; + + $dossiers = array_reverse(RequestFactory::getEpoetryDossiers(), TRUE); + $i = 1; + foreach ($dossiers as $number => $dossier) { + $form['dossiers_wrapper']['dossiers']['#items'][] = new FormattableMarkup('@current Number @number / Code @code / Year @year / Part @part @reset', [ + '@number' => $number, + '@code' => $dossier['code'], + '@year' => $dossier['year'], + '@part' => $dossier['part'], + '@current' => $i == 1 ? '[CURRENT]' : '', + '@reset' => $i == 1 && isset($dossier['reset']) ? '[SET TO RESET]' : '', + ]); + + $i++; + } + + $form['dossiers_wrapper']['reset'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Reset current dossier'), + '#description' => $this->t('Check this box and save if you would like to reset the current dossier so that the next request generates a new dossier.'), + ]; + return $form; } @@ -153,6 +197,15 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s $this->configuration['auto_accept'] = (bool) $form_state->getValue('auto_accept'); $this->configuration['title_prefix'] = $form_state->getValue('title_prefix'); $this->configuration['site_id'] = $form_state->getValue('site_id'); + + $reset_dossier = (bool) $form_state->getValue(['dossiers_wrapper', 'reset']); + if ($reset_dossier) { + $dossiers = array_reverse(RequestFactory::getEpoetryDossiers(), TRUE); + $number = key($dossiers); + $dossier = &$dossiers[$number]; + $dossier['reset'] = TRUE; + RequestFactory::setEpoetryDossiers($dossiers); + } } /** @@ -315,10 +368,9 @@ public function submitRequestToProvider(array &$form, FormStateInterface $form_s $this->createAndSendRequestObject($request, $form, $form_state); } catch (\Throwable $exception) { - // @todo handle error in - // https://citnet.tech.ec.europa.eu/CITnet/jira/browse/EWPP-3037. $request->setRequestStatus(TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED); $this->messenger->addError($this->t('There was a problem sending the request to ePoetry.')); + $request->log('There was a problem with this request: @message', ['@message' => $exception->getMessage()], TranslationRequestLogInterface::ERROR); } $request->save(); } @@ -350,13 +402,14 @@ public function submitRequestToProvider(array &$form, FormStateInterface $form_s */ protected function createAndSendRequestObject(TranslationRequestEpoetryInterface $request, array $form, FormStateInterface $form_state): void { $last_request = $form_state->get('epoetry_last_request'); - if (!$last_request instanceof TranslationRequestEpoetryInterface) { + if (!$last_request instanceof TranslationRequestEpoetryInterface || $this->dossierResetNeeded()) { $dossiers = RequestFactory::getEpoetryDossiers(); // If we are not making a new version request, we need to check if // we have a number set in the system, we need to add a new part // the existing dossier for any new nodes. This is because that is how - // ePoetry expects we send requests. - if ($this->newPartNeeded($request, $form, $form_state)) { + // ePoetry expects we send requests. Of course, if we don't need to reset + // the dossier. + if ($this->newPartNeeded($request, $form, $form_state) && !$this->dossierResetNeeded()) { $object = $this->requestFactory->addNewPartToDossierRequest($request); $response = $this->requestFactory->getRequestClient()->addNewPartToDossier($object); // If we made an addPartToDossier request, we need to increment the @@ -388,9 +441,9 @@ protected function createAndSendRequestObject(TranslationRequestEpoetryInterface } } else { - // If we are doing with an existing translation request, we need to check - // if it was rejected, because if it was, we need to use resubmitRequest - // instead of createNewVersion. + // If we are dealing with an existing translation request, we need to + // check if it was rejected, because if it was, we need to use + // resubmitRequest instead of createNewVersion. if ($last_request->getEpoetryRequestStatus() !== TranslationRequestEpoetryInterface::STATUS_REQUEST_REJECTED) { $object = $this->requestFactory->createNewVersionRequest($request, $last_request); $response = $this->requestFactory->getRequestClient()->createNewVersion($object); @@ -447,9 +500,9 @@ protected function newPartNeeded(TranslationRequestEpoetryInterface $request, ar } $dossiers = array_reverse($dossiers, TRUE); + $dossier = current($dossiers); // We check the last number and if it's corresponding last part is 30, // we reset. - $dossier = current($dossiers); // Before returning, set the reference values onto the request so we can // use in the RequestFactory. $request->setRequestId([ @@ -463,6 +516,27 @@ protected function newPartNeeded(TranslationRequestEpoetryInterface $request, ar return $dossier['part'] < 30; } + /** + * Checks if we need to reset the current dossier. + * + * This happens when an admin edits the poetry translator and indicates that + * the current dossier needs to be reset so that the immediate next request + * because a createLinguisticRequest. + * + * @return bool + * Whether to reset the current dossier. + */ + protected function dossierResetNeeded(): bool { + $dossiers = RequestFactory::getEpoetryDossiers(); + if (empty($dossiers)) { + return FALSE; + } + + $dossiers = array_reverse($dossiers, TRUE); + $dossier = current($dossiers); + return isset($dossier['reset']); + } + /** * Returns the request ID array from a given linguistic request response. * @@ -494,9 +568,6 @@ public static function requestIdFromResponse(LinguisticRequestOut $linguistic_re /** * Returns the last translation requested sent for this entity. * - * In the query, we don't look for the status because at this point, we have - * already checked that there is nothing ongoing. - * * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * @@ -509,6 +580,13 @@ protected function getLastRequest(ContentEntityInterface $entity): ?TranslationR ->condition('content_entity__entity_type', $entity->getEntityTypeId()) ->condition('content_entity__entity_id', $entity->id()) ->condition('bundle', 'epoetry') + // Filter out the requests which have failed because those don't have + // any request IDs. Other statuses we don't need to include as by this + // point we already checked there is nothing ongoing. + ->condition('request_status', [ + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, + ], 'NOT IN') ->sort('id', 'DESC') ->range(0, 1) ->execute(); diff --git a/modules/oe_translation_epoetry/src/RequestFactory.php b/modules/oe_translation_epoetry/src/RequestFactory.php index f41d232d..9837067f 100644 --- a/modules/oe_translation_epoetry/src/RequestFactory.php +++ b/modules/oe_translation_epoetry/src/RequestFactory.php @@ -10,6 +10,7 @@ use Drupal\oe_translation_epoetry\ContentFormatter\ContentFormatterInterface; use GuzzleHttp\ClientInterface; use Http\Adapter\Guzzle7\Client; +use OpenEuropa\EPoetry\Authentication\AuthenticationInterface; use OpenEuropa\EPoetry\Request\Type\AddNewPartToDossier; use OpenEuropa\EPoetry\Request\Type\ContactPersonIn; use OpenEuropa\EPoetry\Request\Type\Contacts; @@ -30,7 +31,6 @@ use OpenEuropa\EPoetry\Request\Type\RequestReferenceIn; use OpenEuropa\EPoetry\Request\Type\ResubmitRequest; use OpenEuropa\EPoetry\RequestClientFactory; -use OpenEuropa\EPoetry\Tests\Authentication\MockAuthentication; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -69,8 +69,7 @@ public function __construct(EventDispatcherInterface $eventDispatcher, LoggerCha // @todo handle failure. } - // @todo provide authentication mechanism. - $authentication = new MockAuthentication('ticket'); + $authentication = $this->getAuthentication(); $http_client = new Client($guzzle); parent::__construct($endpoint, $authentication, $eventDispatcher, $logger, $http_client); } @@ -101,10 +100,11 @@ public static function getEpoetryApplicationName(): ?string { * These are the State-stored dossier values for all the ePoetry requests * that have been made on the current site. * - * @return string|null + * @return array * The ePoetry dossiers. */ - public static function getEpoetryDossiers(): ?array { + public static function getEpoetryDossiers(): array { + \Drupal::state()->resetCache(); return \Drupal::state()->get('oe_translation_epoetry.dossiers', []); } @@ -143,7 +143,7 @@ public function createLinguisticRequest(TranslationRequestEpoetryInterface $requ } /** - * Creates a resubmitRequest from a rejected our ePoetry translation request. + * Creates a resubmitRequest from a rejected ePoetry translation request. * * @param \Drupal\oe_translation_epoetry\TranslationRequestEpoetryInterface $request * The ePoetry translation request entity. @@ -271,9 +271,12 @@ protected function toRequestDetails(TranslationRequestEpoetryInterface $request) ]))->__toString(); $request_details = new RequestDetailsIn(); + $deadline = $request->getDeadline()->getPhpDateTime(); + // Set the end of the day in case the user picks today. + $deadline->setTime(23, 59, 00); $request_details ->setTitle($request_title) - ->setRequestedDeadline($request->getDeadline()->getPhpDateTime()) + ->setRequestedDeadline($deadline) ->setInternalReference('Translation request ' . $request->id()); $contacts = new Contacts(); @@ -303,7 +306,7 @@ protected function toRequestDetails(TranslationRequestEpoetryInterface $request) $productRequestIn = (new ProductRequestIn()) // @todo fix the language mapping. ->setLanguage($language_with_status->getLangcode()) - ->setRequestedDeadline($request->getDeadline()->getPhpDateTime()) + ->setRequestedDeadline($deadline) ->setTrackChanges(FALSE); $products->addProduct($productRequestIn); } @@ -347,4 +350,15 @@ protected function toRequestReference(TranslationRequestEpoetryInterface $reques return $reference; } + /** + * Returns the authentication object. + * + * @return \OpenEuropa\EPoetry\Authentication\AuthenticationInterface + * The authentication object. + */ + protected function getAuthentication(): AuthenticationInterface { + // @todo provide authentication mechanism. + return new MockAuthentication('ticket'); + } + } diff --git a/modules/oe_translation_epoetry/tests/src/FunctionalJavascript/EpoetryTranslationTest.php b/modules/oe_translation_epoetry/tests/src/FunctionalJavascript/EpoetryTranslationTest.php index d9df83a6..e3819ab4 100644 --- a/modules/oe_translation_epoetry/tests/src/FunctionalJavascript/EpoetryTranslationTest.php +++ b/modules/oe_translation_epoetry/tests/src/FunctionalJavascript/EpoetryTranslationTest.php @@ -276,7 +276,7 @@ public function testEpoetrySingleTranslationFlow(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(1, $requests); $xml = reset($requests); - $this->assertEquals('ticketA title prefix: A site ID - Basic translation nodeTranslation request 12032-10-10T12:00:00+00:00PUBLICNEANTNOMessage to the providerCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-nodePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMSIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDE8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0xIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzFdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTVYxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsebgfrdigitWEBTRA', $xml); + $this->assertEquals('ticketA title prefix: A site ID - Basic translation nodeTranslation request 12032-10-10T23:59:00+00:00PUBLICNEANTNOMessage to the providerCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-nodePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMSIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDE8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0xIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzFdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTVYxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsebgfrdigitWEBTRA', $xml); // Assert that we got back a correct response and our request was correctly // updated. @@ -488,7 +488,7 @@ public function testsAddPartsTranslationFlow(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(1, $requests); $xml = reset($requests); - $this->assertEquals('ticketDIGIT20002023A title prefix: A site ID - Basic translation nodeTranslation request 22032-10-10T12:00:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-0PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsefrdigitWEBTRA', $xml); + $this->assertEquals('ticketDIGIT20002023A title prefix: A site ID - Basic translation nodeTranslation request 22032-10-10T23:59:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-0PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsefrdigitWEBTRA', $xml); // Assert that the state dossier got updated correctly. $dossiers = RequestFactory::getEpoetryDossiers(); @@ -535,7 +535,7 @@ public function testsAddPartsTranslationFlow(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(2, $requests); $xml = end($requests); - $this->assertEquals('ticketDIGIT20002023A title prefix: A site ID - Basic translation nodeTranslation request 32032-10-10T12:00:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-1PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMyIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDM8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0zIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzNdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTTExYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsededigitWEBTRA', $xml); + $this->assertEquals('ticketDIGIT20002023A title prefix: A site ID - Basic translation nodeTranslation request 32032-10-10T23:59:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-1PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMyIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDM8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0zIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzNdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTTExYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsededigitWEBTRA', $xml); $dossiers = RequestFactory::getEpoetryDossiers(); $this->assertEquals([ 2000 => [ @@ -574,7 +574,7 @@ public function testsAddPartsTranslationFlow(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(3, $requests); $xml = end($requests); - $this->assertEquals('ticketA title prefix: A site ID - Basic translation nodeTranslation request 42032-10-10T12:00:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-2PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iNCIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDQ8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS00Ij4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzRdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTkYxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalseitdigitWEBTRA', $xml); + $this->assertEquals('ticketA title prefix: A site ID - Basic translation nodeTranslation request 42032-10-10T23:59:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-node-2PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iNCIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDQ8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS00Ij4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzRdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTkYxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalseitdigitWEBTRA', $xml); $dossiers = RequestFactory::getEpoetryDossiers(); $this->assertEquals([ @@ -648,7 +648,7 @@ public function testEpoetryNewVersionRequest(): void { $this->assertCount(1, $requests); $xml = reset($requests); $year = date('Y'); - $this->assertEquals('ticketDIGIT2000' . $year . 'TRA0A title prefix: A site ID - Basic translation node - updateTranslation request 22034-10-10T12:00:00+00:00PUBLICNEANTNOSome message to the providerCONTACTSBasic-translation-node---update.htmlhttp://web:8080/build/en/basic-translation-node-updatePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlIC0gdXBkYXRlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsedeitdigit', $xml); + $this->assertEquals('ticketDIGIT2000' . $year . 'TRA0A title prefix: A site ID - Basic translation node - updateTranslation request 22034-10-10T23:59:00+00:00PUBLICNEANTNOSome message to the providerCONTACTSBasic-translation-node---update.htmlhttp://web:8080/build/en/basic-translation-node-updatePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlIC0gdXBkYXRlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsedeitdigit', $xml); // Assert that we got back a correct response and our request was correctly // updated. $requests = \Drupal::service('plugin.manager.oe_translation_remote.remote_translation_provider_manager')->getExistingTranslationRequests($node, TRUE); @@ -917,7 +917,7 @@ public function testOngoingCreateVersion(): void { $this->assertCount(1, $requests); $xml = reset($requests); $year = date('Y'); - $this->assertEquals('ticketDIGIT2000' . $year . 'TRA0A title prefix: A site ID - Basic translation node - updateTranslation request 22034-10-10T12:00:00+00:00PUBLICNEANTNOSome message to the providerCONTACTSBasic-translation-node---update.htmlhttp://web:8080/build/en/basic-translation-node-updatePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlIC0gdXBkYXRlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsebgdeitdigit', $xml); + $this->assertEquals('ticketDIGIT2000' . $year . 'TRA0A title prefix: A site ID - Basic translation node - updateTranslation request 22034-10-10T23:59:00+00:00PUBLICNEANTNOSome message to the providerCONTACTSBasic-translation-node---update.htmlhttp://web:8080/build/en/basic-translation-node-updatePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMiIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDI8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0yIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzJdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTWwxYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlIC0gdXBkYXRlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsebgdeitdigit', $xml); // Assert that we got back a correct response and our request was correctly // updated. @@ -1284,7 +1284,7 @@ public function testModifyLinguisticRequest(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(1, $requests); $xml = reset($requests); - $this->assertEquals('ticketDIGIT20002023TRA0dedigit', $xml); + $this->assertEquals('ticketDIGIT20002023TRA0dedigit', $xml); // Assert the logs. This set of logs is missing the initial ones because // we created the request programatically. @@ -1487,8 +1487,8 @@ public function testResubmitRejectedRequests(): void { ]); $request->save(); - // Go to the remote translation dashboard and assert we have the active - // request we cannot make a new request, as expected under the normal + // Go to the remote translation dashboard and assert that while we have an + // active request, we cannot make a new one, as expected under the normal // flow. $this->drupalGet($node->toUrl('drupal:content-translation-overview')); $this->clickLink('Remote translations'); @@ -1501,7 +1501,7 @@ public function testResubmitRejectedRequests(): void { 'No', '2035-Oct-10', 'N/A', - // The mock link tu accept the request. + // The mock link to accept the request. 'Accept', ]); $this->assertSession()->fieldDisabled('Translator'); @@ -1564,7 +1564,7 @@ public function testResubmitRejectedRequests(): void { $requests = \Drupal::state()->get('oe_translation_epoetry_mock.mock_requests'); $this->assertCount(1, $requests); $xml = reset($requests); - $this->assertEquals('ticketDIGIT2000' . date('Y') . 'TRA0A title prefix: A site ID - Basic translation nodeTranslation request 32032-10-10T12:00:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-nodePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMyIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDM8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0zIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzNdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTTExYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsefrdigitWEBTRA', $xml); + $this->assertEquals('ticketDIGIT2000' . date('Y') . 'TRA0A title prefix: A site ID - Basic translation nodeTranslation request 32032-10-10T23:59:00+00:00PUBLICNEANTNOCONTACTSBasic-translation-node.htmlhttp://web:8080/build/en/basic-translation-nodePD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+CiAgPGhlYWQ+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KICAgIDxtZXRhIG5hbWU9InJlcXVlc3RJZCIgY29udGVudD0iMyIgLz4KICAgIDxtZXRhIG5hbWU9Imxhbmd1YWdlU291cmNlIiBjb250ZW50PSJlbiIgLz4KICAgIDx0aXRsZT5SZXF1ZXN0IElEIDM8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImFzc2V0IiBpZD0iaXRlbS0zIj4KICAgICAgICAgICAgICAgICAgPCEtLQogICAgICAgICAgbGFiZWw9IlRpdGxlIgogICAgICAgICAgY29udGV4dD0iWzNdW3RpdGxlXVswXVt2YWx1ZV0iCiAgICAgICAgICAtLT4KICAgICAgICAgIDxkaXYgY2xhc3M9ImF0b20iIGlkPSJiTTExYmRHbDBiR1ZkV3pCZFczWmhiSFZsIj5CYXNpYyB0cmFuc2xhdGlvbiBub2RlPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CiAgICAgIDwvYm9keT4KPC9odG1sPgo=ENfalsefrdigitWEBTRA', $xml); // Assert that we got back a correct response and our request was correctly // updated. @@ -1596,13 +1596,13 @@ public function testResubmitRejectedRequests(): void { 'Active', 'ePoetry', 'SenttoDGT', - // The ID is the same as the previous was rejected. + // The ID is the same as the previous was rejected. 'DIGIT/' . date('Y') . '/2000/0/0/TRA', 'No', 'No', '2032-Oct-10', 'N/A', - // The mock link tu accept the request. + // The mock link to accept the request. 'Accept', ]); @@ -1619,6 +1619,268 @@ public function testResubmitRejectedRequests(): void { $this->assertLogMessagesTable($expected_logs); } + /** + * Tests the case when a request crashes or fails. + */ + public function testFailedRequest(): void { + // Create a node and mimic it having been translated via ePoetry. This is + // so that we have a request already in the system that went through and we + // can run assertions about messaging and stuff about past requests. + $node = $this->createBasicTestNode(); + $node->addTranslation('fr', ['title' => 'Basic translation node fr'] + $node->toArray()); + $node->setNewRevision(FALSE); + $node->save(); + $request = $this->createNodeTranslationRequest($node, TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, [ + [ + 'langcode' => 'fr', + 'status' => TranslationRequestEpoetryInterface::STATUS_LANGUAGE_SYNCHRONISED, + ], + ]); + $request->save(); + + // Make a new draft of the node and start a new translation. + $node->set('title', 'Basic translation node - update'); + $node->setNewRevision(TRUE); + $node->save(); + + // Create a node and make an ePoetry request that fails. + \Drupal::state()->set('oe_translation_epoetry_mock_response_error', [ + 'code' => 'ns0:Server', + 'string' => 'There was an error in your request.', + ]); + $this->drupalGet($node->toUrl('drupal:content-translation-overview')); + $this->clickLink('Remote translations'); + $select = $this->assertSession()->selectExists('Translator'); + $select->selectOption('epoetry'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->assertSession()->pageTextContains(sprintf('You are making a request for a new version. The previous version was translated with the %s request ID.', $request->getRequestId(TRUE))); + $this->getSession()->getPage()->checkField('Bulgarian'); + $this->getSession()->getPage()->fillField('translator_configuration[epoetry][deadline][0][value][date]', '10/10/2032'); + $contact_fields = [ + 'Recipient' => 'test_recipient', + 'Webmaster' => 'test_webmaster', + 'Editor' => 'test_editor', + ]; + foreach ($contact_fields as $field => $value) { + $this->getSession()->getPage()->fillField($field, $value); + } + $this->getSession()->getPage()->fillField('Message', 'Message to the provider'); + $this->getSession()->getPage()->pressButton('Save and send'); + + $this->assertSession()->pageTextContains('There was a problem sending the request to ePoetry.'); + + // We have a failed request so no new translations can be made until the + // user dispenses with this request by marking it as finished. + $this->assertSession()->fieldDisabled('Translator'); + + $this->assertRequestStatusTable([ + 'Failed', + 'ePoetry', + // No epoetry status. + '', + // No ID. + '', + 'No', + 'No', + '2032-Oct-10', + 'N/A', + ]); + + $expected_logs = [ + 1 => [ + 'Error', + 'There was a problem with this request: There was an error in your request.', + ], + ]; + $this->assertLogMessagesTable($expected_logs); + + // Go to the dashboard and mark the request as Failed & Finished. + $this->clickLink('Dashboard'); + $this->assertSession()->pageTextNotContains('There are no ongoing remote translation requests'); + $expected_ongoing = [ + 'translator' => 'ePoetry', + 'status' => 'Failed', + 'title' => 'Basic translation node', + 'title_url' => $node->toUrl()->toString(), + 'revision' => $node->getRevisionId(), + 'is_default' => 'Yes', + ]; + $this->assertOngoingTranslations([$expected_ongoing]); + $this->getSession()->getPage()->pressButton('List additional actions'); + $this->clickLink('Mark as finished'); + $this->assertSession()->addressEquals('/en/node/' . $node->id() . '/translations'); + $this->assertSession()->pageTextContains('There are no ongoing remote translation requests'); + $requests = TranslationRequest::loadMultiple(); + $this->assertCount(2, $requests); + $request = end($requests); + $this->assertEquals(TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, $request->getRequestStatus()); + + // Go back to and create a request, this time going through. + \Drupal::state()->delete('oe_translation_epoetry_mock_response_error'); + $this->clickLink('Remote translations'); + $select->selectOption('epoetry'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $request = reset($requests); + $this->assertSession()->pageTextContains(sprintf('You are making a request for a new version. The previous version was translated with the %s request ID.', $request->getRequestId(TRUE))); + $this->getSession()->getPage()->checkField('Bulgarian'); + $this->getSession()->getPage()->fillField('translator_configuration[epoetry][deadline][0][value][date]', '10/10/2032'); + $contact_fields = [ + 'Recipient' => 'test_recipient', + 'Webmaster' => 'test_webmaster', + 'Editor' => 'test_editor', + ]; + foreach ($contact_fields as $field => $value) { + $this->getSession()->getPage()->fillField($field, $value); + } + $this->getSession()->getPage()->fillField('Message', 'Message to the provider'); + $this->getSession()->getPage()->pressButton('Save and send'); + + $this->assertSession()->pageTextContains('The translation request has been sent to ePoetry.'); + + // Assert that we got back a correct response and our request was correctly + // updated. + $requests = \Drupal::service('plugin.manager.oe_translation_remote.remote_translation_provider_manager')->getExistingTranslationRequests($node, TRUE); + // We can only find one ongoing request. + $this->assertCount(1, $requests); + $request = reset($requests); + $this->assertInstanceOf(TranslationRequestEpoetryInterface::class, $request); + $this->assertEquals('en', $request->getSourceLanguageCode()); + $target_languages = $request->getTargetLanguages(); + $this->assertEquals(new LanguageWithStatus('bg', 'Active'), $target_languages['bg']); + $this->assertEquals('Active', $request->getRequestStatus()); + $this->assertEquals('SenttoDGT', $request->getEpoetryRequestStatus()); + $this->assertEquals('epoetry', $request->getTranslatorProvider()->id()); + $this->assertNull($request->getAcceptedDeadline()); + $this->assertFalse($request->isAutoAccept()); + $this->assertFalse($request->isAutoSync()); + $this->assertEquals('2032-10-10', $request->getDeadline()->format('Y-m-d')); + $this->assertEquals('Message to the provider', $request->getMessage()); + $this->assertEquals('DIGIT/' . date('Y') . '/2000/1/0/TRA', $request->getRequestId(TRUE)); + $this->assertEquals([ + 'Recipient' => 'test_recipient', + 'Webmaster' => 'test_webmaster', + 'Editor' => 'test_editor', + ], $request->getContacts()); + + // Assert the request status table. + $this->assertRequestStatusTable([ + 'Active', + 'ePoetry', + 'SenttoDGT', + 'DIGIT/' . date('Y') . '/2000/1/0/TRA', + 'No', + 'No', + '2032-Oct-10', + 'N/A', + // The mock link tu accept the request. + 'Accept', + ]); + } + + /** + * Tests the resetting of the current dossier to force a new dossier creation. + */ + public function testResetDossier(): void { + // Create a node and make a new translation request for it. This will + // start a dossier. + $node = $this->createBasicTestNode(); + $this->drupalGet($node->toUrl('drupal:content-translation-overview')); + $this->clickLink('Remote translations'); + $select = $this->assertSession()->selectExists('Translator'); + $select->selectOption('epoetry'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->getSession()->getPage()->checkField('Bulgarian'); + $this->getSession()->getPage()->fillField('translator_configuration[epoetry][deadline][0][value][date]', '10/10/2032'); + $contact_fields = [ + 'Recipient' => 'test_recipient', + 'Webmaster' => 'test_webmaster', + 'Editor' => 'test_editor', + ]; + foreach ($contact_fields as $field => $value) { + $this->getSession()->getPage()->fillField($field, $value); + } + $this->getSession()->getPage()->fillField('Message', 'Message to the provider'); + $this->getSession()->getPage()->pressButton('Save and send'); + $this->assertSession()->pageTextContains('The translation request has been sent to ePoetry.'); + + // Accept and translate. + $requests = \Drupal::service('plugin.manager.oe_translation_remote.remote_translation_provider_manager')->getExistingTranslationRequests($node, TRUE); + $request = reset($requests); + EpoetryTranslationMockHelper::$databasePrefix = $this->databasePrefix; + EpoetryTranslationMockHelper::notifyRequest($request, [ + 'type' => 'RequestStatusChange', + 'status' => 'Accepted', + ]); + EpoetryTranslationMockHelper::notifyRequest($request, [ + 'type' => 'ProductStatusChange', + 'status' => 'Accepted', + 'language' => 'bg', + ]); + EpoetryTranslationMockHelper::translateRequest($request, 'bg'); + + // Assert the created dossier. + $dossiers = RequestFactory::getEpoetryDossiers(); + $this->assertEquals([ + 1001 => [ + 'part' => 0, + 'code' => 'DIGIT', + 'year' => date('Y'), + ], + ], $dossiers); + + // Log in as an admin and go reset the dossier. + $user = $this->drupalCreateUser([ + 'administer site configuration', + 'access administration pages', + 'access toolbar', + ]); + $this->drupalLogin($user); + $this->drupalGet('/admin/structure/remote-translation-provider/epoetry/edit'); + $this->assertSession()->pageTextContains('[CURRENT] Number 1001 / Code DIGIT / Year ' . date('Y') . ' / Part 0'); + $this->assertSession()->pageTextNotContains('SET TO RESET'); + $this->getSession()->getPage()->checkField('Reset current dossier'); + $this->getSession()->getPage()->pressButton('Save'); + $this->drupalGet('/admin/structure/remote-translation-provider/epoetry/edit'); + $this->assertSession()->pageTextContains('[CURRENT] Number 1001 / Code DIGIT / Year ' . date('Y') . ' / Part 0 [SET TO RESET]'); + + // Now create a new request and assert the dossier has been reset and a + // createLinguisticRequest request is made. + $user = $this->setUpTranslatorUser(); + $this->drupalLogin($user); + $this->drupalGet($node->toUrl('drupal:content-translation-overview')); + $this->clickLink('Remote translations'); + $select->selectOption('epoetry'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->getSession()->getPage()->checkField('Bulgarian'); + $this->getSession()->getPage()->fillField('translator_configuration[epoetry][deadline][0][value][date]', '10/10/2032'); + $contact_fields = [ + 'Recipient' => 'test_recipient', + 'Webmaster' => 'test_webmaster', + 'Editor' => 'test_editor', + ]; + foreach ($contact_fields as $field => $value) { + $this->getSession()->getPage()->fillField($field, $value); + } + $this->getSession()->getPage()->fillField('Message', 'Message to the provider'); + $this->getSession()->getPage()->pressButton('Save and send'); + $this->assertSession()->pageTextContains('The translation request has been sent to ePoetry.'); + + $dossiers = RequestFactory::getEpoetryDossiers(); + $this->assertEquals([ + 1001 => [ + 'part' => 0, + 'code' => 'DIGIT', + 'year' => date('Y'), + 'reset' => TRUE, + ], + 1002 => [ + 'part' => 0, + 'code' => 'DIGIT', + 'year' => date('Y'), + ], + ], $dossiers); + } + /** * Asserts the log messages table output. * diff --git a/modules/oe_translation_remote/oe_translation_remote.module b/modules/oe_translation_remote/oe_translation_remote.module index b75ef153..5f0a2b66 100644 --- a/modules/oe_translation_remote/oe_translation_remote.module +++ b/modules/oe_translation_remote/oe_translation_remote.module @@ -40,6 +40,7 @@ function oe_translation_remote_entity_type_alter(array &$entity_types) { function oe_translation_remote_request_statuses(FieldStorageConfig $definition, ContentEntityInterface $entity = NULL, bool $cacheable): array { $options = [ TranslationRequestRemoteInterface::STATUS_REQUEST_ACTIVE => t('Active'), + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED => t('Failed & Finished'), TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED => t('Finished'), ]; @@ -191,9 +192,14 @@ function oe_translation_remote_oe_translation_request_view(array &$build, Entity $row['request_status'] = $entity->getRequestStatus(); $row['provider'] = $entity->getTranslatorProvider()->label(); + $classes = ['request-status-meta-table']; + if ($entity->getRequestStatus() === TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED) { + $classes[] = 'color-error'; + } + $build['meta'] = [ '#theme' => 'table', - '#attributes' => ['class' => ['request-status-meta-table']], + '#attributes' => ['class' => $classes], '#header' => $header, '#rows' => [$row], '#weight' => -100, diff --git a/modules/oe_translation_remote/src/EventSubscriber/TranslationDashboardAlterSubscriber.php b/modules/oe_translation_remote/src/EventSubscriber/TranslationDashboardAlterSubscriber.php index ecf6fd78..1ebc7a7c 100644 --- a/modules/oe_translation_remote/src/EventSubscriber/TranslationDashboardAlterSubscriber.php +++ b/modules/oe_translation_remote/src/EventSubscriber/TranslationDashboardAlterSubscriber.php @@ -9,6 +9,7 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\oe_translation\Event\ContentTranslationDashboardAlterEvent; use Drupal\oe_translation_remote\Plugin\RemoteTranslationProviderManager; +use Drupal\oe_translation_remote\TranslationRequestRemoteInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -120,6 +121,7 @@ public function alterDashboard(ContentTranslationDashboardAlterEvent $event) { $rows[] = [ 'data' => $row, 'data-revision-id' => $entity->getRevisionId(), + 'class' => $translation_request->getRequestStatus() === TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED ? ['color-error'] : [], ]; } diff --git a/modules/oe_translation_remote/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php b/modules/oe_translation_remote/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php index 020f7abd..9a13d3b4 100644 --- a/modules/oe_translation_remote/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php +++ b/modules/oe_translation_remote/src/EventSubscriber/TranslationRequestOperationsProviderSubscriber.php @@ -42,7 +42,7 @@ public static function getSubscribedEvents() { } /** - * Adds the local translations operations. + * Adds the view link to the operations. * * @param \Drupal\oe_translation\Event\TranslationRequestOperationsProviderEvent $event * The event. diff --git a/modules/oe_translation_remote/src/Form/RemoteTranslationNewForm.php b/modules/oe_translation_remote/src/Form/RemoteTranslationNewForm.php index 46a88074..06ca9406 100644 --- a/modules/oe_translation_remote/src/Form/RemoteTranslationNewForm.php +++ b/modules/oe_translation_remote/src/Form/RemoteTranslationNewForm.php @@ -366,7 +366,7 @@ protected function buildExistingRequestsForm(array $form, FormStateInterface $fo /** * Checks access to create a new translation request. * - * @param \Drupal\Core\Entity\ContentEntityInterface|null $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The current entity. * * @return \Drupal\Core\Access\AccessResultInterface @@ -386,6 +386,7 @@ protected function createNewRequestAccess(ContentEntityInterface $entity): Acces $statuses = [ TranslationRequestRemoteInterface::STATUS_REQUEST_TRANSLATED, TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, ]; $translation_requests = $this->providerManager->getExistingTranslationRequests($entity, FALSE, $statuses); $cache->addCacheTags(['oe_translation_request_list']); diff --git a/modules/oe_translation_remote/src/Form/RemoteTranslatorProviderForm.php b/modules/oe_translation_remote/src/Form/RemoteTranslatorProviderForm.php index 0b55a5d0..654c8858 100644 --- a/modules/oe_translation_remote/src/Form/RemoteTranslatorProviderForm.php +++ b/modules/oe_translation_remote/src/Form/RemoteTranslatorProviderForm.php @@ -174,6 +174,7 @@ public function buildEntity(array $form, FormStateInterface $form_state) { 'plugin_configuration', $plugin_id, ], []); + $plugin = $this->providerManager->createInstance($plugin_id, $plugin_configuration); if (isset($form['plugin_configuration'][$plugin_id])) { diff --git a/modules/oe_translation_remote/src/Plugin/RemoteTranslationProviderManager.php b/modules/oe_translation_remote/src/Plugin/RemoteTranslationProviderManager.php index d4c89b1c..6d4ce862 100644 --- a/modules/oe_translation_remote/src/Plugin/RemoteTranslationProviderManager.php +++ b/modules/oe_translation_remote/src/Plugin/RemoteTranslationProviderManager.php @@ -99,6 +99,7 @@ public function getExistingTranslationRequests(ContentEntityInterface $entity, b if (!$statuses) { $statuses = [ TranslationRequestRemoteInterface::STATUS_REQUEST_FINISHED, + TranslationRequestRemoteInterface::STATUS_REQUEST_FAILED_FINISHED, ]; } diff --git a/modules/oe_translation_remote/src/TranslationRequestRemoteInterface.php b/modules/oe_translation_remote/src/TranslationRequestRemoteInterface.php index b1d55dda..ecd4bd41 100644 --- a/modules/oe_translation_remote/src/TranslationRequestRemoteInterface.php +++ b/modules/oe_translation_remote/src/TranslationRequestRemoteInterface.php @@ -36,11 +36,14 @@ interface TranslationRequestRemoteInterface extends TranslationRequestInterface * job is done. * FINISHED: all the language translations have been synced. * FAILED: the request failed upon initial send. + * FAILED_FINISHED: the request failed upon initial send and was marked as + * finished. */ const STATUS_REQUEST_ACTIVE = 'Active'; const STATUS_REQUEST_TRANSLATED = 'Translated'; const STATUS_REQUEST_FINISHED = 'Finished'; const STATUS_REQUEST_FAILED = 'Failed'; + const STATUS_REQUEST_FAILED_FINISHED = 'Failed & Finished'; /** * Returns the request status. From 8571a6758a99a4acf9997ecb1c8bf57eac817477 Mon Sep 17 00:00:00 2001 From: upchuk Date: Thu, 23 Feb 2023 10:28:10 +0100 Subject: [PATCH 2/2] EWPP-3035: Setting onBehalfOf value. --- .../schema/oe_translation_epoetry.schema.yml | 3 ++ .../src/Event/OnBehalfOfEvent.php | 46 ++++++++++++++++ .../RemoteTranslationProvider/Epoetry.php | 41 ++++++++++++++- .../oe_translation_epoetry_test.info.yml | 7 +++ .../oe_translation_epoetry_test.services.yml | 6 +++ .../EventSubscriber/OnBehalfOfSubscriber.php | 52 +++++++++++++++++++ 6 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 modules/oe_translation_epoetry/src/Event/OnBehalfOfEvent.php create mode 100644 modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.info.yml create mode 100644 modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.services.yml create mode 100644 modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/src/EventSubscriber/OnBehalfOfSubscriber.php diff --git a/modules/oe_translation_epoetry/config/schema/oe_translation_epoetry.schema.yml b/modules/oe_translation_epoetry/config/schema/oe_translation_epoetry.schema.yml index 89e8c57b..11d506b3 100644 --- a/modules/oe_translation_epoetry/config/schema/oe_translation_epoetry.schema.yml +++ b/modules/oe_translation_epoetry/config/schema/oe_translation_epoetry.schema.yml @@ -28,3 +28,6 @@ oe_translation_remote.remote_translation_provider.plugin.epoetry: site_id: type: string label: The site ID + on_behalf: + type: string + label: On behalf of diff --git a/modules/oe_translation_epoetry/src/Event/OnBehalfOfEvent.php b/modules/oe_translation_epoetry/src/Event/OnBehalfOfEvent.php new file mode 100644 index 00000000..6d138cd2 --- /dev/null +++ b/modules/oe_translation_epoetry/src/Event/OnBehalfOfEvent.php @@ -0,0 +1,46 @@ +value; + } + + /** + * Sets the onBehalfOf value. + * + * @param string $value + * The onBehalfOf value. + */ + public function setValue(string $value): void { + $this->value = $value; + } + +} diff --git a/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php b/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php index 751c79c7..07d1d3cc 100644 --- a/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php +++ b/modules/oe_translation_epoetry/src/Plugin/RemoteTranslationProvider/Epoetry.php @@ -13,6 +13,7 @@ use Drupal\Core\State\StateInterface; use Drupal\oe_translation\Entity\TranslationRequestLogInterface; use Drupal\oe_translation\TranslationSourceManagerInterface; +use Drupal\oe_translation_epoetry\Event\OnBehalfOfEvent; use Drupal\oe_translation_epoetry\Plugin\Field\FieldType\ContactItem; use Drupal\oe_translation_epoetry\Plugin\Field\FieldType\ContactItemInterface; use Drupal\oe_translation_epoetry\RequestFactory; @@ -23,6 +24,7 @@ use OpenEuropa\EPoetry\Request\Type\LinguisticRequestOut; use Phpro\SoapClient\Type\ResultInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Provides the ePoetry translator provider plugin. @@ -51,14 +53,24 @@ class Epoetry extends RemoteTranslationProviderBase { */ protected $state; + /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + /** * {@inheritdoc} + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $languageManager, EntityTypeManagerInterface $entityTypeManager, TranslationSourceManagerInterface $translationSourceManager, MessengerInterface $messenger, RequestFactory $requestFactory, StateInterface $state) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $languageManager, EntityTypeManagerInterface $entityTypeManager, TranslationSourceManagerInterface $translationSourceManager, MessengerInterface $messenger, RequestFactory $requestFactory, StateInterface $state, EventDispatcherInterface $eventDispatcher) { parent::__construct($configuration, $plugin_id, $plugin_definition, $languageManager, $entityTypeManager, $translationSourceManager, $messenger); $this->requestFactory = $requestFactory; $this->state = $state; + $this->eventDispatcher = $eventDispatcher; } /** @@ -74,7 +86,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('oe_translation.translation_source_manager'), $container->get('messenger'), $container->get('oe_translation_epoetry.request_factory'), - $container->get('state') + $container->get('state'), + $container->get('event_dispatcher') ); } @@ -87,6 +100,7 @@ public function defaultConfiguration() { 'auto_accept' => FALSE, 'title_prefix' => '', 'site_id' => '', + 'on_behalf' => '', ] + parent::defaultConfiguration(); } @@ -139,6 +153,13 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#required' => TRUE, ]; + $form['on_behalf'] = [ + '#type' => 'textfield', + '#title' => $this->t('On behalf of'), + '#default_value' => $this->configuration['on_behalf'], + '#description' => $this->t('Configure the default DG on behalf of which requests will be sent. This can be overridden per request. Each request needs to send this value so omitting it here will still make it require on the request page.'), + ]; + $form['auto_accept'] = [ '#type' => 'checkbox', '#title' => $this->t('Auto-accept translations'), @@ -197,6 +218,7 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s $this->configuration['auto_accept'] = (bool) $form_state->getValue('auto_accept'); $this->configuration['title_prefix'] = $form_state->getValue('title_prefix'); $this->configuration['site_id'] = $form_state->getValue('site_id'); + $this->configuration['on_behalf'] = $form_state->getValue('on_behalf'); $reset_dossier = (bool) $form_state->getValue(['dossiers_wrapper', 'reset']); if ($reset_dossier) { @@ -306,6 +328,21 @@ public function newTranslationRequestForm(array &$form, FormStateInterface $form '#required' => TRUE, ]; } + + $default_value = $this->configuration['on_behalf']; + $event = new OnBehalfOfEvent(); + $this->eventDispatcher->dispatch($event, OnBehalfOfEvent::NAME); + if ($event->getValue()) { + $default_value = $event->getValue(); + } + $form['on_behalf'] = [ + '#type' => 'textfield', + '#title' => $this->t('On behalf of'), + '#default_value' => $default_value, + '#description' => $this->t('The DG on behalf of which requests will be sent. This needs to be a valid acronym of the DG in question.'), + '#required' => TRUE, + ]; + return $form; } diff --git a/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.info.yml b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.info.yml new file mode 100644 index 00000000..fb127e53 --- /dev/null +++ b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.info.yml @@ -0,0 +1,7 @@ +name: OpenEuropa Translation ePoetry Test +description: Test module for the ePoetry integration +package: Testing +type: module +core_version_requirement: ^9.4 +dependencies: + - oe_translation:oe_translation_epoetry diff --git a/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.services.yml b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.services.yml new file mode 100644 index 00000000..5881db75 --- /dev/null +++ b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/oe_translation_epoetry_test.services.yml @@ -0,0 +1,6 @@ +services: + oe_translation_epoetry_test.on_behalf_of_subscriber: + class: Drupal\oe_translation_epoetry_test\EventSubscriber\OnBehalfOfSubscriber + arguments: ['@state'] + tags: + - { name: event_subscriber } diff --git a/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/src/EventSubscriber/OnBehalfOfSubscriber.php b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/src/EventSubscriber/OnBehalfOfSubscriber.php new file mode 100644 index 00000000..69baf231 --- /dev/null +++ b/modules/oe_translation_epoetry/tests/oe_translation_epoetry_test/src/EventSubscriber/OnBehalfOfSubscriber.php @@ -0,0 +1,52 @@ +state = $state; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return [OnBehalfOfEvent::NAME => 'getOnBehalfOf']; + } + + /** + * Sets a test onBehalfOf value. + * + * @param \Drupal\oe_translation_epoetry\Event\OnBehalfOfEvent $event + * The event. + */ + public function getOnBehalfOf(OnBehalfOfEvent $event): void { + if ($this->state->get('oe_translation_epoetry_test.on_behalf')) { + $event->setValue($this->state->get('oe_translation_epoetry_test.on_behalf')); + } + } + +}