Commit 50d30d97 authored by catch's avatar catch

Issue #2751223 by maxocub, jeroenbegyn, Gábor Hojtsy, Jo Fitzgerald: D6 & D7...

Issue #2751223 by maxocub, jeroenbegyn, Gábor Hojtsy, Jo Fitzgerald: D6 & D7 users are migrated into D8 with incorrect langcode
parent 5c93d7e3
......@@ -41044,11 +41044,29 @@
'login' => '0',
'status' => '1',
'timezone' => 'America/Chicago',
'language' => 'en',
'language' => 'is',
'picture' => '0',
'init' => 'odo@local.host',
'data' => 'a:1:{s:7:"contact";i:1;}',
))
->values(array(
'uid' => '3',
'name' => 'Bob',
'pass' => '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ',
'mail' => 'bob@local.host',
'theme' => '',
'signature' => '',
'signature_format' => 'filtered_html',
'created' => '1440532218',
'access' => '0',
'login' => '0',
'status' => '1',
'timezone' => 'America/New_York',
'language' => 'fr',
'picture' => '0',
'init' => 'bob@local.host',
'data' => 'a:1:{s:7:"contact";i:1;}',
))
->execute();
$connection->schema()->createTable('users_roles', array(
......@@ -41084,6 +41102,14 @@
'uid' => '1',
'rid' => '3',
))
->values(array(
'uid' => '2',
'rid' => '3',
))
->values(array(
'uid' => '3',
'rid' => '3',
))
->execute();
$connection->schema()->createTable('variable', array(
......@@ -61,7 +61,7 @@ protected function getEntityCounts() {
'taxonomy_term' => 18,
'taxonomy_vocabulary' => 3,
'tour' => 4,
'user' => 3,
'user' => 4,
'user_role' => 4,
'menu_link_content' => 9,
'view' => 12,
......
......@@ -16,7 +16,18 @@ process:
timezone:
plugin: user_update_7002
source: timezone
preferred_langcode: language
langcode:
plugin: user_langcode
source: language
fallback_to_site_default: false
preferred_langcode:
plugin: user_langcode
source: language
fallback_to_site_default: true
preferred_admin_langcode:
plugin: user_langcode
source: language
fallback_to_site_default: true
init: init
roles:
plugin: migration
......@@ -34,6 +45,8 @@ migration_dependencies:
required:
- d6_user_role
optional:
- language
- default_language
- d6_user_picture_file
- user_picture_entity_display
- user_picture_entity_form_display
......@@ -15,9 +15,18 @@ process:
login: login
status: status
timezone: timezone
langcode: language
preferred_langcode: language
preferred_admin_langcode: language
langcode:
plugin: user_langcode
source: language
fallback_to_site_default: false
preferred_langcode:
plugin: user_langcode
source: language
fallback_to_site_default: true
preferred_admin_langcode:
plugin: user_langcode
source: language
fallback_to_site_default: true
init: init
roles:
plugin: migration
......@@ -38,6 +47,8 @@ migration_dependencies:
- d7_user_role
optional:
- d7_file
- language
- default_language
- user_picture_field_instance
- user_picture_entity_display
- user_picture_entity_form_display
......
<?php
namespace Drupal\user\Plugin\migrate\process;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a process plugin for the user langcode.
*
* @MigrateProcessPlugin(
* id = "user_langcode"
* )
*/
class UserLangcode extends ProcessPluginBase implements ContainerFactoryPluginInterface {
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManager
*/
protected $languageManager;
/**
* Constructs a UserLangcode object.
*
* @param array $configuration
* Plugin configuration.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definiiton.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManager $language_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (!isset($this->configuration['fallback_to_site_default'])) {
$this->configuration['fallback_to_site_default'] = TRUE;
}
// If the user's language is empty, it means the locale module was not
// installed, so the user's langcode should be English and the user's
// preferred_langcode and preferred_admin_langcode should fallback to the
// default language.
if (empty($value)) {
if ($this->configuration['fallback_to_site_default']) {
return $this->languageManager->getDefaultLanguage()->getId();
}
else {
return 'en';
}
}
// If the user's language does not exists, use the default language.
elseif ($this->languageManager->getLanguage($value) === NULL) {
return $this->languageManager->getDefaultLanguage()->getId();
}
// If the langcode is a valid one, just return it.
return $value;
}
}
......@@ -12,6 +12,11 @@
*/
class MigrateUserProfileValuesTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['language'];
/**
* {@inheritdoc}
*/
......@@ -19,6 +24,7 @@ protected function setUp() {
parent::setUp();
$this->executeMigrations([
'language',
'user_profile_field',
'user_profile_field_instance',
'user_profile_entity_display',
......
......@@ -19,6 +19,11 @@ class MigrateUserTest extends MigrateDrupal6TestBase {
use FileMigrationTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['language'];
/**
* {@inheritdoc}
*/
......@@ -60,6 +65,7 @@ protected function setUp() {
file_put_contents($file->getFileUri(), file_get_contents('core/modules/simpletest/files/image-2.jpg'));
$file->save();
$this->executeMigration('language');
$this->migrateUsers();
}
......@@ -91,28 +97,47 @@ public function testUser() {
/** @var \Drupal\user\UserInterface $user */
$user = User::load($source->uid);
$this->assertIdentical($source->uid, $user->id());
$this->assertIdentical($source->name, $user->label());
$this->assertIdentical($source->mail, $user->getEmail());
$this->assertIdentical($source->created, $user->getCreatedTime());
$this->assertIdentical($source->access, $user->getLastAccessedTime());
$this->assertIdentical($source->login, $user->getLastLoginTime());
$this->assertSame($source->uid, $user->id());
$this->assertSame($source->name, $user->label());
$this->assertSame($source->mail, $user->getEmail());
$this->assertSame($source->created, $user->getCreatedTime());
$this->assertSame($source->access, $user->getLastAccessedTime());
$this->assertSame($source->login, $user->getLastLoginTime());
$is_blocked = $source->status == 0;
$this->assertIdentical($is_blocked, $user->isBlocked());
$this->assertSame($is_blocked, $user->isBlocked());
$expected_timezone_name = $source->timezone_name ?: $this->config('system.date')->get('timezone.default');
$this->assertSame($expected_timezone_name, $user->getTimeZone());
$this->assertSame($source->init, $user->getInitialEmail());
$this->assertSame($roles, $user->getRoles());
// Ensure the user's langcode, preferred_langcode and
// preferred_admin_langcode are valid.
// $user->getPreferredLangcode() might fallback to default language if the
// user preferred language is not configured on the site. We just want to
// test if the value was imported correctly.
$this->assertIdentical($source->language, $user->preferred_langcode->value);
$expected_timezone_name = $source->timezone_name ?: $this->config('system.date')->get('timezone.default');
$this->assertIdentical($expected_timezone_name, $user->getTimeZone());
$this->assertIdentical($source->init, $user->getInitialEmail());
$this->assertIdentical($roles, $user->getRoles());
$language_manager = $this->container->get('language_manager');
$default_langcode = $language_manager->getDefaultLanguage()->getId();
if (empty($source->language)) {
$this->assertSame('en', $user->langcode->value);
$this->assertSame($default_langcode, $user->preferred_langcode->value);
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
}
elseif ($language_manager->getLanguage($source->language) === NULL) {
$this->assertSame($default_langcode, $user->langcode->value);
$this->assertSame($default_langcode, $user->preferred_langcode->value);
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
}
else {
$this->assertSame($source->language, $user->langcode->value);
$this->assertSame($source->language, $user->preferred_langcode->value);
$this->assertSame($source->language, $user->preferred_admin_langcode->value);
}
// We have one empty picture in the data so don't try load that.
if (!empty($source->picture)) {
// Test the user picture.
$file = File::load($user->user_picture->target_id);
$this->assertIdentical(basename($source->picture), $file->getFilename());
$this->assertSame(basename($source->picture), $file->getFilename());
}
else {
// Ensure the user does not have a picture.
......
......@@ -3,6 +3,7 @@
namespace Drupal\Tests\user\Kernel\Migrate\d7;
use Drupal\comment\Entity\CommentType;
use Drupal\Core\Database\Database;
use Drupal\node\Entity\NodeType;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
......@@ -25,6 +26,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
'datetime',
'file',
'image',
'language',
'link',
'node',
'system',
......@@ -49,6 +51,7 @@ protected function setUp() {
$this->createType('test_content_type');
Vocabulary::create(['vid' => 'test_vocabulary'])->save();
$this->executeMigrations([
'language',
'user_picture_field',
'user_picture_field_instance',
'd7_user_role',
......@@ -88,6 +91,8 @@ protected function createType($id) {
* The user's email address.
* @param string $password
* The password for this user.
* @param int $created
* The user's creation time.
* @param int $access
* The last access time.
* @param int $login
......@@ -96,37 +101,59 @@ protected function createType($id) {
* Whether or not the account is blocked.
* @param string $langcode
* The user account's language code.
* @param string $timezone
* The user account's timezone name.
* @param string $init
* The user's initial email address.
* @param string[] $roles
* Role IDs the user account is expected to have.
* @param bool $has_picture
* Whether the user is expected to have a picture attached.
* @param int $field_integer
* The value of the integer field.
* @param bool $has_picture
* Whether the user is expected to have a picture attached.
*/
protected function assertEntity($id, $label, $mail, $password, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE, $field_integer = NULL) {
protected function assertEntity($id, $label, $mail, $password, $created, $access, $login, $blocked, $langcode, $timezone, $init, $roles, $field_integer, $has_picture = FALSE) {
/** @var \Drupal\user\UserInterface $user */
$user = User::load($id);
$this->assertTrue($user instanceof UserInterface);
$this->assertIdentical($label, $user->label());
$this->assertIdentical($mail, $user->getEmail());
$this->assertIdentical($access, $user->getLastAccessedTime());
$this->assertIdentical($login, $user->getLastLoginTime());
$this->assertIdentical($blocked, $user->isBlocked());
$this->assertSame($label, $user->label());
$this->assertSame($mail, $user->getEmail());
$this->assertSame($password, $user->getPassword());
$this->assertSame($created, $user->getCreatedTime());
$this->assertSame($access, $user->getLastAccessedTime());
$this->assertSame($login, $user->getLastLoginTime());
$this->assertNotSame($blocked, $user->isBlocked());
// Ensure the user's langcode, preferred_langcode and
// preferred_admin_langcode are valid.
// $user->getPreferredLangcode() might fallback to default language if the
// user preferred language is not configured on the site. We just want to
// test if the value was imported correctly.
$this->assertIdentical($langcode, $user->langcode->value);
$this->assertIdentical($langcode, $user->preferred_langcode->value);
$this->assertIdentical($langcode, $user->preferred_admin_langcode->value);
$this->assertIdentical($init, $user->getInitialEmail());
$this->assertIdentical($roles, $user->getRoles());
$this->assertIdentical($has_picture, !$user->user_picture->isEmpty());
$this->assertIdentical($password, $user->getPassword());
$language_manager = $this->container->get('language_manager');
$default_langcode = $language_manager->getDefaultLanguage()->getId();
if ($langcode == '') {
$this->assertSame('en', $user->langcode->value);
$this->assertSame($default_langcode, $user->preferred_langcode->value);
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
}
elseif ($language_manager->getLanguage($langcode) === NULL) {
$this->assertSame($default_langcode, $user->langcode->value);
$this->assertSame($default_langcode, $user->preferred_langcode->value);
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
}
else {
$this->assertSame($langcode, $user->langcode->value);
$this->assertSame($langcode, $user->preferred_langcode->value);
$this->assertSame($langcode, $user->preferred_admin_langcode->value);
}
$this->assertSame($timezone, $user->getTimeZone());
$this->assertSame($init, $user->getInitialEmail());
$this->assertSame($roles, $user->getRoles());
$this->assertSame($has_picture, !$user->user_picture->isEmpty());
if (!is_null($field_integer)) {
$this->assertTrue($user->hasField('field_integer'));
$this->assertEquals($field_integer, $user->field_integer->value);
$this->assertEquals($field_integer[0], $user->field_integer->value);
}
}
......@@ -134,22 +161,65 @@ protected function assertEntity($id, $label, $mail, $password, $access, $login,
* Tests the Drupal 7 user to Drupal 8 migration.
*/
public function testUser() {
$password = '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ';
$this->assertEntity(2, 'Odo', 'odo@local.host', $password, '0', '0', FALSE, 'en', 'odo@local.host', [RoleInterface::AUTHENTICATED_ID], FALSE, 99);
// Ensure that the user can authenticate.
$this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
// After authenticating the password will be rehashed because the password
// stretching iteration count has changed from 15 in Drupal 7 to 16 in
// Drupal 8.
$user = User::load(2);
$rehash = $user->getPassword();
$this->assertNotEquals($password, $rehash);
// Authenticate again and there should be no re-hash.
$this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
$user = User::load(2);
$this->assertEquals($rehash, $user->getPassword());
$users = Database::getConnection('default', 'migrate')
->select('users', 'u')
->fields('u')
->condition('uid', 1, '>')
->execute()
->fetchAll();
foreach ($users as $source) {
$rids = Database::getConnection('default', 'migrate')
->select('users_roles', 'ur')
->fields('ur', array('rid'))
->condition('ur.uid', $source->uid)
->execute()
->fetchCol();
$roles = array(RoleInterface::AUTHENTICATED_ID);
$id_map = $this->getMigration('d7_user_role')->getIdMap();
foreach ($rids as $rid) {
$role = $id_map->lookupDestinationId(array($rid));
$roles[] = reset($role);
}
$field_integer = Database::getConnection('default', 'migrate')
->select('field_data_field_integer', 'fi')
->fields('fi', array('field_integer_value'))
->condition('fi.entity_id', $source->uid)
->execute()
->fetchCol();
$field_integer = !empty($field_integer) ? $field_integer : NULL;
$this->assertEntity(
$source->uid,
$source->name,
$source->mail,
$source->pass,
$source->created,
$source->access,
$source->login,
$source->status,
$source->language,
$source->timezone,
$source->init,
$roles,
$field_integer
);
// Ensure that the user can authenticate.
$this->assertEquals($source->uid, $this->container->get('user.auth')->authenticate($source->name, 'a password'));
// After authenticating the password will be rehashed because the password
// stretching iteration count has changed from 15 in Drupal 7 to 16 in
// Drupal 8.
$user = User::load($source->uid);
$rehash = $user->getPassword();
$this->assertNotEquals($source->pass, $rehash);
// Authenticate again and there should be no re-hash.
$this->assertEquals($source->uid, $this->container->get('user.auth')->authenticate($source->name, 'a password'));
$user = User::load($source->uid);
$this->assertEquals($rehash, $user->getPassword());
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment