Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BNF: Library import forms. DDFHER-166 #1884

Merged
merged 3 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
26 changes: 26 additions & 0 deletions web/modules/custom/bnf/bnf.module
Original file line number Diff line number Diff line change
Expand Up @@ -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().
Expand Down Expand Up @@ -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'];
}
6 changes: 6 additions & 0 deletions web/modules/custom/bnf/bnf_client/bnf_client.links.menu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
bnf_client.import_content:
title: 'Import BNF content'
parent: system.admin_content
route_name: bnf_client.import_form
weight: 10
4 changes: 2 additions & 2 deletions web/modules/custom/bnf/bnf_client/bnf_client.module
Original file line number Diff line number Diff line change
Expand Up @@ -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')) {
Expand Down
2 changes: 2 additions & 0 deletions web/modules/custom/bnf/bnf_client/bnf_client.permissions.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
bnf client export nodes:
title: 'Can export nodes to BNF'
bnf client import nodes:
title: 'Can import nodes from BNF'
16 changes: 16 additions & 0 deletions web/modules/custom/bnf/bnf_client/bnf_client.routing.yml
Original file line number Diff line number Diff line change
@@ -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'
134 changes: 134 additions & 0 deletions web/modules/custom/bnf/bnf_client/src/Form/BnfImportConfirmForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

namespace Drupal\bnf_client\Form;

use Drupal\bnf\Exception\AlreadyExistsException;
use Drupal\bnf\Services\BnfImporter;
use Drupal\Core\DependencyInjection\AutowireTrait;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Displaying an import preview, and allowing editor to import.
*/
class BnfImportConfirmForm implements FormInterface, ContainerInjectionInterface {
use StringTranslationTrait;

use AutowireTrait;

/**
* {@inheritDoc}
*/
public function __construct(
protected RouteMatchInterface $routeMatch,
protected MessengerInterface $messenger,
protected BnfImporter $bnfImporter,
protected LoggerInterface $logger,
) {}

/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container): static {
return new static(
$container->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']));
}
}

}

}
94 changes: 94 additions & 0 deletions web/modules/custom/bnf/bnf_client/src/Form/BnfImportForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace Drupal\bnf_client\Form;

use Drupal\Component\Uuid\Uuid;
use Drupal\Core\DependencyInjection\AutowireTrait;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use function Safe\get_meta_tags;

/**
* An import form, letting editors input URL or UUID from BNF.
*/
class BnfImportForm implements FormInterface, ContainerInjectionInterface {
use StringTranslationTrait;

use AutowireTrait;

/**
* {@inheritDoc}
*/
public function getFormId(): string {
return 'bnf_initial_form';
}

/**
* {@inheritDoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$form['#title'] = $this->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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
Expand Down
Loading