From 17856e0b9605f4ce0d2ba7b7e8505d15735df567 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Thu, 14 Feb 2019 00:26:54 +0100 Subject: [PATCH] handle deleted user during import from v1 (#569) --- src/Command/KimaiImporterCommand.php | 60 +++++++++++++++++++++++++--- var/docs/installation.md | 4 +- var/docs/migration_v1.md | 10 +++-- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/Command/KimaiImporterCommand.php b/src/Command/KimaiImporterCommand.php index 2a5166b9..c98de081 100644 --- a/src/Command/KimaiImporterCommand.php +++ b/src/Command/KimaiImporterCommand.php @@ -127,6 +127,7 @@ class KimaiImporterCommand extends Command ->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('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'); 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; } @@ -260,7 +268,7 @@ class KimaiImporterCommand extends Command } try { - $counter = $this->importCustomers($io, $customer, $country); + $counter = $this->importCustomers($io, $customer, $country, $currency); $allImports += $counter; $io->success('Imported customers: ' . $counter); } catch (\Exception $ex) { @@ -576,10 +584,11 @@ class KimaiImporterCommand extends Command * @param SymfonyStyle $io * @param array $customers * @param string $country + * @param string $currency * @return int * @throws \Exception */ - protected function importCustomers(SymfonyStyle $io, $customers, $country) + protected function importCustomers(SymfonyStyle $io, $customers, $country, $currency) { $counter = 0; $entityManager = $this->getDoctrine()->getManager(); @@ -607,6 +616,7 @@ class KimaiImporterCommand extends Command ->setTimezone($oldCustomer['timezone']) ->setVisible($isActive) ->setCountry(strtoupper($country)) + ->setCurrency(strtoupper($currency)) ; if (!$this->validateImport($io, $customer)) { @@ -910,6 +920,7 @@ class KimaiImporterCommand extends Command { $counter = 0; $activityCounter = 0; + $userCounter = 0; $entityManager = $this->getDoctrine()->getManager(); $total = count($records); @@ -949,11 +960,45 @@ class KimaiImporterCommand extends Command $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']])) { - $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(); @@ -1028,6 +1073,9 @@ class KimaiImporterCommand extends Command } $io->writeln(' (' . $counter . '/' . $total . ')'); + if ($userCounter > 0) { + $io->success('Created new users during timesheet import: ' . $userCounter); + } if ($activityCounter > 0) { $io->success('Created new activities during timesheet import: ' . $activityCounter); } diff --git a/var/docs/installation.md b/var/docs/installation.md index 49ee967d..73ed4b29 100644 --- a/var/docs/installation.md +++ b/var/docs/installation.md @@ -75,9 +75,9 @@ For available roles, please refer to the [user documentation](users.md). > **NOTE** > > 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: -> 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 :-) diff --git a/var/docs/migration_v1.md b/var/docs/migration_v1.md index 45c7a6f9..5a647551 100644 --- a/var/docs/migration_v1.md +++ b/var/docs/migration_v1.md @@ -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 - Customers in Kimai 2 are only used for recording - 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 - 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: ```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. A sample command could look like that: ```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. -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.