handle deleted user during import from v1 (#569)
This commit is contained in:
@@ -127,6 +127,7 @@ class KimaiImporterCommand extends Command
|
|||||||
->addArgument('prefix', InputArgument::REQUIRED, 'The database prefix for the old Kimai v1 tables')
|
->addArgument('prefix', InputArgument::REQUIRED, 'The database prefix for the old Kimai v1 tables')
|
||||||
->addArgument('password', InputArgument::REQUIRED, 'The new password for all imported user')
|
->addArgument('password', InputArgument::REQUIRED, 'The new password for all imported user')
|
||||||
->addArgument('country', InputArgument::OPTIONAL, 'The default country for customer (2-character uppercase)', 'DE')
|
->addArgument('country', InputArgument::OPTIONAL, 'The default country for customer (2-character uppercase)', 'DE')
|
||||||
|
->addArgument('currency', InputArgument::OPTIONAL, 'The default currency for customer (code like EUR, CHF, GBP or USD)', 'EUR')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +159,14 @@ class KimaiImporterCommand extends Command
|
|||||||
|
|
||||||
$country = $input->getArgument('country');
|
$country = $input->getArgument('country');
|
||||||
if (2 != trim(strlen($country))) {
|
if (2 != trim(strlen($country))) {
|
||||||
$io->error('Country length needs to be exactly 2 character');
|
$io->error('Country code needs to be exactly 2 character');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currency = $input->getArgument('currency');
|
||||||
|
if (3 != trim(strlen($currency))) {
|
||||||
|
$io->error('Currency code needs to be exactly 3 character');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -260,7 +268,7 @@ class KimaiImporterCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$counter = $this->importCustomers($io, $customer, $country);
|
$counter = $this->importCustomers($io, $customer, $country, $currency);
|
||||||
$allImports += $counter;
|
$allImports += $counter;
|
||||||
$io->success('Imported customers: ' . $counter);
|
$io->success('Imported customers: ' . $counter);
|
||||||
} catch (\Exception $ex) {
|
} catch (\Exception $ex) {
|
||||||
@@ -576,10 +584,11 @@ class KimaiImporterCommand extends Command
|
|||||||
* @param SymfonyStyle $io
|
* @param SymfonyStyle $io
|
||||||
* @param array $customers
|
* @param array $customers
|
||||||
* @param string $country
|
* @param string $country
|
||||||
|
* @param string $currency
|
||||||
* @return int
|
* @return int
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function importCustomers(SymfonyStyle $io, $customers, $country)
|
protected function importCustomers(SymfonyStyle $io, $customers, $country, $currency)
|
||||||
{
|
{
|
||||||
$counter = 0;
|
$counter = 0;
|
||||||
$entityManager = $this->getDoctrine()->getManager();
|
$entityManager = $this->getDoctrine()->getManager();
|
||||||
@@ -607,6 +616,7 @@ class KimaiImporterCommand extends Command
|
|||||||
->setTimezone($oldCustomer['timezone'])
|
->setTimezone($oldCustomer['timezone'])
|
||||||
->setVisible($isActive)
|
->setVisible($isActive)
|
||||||
->setCountry(strtoupper($country))
|
->setCountry(strtoupper($country))
|
||||||
|
->setCurrency(strtoupper($currency))
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!$this->validateImport($io, $customer)) {
|
if (!$this->validateImport($io, $customer)) {
|
||||||
@@ -910,6 +920,7 @@ class KimaiImporterCommand extends Command
|
|||||||
{
|
{
|
||||||
$counter = 0;
|
$counter = 0;
|
||||||
$activityCounter = 0;
|
$activityCounter = 0;
|
||||||
|
$userCounter = 0;
|
||||||
$entityManager = $this->getDoctrine()->getManager();
|
$entityManager = $this->getDoctrine()->getManager();
|
||||||
$total = count($records);
|
$total = count($records);
|
||||||
|
|
||||||
@@ -949,11 +960,45 @@ class KimaiImporterCommand extends Command
|
|||||||
|
|
||||||
$duration = $oldRecord['end'] - $oldRecord['start'];
|
$duration = $oldRecord['end'] - $oldRecord['start'];
|
||||||
|
|
||||||
// FIXME create user on the fly
|
// ----------------------- unknown user, damned missing data integrity in Kimai v1 -----------------------
|
||||||
if (!isset($this->users[$oldRecord['userID']])) {
|
if (!isset($this->users[$oldRecord['userID']])) {
|
||||||
$io->error('Could not import timesheet record, unknown user: ' . $oldRecord['userID']);
|
|
||||||
continue;
|
$tempUserName = uniqid();
|
||||||
|
$tempPassword = uniqid() . uniqid();
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername($tempUserName)
|
||||||
|
->setAlias('Import: ' . $tempUserName)
|
||||||
|
->setEmail($tempUserName . '@example.com')
|
||||||
|
->setPlainPassword($tempPassword)
|
||||||
|
->setEnabled(false)
|
||||||
|
->setRoles([USER::ROLE_USER])
|
||||||
|
;
|
||||||
|
|
||||||
|
$pwd = $this->encoder->encodePassword($user, $user->getPlainPassword());
|
||||||
|
$user->setPassword($pwd);
|
||||||
|
|
||||||
|
if (!$this->validateImport($io, $user)) {
|
||||||
|
$io->error('Found timesheet record for unknown user and failed to create user, skipping timesheet: ' . $oldRecord['timeEntryID']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$entityManager->persist($user);
|
||||||
|
$entityManager->flush();
|
||||||
|
if ($this->debug) {
|
||||||
|
$io->success('Created deactivated user: ' . $user->getUsername());
|
||||||
|
}
|
||||||
|
$userCounter++;
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
$io->error('Failed to create user: ' . $user->getUsername());
|
||||||
|
$io->error('Reason: ' . $ex->getMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users[$oldRecord['userID']] = $user;
|
||||||
}
|
}
|
||||||
|
// ----------------------- unknown user end -----------------------
|
||||||
|
|
||||||
$timesheet = new Timesheet();
|
$timesheet = new Timesheet();
|
||||||
|
|
||||||
@@ -1028,6 +1073,9 @@ class KimaiImporterCommand extends Command
|
|||||||
}
|
}
|
||||||
$io->writeln(' (' . $counter . '/' . $total . ')');
|
$io->writeln(' (' . $counter . '/' . $total . ')');
|
||||||
|
|
||||||
|
if ($userCounter > 0) {
|
||||||
|
$io->success('Created new users during timesheet import: ' . $userCounter);
|
||||||
|
}
|
||||||
if ($activityCounter > 0) {
|
if ($activityCounter > 0) {
|
||||||
$io->success('Created new activities during timesheet import: ' . $activityCounter);
|
$io->success('Created new activities during timesheet import: ' . $activityCounter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,9 +75,9 @@ For available roles, please refer to the [user documentation](users.md).
|
|||||||
> **NOTE**
|
> **NOTE**
|
||||||
>
|
>
|
||||||
> If you want to use a fully-featured web server (like Nginx or Apache) to run
|
> If you want to use a fully-featured web server (like Nginx or Apache) to run
|
||||||
> Kimai, configure it to point at the `public/` directory of the project.
|
> Kimai, configure it to point its DocumentRoot at the `public/` directory.
|
||||||
> For more details, see:
|
> For more details, see:
|
||||||
> http://symfony.com/doc/current/cookbook/configuration/web_server_configuration.html
|
> https://symfony.com/doc/current/setup/web_server_configuration.html
|
||||||
|
|
||||||
Installation complete: enjoy time-tracking :-)
|
Installation complete: enjoy time-tracking :-)
|
||||||
|
|
||||||
|
|||||||
@@ -9,19 +9,21 @@ Before importing your data from a Kimai v1 installation, please read the followi
|
|||||||
- fixed-rates and hourly-rates and total rate for timesheet entries are imported
|
- fixed-rates and hourly-rates and total rate for timesheet entries are imported
|
||||||
- Customers in Kimai 2 are only used for recording
|
- Customers in Kimai 2 are only used for recording
|
||||||
- they cannot login and no user accounts will be created for them
|
- they cannot login and no user accounts will be created for them
|
||||||
- country has to be manually assigned afterwards to customers, as there is no field in Kimai v1 for that
|
- they have a country code, which can be set during import or edited afterwards (Kimai v1 doesn't know the country)
|
||||||
|
- they have a currency code, which can be set during import or edited afterwards (Kimai v1 only knows one global currency)
|
||||||
- You have to supply the default password that is used for every imported user, as their password will be resetted
|
- You have to supply the default password that is used for every imported user, as their password will be resetted
|
||||||
- Data that was deleted in Kimai v1 (user, customer, projects, activities) will be imported and set to `invisible` (if you don't want that, you have to delete all entries that have the value `1` in the `trash` column before importing)
|
- Data that was deleted in Kimai v1 (user, customer, projects, activities) will be imported and set to `invisible` (if you don't want that, you have to delete all entries that have the value `1` in the `trash` column before importing)
|
||||||
|
|
||||||
A possible full command for import:
|
A possible full command for import:
|
||||||
```bash
|
```bash
|
||||||
bin/console kimai:import-v1 "mysql://user:password@127.0.0.1:3306/database?charset=utf8" "db_prefix" "password" "country"
|
bin/console kimai:import-v1 "mysql://user:password@127.0.0.1:3306/database?charset=utf8" "db_prefix" "password" "country" "currency"
|
||||||
```
|
```
|
||||||
|
The fields "country" and "currency" are optional and will be set to DE and EUR if not given.
|
||||||
|
|
||||||
It is recommended to test the import in a fresh database. You can test your import as often as you like and fix possible problems in your installation.
|
It is recommended to test the import in a fresh database. You can test your import as often as you like and fix possible problems in your installation.
|
||||||
A sample command could look like that:
|
A sample command could look like that:
|
||||||
```bash
|
```bash
|
||||||
bin/console doctrine:schema:drop --force && bin/console doctrine:schema:create && bin/console kimai:import-v1 "mysql://kimai:test@127.0.0.1:3306/kimai?charset=latin1" "kimai_" "test123" "de"
|
bin/console doctrine:schema:drop --force && bin/console doctrine:schema:create && bin/console kimai:import-v1 "mysql://kimai:test@127.0.0.1:3306/kimai?charset=latin1" "kimai_" "test123" "CH" "CHF"
|
||||||
```
|
```
|
||||||
That will drop the configured Kimai v2 database schema and re-create it, before importing the data from the `mysql` database at `127.0.0.1` on port `3306` authenticating the user `kimai` with the password `test` for import.
|
That will drop the configured Kimai v2 database schema and re-create it, before importing the data from the `mysql` database at `127.0.0.1` on port `3306` authenticating the user `kimai` with the password `test` for import.
|
||||||
The connection will use the charset `latin1` and the default table prefix `kimai_` for reading data. Imported users can login with the password `test123` and all customer will have the country `de` assigned.
|
The connection will use the charset `latin1` and the default table prefix `kimai_` for reading data. Imported users can login with the password `test123` and all customer will have the country `CH` and the currency `CHF` assigned.
|
||||||
|
|||||||
Reference in New Issue
Block a user