diff --git a/docker-compose.yml b/docker-compose.yml index 6d3e29e6c..cfaadee76 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ x-environment: WEBROOT: web GRAPHQL_USER_NAME: graphql_consumer GRAPHQL_USER_PASSWORD: test - BNF_SERVER_GRAPHQL_ENDPOINT: "https://dpl-cms.local/graphql" + BNF_SERVER_BASE_ENDPOINT: "https://dpl-cms.local" # Uncomment if you like to have the system behave like in production #LAGOON_ENVIRONMENT_TYPE: production diff --git a/web/modules/custom/bnf/bnf.module b/web/modules/custom/bnf/bnf.module index d19fd7ed8..11e83cce5 100644 --- a/web/modules/custom/bnf/bnf.module +++ b/web/modules/custom/bnf/bnf.module @@ -3,6 +3,7 @@ use Drupal\bnf\BnfStateEnum; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\node\NodeInterface; /** * Implements hook_entity_base_field_info(). @@ -41,3 +42,28 @@ function bnf_get_bnf_state_allowed_values(): array { } return $values; } + +/** + * Implements theme_preprocess_html(). + * + * Adding the node UUID as a metatag, that we can use when the user submits + * a URL to the BNF import form. + */ +function bnf_preprocess_html(array &$variables): void { + $route = \Drupal::routeMatch(); + $node = $route->getParameter('node'); + + if ($route->getRouteName() !== 'entity.node.canonical' || !($node instanceof NodeInterface)) { + return; + } + + $uuid_metatag = [ + '#tag' => 'meta', + '#attributes' => [ + 'name' => 'uuid', + 'content' => $node->uuid(), + ], + ]; + + $variables['page']['#attached']['html_head'][] = [$uuid_metatag, 'node-uuid']; +} diff --git a/web/modules/custom/bnf/bnf_client/bnf_client.links.menu.yml b/web/modules/custom/bnf/bnf_client/bnf_client.links.menu.yml new file mode 100644 index 000000000..5bce3976d --- /dev/null +++ b/web/modules/custom/bnf/bnf_client/bnf_client.links.menu.yml @@ -0,0 +1,6 @@ +--- +bnf_client.import_content: + title: 'Import BNF content' + parent: system.admin_content + route_name: bnf_client.import_form + weight: 10 diff --git a/web/modules/custom/bnf/bnf_client/bnf_client.module b/web/modules/custom/bnf/bnf_client/bnf_client.module index fdfd80cc6..b1ed8d70b 100644 --- a/web/modules/custom/bnf/bnf_client/bnf_client.module +++ b/web/modules/custom/bnf/bnf_client/bnf_client.module @@ -8,12 +8,12 @@ use Drupal\drupal_typed\DrupalTyped; /** * Implements hook_form_FORM_ID_alter(). * - * Altering the node form, and adding an option to export the node to BNF. + * Altering the article form, and adding an option to export the node to BNF. * If checked, a custom form submit handler will take care of the rest. * * @see bnf_client_form_node_form_submit() */ -function bnf_client_form_node_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void { +function bnf_client_form_node_article_edit_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void { $current_user = \Drupal::currentUser(); if (!$current_user->hasPermission('bnf client export nodes')) { diff --git a/web/modules/custom/bnf/bnf_client/bnf_client.permissions.yml b/web/modules/custom/bnf/bnf_client/bnf_client.permissions.yml index e8a3704a5..b3a94242f 100644 --- a/web/modules/custom/bnf/bnf_client/bnf_client.permissions.yml +++ b/web/modules/custom/bnf/bnf_client/bnf_client.permissions.yml @@ -1,2 +1,4 @@ bnf client export nodes: title: 'Can export nodes to BNF' +bnf client import nodes: + title: 'Can import nodes from BNF' diff --git a/web/modules/custom/bnf/bnf_client/bnf_client.routing.yml b/web/modules/custom/bnf/bnf_client/bnf_client.routing.yml new file mode 100644 index 000000000..6d3987e66 --- /dev/null +++ b/web/modules/custom/bnf/bnf_client/bnf_client.routing.yml @@ -0,0 +1,16 @@ +--- +bnf_client.import_form: + path: '/admin/bnf/import' + defaults: + _form: '\Drupal\bnf_client\Form\BnfImportForm' + _title: 'Import' + requirements: + _permission: 'bnf client import nodes' + +bnf_client.import_confirm_form: + path: '/admin/bnf/import/{uuid}' + defaults: + _form: '\Drupal\bnf_client\Form\BnfImportConfirmForm' + _title: 'Confirm import' + requirements: + _permission: 'bnf client import nodes' diff --git a/web/modules/custom/bnf/bnf_client/src/Form/BnfImportConfirmForm.php b/web/modules/custom/bnf/bnf_client/src/Form/BnfImportConfirmForm.php new file mode 100644 index 000000000..8c8af244c --- /dev/null +++ b/web/modules/custom/bnf/bnf_client/src/Form/BnfImportConfirmForm.php @@ -0,0 +1,134 @@ +get('current_route_match'), + $container->get('messenger'), + $container->get('bnf.importer'), + $container->get('logger.channel.bnf'), + ); + } + + /** + * {@inheritDoc} + */ + public function getFormId(): string { + return 'bnf_import_form_form'; + } + + /** + * {@inheritDoc} + */ + public function buildForm(array $form, FormStateInterface $form_state): array { + $form['#title'] = $this->t('Confirm import of BNF content', [], ['context' => 'BNF']); + + $uuid = $this->routeMatch->getParameter('uuid'); + $bnfServer = (string) getenv('BNF_SERVER_BASE_ENDPOINT') . '/graphql'; + + $form_state->set('uuid', $uuid); + $form_state->set('bnfServer', $bnfServer); + + $importable = TRUE; + + try { + $nodeData = $this->bnfImporter->loadNodeData($uuid, $bnfServer); + } + catch (\Exception $e) { + $importable = FALSE; + + $this->messenger->addError($this->t('Cannot import this node from BNF.', [], ['context' => 'BNF'])); + + if ($e instanceof AlreadyExistsException) { + $this->messenger->addError($this->t('Node has previously been imported from BNF.', [], ['context' => 'BNF'])); + } + } + + $form['uuid'] = [ + '#title' => 'UUID', + '#type' => 'textfield', + '#default_value' => $uuid, + '#disabled' => TRUE, + ]; + + $form['label'] = [ + '#title' => $this->t('Content label', [], ['context' => 'BNF']), + '#type' => 'textfield', + '#default_value' => $nodeData['title'] ?? NULL, + '#disabled' => TRUE, + ]; + + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Import content'), + '#disabled' => !$importable, + ]; + + return $form; + } + + /** + * {@inheritDoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state): void { + + } + + /** + * {@inheritDoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state): void { + $uuid = $form_state->get('uuid'); + $bnfServer = $form_state->get('bnfServer'); + + try { + $node = $this->bnfImporter->importNode($uuid, $bnfServer); + $form_state->setRedirect('entity.node.edit_form', ['node' => $node->id()]); + } + catch (\Exception $e) { + $this->logger->error('Could not import node from BNF. @message', ['@message' => $e->getMessage()]); + + $this->messenger->addError($this->t('Could not import node from BNF.', [], ['context' => 'BNF'])); + + if ($e instanceof AlreadyExistsException) { + $this->messenger->addError($this->t('Node has previously been imported from BNF.', [], ['context' => 'BNF'])); + } + } + + } + +} diff --git a/web/modules/custom/bnf/bnf_client/src/Form/BnfImportForm.php b/web/modules/custom/bnf/bnf_client/src/Form/BnfImportForm.php new file mode 100644 index 000000000..9c07ca218 --- /dev/null +++ b/web/modules/custom/bnf/bnf_client/src/Form/BnfImportForm.php @@ -0,0 +1,94 @@ +t('Import nodes from BNF', [], ['context' => 'BNF']); + $form['reference'] = [ + '#type' => 'textfield', + '#title' => $this->t('URL or UUID of content'), + ]; + + $form['actions'] = [ + '#type' => 'actions', + ]; + + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Preview content'), + ]; + + return $form; + } + + /** + * {@inheritDoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state): void { + $reference = $form_state->getValue('reference'); + $uuid = $this->parseAndValidateUuid($reference); + + if (empty($uuid)) { + $form_state->setErrorByName( + 'reference', + $this->t('Invalid URL or UUID.', [], ['context' => 'BNF']) + ); + } + + $form_state->set('uuid', $uuid); + } + + /** + * {@inheritDoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state): void { + $uuid = $form_state->get('uuid'); + $form_state->setRedirect('bnf_client.import_confirm_form', ['uuid' => $uuid]); + } + + /** + * Getting and validate a UUID from string or URL. + */ + protected function parseAndValidateUuid(string $reference): string|false { + try { + // Detect if reference is a URL. + if (filter_var($reference, FILTER_VALIDATE_URL)) { + // Finding the metatag that contains the UUID. + $meta_tags = get_meta_tags($reference); + $reference = $meta_tags['uuid'] ?? NULL; + } + + return Uuid::isValid((string) $reference) ? $reference : FALSE; + } + catch (\Exception) { + return FALSE; + } + } + +} diff --git a/web/modules/custom/bnf/bnf_client/src/Services/BnfExporter.php b/web/modules/custom/bnf/bnf_client/src/Services/BnfExporter.php index b4803e9f7..c2c426ef0 100644 --- a/web/modules/custom/bnf/bnf_client/src/Services/BnfExporter.php +++ b/web/modules/custom/bnf/bnf_client/src/Services/BnfExporter.php @@ -55,7 +55,7 @@ public function exportNode(NodeInterface $node): void { GRAPHQL; try { - $bnfServer = (string) getenv('BNF_SERVER_GRAPHQL_ENDPOINT'); + $bnfServer = (string) getenv('BNF_SERVER_BASE_ENDPOINT') . '/graphql'; if (!filter_var($bnfServer, FILTER_VALIDATE_URL)) { throw new \InvalidArgumentException('The provided BNF server URL is not valid.');