diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 1637ee098..09897fec2 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -19,6 +19,8 @@ namespace Chill\MainBundle\DependencyInjection; +use Chill\MainBundle\Entity\UserJob; +use Chill\MainBundle\Form\UserJobType; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; @@ -264,6 +266,27 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ + 'cruds' => [ + [ + 'class' => UserJob::class, + 'name' => 'admin_user_job', + 'base_path' => '/admin/main/user-job', + 'base_role' => 'ROLE_ADMIN', + 'form_class' => UserJobType::class, + 'actions' => [ + 'index' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/UserJob/index.html.twig', + ], + 'new' => [ + 'role' => 'ROLE_ADMIN' + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN' + ] + ], + ], + ], 'apis' => [ [ 'class' => \Chill\MainBundle\Entity\Address::class, diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 76bb7b54d..140e0889c 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -5,6 +5,7 @@ namespace Chill\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Chill\MainBundle\Entity\UserJob; use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; @@ -20,7 +21,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap; * }) */ class User implements AdvancedUserInterface { - + /** * @var integer * @@ -36,7 +37,7 @@ class User implements AdvancedUserInterface { * @ORM\Column(type="string", length=80) */ private $username; - + /** * @var string * @@ -46,14 +47,19 @@ class User implements AdvancedUserInterface { * unique=true) */ private $usernameCanonical; - + + /** + * @ORM\Column(type="string", length=200) + */ + private string $label = ''; + /** * @var string * * @ORM\Column(type="string", length=150, nullable=true) */ private $email; - + /** * @var string * @@ -64,14 +70,14 @@ class User implements AdvancedUserInterface { * unique=true) */ private $emailCanonical; - + /** * @var string * * @ORM\Column(type="string", length=255) */ private $password; - + /** * @var string * @internal must be set to null if we use bcrypt @@ -79,7 +85,7 @@ class User implements AdvancedUserInterface { * @ORM\Column(type="string", length=255, nullable=true) */ private $salt = null; - + /** * @var boolean * @@ -87,14 +93,14 @@ class User implements AdvancedUserInterface { * sf4 check: in yml was false by default !? */ private $locked = true; - + /** * @var boolean * * @ORM\Column(type="boolean") */ private $enabled = true; - + /** * @var Collection * @@ -112,7 +118,25 @@ class User implements AdvancedUserInterface { * @ORM\Column(type="json_array", nullable=true) */ private $attributes; - + + /** + * @var Center|null + * @ORM\ManyToOne(targetEntity=Center::class) + */ + private ?Center $mainCenter = null; + + /** + * @var Scope|null + * @ORM\ManyToOne(targetEntity=Scope::class) + */ + private ?Scope $mainScope = null; + + /** + * @var UserJob|null + * @ORM\ManyToOne(targetEntity=UserJob::class) + */ + private ?UserJob $userJob = null; + /** * User constructor. */ @@ -120,13 +144,13 @@ class User implements AdvancedUserInterface { { $this->groupCenters = new ArrayCollection(); } - + /** * @return string */ public function __toString() { - return $this->getUsername(); + return $this->getLabel(); } /** @@ -148,10 +172,14 @@ class User implements AdvancedUserInterface { public function setUsername($name) { $this->username = $name; - + + if (empty($this->getLabel())) { + $this->setLabel($name); + } + return $this; } - + /** * @return string */ @@ -159,11 +187,11 @@ class User implements AdvancedUserInterface { { return $this->username; } - + /** */ public function eraseCredentials() {} - + /** * @return array */ @@ -171,7 +199,7 @@ class User implements AdvancedUserInterface { { return array('ROLE_USER'); } - + /** * @return null|string */ @@ -179,7 +207,7 @@ class User implements AdvancedUserInterface { { return $this->salt; } - + /** * @param $usernameCanonical * @return $this @@ -187,10 +215,10 @@ class User implements AdvancedUserInterface { public function setUsernameCanonical($usernameCanonical) { $this->usernameCanonical = $usernameCanonical; - + return $this; } - + /** * @return string */ @@ -198,7 +226,7 @@ class User implements AdvancedUserInterface { { return $this->usernameCanonical; } - + /** * @param $email * @return $this @@ -206,10 +234,10 @@ class User implements AdvancedUserInterface { public function setEmail($email) { $this->email = $email; - + return $this; } - + /** * @return string */ @@ -217,7 +245,7 @@ class User implements AdvancedUserInterface { { return $this->email; } - + /** * @param $emailCanonical * @return $this @@ -225,10 +253,10 @@ class User implements AdvancedUserInterface { public function setEmailCanonical($emailCanonical) { $this->emailCanonical = $emailCanonical; - + return $this; } - + /** * @return string */ @@ -236,7 +264,7 @@ class User implements AdvancedUserInterface { { return $this->emailCanonical; } - + /** * @param $password * @return $this @@ -244,7 +272,7 @@ class User implements AdvancedUserInterface { function setPassword($password) { $this->password = $password; - + return $this; } @@ -255,7 +283,7 @@ class User implements AdvancedUserInterface { { return $this->password; } - + /** * @param $salt * @return $this @@ -265,7 +293,7 @@ class User implements AdvancedUserInterface { $this->salt = $salt; return $this; } - + /** * @return bool */ @@ -273,7 +301,7 @@ class User implements AdvancedUserInterface { { return true; } - + /** * @return bool */ @@ -281,7 +309,7 @@ class User implements AdvancedUserInterface { { return $this->locked; } - + /** * @return bool */ @@ -289,7 +317,7 @@ class User implements AdvancedUserInterface { { return true; } - + /** * @return bool */ @@ -297,17 +325,17 @@ class User implements AdvancedUserInterface { { return $this->enabled; } - + /** * @param bool $enabled */ public function setEnabled($enabled) { $this->enabled = $enabled; - + return $this; } - + /** * @return GroupCenter */ @@ -315,7 +343,7 @@ class User implements AdvancedUserInterface { { return $this->groupCenters; } - + /** * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter * @return \Chill\MainBundle\Entity\User @@ -325,7 +353,7 @@ class User implements AdvancedUserInterface { $this->groupCenters->add($groupCenter); return $this; } - + /** * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter * @throws \RuntimeException if the groupCenter is not in the collection @@ -337,9 +365,9 @@ class User implements AdvancedUserInterface { . "it seems not to be associated with the user. Aborting.")); } } - + /** - * This function check that groupCenter are present only once. The validator + * This function check that groupCenter are present only once. The validator * use this function to avoid a user to be associated to the same groupCenter * more than once. */ @@ -350,7 +378,7 @@ class User implements AdvancedUserInterface { if (in_array($groupCenter->getId(), $groupCentersIds)) { $context->buildViolation("The user has already those permissions") ->addViolation(); - + } else { $groupCentersIds[] = $groupCenter->getId(); } @@ -384,4 +412,76 @@ class User implements AdvancedUserInterface { return $this->attributes; } + + /** + * @return string + */ + public function getLabel(): string + { + return $this->label; + } + + /** + * @param string $label + * @return User + */ + public function setLabel(string $label): User + { + $this->label = $label; + return $this; + } + + /** + * @return Center|null + */ + public function getMainCenter(): ?Center + { + return $this->mainCenter; + } + + /** + * @param Center|null $mainCenter + * @return User + */ + public function setMainCenter(?Center $mainCenter): User + { + $this->mainCenter = $mainCenter; + return $this; + } + + /** + * @return Scope|null + */ + public function getMainScope(): ?Scope + { + return $this->mainScope; + } + + /** + * @param Scope|null $mainScope + * @return User + */ + public function setMainScope(?Scope $mainScope): User + { + $this->mainScope = $mainScope; + return $this; + } + + /** + * @return UserJob|null + */ + public function getUserJob(): ?UserJob + { + return $this->userJob; + } + + /** + * @param UserJob|null $userJob + * @return User + */ + public function setUserJob(?UserJob $userJob): User + { + $this->userJob = $userJob; + return $this; + } } diff --git a/src/Bundle/ChillMainBundle/Entity/UserJob.php b/src/Bundle/ChillMainBundle/Entity/UserJob.php new file mode 100644 index 000000000..9d1ca9157 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/UserJob.php @@ -0,0 +1,76 @@ +id; + } + + /** + * @return array|string[] + */ + public function getLabel(): array + { + return $this->label; + } + + /** + * @param array|string[] $label + * @return UserJob + */ + public function setLabel(array $label): UserJob + { + $this->label = $label; + return $this; + } + + /** + * @return bool + */ + public function isActive(): bool + { + return $this->active; + } + + /** + * @param bool $active + * @return UserJob + */ + public function setActive(bool $active): UserJob + { + $this->active = $active; + return $this; + } +} diff --git a/src/Bundle/ChillMainBundle/Form/UserJobType.php b/src/Bundle/ChillMainBundle/Form/UserJobType.php new file mode 100644 index 000000000..eec718261 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/UserJobType.php @@ -0,0 +1,27 @@ +add('label', TranslatableStringFormType::class, [ + 'label' => 'Label', + 'required' => true + ]) + ->add('active', ChoiceType::class, [ + 'choices' => [ + 'Active' => true, + 'Inactive' => false + ] + ]) + ; + } + +} diff --git a/src/Bundle/ChillMainBundle/Form/UserType.php b/src/Bundle/ChillMainBundle/Form/UserType.php index 5196ee6c0..09e2d1391 100644 --- a/src/Bundle/ChillMainBundle/Form/UserType.php +++ b/src/Bundle/ChillMainBundle/Form/UserType.php @@ -2,7 +2,15 @@ namespace Chill\MainBundle\Form; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\UserJob; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -16,6 +24,16 @@ use Chill\MainBundle\Form\UserPasswordType; class UserType extends AbstractType { + private TranslatableStringHelper $translatableStringHelper; + + /** + * @param TranslatableStringHelper $translatableStringHelper + */ + public function __construct(TranslatableStringHelper $translatableStringHelper) + { + $this->translatableStringHelper = $translatableStringHelper; + } + /** * @param FormBuilderInterface $builder * @param array $options @@ -24,7 +42,40 @@ class UserType extends AbstractType { $builder ->add('username') - ->add('email') + ->add('email', EmailType::class, [ + 'required' => true + ]) + ->add('label', TextType::class) + ->add('mainCenter', EntityType::class, [ + 'label' => 'main center', + 'required' => false, + 'placeholder' => 'choose a main center', + 'class' => Center::class, + 'query_builder' => function (EntityRepository $er) { + $qb = $er->createQueryBuilder('c'); + $qb->addOrderBy('c.name'); + + return $qb; + } + ]) + ->add('mainScope', EntityType::class, [ + 'label' => 'Choose a main scope', + 'required' => false, + 'placeholder' => 'choose a main scope', + 'class' => Scope::class, + 'choice_label' => function (Scope $c) { + return $this->translatableStringHelper->localize($c->getName()); + }, + ]) + ->add('userJob', EntityType::class, [ + 'label' => 'Choose a job', + 'required' => false, + 'placeholder' => 'choose a job', + 'class' => UserJob::class, + 'choice_label' => function (UserJob $c) { + return $this->translatableStringHelper->localize($c->getLabel()); + }, + ]) ; if ($options['is_creation']) { $builder->add('plainPassword', RepeatedType::class, array( diff --git a/src/Bundle/ChillMainBundle/Resources/views/CRUD/Admin/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/CRUD/Admin/index.html.twig new file mode 100644 index 000000000..1dc0acc81 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/CRUD/Admin/index.html.twig @@ -0,0 +1,8 @@ +{% extends '@ChillMain/Admin/layout.html.twig' %} + +{% block title %}{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}{% endblock %} + +{% block content %} + {% embed '@ChillMain/CRUD/_index.html.twig' %} + {% endembed %} +{% endblock content %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/UserJob/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/UserJob/index.html.twig new file mode 100644 index 000000000..8f037f150 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/UserJob/index.html.twig @@ -0,0 +1,26 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block content %} + {% embed '@ChillMain/CRUD/_index.html.twig' %} + {% block table_entities_thead_tr %} + id + label +   + {% endblock %} + {% block table_entities_tbody %} + {% for entity in entities %} + + {{ entity.id }} + {{ entity.label|localize_translatable_string }} + + + + + {% endfor %} + {% endblock %} + {% endembed %} +{% endblock content %} diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index bd5c1ece5..f719edb55 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -113,6 +113,10 @@ services: tags: - { name: form.type } + Chill\MainBundle\Form\UserType: + autowire: true + autoconfigure: true + Chill\MainBundle\Form\PermissionsGroupType: tags: - { name: form.type } @@ -123,3 +127,4 @@ services: - "@security.token_storage" tags: - { name: form.type } + diff --git a/src/Bundle/ChillMainBundle/config/validation.yaml b/src/Bundle/ChillMainBundle/config/validation.yaml index dd5f8d985..79cf4d8f9 100644 --- a/src/Bundle/ChillMainBundle/config/validation.yaml +++ b/src/Bundle/ChillMainBundle/config/validation.yaml @@ -18,6 +18,8 @@ Chill\MainBundle\Entity\User: min: 3 email: - Email: ~ + label: + - NotBlank: ~ constraints: - Callback: callback: isGroupCenterPresentOnce diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php b/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php new file mode 100644 index 000000000..4e252c3a3 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php @@ -0,0 +1,53 @@ +addSql('CREATE SEQUENCE chill_main_user_job_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_main_user_job (id INT NOT NULL, label JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('ALTER TABLE users ADD label VARCHAR(200) NULL DEFAULT NULL'); + $this->addSql('UPDATE users SET label=username'); + $this->addSql('ALTER TABLE users ALTER label DROP DEFAULT'); + $this->addSql('ALTER TABLE users ALTER label SET NOT NULL'); + $this->addSql('ALTER TABLE users ADD mainCenter_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ADD mainScope_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ADD userJob_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ALTER usernamecanonical SET NOT NULL'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E92C2125C1 FOREIGN KEY (mainCenter_id) REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E9115E73F3 FOREIGN KEY (mainScope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E964B65C5B FOREIGN KEY (userJob_id) REFERENCES chill_main_user_job (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_1483A5E92C2125C1 ON users (mainCenter_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E9115E73F3 ON users (mainScope_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E964B65C5B ON users (userJob_id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E964B65C5B'); + $this->addSql('DROP SEQUENCE chill_main_user_job_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_user_job'); + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E92C2125C1'); + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E9115E73F3'); + $this->addSql('ALTER TABLE users DROP label'); + $this->addSql('ALTER TABLE users DROP mainCenter_id'); + $this->addSql('ALTER TABLE users DROP mainScope_id'); + $this->addSql('ALTER TABLE users DROP userJob_id'); + $this->addSql('ALTER TABLE users ALTER usernameCanonical DROP NOT NULL'); + } +}