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'); } }