Easy_solution/src/Controller/UserController.php

602 lines
25 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Controller;
use App\Entity\Apps;
use App\Entity\Roles;
use App\Entity\User;
use App\Entity\UserOrganizatonApp;
use App\Entity\UsersOrganizations;
use App\Form\UserForm;
use App\Repository\OrganizationsRepository;
use App\Repository\UserRepository;
use App\Repository\UsersOrganizationsRepository;
use App\Service\ActionService;
use App\Service\UserOrganizationAppService;
use App\Service\UserOrganizationService;
use App\Service\UserService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
#[Route(path: '/user', name: 'user_')]
class UserController extends AbstractController
{
private const NOT_FOUND = 'Entity not found';
private const ACCESS_DENIED = 'Access denied';
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly UserService $userService,
private readonly ActionService $actionService,
private readonly UserOrganizationAppService $userOrganizationAppService,
private readonly UserOrganizationService $userOrganizationService,
private readonly UserRepository $userRepository,
private readonly UsersOrganizationsRepository $uoRepository,
private readonly OrganizationsRepository $organizationRepository,
)
{
}
#[Route('/', name: 'index', methods: ['GET'])]
public function index(): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$user = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
$uo = $this->uoRepository->findUsersWithOrganization();
$noOrgUsers = $this->userService->formatNoOrgUsersAsAssoc(
$this->userRepository->findUsersWithoutOrganization());
$usersByOrganization = $this->userService->groupByOrganization($uo);
$usersByOrganization += $noOrgUsers;
//Log action
$this->actionService->createAction("View all users", $user, null, "All");
} else {
$usersByOrganization = [];
}
return $this->render('user/index.html.twig', [
'usersByOrganization' => $usersByOrganization,
]);
}
#[Route('/view/{id}', name: 'show', methods: ['GET'])]
public function view(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser)) {
$user = $this->userRepository->find($id);
try {
$orgId = $request->query->get('organizationId');
if ($orgId) {
$orgs = $this->organizationRepository->findBy(['id' => $orgId]);
$uo = $this->uoRepository->findBy(['users' => $user, 'organization' => $orgs]);
if (!$uo) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uoActive = $uo[0]->isActive();
} else {
$uo = $this->uoRepository->findBy(['users' => $user, 'isActive' => true]);
foreach ($uo as $u) {
$orgs[] = $u->getOrganization();
}
}
$uoa = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy(['userOrganization' => $uo, 'isActive' => true]);
$uoas = $this->userOrganizationAppService->groupUserOrganizationAppsByApplication($uoa);
$this->actionService->createAction("View user information", $actingUser, null, $user->getUserIdentifier());
} catch (\Exception $e) {
//ignore
}
} else {
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
return $this->render('user/show.html.twig', [
'user' => $user,
'uoas' => $uoas ?? null,
'orgs' => $orgs ?? null,
'organizationId' => $orgId ?? null,
'uoActive' => $uoActive ?? null// specific for single organization context and deactivate user from said org
]);
}
#[Route('/edit/{id}', name: 'edit', methods: ['GET', 'POST'])]
public function edit(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser)) {
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$form = $this->createForm(UserForm::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Handle file upload
$picture = $form->get('pictureUrl')->getData();
if ($picture) {
$this->userService->handleProfilePicture($user, $picture);
}
$user->setModifiedAt(new \DateTimeImmutable('now'));
$this->entityManager->persist($user);
$this->entityManager->flush();
if ($request->get('organizationId')) {
$org = $this->organizationRepository->find($request->get('organizationId'));
if ($org) {
$this->actionService->createAction("Edit user information", $actingUser, $org, $user->getUserIdentifier());
}
} else {
$this->actionService->createAction("Edit user information", $actingUser, null, $user->getUserIdentifier());
}
return $this->redirectToRoute('user_show', ['id' => $user->getId(), 'organizationId' => $request->get('organizationId')]);
}
return $this->render('user/edit.html.twig', [
'user' => $user,
'form' => $form->createView(),
'organizationId' => $request->get('organizationId')
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
public function new(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser)) {
$user = new User();
$form = $this->createForm(UserForm::class, $user);
$form->handleRequest($request);
$orgId = $request->get('organizationId');
if ($form->isSubmitted() && $form->isValid()) {
// Handle file upload
$picture = $form->get('pictureUrl')->getData();
if ($picture) {
$this->userService->handleProfilePicture($user, $picture);
}
// else {
// $user->setPictureUrl("");
// }
//FOR TEST PURPOSES, SETTING A DEFAULT RANDOM PASSWORD
$user->setPassword($this->userService->generateRandomPassword());
if ($orgId) {
$org = $this->organizationRepository->find($orgId);
if ($org) {
$uo = new UsersOrganizations();
$uo->setUsers($user);
$uo->setOrganization($org);
$this->entityManager->persist($uo);
$this->actionService->createAction("Create new user", $user, $org, "Added user to organization" . $user->getUserIdentifier() . " for organization " . $org->getName());
}
}
$this->actionService->createAction("Create new user", $actingUser, null, $user->getUserIdentifier());
$this->entityManager->persist($user);
$this->entityManager->flush();
return $this->redirectToRoute('user_index');
}
return $this->render('user/new.html.twig', [
'user' => $user,
'form' => $form->createView(),
'organizationId' => $orgId
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/deactivate/{id}', name: 'deactivate', methods: ['GET', 'POST'])]
public function deactivate(int $id): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true)) {
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$user->setIsActive(false);
$user->setModifiedAt(new \DateTimeImmutable('now'));
$this->userOrganizationService->deactivateAllUserOrganizationLinks($user, $actingUser);
if($this->userService->isUserConnected($user->getUserIdentifier())){
$this->userService->revokeUserTokens($user->getUserIdentifier());
}
$this->entityManager->persist($user);
$this->entityManager->flush();
$this->actionService->createAction("Deactivate user", $actingUser, null, $user->getUserIdentifier());
return $this->redirectToRoute('user_index');
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/activate/{id}', name: 'activate', methods: ['GET', 'POST'])]
public function activate(int $id): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true)) {
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$user->setIsActive(true);
$user->setModifiedAt(new \DateTimeImmutable('now'));
$this->entityManager->persist($user);
$this->entityManager->flush();
$this->actionService->createAction("Activate user", $actingUser, null, $user->getUserIdentifier());
return $this->redirectToRoute('user_index');
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/organization/deactivate/{id}', name: 'deactivate_organization', methods: ['GET', 'POST'])]
public function deactivateUserInOrganization(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true)) {
$orgId = $request->get('organizationId');
$org = $this->organizationRepository->find($orgId);
if (!$org) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uo = $this->uoRepository->findOneBy(['users' => $user,
'organization' => $org,
'isActive' => true]);
if (!$uo) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uo->setIsActive(false);
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo);
$this->entityManager->persist($uo);
$this->entityManager->flush();
$this->actionService->createAction("Deactivate user in organization", $actingUser, $org, $org->getName() . " for user " . $user->getUserIdentifier());
return new Response('', Response::HTTP_NO_CONTENT); //204
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/organization/activate/{id}', name: 'activate_organization', methods: ['GET', 'POST'])]
public function activateUserInOrganization(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true)) {
$orgId = $request->get('organizationId');
$org = $this->organizationRepository->find($orgId);
if (!$org) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uo = $this->uoRepository->findOneBy(['users' => $user,
'organization' => $org,
'isActive' => false]);
if (!$uo) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uo->setIsActive(true);
$this->entityManager->persist($uo);
$this->entityManager->flush();
$this->actionService->createAction("Activate user in organization", $actingUser, $org, $org->getName() . " for user " . $user->getUserIdentifier());
return $this->redirectToRoute('user_index');
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
#[Route('/delete/{id}', name: 'delete', methods: ['GET', 'POST'])]
public function delete(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted("ROLE_SUPER_ADMIN");
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
$user = $this->userRepository->find($id);
if (!$user) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$user->setIsActive(false);
$user->setModifiedAt(new \DateTimeImmutable('now'));
$this->userOrganizationService->deactivateAllUserOrganizationLinks($user, $actingUser);
$user->setIsDeleted(true);
if($this->userService->isUserConnected($user)){
$this->userService->revokeUserTokens($user->getUserIdentifier());
}
$this->entityManager->persist($user);
$this->entityManager->flush();
$this->actionService->createAction("Delete user", $actingUser, null, $user->getUserIdentifier());
return new Response('', Response::HTTP_NO_CONTENT); //204
}
#[Route(path: '/application/roles/{id}', name: 'application_role', methods: ['GET', 'POST'])]
public function applicationRole(int $id, Request $request): Response
{
$this->denyAccessUnlessGranted("ROLE_ADMIN");
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true)) {
$uo = $this->userOrganizationService->getByIdOrFail($id);
$application = $this->entityManager->getRepository(Apps::class)->find($request->get('applicationId'));
if (!$application) {
throw $this->createNotFoundException(self::NOT_FOUND);
}
$selectedRolesIds = $request->get('roles', []);
$roleUser = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'USER']);
if (!$roleUser) {
throw $this->createNotFoundException('Default role not found');
}
if (!empty($selectedRolesIds)) {
$this->userOrganizationAppService->syncRolesForUserOrganizationApp(
$uo,
$application,
$selectedRolesIds,
$actingUser
);
} else {
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo, $application);
}
$user = $uo->getUsers();
return $this->redirectToRoute('user_show', [
'user' => $user,
'id' => $user->getId(),
'organizationId' => $uo->getOrganization()->getId()
]);
}
throw $this->createAccessDeniedException();
}
/*
* AJAX endpoint for user listing with pagination
* Get all the users that aren´t deleted and are active
*/
#[Route(path: '/data', name: 'data', methods: ['GET'])]
public function data(Request $request): JsonResponse
{
$this->denyAccessUnlessGranted("ROLE_ADMIN");
$page = max(1, (int)$request->query->get('page', 1));
$size = max(1, (int)$request->query->get('size', 10));
// Get filter parameters
$filters = $request->query->all('filter', []);
$repo = $this->userRepository;
// Base query
$qb = $repo->createQueryBuilder('u')
->where('u.isDeleted = :del')->setParameter('del', false);
// Apply filters
if (!empty($filters['name'])) {
$qb->andWhere('u.surname LIKE :name')
->setParameter('name', '%' . $filters['name'] . '%');
}
if (!empty($filters['prenom'])) {
$qb->andWhere('u.name LIKE :prenom')
->setParameter('prenom', '%' . $filters['prenom'] . '%');
}
if (!empty($filters['email'])) {
$qb->andWhere('u.email LIKE :email')
->setParameter('email', '%' . $filters['email'] . '%');
}
$countQb = clone $qb;
$total = (int)$countQb->select('COUNT(u.id)')->getQuery()->getSingleScalarResult();
// Pagination
$offset = ($page - 1) * $size;
$rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult();
// Map to array
$data = array_map(function (User $user) {
return [
'id' => $user->getId(),
'pictureUrl' => $user->getPictureUrl(),
'name' => $user->getSurname(),
'prenom' => $user->getName(),
'email' => $user->getEmail(),
'isConnected' => $this->userService->isUserConnected($user->getUserIdentifier()),
'showUrl' => $this->generateUrl('user_show', ['id' => $user->getId()]),
'statut' => $user->isActive(),
];
}, $rows);
$lastPage = (int)ceil($total / $size);
return $this->json([
'data' => $data,
'last_page' => $lastPage,
'total' => $total,
]);
}
#[Route(path: '/indexTest', name: 'indexTest', methods: ['GET'])]
public function indexTest(): Response
{
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_ADMIN")) {
$totalUsers = $this->userRepository->count(['isDeleted' => false, 'isActive' => true]);
return $this->render('user/indexTest.html.twig', [
'users' => $totalUsers
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
/*
* AJAX endpoint for new users listing
* Get the 5 most recently created users for an organization
*/
#[Route(path: '/data/new', name: 'dataNew', methods: ['GET'])]
public function dataNew(Request $request): JsonResponse
{
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_ADMIN")) {
$orgId = $request->query->get('orgId');
$uos = $this->uoRepository->findBy(['organization' => $orgId, 'isActive' =>true], limit: 5, orderBy: ['createdAt' => 'DESC']);
// Map to array (keep isConnected)
$data = array_map(function (UsersOrganizations $uo) {
$user = $uo->getUsers();
$initials = $user->getName()[0] . $user->getSurname()[0];
return [
'pictureUrl' => $user->getPictureUrl(),
'email' => $user->getEmail(),
'isConnected' => $this->userService->isUserConnected($user->getUserIdentifier()),
'showUrl' => $this->generateUrl('user_show', ['id' => $user->getId()]),
'initials' => strtoupper($initials),
];
}, $uos);
return $this->json([
'data' => $data,
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
/*
* AJAX endpoint for admin users listing
* Get all admin users for an organization
*/
#[Route(path: '/data/admin', name: 'dataAdmin', methods: ['GET'])]
public function dataAdmin(Request $request): JsonResponse
{
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_ADMIN")) {
$orgId = $request->query->get('orgId');
$uos = $this->uoRepository->findBy(['organization' => $orgId]);
$roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']);
$users = [];
foreach ($uos as $uo) {
if ($this->entityManager->getRepository(UserOrganizatonApp::class)->findOneBy(['userOrganization' => $uo, 'role' => $roleAdmin])) {
$users[] = $uo;
}
}
// Map to array (keep isConnected)
$data = array_map(function (UsersOrganizations $uo) {
$user = $uo->getUsers();
$initials = $user->getName()[0] . $user->getSurname()[0];
return [
'pictureUrl' => $user->getPictureUrl(),
'email' => $user->getEmail(),
'isConnected' => $this->userService->isUserConnected($user->getUserIdentifier()),
'showUrl' => $this->generateUrl('user_show', ['id' => $user->getId()]),
'initials' => strtoupper($initials),
];
}, $users);
return $this->json([
'data' => $data,
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
/*
* AJAX endpoint for All users in an organization
*/
#[Route(path: '/data/organization', name: 'dataUserOrganization', methods: ['GET'])]
public function dataUserOrganization(Request $request): JsonResponse
{
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_ADMIN")) {
$orgId = $request->query->get('orgId');
$page = max(1, (int)$request->query->get('page', 1));
$size = max(1, (int)$request->query->get('size', 10));
// Optional: read Tabulator remote sort/filter payloads
// $sorters = $request->query->all('sorters') ?? [];
// $filters = $request->query->all('filters') ?? [];
$repo = $this->uoRepository;
// Base query
$qb = $repo->createQueryBuilder('uo')
->where('uo.organization = :orgId')
->setParameter('orgId', $orgId);
$countQb = clone $qb;
$total = (int)$countQb->select('COUNT(uo.id)')->getQuery()->getSingleScalarResult();
// Pagination
$offset = ($page - 1) * $size;
$rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult();
// Map to array
$data = array_map(function (UsersOrganizations $uo) {
$user = $uo->getUsers();
return [
'pictureUrl' => $user->getPictureUrl(),
'name' => $user->getSurname(),
'prenom' => $user->getName(),
'email' => $user->getEmail(),
'isConnected' => $this->userService->isUserConnected($user->getUserIdentifier()),
'statut' => $uo->isActive(),
'showUrl' => $this->generateUrl('user_show', [
'id' => $user->getId(),
'organizationId' => $uo->getOrganization()->getId(),
]),
'id' => $user->getId(),
];
}, $rows);
// Return Tabulator-compatible response
$lastPage = (int)ceil($total / $size);
return $this->json([
'data' => $data,
'last_page' => $lastPage,
'total' => $total,
]);
}
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
}
}