extends User entity + alter admin (WIP)

This commit is contained in:
Julien Fastré 2021-09-03 17:28:03 +02:00
parent 960bac8c37
commit 9b38e486df
10 changed files with 413 additions and 42 deletions

View File

@ -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,

View File

@ -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;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("chill_main_user_job")
*/
class UserJob
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected ?int $id = null;
/**
* @var array|string[]A
* @ORM\Column(name="label", type="json")
*/
protected array $label = [];
/**
* @var bool
* @ORM\Column(name="active", type="boolean")
*/
protected bool $active = true;
/**
* @return int|null
*/
public function getId(): ?int
{
return $this->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;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Chill\MainBundle\Form;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
class UserJobType extends \Symfony\Component\Form\AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TranslatableStringFormType::class, [
'label' => 'Label',
'required' => true
])
->add('active', ChoiceType::class, [
'choices' => [
'Active' => true,
'Inactive' => false
]
])
;
}
}

View File

@ -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(

View File

@ -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 %}

View File

@ -0,0 +1,26 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block table_entities_thead_tr %}
<th>id</th>
<th>label</th>
<th>&nbsp;</th>
{% endblock %}
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.label|localize_translatable_string }}</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_crud_admin_user_job_edit', { 'id': entity.id}) }}" class="btn btn-sm btn-edit btn-mini"></a>
</li>
</ul>
</td>
</tr>
{% endfor %}
{% endblock %}
{% endembed %}
{% endblock content %}

View File

@ -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 }

View File

@ -18,6 +18,8 @@ Chill\MainBundle\Entity\User:
min: 3
email:
- Email: ~
label:
- NotBlank: ~
constraints:
- Callback:
callback: isGroupCenterPresentOnce

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Add metadata on users
*/
final class Version20210903144853 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add metadata on users';
}
public function up(Schema $schema): void
{
$this->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');
}
}