add user CRUD
This commit is contained in:
parent
1c545bfb63
commit
7497232a5a
|
@ -45,5 +45,6 @@ security:
|
||||||
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
- { path: ^/resetting, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
- { path: ^/resetting, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
|
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
|
||||||
|
- { path: ^/admin/user, roles: ROLE_ADMIN }
|
||||||
- { path: ^/admin, roles: ROLE_USER }
|
- { path: ^/admin, roles: ROLE_USER }
|
||||||
- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
|
|
|
@ -98,7 +98,7 @@ class AuthController extends AbstractController
|
||||||
EntityManager $entityManager
|
EntityManager $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
if ($this->getUser()) {
|
if ($this->getUser()) {
|
||||||
return $this->redirectToRoute('index');
|
return $this->redirectToRoute('admin_dashboard_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
$account = $repository->findOneByConfirmationToken($token);
|
$account = $repository->findOneByConfirmationToken($token);
|
||||||
|
|
|
@ -92,6 +92,7 @@ class CategoryAdminController extends AdminController
|
||||||
{
|
{
|
||||||
$posts = $postQuery->create()
|
$posts = $postQuery->create()
|
||||||
->orderBy('.publishedAt', 'DESC')
|
->orderBy('.publishedAt', 'DESC')
|
||||||
|
->orderBy('.createdAt', 'DESC')
|
||||||
->inCategory($entity)
|
->inCategory($entity)
|
||||||
->paginate(1, 10)
|
->paginate(1, 10)
|
||||||
;
|
;
|
||||||
|
|
160
src/Controller/User/UserAdminController.php
Normal file
160
src/Controller/User/UserAdminController.php
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\User;
|
||||||
|
|
||||||
|
use App\Controller\Admin\AdminController;
|
||||||
|
use App\Entity\User as Entity;
|
||||||
|
use App\Factory\UserFactory as EntityFactory;
|
||||||
|
use App\Form\UserType as EntityType;
|
||||||
|
use App\Manager\EntityManager;
|
||||||
|
use App\Repository\UserRepositoryQuery;
|
||||||
|
use App\Repository\UserRepositoryQuery as RepositoryQuery;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use App\Repository\Blog\PostRepositoryQuery;
|
||||||
|
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use App\Event\Account\PasswordRequestEvent;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/admin/user")
|
||||||
|
*/
|
||||||
|
class UserAdminController extends AdminController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/{page}", name="admin_user_index", requirements={"page": "\d+"})
|
||||||
|
*/
|
||||||
|
public function index(int $page = 1, RepositoryQuery $query, Request $request): Response
|
||||||
|
{
|
||||||
|
$pager = $query->paginate($page);
|
||||||
|
|
||||||
|
return $this->render('user/user_admin/index.html.twig', [
|
||||||
|
'pager' => $pager,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/new", name="admin_user_new")
|
||||||
|
*/
|
||||||
|
public function new(
|
||||||
|
EntityFactory $factory,
|
||||||
|
EntityManager $entityManager,
|
||||||
|
UserPasswordEncoderInterface $encoder,
|
||||||
|
Request $request
|
||||||
|
): Response
|
||||||
|
{
|
||||||
|
$entity = $factory->create($this->getUser());
|
||||||
|
$form = $this->createForm(EntityType::class, $entity);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$entityManager->create($entity);
|
||||||
|
$this->addFlash('success', 'Donnée enregistrée.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('admin_user_edit', [
|
||||||
|
'entity' => $entity->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->addFlash('warning', 'Le formulaire est invalide.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('user/user_admin/new.html.twig', [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'entity' => $entity,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/edit/{entity}", name="admin_user_edit")
|
||||||
|
*/
|
||||||
|
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||||
|
{
|
||||||
|
$form = $this->createForm(EntityType::class, $entity);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$entityManager->update($entity);
|
||||||
|
$this->addFlash('success', 'Donnée enregistrée.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('admin_user_edit', [
|
||||||
|
'entity' => $entity->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->addFlash('warning', 'Le formulaire est invalide.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('user/user_admin/edit.html.twig', [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'entity' => $entity,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/show/{entity}", name="admin_user_show")
|
||||||
|
*/
|
||||||
|
public function show(Entity $entity, PostRepositoryQuery $postQuery): Response
|
||||||
|
{
|
||||||
|
$posts = $postQuery->create()
|
||||||
|
->orderBy('.publishedAt', 'DESC')
|
||||||
|
->orderBy('.createdAt', 'DESC')
|
||||||
|
->filterByAuthor($entity)
|
||||||
|
->paginate(1, 10)
|
||||||
|
;
|
||||||
|
|
||||||
|
return $this->render('user/user_admin/show.html.twig', [
|
||||||
|
'entity' => $entity,
|
||||||
|
'posts' => $posts,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/resetting_request/{entity}", name="admin_user_resetting_request", methods={"POST"})
|
||||||
|
*/
|
||||||
|
public function requestResetting(
|
||||||
|
Entity $entity,
|
||||||
|
EntityManager $entityManager,
|
||||||
|
TokenGeneratorInterface $tokenGenerator,
|
||||||
|
EventDispatcherInterface $eventDispatcher,
|
||||||
|
Request $request
|
||||||
|
): Response
|
||||||
|
{
|
||||||
|
if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) {
|
||||||
|
$entity->setConfirmationToken($tokenGenerator->generateToken());
|
||||||
|
$entity->setPasswordRequestedAt(new \DateTime('now'));
|
||||||
|
|
||||||
|
$entityManager->update($entity);
|
||||||
|
$eventDispatcher->dispatch(new PasswordRequestEvent($entity), PasswordRequestEvent::EVENT);
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Demande envoyée.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute('admin_user_edit', [
|
||||||
|
'entity' => $entity->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/delete/{entity}", name="admin_user_delete", methods={"DELETE"})
|
||||||
|
*/
|
||||||
|
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||||
|
{
|
||||||
|
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
|
||||||
|
$entityManager->delete($entity);
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Données supprimées.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute('admin_user_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSection(): string
|
||||||
|
{
|
||||||
|
return 'user';
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,6 +71,7 @@ class Post implements EntityInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="posts")
|
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="posts")
|
||||||
|
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||||
*/
|
*/
|
||||||
private $author;
|
private $author;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity(repositoryClass=UserRepository::class)
|
* @ORM\Entity(repositoryClass=UserRepository::class)
|
||||||
* @ORM\HasLifecycleCallbacks
|
* @ORM\HasLifecycleCallbacks
|
||||||
* @ORM\Table(name="`user`")
|
|
||||||
*/
|
*/
|
||||||
class User implements UserInterface, TwoFactorInterface, EntityInterface
|
class User implements UserInterface, TwoFactorInterface, EntityInterface
|
||||||
{
|
{
|
||||||
|
@ -72,6 +71,11 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
|
||||||
*/
|
*/
|
||||||
private $posts;
|
private $posts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="boolean", options={"default"=0})
|
||||||
|
*/
|
||||||
|
private $isWriter;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->posts = new ArrayCollection();
|
$this->posts = new ArrayCollection();
|
||||||
|
@ -109,9 +113,9 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
|
||||||
*/
|
*/
|
||||||
public function getRoles(): array
|
public function getRoles(): array
|
||||||
{
|
{
|
||||||
$roles = $this->roles;
|
if ($this->getIsWriter()) {
|
||||||
// guarantee every user at least has ROLE_USER
|
$roles[] = 'ROLE_WRITER';
|
||||||
$roles[] = 'ROLE_USER';
|
}
|
||||||
|
|
||||||
if ($this->getIsAdmin()) {
|
if ($this->getIsAdmin()) {
|
||||||
$roles[] = 'ROLE_ADMIN';
|
$roles[] = 'ROLE_ADMIN';
|
||||||
|
@ -276,4 +280,16 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getIsWriter(): ?bool
|
||||||
|
{
|
||||||
|
return $this->isWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsWriter(bool $isWriter): self
|
||||||
|
{
|
||||||
|
$this->isWriter = $isWriter;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
36
src/Factory/UserFactory.php
Normal file
36
src/Factory/UserFactory.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
|
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class UserFactory.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class UserFactory
|
||||||
|
{
|
||||||
|
protected TokenGeneratorInterface $tokenGenerator;
|
||||||
|
protected UserPasswordEncoderInterface $encoder;
|
||||||
|
|
||||||
|
public function __construct(TokenGeneratorInterface $tokenGenerator, UserPasswordEncoderInterface $encoder)
|
||||||
|
{
|
||||||
|
$this->tokenGenerator = $tokenGenerator;
|
||||||
|
$this->encoder = $encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): User
|
||||||
|
{
|
||||||
|
$entity = new User();
|
||||||
|
|
||||||
|
$entity->setPassword($this->encoder->encodePassword(
|
||||||
|
$entity,
|
||||||
|
$this->tokenGenerator->generateToken()
|
||||||
|
));
|
||||||
|
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
}
|
92
src/Form/UserType.php
Normal file
92
src/Form/UserType.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\Email;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
|
|
||||||
|
class UserType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add(
|
||||||
|
'email',
|
||||||
|
EmailType::class,
|
||||||
|
[
|
||||||
|
'label' => 'E-mail',
|
||||||
|
'required' => true,
|
||||||
|
'attr' => [
|
||||||
|
],
|
||||||
|
'constraints' => [
|
||||||
|
new Email(),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
'displayName',
|
||||||
|
TextType::class,
|
||||||
|
[
|
||||||
|
'label' => 'Nom complet',
|
||||||
|
'required' => true,
|
||||||
|
'attr' => [
|
||||||
|
],
|
||||||
|
'constraints' => [
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
'displayName',
|
||||||
|
TextType::class,
|
||||||
|
[
|
||||||
|
'label' => 'Nom complet',
|
||||||
|
'required' => true,
|
||||||
|
'attr' => [
|
||||||
|
],
|
||||||
|
'constraints' => [
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
'isAdmin',
|
||||||
|
CheckboxType::class,
|
||||||
|
[
|
||||||
|
'label' => 'Administrateur⋅trice',
|
||||||
|
'required' => false,
|
||||||
|
'attr' => [
|
||||||
|
],
|
||||||
|
'constraints' => [
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
'isWriter',
|
||||||
|
CheckboxType::class,
|
||||||
|
[
|
||||||
|
'label' => 'Rédacteur⋅trice',
|
||||||
|
'required' => false,
|
||||||
|
'attr' => [
|
||||||
|
],
|
||||||
|
'constraints' => [
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => User::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ namespace App\Repository\Blog;
|
||||||
use App\Entity\Blog\Category;
|
use App\Entity\Blog\Category;
|
||||||
use App\Repository\RepositoryQuery;
|
use App\Repository\RepositoryQuery;
|
||||||
use Knp\Component\Pager\PaginatorInterface;
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
use App\Entity\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class PostRepositoryQuery.
|
* class PostRepositoryQuery.
|
||||||
|
@ -30,4 +31,14 @@ class PostRepositoryQuery extends RepositoryQuery
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function filterByAuthor(User $user)
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->andWhere('.author = :author')
|
||||||
|
->setParameter(':author', $user->getId())
|
||||||
|
;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,49 +50,53 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h6 class="sidebar-heading justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
{% if is_granted('ROLE_WRITER') %}
|
||||||
<span>Contenu</span>
|
<h6 class="sidebar-heading justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
</h6>
|
<span>Contenu</span>
|
||||||
|
</h6>
|
||||||
|
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ macros.active_class('page', section) }}" href="{{ path('admin_dashboard_index') }}">
|
<a class="nav-link {{ macros.active_class('page', section) }}" href="{{ path('admin_dashboard_index') }}">
|
||||||
<span class="fa fa-file-alt"></span>
|
<span class="fa fa-file-alt"></span>
|
||||||
|
|
||||||
<span class="nav-item-label">Pages</span>
|
<span class="nav-item-label">Pages</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ macros.active_class('blog_post', section) }}" href="{{ path('admin_blog_post_index') }}">
|
<a class="nav-link {{ macros.active_class('blog_post', section) }}" href="{{ path('admin_blog_post_index') }}">
|
||||||
<span class="fa fa-pen"></span>
|
<span class="fa fa-pen"></span>
|
||||||
|
|
||||||
<span class="nav-item-label">Articles</span>
|
<span class="nav-item-label">Articles</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ macros.active_class('blog_category', section) }}" href="{{ path('admin_blog_category_index') }}">
|
<a class="nav-link {{ macros.active_class('blog_category', section) }}" href="{{ path('admin_blog_category_index') }}">
|
||||||
<span class="fa fa-puzzle-piece"></span>
|
<span class="fa fa-puzzle-piece"></span>
|
||||||
|
|
||||||
<span class="nav-item-label">Catégories</span>
|
<span class="nav-item-label">Catégories</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h6 class="sidebar-heading justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
{% if is_granted('ROLE_ADMIN') %}
|
||||||
<span>Administration</span>
|
<h6 class="sidebar-heading justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
</h6>
|
<span>Administration</span>
|
||||||
|
</h6>
|
||||||
|
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ macros.active_class('user', section) }}" href="{{ path('admin_dashboard_index') }}">
|
<a class="nav-link {{ macros.active_class('user', section) }}" href="{{ path('admin_user_index') }}">
|
||||||
<span class="fa fa-user"></span>
|
<span class="fa fa-user"></span>
|
||||||
|
|
||||||
<span class="nav-item-label">Utilisateurs</span>
|
<span class="nav-item-label">Utilisateurs</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="col-11 col-md-10 ml-sm-auto col-lg-10 body">
|
<div class="col-11 col-md-10 ml-sm-auto col-lg-10 body">
|
||||||
|
|
|
@ -55,7 +55,8 @@
|
||||||
{% set categories = categories|merge(['<a href="' ~ url ~ '">' ~ category.title ~ '</a>']) %}
|
{% set categories = categories|merge(['<a href="' ~ url ~ '">' ~ category.title ~ '</a>']) %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
Dans {{ categories|join(', ')|raw }} par <a href="">{{ item.author.displayName }}</a>
|
Dans {{ categories|join(', ')|raw }}
|
||||||
|
par <a href="">{{ item.author ? item.author.displayName : '-' }}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="col-2">
|
<td class="col-2">
|
||||||
<span class="btn btn-sm btn-light">
|
<span class="btn btn-sm btn-light">
|
||||||
|
|
12
templates/user/user_admin/_form.html.twig
Normal file
12
templates/user/user_admin/_form.html.twig
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 p-3">
|
||||||
|
<div class="row">
|
||||||
|
{% for item in ['displayName', 'email', 'isAdmin', 'isWriter'] %}
|
||||||
|
<div class="col-12">
|
||||||
|
{{ form_row(form[item]) }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
64
templates/user/user_admin/edit.html.twig
Normal file
64
templates/user/user_admin/edit.html.twig
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
{% extends 'admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="mr-auto w-50">
|
||||||
|
<h1 class="display-5">{{ entity.displayName }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{{ path('admin_user_index') }}" class="btn btn-light">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
Retour à la liste
|
||||||
|
</a>
|
||||||
|
<a href="{{ path('admin_user_show', {entity: entity.id}) }}" class="btn btn-secondary">
|
||||||
|
<span class="fa fa-eye pr-1"></span>
|
||||||
|
Voir
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button type="submit" form="form-main" class="btn btn-primary">
|
||||||
|
<span class="fa fa-save pr-1"></span>
|
||||||
|
Enregistrer
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-white dropdown-toggle dropdown-toggle-hide-after" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
⋅⋅⋅
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
|
<button type="submit" form="form-resetting-request" class="dropdown-item">
|
||||||
|
Envoye un mail de récupération
|
||||||
|
</button>
|
||||||
|
<button type="submit" form="form-delete" class="dropdown-item">
|
||||||
|
Supprimer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ app.request.uri }}" method="post" id="form-main" enctype="multipart/form-data">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active">
|
||||||
|
<div class="tab-form">
|
||||||
|
{{ include('user/user_admin/_form.html.twig') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form method="post" action="{{ path('admin_user_delete', {entity: entity.id}) }}" id="form-delete" data-form-confirm>
|
||||||
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ entity.id) }}">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form method="post" action="{{ path('admin_user_resetting_request', {entity: entity.id}) }}" id="form-resetting-request" data-form-confirm>
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('resetting_request' ~ entity.id) }}">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
71
templates/user/user_admin/index.html.twig
Normal file
71
templates/user/user_admin/index.html.twig
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
{% extends 'admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 {% if pager.getPaginationData.pageCount < 2 %}pb-5{% endif %}">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="mr-auto w-50">
|
||||||
|
<h1 class="display-5">Utilisateurs</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{{ path('admin_user_new') }}" class="btn btn-primary">
|
||||||
|
<span class="fa fa-plus pr-1"></span>
|
||||||
|
Nouveau
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ knp_pagination_render(pager) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table" data-table-fixed>
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th class="col-10">Utilisateurs</th>
|
||||||
|
<th class="col-2 text-right">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in pager %}
|
||||||
|
{% set edit = path('admin_user_edit', {entity: item.id}) %}
|
||||||
|
{% set show = path('admin_user_show', {entity: item.id}) %}
|
||||||
|
|
||||||
|
<tr data-dblclick="{{ edit }}">
|
||||||
|
<td class="col-10">
|
||||||
|
<a href="{{ show }}" class="font-weight-bold text-body d-block">
|
||||||
|
{{ item.displayName }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{{ item.email }}
|
||||||
|
</td>
|
||||||
|
<td class="col-2 text-right">
|
||||||
|
<a href="{{ edit }}" class="btn btn-sm btn-primary mr-1">
|
||||||
|
<span class="fa fa-edit"></span>
|
||||||
|
</a>
|
||||||
|
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
|
||||||
|
<span class="fa fa-trash"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<form method="post" action="{{ path('admin_user_delete', {entity: item.id}) }}" id="form-delete-{{ item.id }}" data-form-confirm>
|
||||||
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td class="col-12 text-center p-4 text-black-50">
|
||||||
|
<div class="display-1">
|
||||||
|
<span class="fa fa-search"></span>
|
||||||
|
</div>
|
||||||
|
<div class="display-5 mt-3">
|
||||||
|
Aucun résultat
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
39
templates/user/user_admin/new.html.twig
Normal file
39
templates/user/user_admin/new.html.twig
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends 'admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="mr-auto w-50">
|
||||||
|
<h1 class="display-5">Nouveau⋅elle utilisateur⋅tice</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{{ path('admin_user_index') }}" class="btn btn-light">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
|
||||||
|
Retour à la liste
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button type="submit" form="form-main" class="btn btn-primary">
|
||||||
|
<span class="fa fa-save pr-1"></span>
|
||||||
|
|
||||||
|
Enregistrer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ app.request.uri }}" method="post" id="form-main" enctype="multipart/form-data">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active">
|
||||||
|
<div class="tab-form">
|
||||||
|
{{ include('user/user_admin/_form.html.twig') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
84
templates/user/user_admin/show.html.twig
Normal file
84
templates/user/user_admin/show.html.twig
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
{% extends 'admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="mr-auto w-50">
|
||||||
|
<h1 class="display-5">{{ entity.displayName }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{{ path('admin_user_index') }}" class="btn btn-secondary">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
|
||||||
|
Retour à la liste
|
||||||
|
</a>
|
||||||
|
<a href="{{ path('admin_user_edit', {entity: entity.id}) }}" class="btn btn-primary">
|
||||||
|
<span class="fa fa-edit pr-1"></span>
|
||||||
|
|
||||||
|
Éditer
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 p-3">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span class="font-weight-bold pb-2 d-block">Titre</span>
|
||||||
|
|
||||||
|
{{ entity.displayName }}
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span class="font-weight-bold pb-2 d-block">Sous-titre</span>
|
||||||
|
|
||||||
|
{{ entity.email }}
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span class="font-weight-bold pb-2 d-block">Permissions</span>
|
||||||
|
|
||||||
|
{{ entity.roles|join(', ')|replace({
|
||||||
|
ROLE_USER: 'Utilisateur⋅trice',
|
||||||
|
ROLE_WRITER: 'Rédacteur⋅trice',
|
||||||
|
ROLE_ADMIN: 'Administrateur⋅trice',
|
||||||
|
}) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Derniers articles</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in posts %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ path('admin_blog_post_show', {entity: item.id}) }}" class="text-body">
|
||||||
|
{{ item.title }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center p-4 text-black-50">
|
||||||
|
<div class="display-1">
|
||||||
|
<span class="fa fa-search"></span>
|
||||||
|
</div>
|
||||||
|
<div class="display-5 mt-3">
|
||||||
|
Aucun résultat
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue