Skip to content
Snippets Groups Projects
Unverified Commit 175fa94b authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2562845 by quietone, rakesh.gectcr, iMiksu, Jo Fitzgerald, maxocub,...

Issue #2562845 by quietone, rakesh.gectcr, iMiksu, Jo Fitzgerald, maxocub, heddn, mikeryan, alexpott, phenaproxima, jhodgdon: Validate file path on Credential form
parent f290f49f
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
...@@ -2,9 +2,12 @@ ...@@ -2,9 +2,12 @@
namespace Drupal\migrate_drupal_ui\Form; namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface; use Drupal\Core\Render\RendererInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory; use Drupal\Core\TempStore\PrivateTempStoreFactory;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\TransferException;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
...@@ -21,6 +24,20 @@ class CredentialForm extends MigrateUpgradeFormBase { ...@@ -21,6 +24,20 @@ class CredentialForm extends MigrateUpgradeFormBase {
*/ */
protected $renderer; protected $renderer;
/**
* The HTTP client to fetch the files with.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $httpClient;
/**
* An array of error information.
*
* @var array
*/
protected $errors = [];
/** /**
* CredentialForm constructor. * CredentialForm constructor.
* *
...@@ -28,10 +45,13 @@ class CredentialForm extends MigrateUpgradeFormBase { ...@@ -28,10 +45,13 @@ class CredentialForm extends MigrateUpgradeFormBase {
* The renderer service. * The renderer service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private tempstore factory. * The private tempstore factory.
* @param \GuzzleHttp\ClientInterface $http_client
* A Guzzle client object.
*/ */
public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private) { public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private, ClientInterface $http_client) {
parent::__construct($tempstore_private); parent::__construct($tempstore_private);
$this->renderer = $renderer; $this->renderer = $renderer;
$this->httpClient = $http_client;
} }
/** /**
...@@ -40,7 +60,8 @@ public function __construct(RendererInterface $renderer, PrivateTempStoreFactory ...@@ -40,7 +60,8 @@ public function __construct(RendererInterface $renderer, PrivateTempStoreFactory
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('renderer'), $container->get('renderer'),
$container->get('tempstore.private') $container->get('tempstore.private'),
$container->get('http_client')
); );
} }
...@@ -75,6 +96,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -75,6 +96,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
$default_options = []; $default_options = [];
$form['help'] = [
'#type' => 'item',
'#description' => $this->t('Provide the information to access the Drupal site you want to upgrade. Files can be imported into the upgraded site as well. See the <a href=":url">Upgrade documentation for more detailed instructions</a>.', [':url' => 'https://www.drupal.org/upgrade/migrate']),
];
$form['version'] = [ $form['version'] = [
'#type' => 'radios', '#type' => 'radios',
'#default_value' => 7, '#default_value' => 7,
...@@ -145,6 +171,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -145,6 +171,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
':input[name="version"]' => ['value' => '6'], ':input[name="version"]' => ['value' => '6'],
], ],
], ],
'#element_validate' => ['::validatePaths'],
]; ];
$form['source']['source_base_path'] = [ $form['source']['source_base_path'] = [
...@@ -156,6 +183,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -156,6 +183,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
':input[name="version"]' => ['value' => '7'], ':input[name="version"]' => ['value' => '7'],
], ],
], ],
'#element_validate' => ['::validatePaths'],
]; ];
$form['source']['source_private_file_path'] = [ $form['source']['source_private_file_path'] = [
...@@ -168,6 +196,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -168,6 +196,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
':input[name="version"]' => ['value' => '7'], ':input[name="version"]' => ['value' => '7'],
], ],
], ],
'#element_validate' => ['::validatePaths'],
]; ];
return $form; return $form;
...@@ -177,7 +206,6 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -177,7 +206,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validateForm(array &$form, FormStateInterface $form_state) { public function validateForm(array &$form, FormStateInterface $form_state) {
// Retrieve the database driver from the form, use reflection to get the // Retrieve the database driver from the form, use reflection to get the
// namespace, and then construct a valid database array the same as in // namespace, and then construct a valid database array the same as in
// settings.php. // settings.php.
...@@ -194,35 +222,61 @@ public function validateForm(array &$form, FormStateInterface $form_state) { ...@@ -194,35 +222,61 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
// Validate the driver settings and just end here if we have any issues. // Validate the driver settings and just end here if we have any issues.
if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) { if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
foreach ($errors as $name => $message) { foreach ($errors as $name => $message) {
$form_state->setErrorByName($name, $message); $this->errors[$name] = $message;
} }
return;
} }
else {
try { try {
$connection = $this->getConnection($database); $connection = $this->getConnection($database);
$version = (string) $this->getLegacyDrupalVersion($connection); $version = (string) $this->getLegacyDrupalVersion($connection);
if (!$version) { if (!$version) {
$form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.')); $this->errors[$database['driver'] . '][database'] = $this->t('Source database does not contain a recognizable Drupal version.');
}
elseif ($version !== (string) $form_state->getValue('version')) {
$this->errors['version'] = $this->t('Source database is Drupal version @version but version @selected was selected.',
[
'@version' => $version,
'@selected' => $form_state->getValue('version'),
]);
}
else {
// Setup migrations and save form data to private store.
$this->setupMigrations($database, $form_state);
}
} }
elseif ($version !== (string) $form_state->getValue('version')) { catch (\Exception $e) {
$form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database is Drupal version @version but version @selected was selected.', [ $this->errors[$database['driver'] . '][database'] = $e->getMessage();
'@version' => $version,
'@selected' => $form_state->getValue('version'),
]));
} }
else { }
// Setup migrations and save form data to private store.
$this->setupMigrations($database, $form_state); // Display all errors as a list of items.
if ($this->errors) {
$form_state->setError($form, $this->t('<h3>Resolve all issues below to continue the upgrade.</h3>'));
foreach ($this->errors as $name => $message) {
$form_state->setErrorByName($name, $message);
} }
} }
catch (\Exception $e) { }
$error_message = [
'#title' => $this->t('Resolve the issue below to continue the upgrade.'), /**
'#theme' => 'item_list', * The #element_validate handler for the source path elements.
'#items' => [$e->getMessage()], *
]; * Ensures that entered path can be read.
$form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message)); */
public function validatePaths($element, FormStateInterface $form_state) {
if ($source = $element['#value']) {
$msg = $this->t('Unable to read from @title.', ['@title' => $element['#title']]);
if (UrlHelper::isExternal($source)) {
try {
$this->httpClient->head($source);
}
catch (TransferException $e) {
$this->errors[$element['#name']] = $msg . ' ' . $e->getMessage();
}
}
elseif (!file_exists($source) || (!is_dir($source)) || (!is_readable($source))) {
$this->errors[$element['#name']] = $msg;
}
} }
} }
......
...@@ -68,16 +68,35 @@ public function testMigrateUpgradeExecute() { ...@@ -68,16 +68,35 @@ public function testMigrateUpgradeExecute() {
// Ensure submitting the form with invalid database credentials gives us a // Ensure submitting the form with invalid database credentials gives us a
// nice warning. // nice warning.
$this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade')); $this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
$session->pageTextContains('Resolve the issue below to continue the upgrade.'); $session->pageTextContains('Resolve all issues below to continue the upgrade.');
$this->drupalPostForm(NULL, $edits, t('Review upgrade')); $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
// Ensure we get errors about missing modules. // Ensure we get errors about missing modules.
$session->pageTextContains(t('Resolve the issue below to continue the upgrade')); $session->pageTextContains(t('Resolve all issues below to continue the upgrade.'));
$session->pageTextContains(t('The no_source_module plugin must define the source_module property.')); $session->pageTextContains(t('The no_source_module plugin must define the source_module property.'));
// Uninstall the module causing the missing module error messages. // Uninstall the module causing the missing module error messages.
$this->container->get('module_installer')->uninstall(['migration_provider_test'], TRUE); $this->container->get('module_installer')->uninstall(['migration_provider_test'], TRUE);
// Test the file sources.
$this->drupalGet('/upgrade');
$this->drupalPostForm(NULL, [], t('Continue'));
if ($version == 6) {
$paths['d6_source_base_path'] = DRUPAL_ROOT . '/wrong-path';
}
else {
$paths['source_base_path'] = 'https://example.com/wrong-path';
$paths['source_private_file_path'] = DRUPAL_ROOT . '/wrong-path';
}
$this->drupalPostForm(NULL, $paths + $edits, t('Review upgrade'));
if ($version == 6) {
$session->responseContains('Unable to read from Files directory.');
}
else {
$session->responseContains('Unable to read from Public files directory.');
$session->responseContains('Unable to read from Private file directory.');
}
// Restart the upgrade process. // Restart the upgrade process.
$this->drupalGet('/upgrade'); $this->drupalGet('/upgrade');
$session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.'); $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment