cs: Fix code style (safe rules only).

This commit is contained in:
Pol Dellaiera
2021-11-23 14:06:38 +01:00
parent 149d7ce991
commit 8f96a1121d
1223 changed files with 65199 additions and 64625 deletions

View File

@@ -1,47 +1,47 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\PermissionsGroup;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use League\Csv\Reader;
use League\Csv\Writer;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use League\Csv\Reader;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\Center;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\PermissionsGroup;
use Symfony\Component\Console\Question\ChoiceQuestion;
use League\Csv\Writer;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function bin2hex;
use function implode;
use function random_bytes;
use function trim;
class ChillImportUsersCommand extends Command
{
protected EntityManagerInterface $em;
protected ValidatorInterface $validator;
protected LoggerInterface $logger;
protected UserPasswordEncoderInterface $passwordEncoder;
protected UserRepository $userRepository;
protected bool $doChanges = true;
protected OutputInterface $tempOutput;
protected InputInterface $tempInput;
/**
* Centers and aliases.
*
@@ -49,12 +49,28 @@ class ChillImportUsersCommand extends Command
*/
protected array $centers;
protected array $permissionGroups;
protected bool $doChanges = true;
protected EntityManagerInterface $em;
protected array $groupCenters;
protected LoggerInterface $logger;
protected Writer $output;
protected UserPasswordEncoderInterface $passwordEncoder;
protected array $permissionGroups;
protected InputInterface $tempInput;
protected OutputInterface $tempOutput;
protected UserRepository $userRepository;
protected ValidatorInterface $validator;
public function __construct(
EntityManagerInterface $em,
LoggerInterface $logger,
@@ -71,6 +87,27 @@ class ChillImportUsersCommand extends Command
parent::__construct('chill:main:import-users');
}
protected function appendUserToFile(User $user)
{
$this->output->insertOne([
$user->getEmail(),
$user->getUsername(),
$user->getId(),
]);
}
protected function concatenateViolations(ConstraintViolationListInterface $list)
{
$str = [];
foreach ($list as $e) {
/* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */
$str[] = $e->getMessage();
}
return implode(';', $str);
}
protected function configure()
{
$this
@@ -82,6 +119,99 @@ class ChillImportUsersCommand extends Command
->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file');
}
protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter
{
if (array_key_exists($center->getId(), $this->groupCenters)) {
if (array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) {
return $this->groupCenters[$center->getId()][$pg->getId()];
}
}
$repository = $this->em->getRepository(GroupCenter::class);
$groupCenter = $repository->findOneBy([
'center' => $center,
'permissionsGroup' => $pg,
]);
if (null === $groupCenter) {
$groupCenter = new GroupCenter();
$groupCenter
->setCenter($center)
->setPermissionsGroup($pg);
$this->em->persist($groupCenter);
}
$this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter;
return $groupCenter;
}
protected function createUser($offset, $data)
{
$user = new User();
$user
->setEmail(trim($data['email']))
->setUsername(trim($data['username']))
->setEnabled(true)
->setPassword($this->passwordEncoder->encodePassword(
$user,
bin2hex(random_bytes(32))
));
$errors = $this->validator->validate($user);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf('%d errors found with user with username "%s" at line %d', $errors->count(), $data['username'], $offset));
$this->tempOutput->writeln($errorMessages);
throw new RuntimeException('Found errors while creating an user. '
. 'Watch messages in command output');
}
$pgs = $this->getPermissionGroup($data['permission group']);
$centers = $this->getCenters($data['center']);
foreach ($pgs as $pg) {
foreach ($centers as $center) {
$groupcenter = $this->createOrGetGroupCenter($center, $pg);
if (false === $user->getGroupCenters()->contains($groupcenter)) {
$user->addGroupCenter($groupcenter);
}
}
}
if ($this->doChanges) {
$this->em->persist($user);
$this->em->flush();
}
$this->logger->notice('Create user', [
'username' => $user->getUsername(),
'id' => $user->getId(),
'nb_of_groupCenters' => $user->getGroupCenters()->count(),
]);
return $user;
}
protected function doesUserExists($data)
{
if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) {
return true;
}
if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) {
return true;
}
return false;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->tempOutput = $output;
@@ -99,221 +229,11 @@ class ChillImportUsersCommand extends Command
try {
$this->loadUsers();
}
catch(\Exception $e) {
} catch (Exception $e) {
throw $e;
}
}
protected function prepareWriter()
{
$this->output = $output = Writer::createFromPath($this->tempInput
->getOption('csv-dump'), 'a+');
$output->insertOne([
'email',
'username',
'id'
]);
}
protected function appendUserToFile(User $user)
{
$this->output->insertOne( [
$user->getEmail(),
$user->getUsername(),
$user->getId()
]);
}
protected function loadUsers()
{
$reader = Reader::createFromPath($this->tempInput->getArgument('csvfile'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $line => $r) {
$this->logger->debug("starting handling new line", [
'line' => $line
]);
if ($this->doesUserExists($r)) {
$this->tempOutput->writeln(sprintf("User with username '%s' already "
. "exists, skipping", $r["username"]));
$this->logger->info("One user already exists, skipping creation", [
'username_in_file' => $r['username'],
'email_in_file' => $r['email'],
'line' => $line
]);
continue;
}
$user = $this->createUser($line, $r);
$this->appendUserToFile($user);
}
}
protected function doesUserExists($data)
{
if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) {
return true;
}
if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) {
return true;
}
return false;
}
protected function createUser($offset, $data)
{
$user = new User();
$user
->setEmail(\trim($data['email']))
->setUsername(\trim($data['username']))
->setEnabled(true)
->setPassword($this->passwordEncoder->encodePassword($user,
\bin2hex(\random_bytes(32))))
;
$errors = $this->validator->validate($user);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf("%d errors found with user with username \"%s\" at line %d", $errors->count(), $data['username'], $offset));
$this->tempOutput->writeln($errorMessages);
throw new \RuntimeException("Found errors while creating an user. "
. "Watch messages in command output");
}
$pgs = $this->getPermissionGroup($data['permission group']);
$centers = $this->getCenters($data['center']);
foreach($pgs as $pg) {
foreach ($centers as $center) {
$groupcenter = $this->createOrGetGroupCenter($center, $pg);
if (FALSE === $user->getGroupCenters()->contains($groupcenter)) {
$user->addGroupCenter($groupcenter);
}
}
}
if ($this->doChanges) {
$this->em->persist($user);
$this->em->flush();
}
$this->logger->notice("Create user", [
'username' => $user->getUsername(),
'id' => $user->getId(),
'nb_of_groupCenters' => $user->getGroupCenters()->count()
]);
return $user;
}
protected function getPermissionGroup($alias)
{
if (\array_key_exists($alias, $this->permissionGroups)) {
return $this->permissionGroups[$alias];
}
$permissionGroupsByName = [];
foreach($this->em->getRepository(PermissionsGroup::class)
->findAll() as $permissionGroup) {
$permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup;
}
if (count($permissionGroupsByName) === 0) {
throw new \RuntimeException("no permission groups found. Create them "
. "before importing users");
}
$question = new ChoiceQuestion("To which permission groups associate with \"$alias\" ?",
\array_keys($permissionGroupsByName));
$question
->setMultiselect(true)
->setAutocompleterValues(\array_keys($permissionGroupsByName))
->setNormalizer(function($value) {
if (NULL === $value) { return ''; }
return \trim($value);
})
;
$helper = $this->getHelper('question');
$keys = $helper->ask($this->tempInput, $this->tempOutput, $question);
$this->tempOutput->writeln("You have chosen ".\implode(", ", $keys));
if ($helper->ask($this->tempInput, $this->tempOutput,
new ConfirmationQuestion("Are you sure ?", true))) {
foreach ($keys as $key) {
$this->permissionGroups[$alias][] = $permissionGroupsByName[$key];
}
return $this->permissionGroups[$alias];
}
$this->logger->error('Error while responding to a a question');
$this->tempOutput->writeln('Ok, I accept, but I do not know what to do. Please try again.');
throw new \RuntimeException('Error while responding to a question');
}
protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter
{
if (\array_key_exists($center->getId(), $this->groupCenters)) {
if (\array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) {
return $this->groupCenters[$center->getId()][$pg->getId()];
}
}
$repository = $this->em->getRepository(GroupCenter::class);
$groupCenter = $repository->findOneBy(array(
'center' => $center,
'permissionsGroup' => $pg
));
if ($groupCenter === NULL) {
$groupCenter = new GroupCenter();
$groupCenter
->setCenter($center)
->setPermissionsGroup($pg)
;
$this->em->persist($groupCenter);
}
$this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter;
return $groupCenter;
}
protected function prepareGroupingCenters()
{
$reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $r) {
$this->centers[$r['alias']] =
\array_merge(
$this->centers[$r['alias']] ?? [],
$this->getCenters($r['center']
)
);
}
}
/**
* return a list of centers matching the name of alias.
*
@@ -326,14 +246,15 @@ class ChillImportUsersCommand extends Command
* and suggested to user
*
* @param string $name the name of the center or the alias regrouping center
*
* @return Center[]
*/
protected function getCenters($name)
{
// sanitize
$name = \trim($name);
$name = trim($name);
if (\array_key_exists($name, $this->centers)) {
if (array_key_exists($name, $this->centers)) {
return $this->centers[$name];
}
@@ -351,23 +272,23 @@ class ChillImportUsersCommand extends Command
$center = (new Center())
->setName($name);
$this->tempOutput->writeln("Center with name \"$name\" not found.");
$this->tempOutput->writeln("Center with name \"{$name}\" not found.");
$qFormatter = $this->getHelper('question');
$question = new ConfirmationQuestion("Create a center with name \"$name\" ?", true);
$question = new ConfirmationQuestion("Create a center with name \"{$name}\" ?", true);
if ($qFormatter->ask($this->tempInput, $this->tempOutput, $question)) {
$this->centers[$name] = [ $center ];
$this->centers[$name] = [$center];
$errors = $this->validator->validate($center);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf("%d errors found with center with name \"%s\"", $errors->count(), $name));
$this->tempOutput->writeln(sprintf('%d errors found with center with name "%s"', $errors->count(), $name));
$this->tempOutput->writeln($errorMessages);
throw new \RuntimeException("Found errors while creating one center. "
. "Watch messages in command output");
throw new RuntimeException('Found errors while creating one center. '
. 'Watch messages in command output');
}
$this->em->persist($center);
@@ -378,16 +299,115 @@ class ChillImportUsersCommand extends Command
return null;
}
protected function concatenateViolations(ConstraintViolationListInterface $list)
protected function getPermissionGroup($alias)
{
$str = [];
foreach ($list as $e) {
/* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */
$str[] = $e->getMessage();
if (array_key_exists($alias, $this->permissionGroups)) {
return $this->permissionGroups[$alias];
}
return \implode(";", $str);
$permissionGroupsByName = [];
foreach ($this->em->getRepository(PermissionsGroup::class)
->findAll() as $permissionGroup) {
$permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup;
}
if (count($permissionGroupsByName) === 0) {
throw new RuntimeException('no permission groups found. Create them '
. 'before importing users');
}
$question = new ChoiceQuestion(
"To which permission groups associate with \"{$alias}\" ?",
array_keys($permissionGroupsByName)
);
$question
->setMultiselect(true)
->setAutocompleterValues(array_keys($permissionGroupsByName))
->setNormalizer(function ($value) {
if (null === $value) {
return '';
}
return trim($value);
});
$helper = $this->getHelper('question');
$keys = $helper->ask($this->tempInput, $this->tempOutput, $question);
$this->tempOutput->writeln('You have chosen ' . implode(', ', $keys));
if ($helper->ask(
$this->tempInput,
$this->tempOutput,
new ConfirmationQuestion('Are you sure ?', true)
)) {
foreach ($keys as $key) {
$this->permissionGroups[$alias][] = $permissionGroupsByName[$key];
}
return $this->permissionGroups[$alias];
}
$this->logger->error('Error while responding to a a question');
$this->tempOutput->writeln('Ok, I accept, but I do not know what to do. Please try again.');
throw new RuntimeException('Error while responding to a question');
}
protected function loadUsers()
{
$reader = Reader::createFromPath($this->tempInput->getArgument('csvfile'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $line => $r) {
$this->logger->debug('starting handling new line', [
'line' => $line,
]);
if ($this->doesUserExists($r)) {
$this->tempOutput->writeln(sprintf("User with username '%s' already "
. 'exists, skipping', $r['username']));
$this->logger->info('One user already exists, skipping creation', [
'username_in_file' => $r['username'],
'email_in_file' => $r['email'],
'line' => $line,
]);
continue;
}
$user = $this->createUser($line, $r);
$this->appendUserToFile($user);
}
}
protected function prepareGroupingCenters()
{
$reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $r) {
$this->centers[$r['alias']] =
array_merge(
$this->centers[$r['alias']] ?? [],
$this->getCenters(
$r['center']
)
);
}
}
protected function prepareWriter()
{
$this->output = $output = Writer::createFromPath($this->tempInput
->getOption('csv-dump'), 'a+');
$output->insertOne([
'email',
'username',
'id',
]);
}
}

View File

@@ -1,88 +1,92 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Mailer;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use InvalidArgumentException;
use League\Csv\Reader;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use League\Csv\Reader;
use Psr\Log\LoggerInterface;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Mailer;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use function array_key_exists;
use function array_merge;
use function in_array;
use function trim;
/**
* Class ChillUserSendRenewPasswordCodeCommand
*
* @package Chill\MainBundle\Command
* Class ChillUserSendRenewPasswordCodeCommand.
*/
class ChillUserSendRenewPasswordCodeCommand extends Command
{
/**
*
* @var LoggerInterface
*/
protected $logger;
/**
*
* @var EntityManagerInterface
*/
protected $em;
/**
*
* @var Mailer
*/
protected $mailer;
/**
*
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
*
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The current input interface
* @var LoggerInterface
*/
protected $logger;
/**
* @var Mailer
*/
protected $mailer;
/**
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
* The current input interface.
*
* @var InputInterface
*/
private $input;
/**
* The current output interface
* The current output interface.
*
* @var OutputInterface
*/
private $output;
public function __construct(
LoggerInterface $logger,
EntityManagerInterface $em,
RecoverPasswordHelper $recoverPasswordHelper,
LoggerInterface $logger,
EntityManagerInterface $em,
RecoverPasswordHelper $recoverPasswordHelper,
EventDispatcherInterface $eventDispatcher
) {
$this->logger = $logger;
$this->em = $em;
$this->recoverPasswordHelper = $recoverPasswordHelper;
$this->eventDispatcher = $eventDispatcher;
parent::__construct();
}
protected function configure()
{
$this
@@ -91,113 +95,114 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
->addArgument('csvfile', InputArgument::REQUIRED, 'CSV file with the list of users')
->addOption('template', null, InputOption::VALUE_REQUIRED, 'Template for email')
->addOption('expiration', null, InputOption::VALUE_REQUIRED, 'Expiration of the link, as an unix timestamp')
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password')
;
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->output = $output;
$reader = $this->getReader();
foreach($reader->getRecords() as $offset => $r) {
foreach ($reader->getRecords() as $offset => $r) {
$user = $this->getUser($r);
if ($user === null) {
if (null === $user) {
$this->onUserNotFound($r, $offset);
continue;
}
$this->sendRecoverCode($user);
}
}
protected function sendRecoverCode(User $user)
{
if (empty($user->getEmail())) {
$this->logger->alert("User without email", [
'user_id' => $user->getId(),
'username' => $user->getUsername()
]);
return;
}
$template = $this->input->getOption('template');
$expiration = \DateTime::createFromFormat('U',
$this->input->getOption('expiration'));
$this->recoverPasswordHelper
->sendRecoverEmail(
$user,
$expiration,
$template,
[ 'expiration' => $expiration],
false,
[ '_locale' => 'fr' ],
$this->input->getOption('subject')
);
}
protected function onUserNotFound($row, $offset)
{
$this->logger->alert('User not found', \array_merge([
'offset' => $offset
], $row));
}
protected function getUser($row)
{
/* @var $userRepository \Chill\MainBundle\Repository\UserRepository */
$userRepository = $this->em->getRepository(User::class);
try {
if (\array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim($row['email']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
// continue, we will try username
}
try {
if (\array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim($row['username']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
/**
*
* @throws Exception
*
* @return Reader
* @throws \Exception
*/
protected function getReader()
{
try {
$reader = Reader::createFromPath($this->input->getArgument('csvfile'));
} catch (\Exception $e) {
$this->logger->error("The csv file could not be read", [
'path' => $this->input->getArgument('csvfile')
} catch (Exception $e) {
$this->logger->error('The csv file could not be read', [
'path' => $this->input->getArgument('csvfile'),
]);
throw $e;
}
$reader->setHeaderOffset(0);
$headers = $reader->getHeader();
if (FALSE === \in_array('username', $headers)
&& FALSE === \in_array('email', $headers)) {
throw new \InvalidArgumentException("The csv file does not have an "
. "username or email header");
if (false === in_array('username', $headers)
&& false === in_array('email', $headers)) {
throw new InvalidArgumentException('The csv file does not have an '
. 'username or email header');
}
return $reader;
}
protected function getUser($row)
{
/* @var $userRepository \Chill\MainBundle\Repository\UserRepository */
$userRepository = $this->em->getRepository(User::class);
try {
if (array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['email']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
// continue, we will try username
}
try {
if (array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['username']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
protected function onUserNotFound($row, $offset)
{
$this->logger->alert('User not found', array_merge([
'offset' => $offset,
], $row));
}
protected function sendRecoverCode(User $user)
{
if (empty($user->getEmail())) {
$this->logger->alert('User without email', [
'user_id' => $user->getId(),
'username' => $user->getUsername(),
]);
return;
}
$template = $this->input->getOption('template');
$expiration = DateTime::createFromFormat(
'U',
$this->input->getOption('expiration')
);
$this->recoverPasswordHelper
->sendRecoverEmail(
$user,
$expiration,
$template,
['expiration' => $expiration],
false,
['_locale' => 'fr'],
$this->input->getOption('subject')
);
}
}

View File

@@ -1,69 +1,57 @@
<?php
/*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
/*
* Load or update the languages entities command
*/
class LoadAndUpdateLanguagesCommand extends Command
{
public const INCLUDE_ANCIENT = 'include_ancient';
public const INCLUDE_REGIONAL_VERSION = 'include_regional';
// Array of ancien languages (to exclude)
private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga',
'dum', 'enm', 'frm', 'gmh', 'mga', 'akk', 'phn', 'zxx', 'got', 'und', ];
private $availableLanguages;
/**
* @var EntityManager
*/
private $entityManager;
private $availableLanguages;
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ["ro_MD"];
private $regionalVersionToInclude = ['ro_MD'];
// Array of ancien languages (to exclude)
private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga",
"dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"];
const INCLUDE_REGIONAL_VERSION = 'include_regional';
const INCLUDE_ANCIENT = 'include_ancient';
/**
* LoadCountriesCommand constructor.
*
* @param EntityManager $entityManager
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
{
$this->entityManager=$entityManager;
$this->availableLanguages=$availableLanguages;
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
@@ -72,23 +60,24 @@ class LoadAndUpdateLanguagesCommand extends Command
{
$this
->setName('chill:main:languages:populate')
->setDescription('Load or update languages in db. This command does not delete existing '.
->setDescription('Load or update languages in db. This command does not delete existing ' .
'languages, but will update names according to available languages')
->addOption(
self::INCLUDE_REGIONAL_VERSION,
null,
InputOption::VALUE_NONE,
'Include the regional languages. The regional languages are languages with code containing _ excepted '
. implode(',', $this->regionalVersionToInclude) . '.')
self::INCLUDE_REGIONAL_VERSION,
null,
InputOption::VALUE_NONE,
'Include the regional languages. The regional languages are languages with code containing _ excepted '
. implode(',', $this->regionalVersionToInclude) . '.'
)
->addOption(
self::INCLUDE_ANCIENT,
null,
InputOption::VALUE_NONE,
'Include the ancient languages that are languages with code '
. implode(', ', $this->ancientToExclude) . '.')
;
self::INCLUDE_ANCIENT,
null,
InputOption::VALUE_NONE,
'Include the ancient languages that are languages with code '
. implode(', ', $this->ancientToExclude) . '.'
);
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
@@ -98,7 +87,7 @@ class LoadAndUpdateLanguagesCommand extends Command
$em = $this->entityManager;
$chillAvailableLanguages = $this->availableLanguages;
$languageBundle = Intl::getLanguageBundle();
$languages = array();
$languages = [];
foreach ($chillAvailableLanguages as $avLang) {
$languages[$avLang] = $languageBundle->getLanguageNames($avLang);
@@ -109,25 +98,25 @@ class LoadAndUpdateLanguagesCommand extends Command
foreach ($languageCodes as $code) {
$excludeCode = (
(
! $input->getOption(self::INCLUDE_REGIONAL_VERSION)
!$input->getOption(self::INCLUDE_REGIONAL_VERSION)
and strpos($code, '_')
and !in_array($code, $this->regionalVersionToInclude)
) or (
! $input->getOption(self::INCLUDE_ANCIENT)
!$input->getOption(self::INCLUDE_ANCIENT)
and in_array($code, $this->ancientToExclude)
)
);
$langageDB = $em->getRepository('ChillMainBundle:Language')->find($code);
if(! $excludeCode) {
if (! $langageDB) {
if (!$excludeCode) {
if (!$langageDB) {
$langageDB = new \Chill\MainBundle\Entity\Language();
$langageDB->setId($code);
$em->persist($langageDB);
}
$avLangNames = array();
$avLangNames = [];
foreach ($chillAvailableLanguages as $avLang) {
$avLangNames[$avLang] = $languages[$avLang][$code];
@@ -135,10 +124,10 @@ class LoadAndUpdateLanguagesCommand extends Command
$langageDB->setName($avLangNames);
} else {
if($langageDB) {
if ($langageDB) {
$em->remove($langageDB);
}
echo "Code excluded : ".$code." - ".$languageBundle->getLanguageName($code)."\n";
echo 'Code excluded : ' . $code . ' - ' . $languageBundle->getLanguageName($code) . "\n";
}
}

View File

@@ -1,74 +1,41 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
/**
*
* @author Julien Fastré <julien.fastre@champs-libres.coop
*
*/
class LoadCountriesCommand extends Command
{
private $availableLanguages;
/**
* @var EntityManager
*/
private $entityManager;
private $availableLanguages;
/**
* LoadCountriesCommand constructor.
*
* @param EntityManager $entityManager
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
{
$this->entityManager=$entityManager;
$this->availableLanguages=$availableLanguages;
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
*/
protected function configure()
{
$this->setName('chill:main:countries:populate')
->setDescription('Load or update countries in db. This command does not delete existing countries, '.
'but will update names according to available languages');
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
foreach($countries as $country) {
$countryStored = $em->getRepository('ChillMainBundle:Country')
->findOneBy(array('countryCode' => $country->getCountryCode()));
if (NULL === $countryStored) {
$em->persist($country);
} else {
$countryStored->setName($country->getName());
}
}
$em->flush();
}
public static function prepareCountryList($languages)
{
$regionBundle = Intl::getRegionBundle();
@@ -78,10 +45,10 @@ class LoadCountriesCommand extends Command
$countries[$language] = $regionBundle->getCountryNames($language);
}
$countryEntities = array();
$countryEntities = [];
foreach ($countries[$languages[0]] as $countryCode => $name) {
$names = array();
$names = [];
foreach ($languages as $language) {
$names[$language] = $countries[$language][$countryCode];
@@ -94,4 +61,38 @@ class LoadCountriesCommand extends Command
return $countryEntities;
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
*/
protected function configure()
{
$this->setName('chill:main:countries:populate')
->setDescription('Load or update countries in db. This command does not delete existing countries, ' .
'but will update names according to available languages');
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
foreach ($countries as $country) {
$countryStored = $em->getRepository('ChillMainBundle:Country')
->findOneBy(['countryCode' => $country->getCountryCode()]);
if (null === $countryStored) {
$em->persist($country);
} else {
$countryStored->setName($country->getName());
}
}
$em->flush();
}
}

View File

@@ -1,20 +1,28 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Country;
use Doctrine\ORM\EntityManager;
use Chill\MainBundle\Entity\PostalCode;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Filesystem\Filesystem;
use Chill\MainBundle\Entity\PostalCode;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class LoadPostalCodesCommand extends Command
@@ -33,38 +41,38 @@ class LoadPostalCodesCommand extends Command
protected function configure()
{
$this->setName('chill:main:postal-code:populate')
->setDescription("Add the postal code from a csv file.")
->setHelp("This script will try to avoid existing postal code "
->setDescription('Add the postal code from a csv file.')
->setHelp('This script will try to avoid existing postal code '
. "using the postal code and name. \n"
. "The CSV file must have the following columns: "
. "postal code, label, country code."
. "Optionally, the csv file can have the following "
. "columns after the country code: reference code, latitude, longitude, source. "
. "The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. "
. "The CSV file should not have any header row.")
->addArgument('csv_file', InputArgument::REQUIRED, "the path to "
. "the csv file. See the help for specifications.")
->addOption(
'delimiter',
'd',
InputOption::VALUE_OPTIONAL,
"The delimiter character of the csv file",
",")
->addOption(
'enclosure',
null,
InputOption::VALUE_OPTIONAL,
"The enclosure character of the csv file",
'"'
)
->addOption(
'escape',
null,
InputOption::VALUE_OPTIONAL,
"The escape character of the csv file",
"\\"
)
;
. 'The CSV file must have the following columns: '
. 'postal code, label, country code.'
. 'Optionally, the csv file can have the following '
. 'columns after the country code: reference code, latitude, longitude, source. '
. 'The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. '
. 'The CSV file should not have any header row.')
->addArgument('csv_file', InputArgument::REQUIRED, 'the path to '
. 'the csv file. See the help for specifications.')
->addOption(
'delimiter',
'd',
InputOption::VALUE_OPTIONAL,
'The delimiter character of the csv file',
','
)
->addOption(
'enclosure',
null,
InputOption::VALUE_OPTIONAL,
'The enclosure character of the csv file',
'"'
)
->addOption(
'escape',
null,
InputOption::VALUE_OPTIONAL,
'The escape character of the csv file',
'\\'
);
}
protected function execute(InputInterface $input, OutputInterface $output)
@@ -79,90 +87,77 @@ class LoadPostalCodesCommand extends Command
$num = 0;
$line = 0;
while (($row = fgetcsv(
$csv,
0,
$input->getOption('delimiter'),
$input->getOption('enclosure'),
$input->getOption('escape'))) !== false) {
try{
while (false !== ($row = fgetcsv(
$csv,
0,
$input->getOption('delimiter'),
$input->getOption('enclosure'),
$input->getOption('escape')
))) {
try {
$this->addPostalCode($row, $output);
$num++;
++$num;
} catch (ExistingPostalCodeException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
} catch (CountryCodeNotFoundException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
} catch (PostalCodeNotValidException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
}
$line ++;
++$line;
}
$this->entityManager->flush();
$output->writeln('<info>'.$num.' were added !</info>');
}
private function getCSVResource(InputInterface $input)
{
$fs = new Filesystem();
$filename = $input->getArgument('csv_file');
if (!$fs->exists($filename)) {
throw new \RuntimeException("The file does not exists or you do not "
. "have the right to read it.");
}
$resource = fopen($filename, 'r');
if ($resource == FALSE) {
throw new \RuntimeException("The file '$filename' could not be opened.");
}
return $resource;
$output->writeln('<info>' . $num . ' were added !</info>');
}
private function addPostalCode($row, OutputInterface $output)
{
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$output->writeln('handling row: '. $row[0].' | '. $row[1].' | '. $row[2]);
$output->writeln('handling row: ' . $row[0] . ' | ' . $row[1] . ' | ' . $row[2]);
}
$em = $this->entityManager;
$country = $em
->getRepository(Country::class)
->findOneBy(array('countryCode' => $row[2]));
->getRepository(Country::class)
->findOneBy(['countryCode' => $row[2]]);
if ($country === NULL) {
throw new CountryCodeNotFoundException(sprintf("The country with code %s is not found. Aborting to insert postal code with %s - %s",
$row[2], $row[0], $row[1]));
if (null === $country) {
throw new CountryCodeNotFoundException(sprintf(
'The country with code %s is not found. Aborting to insert postal code with %s - %s',
$row[2],
$row[0],
$row[1]
));
}
// try to find an existing postal code
$existingPC = $em
->getRepository(PostalCode::class)
->findBy(array('code' => $row[0], 'name' => $row[1]));
->getRepository(PostalCode::class)
->findBy(['code' => $row[0], 'name' => $row[1]]);
if (count($existingPC) > 0) {
throw new ExistingPostalCodeException(sprintf("A postal code with code : %s and name : %s already exists, skipping",
$row[0], $row[1]));
throw new ExistingPostalCodeException(sprintf(
'A postal code with code : %s and name : %s already exists, skipping',
$row[0],
$row[1]
));
}
$postalCode = (new PostalCode())
->setCode($row[0])
->setName($row[1])
->setCountry($country)
;
->setCode($row[0])
->setName($row[1])
->setCountry($country);
if (NULL != $row[3]){
if (null != $row[3]) {
$postalCode->setRefPostalCodeId($row[3]);
}
if (NULL != $row[4] & NULL != $row[5]){
if (null != $row[4] & null != $row[5]) {
$postalCode->setCenter(Point::fromLonLat((float) $row[5], (float) $row[4]));
}
if (NULL != $row[6]){
if (null != $row[6]) {
$postalCode->setPostalCodeSource($row[6]);
}
@@ -171,35 +166,53 @@ class LoadPostalCodesCommand extends Command
if ($errors->count() == 0) {
$em->persist($postalCode);
} else {
$msg = "";
$msg = '';
foreach ($errors as $error) {
$msg .= " ".$error->getMessage();
$msg .= ' ' . $error->getMessage();
}
throw new PostalCodeNotValidException($msg);
}
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$output->writeln(sprintf('Creating postal code with code: %s, name: %s, countryCode: %s',
$postalCode->getCode(), $postalCode->getName(), $postalCode->getCountry()->getCountryCode()));
$output->writeln(sprintf(
'Creating postal code with code: %s, name: %s, countryCode: %s',
$postalCode->getCode(),
$postalCode->getName(),
$postalCode->getCountry()->getCountryCode()
));
}
}
private function getCSVResource(InputInterface $input)
{
$fs = new Filesystem();
$filename = $input->getArgument('csv_file');
if (!$fs->exists($filename)) {
throw new RuntimeException('The file does not exists or you do not '
. 'have the right to read it.');
}
$resource = fopen($filename, 'r');
if (false == $resource) {
throw new RuntimeException("The file '{$filename}' could not be opened.");
}
return $resource;
}
}
class ExistingPostalCodeException extends \Exception
class ExistingPostalCodeException extends Exception
{
}
class CountryCodeNotFoundException extends \Exception
class CountryCodeNotFoundException extends Exception
{
}
class PostalCodeNotValidException extends \Exception
class PostalCodeNotValidException extends Exception
{
}

View File

@@ -1,101 +1,55 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2014 Champs-Libres Coopérative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManager;
use LogicException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
use Symfony\Component\Security\Core\Security;
/**
* Class SetPasswordCommand
*
* @package Chill\MainBundle\Command
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Class SetPasswordCommand.
*/
class SetPasswordCommand extends Command
{
/**
* @var EntityManager
*/
private $entityManager;
/**
* SetPasswordCommand constructor.
*
* @param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
parent::__construct();
}
public function configure()
{
$this->setName('chill:user:set_password')
->setDescription('set a password to user')
->addArgument('username', InputArgument::REQUIRED, 'the user\'s '
. 'username you want to change password')
->addArgument('password', InputArgument::OPTIONAL, 'the new password')
;
}
public function execute(InputInterface $input, OutputInterface $output)
{
$user = $this->_getUser($input->getArgument('username'));
if ($user === NULL) {
throw new \LogicException("The user with username '".
$input->getArgument('username')."' is not found");
}
$password = $input->getArgument('password');
if ($password === NULL) {
$dialog = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, "<question>the new password :"
. "</question>");
}
$this->_setPassword($user, $password);
}
public function _getUser($username)
{
return $this->entityManager
->getRepository('ChillMainBundle:User')
->findOneBy(array('username' => $username));
->findOneBy(['username' => $username]);
}
public function _setPassword(User $user, $password)
{
$defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000);
$encoders = [
User::class => $defaultEncoder
User::class => $defaultEncoder,
];
$encoderFactory = new EncoderFactory($encoders);
$user->setPassword(
@@ -103,4 +57,33 @@ class SetPasswordCommand extends Command
);
$this->entityManager->flush($user);
}
public function configure()
{
$this->setName('chill:user:set_password')
->setDescription('set a password to user')
->addArgument('username', InputArgument::REQUIRED, 'the user\'s '
. 'username you want to change password')
->addArgument('password', InputArgument::OPTIONAL, 'the new password');
}
public function execute(InputInterface $input, OutputInterface $output)
{
$user = $this->_getUser($input->getArgument('username'));
if (null === $user) {
throw new LogicException("The user with username '" .
$input->getArgument('username') . "' is not found");
}
$password = $input->getArgument('password');
if (null === $password) {
$dialog = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, '<question>the new password :'
. '</question>');
}
$this->_setPassword($user, $password);
}
}