125 lines
4.7 KiB
PHP
125 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Controller\Admin;
|
|
|
|
use App\Dto\AdminUserData;
|
|
use App\Entity\User;
|
|
use App\Form\AdminUserType;
|
|
use App\Repository\UserRepository;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
|
|
/**
|
|
* UserController exposes moderator/admin user management tools.
|
|
*/
|
|
#[IsGranted('ROLE_MODERATOR')]
|
|
class UserController extends AbstractController
|
|
{
|
|
public function __construct(
|
|
private readonly EntityManagerInterface $entityManager,
|
|
private readonly UserPasswordHasherInterface $passwordHasher,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Lists all users and handles manual account creation.
|
|
*/
|
|
#[Route('/admin/users', name: 'admin_users', methods: ['GET', 'POST'])]
|
|
public function index(Request $request, UserRepository $users): Response
|
|
{
|
|
$formData = new AdminUserData();
|
|
$form = $this->createForm(AdminUserType::class, $formData);
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
// Form collects only high-level metadata; everything else is defaulted here.
|
|
$plainPassword = (string) $form->get('plainPassword')->getData();
|
|
$newUser = new User();
|
|
$newUser->setEmail($formData->email);
|
|
$newUser->setDisplayName($formData->displayName);
|
|
$newUser->setPassword($this->passwordHasher->hashPassword($newUser, $plainPassword));
|
|
$this->entityManager->persist($newUser);
|
|
$this->entityManager->flush();
|
|
$this->addFlash('success', 'User account created.');
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
|
|
return $this->render('admin/users.html.twig', [
|
|
'form' => $form->createView(),
|
|
'rows' => $users->findAllWithStats(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Deletes a user account (moderators cannot delete admins).
|
|
*/
|
|
#[Route('/admin/users/{id}/delete', name: 'admin_users_delete', methods: ['POST'])]
|
|
public function delete(User $target, Request $request): Response
|
|
{
|
|
if (!$this->isCsrfTokenValid('delete-user-' . $target->getId(), (string) $request->request->get('_token'))) {
|
|
throw $this->createAccessDeniedException('Invalid CSRF token.');
|
|
}
|
|
|
|
/** @var User|null $current */
|
|
$current = $this->getUser();
|
|
if ($current && $target->getId() === $current->getId()) {
|
|
// Protect against accidental lockouts by blocking self-deletes.
|
|
$this->addFlash('danger', 'You cannot delete your own account.');
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
|
|
if (in_array('ROLE_ADMIN', $target->getRoles(), true)) {
|
|
$this->addFlash('danger', 'Administrators cannot delete other administrators.');
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
|
|
$this->entityManager->remove($target);
|
|
$this->entityManager->flush();
|
|
$this->addFlash('success', 'User deleted.');
|
|
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
|
|
/**
|
|
* Promotes a user to moderator (admins only).
|
|
*/
|
|
#[Route('/admin/users/{id}/promote', name: 'admin_users_promote', methods: ['POST'])]
|
|
#[IsGranted('ROLE_ADMIN')]
|
|
public function promote(User $target, Request $request): Response
|
|
{
|
|
if (!$this->isCsrfTokenValid('promote-user-' . $target->getId(), (string) $request->request->get('_token'))) {
|
|
throw $this->createAccessDeniedException('Invalid CSRF token.');
|
|
}
|
|
|
|
$roles = $target->getRoles();
|
|
if (in_array('ROLE_ADMIN', $roles, true)) {
|
|
$this->addFlash('danger', 'Administrators already include moderator permissions.');
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
$isModerator = in_array('ROLE_MODERATOR', $roles, true);
|
|
|
|
if ($isModerator) {
|
|
// Toggle-style UX: hitting the endpoint again demotes the moderator.
|
|
$filtered = array_values(array_filter($roles, static fn(string $role) => $role !== 'ROLE_MODERATOR'));
|
|
$target->setRoles($filtered);
|
|
$this->entityManager->flush();
|
|
$this->addFlash('success', 'Moderator privileges removed.');
|
|
} else {
|
|
$roles[] = 'ROLE_MODERATOR';
|
|
$target->setRoles(array_values(array_unique($roles)));
|
|
$this->entityManager->flush();
|
|
$this->addFlash('success', 'User promoted to moderator.');
|
|
}
|
|
|
|
return $this->redirectToRoute('admin_users');
|
|
}
|
|
}
|
|
|
|
|
|
|