diff --git a/assets/controllers/user_controller.js b/assets/controllers/user_controller.js index c94cd8e..44847d0 100644 --- a/assets/controllers/user_controller.js +++ b/assets/controllers/user_controller.js @@ -366,7 +366,8 @@ export default class extends Controller { vertAlign: "middle", headerSort: false, formatter: (cell) => { - const url = cell.getValue(); + const url = cell.getValue() + '?organizationId=' + this.orgIdValue; + console.log(url); if (url) { return eyeIconLink(url); } diff --git a/src/Controller/OrganizationController.php b/src/Controller/OrganizationController.php index 96df1a2..9691197 100644 --- a/src/Controller/OrganizationController.php +++ b/src/Controller/OrganizationController.php @@ -94,9 +94,10 @@ class OrganizationController extends AbstractController $this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getId(), "Organization Created"); $this->loggerService->logSuperAdmin($actingUser->getId(), $actingUser->getId(), "Organization Created", $organization->getId()); $this->actionService->createAction("Create Organization", $actingUser, $organization, $organization->getName()); + $this->addFlash('success', 'Organisation crée avec succès.'); return $this->redirectToRoute('organization_index'); } catch (Exception $e) { - $this->addFlash('error', 'Error creating organization: ' . $e->getMessage()); + $this->addFlash('error', 'Erreur lors de la création de l\'organization'); $this->loggerService->logError('Error creating organization', ['acting_user_id' => $actingUser->getId(), 'error' => $e->getMessage()]); } } @@ -122,7 +123,7 @@ class OrganizationController extends AbstractController 'org_id' => $id, 'message' => 'Organization not found for edit'], $actingUser->getId() ); - $this->addFlash('error', self::NOT_FOUND); + $this->addFlash('error', 'Erreur, l\'organization est introuvable.'); return $this->redirectToRoute('organization_index'); } if (!$this->isGranted("ROLE_SUPER_ADMIN")) { @@ -134,7 +135,7 @@ class OrganizationController extends AbstractController 'org_id' => $organization->getId(), 'message' => 'UO link not found for edit organization' ], $actingUser->getId()); - $this->addFlash('error', self::ACCESS_DENIED); + $this->addFlash('error', 'Erreur, accès refusé.'); return $this->redirectToRoute('organization_index'); } $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']); @@ -145,7 +146,7 @@ class OrganizationController extends AbstractController 'role_id' => $roleAdmin->getId(), 'message' => 'UOA link not found for edit organization, user is not admin of organization' ], $actingUser->getId()); - $this->addFlash('error', self::ACCESS_DENIED); + $this->addFlash('error', 'Erreur, accès refusé.'); return $this->redirectToRoute('organization_index'); } } @@ -164,9 +165,11 @@ class OrganizationController extends AbstractController $this->loggerService->logSuperAdmin($actingUser->getId(), $actingUser->getId(), "Organization Edited", $organization->getId()); } $this->actionService->createAction("Edit Organization", $actingUser, $organization, $organization->getName()); + $this->addFlash('success', 'Organisation modifiée avec succès.'); return $this->redirectToRoute('organization_index'); }catch (Exception $e) { - $this->addFlash('error', 'Error editing organization: ' . $e->getMessage()); + $this->addFlash('error', 'Erreur lors de la modification de l\'organization'); + $this->loggerService->logError('Error editing organization', ['acting_user_id' => $actingUser->getId(), 'error' => $e->getMessage()]); } } return $this->render('organization/edit.html.twig', [ @@ -186,12 +189,13 @@ class OrganizationController extends AbstractController 'org_id' => $id, 'message' => 'Organization not found for view' ], $actingUser->getId()); - $this->addFlash('error', self::NOT_FOUND); + $this->addFlash('error', 'Erreur, l\'organization est introuvable.'); return $this->redirectToRoute('organization_index'); } //check if the user is admin of the organization if (!$this->userService->isAdminOfOrganization($organization) && !$this->isGranted("ROLE_SUPER_ADMIN")) { $this->loggerService->logAccessDenied($actingUser->getId()); + $this->addFlash('error', 'Erreur, accès refusé.'); throw new AccessDeniedHttpException('Access denied'); } @@ -222,6 +226,7 @@ class OrganizationController extends AbstractController 'org_id' => $id, 'message' => 'Organization not found for delete' ], $actingUser->getId()); + $this->addFlash('error', 'Erreur, l\'organization est introuvable.'); throw $this->createNotFoundException(self::NOT_FOUND); } try { @@ -232,9 +237,15 @@ class OrganizationController extends AbstractController $this->entityManager->persist($organization); $this->actionService->createAction("Delete Organization", $actingUser, $organization, $organization->getName()); + $this->entityManager->flush(); + $this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getId(),'Organization Deleted'); + if ($this->isGranted("ROLE_SUPER_ADMIN")) { + $this->loggerService->logSuperAdmin($actingUser->getId(), $actingUser->getId(),'Organization Deleted', $organization->getId()); + } + $this->addFlash('success', 'Organisation supprimée avec succès.'); }catch (\Exception $e){ $this->loggerService->logError($actingUser->getId(), ['message' => 'Error deleting organization: '.$e->getMessage()]); - $this->addFlash('error', 'Error deleting organization: ' . $e->getMessage()); + $this->addFlash('error', 'Erreur lors de la suppression de l\'organization.'); } return $this->redirectToRoute('organization_index'); @@ -251,6 +262,7 @@ class OrganizationController extends AbstractController 'org_id' => $id, 'message' => 'Organization not found for deactivate' ], $actingUser->getId()); + $this->addFlash('error', 'Erreur, l\'organization est introuvable.'); throw $this->createNotFoundException(self::NOT_FOUND); } @@ -259,7 +271,7 @@ class OrganizationController extends AbstractController $this->entityManager->persist($organization); $this->actionService->createAction("Deactivate Organization", $actingUser, $organization, $organization->getName()); $this->loggerService->logSuperAdmin($actingUser->getId(), $actingUser->getId(),'Organization deactivated', $organization->getId()); - + $this->addFlash('success', 'Organisation désactivé avec succès.'); return $this->redirectToRoute('organization_index'); } @@ -274,6 +286,7 @@ class OrganizationController extends AbstractController 'org_id' => $id, 'message' => 'Organization not found for activate' ], $actingUser->getId()); + $this->addFlash('error', 'Erreur, l\'organization est introuvable.'); throw $this->createNotFoundException(self::NOT_FOUND); } $organization->setIsActive(true); @@ -281,6 +294,7 @@ class OrganizationController extends AbstractController $this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getId(),'Organization Activated'); $this->loggerService->logSuperAdmin($actingUser->getId(), $actingUser->getId(),'Organization Activated', $organization->getId()); $this->actionService->createAction("Activate Organization", $actingUser, $organization, $organization->getName()); + $this->addFlash('success', 'Organisation activée avec succès.'); return $this->redirectToRoute('organization_index'); } diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 32dc466..1f4ef43 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -79,10 +79,12 @@ class UserController extends AbstractController $user = $this->userRepository->find($id); if (!$user) { $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); + $this->addFlash('error', "L'utilisateur demandé n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } if (!$this->userService->hasAccessTo($user)) { $this->loggerService->logAccessDenied($actingUser->getId()); + $this->addFlash('error', "L'utilisateur demandé n'existe pas."); throw new AccessDeniedHttpException (self::ACCESS_DENIED); } try { @@ -111,6 +113,7 @@ class UserController extends AbstractController 'user_id' => $user->getId(), 'organization_id' => $orgId], $actingUser->getId()); + $this->addFlash('error', "L'utilisateur n'est pas actif dans cette organisation."); throw $this->createNotFoundException(self::NOT_FOUND); } @@ -129,10 +132,10 @@ class UserController extends AbstractController 'user_id' => $user->getId(), 'organization_id' => $orgId], $actingUser->getId()); + $this->addFlash('error', "L'utilisateur n'est pas actif dans une organisation."); throw $this->createNotFoundException(self::NOT_FOUND); } } - // Charger les liens UserOrganizationApp (UOA) actifs pour les UO trouvées // Load user-organization-app roles (can be empty) $uoa = $this->entityManager @@ -141,14 +144,6 @@ class UserController extends AbstractController 'userOrganization' => $uoList, 'isActive' => true, ]); - if (!$uoa) { - $this->loggerService->logEntityNotFound('UsersOrganizationApplication', [ - 'user_id' => $user->getId(), - 'organization_id' => $orgId], - $actingUser->getId()); - throw $this->createNotFoundException(self::NOT_FOUND); - } - // Group UOA by app and ensure every app has a group $data['uoas'] = $this->userOrganizationAppService ->groupUserOrganizationAppsByApplication( @@ -170,12 +165,13 @@ class UserController extends AbstractController // ------------------------------------------------------------------- // Calcul du flag de modification : utilisateur admin ET exactement 1 UO - $canEdit = $this->userService->canEditRolesCheck($actingUser, $user, $organization, $this->isGranted('ROLE_ADMIN'), $singleUo); + $canEdit = $this->userService->canEditRolesCheck($actingUser, $user,$this->isGranted('ROLE_ADMIN'), $singleUo, $organization); } catch (\Exception $e) { - // En cas d'erreur, désactiver l'édition et logger l'exception - $canEdit = false; $this->errorLogger->error($e->getMessage()); + $this->addFlash('error', 'Une erreur est survenue lors du chargement des informations utilisateur.'); + $referer = $request->headers->get('referer'); + return $this->redirect($referer ?? $this->generateUrl('app_index')); } return $this->render('user/show.html.twig', [ 'user' => $user, @@ -195,6 +191,7 @@ class UserController extends AbstractController $user = $this->userRepository->find($id); if (!$user) { $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); + $this->addFlash('error', "L'utilisateur demandé n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } try { @@ -227,9 +224,11 @@ class UserController extends AbstractController "Super Admin accessed user edit page", ); } + $this->addFlash('success', 'Information modifié avec success.'); return $this->redirectToRoute('user_show', ['id' => $user->getId(), 'organizationId' => $orgId]); } $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); + $this->addFlash('error', "L'organisation n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } if ($this->isGranted('ROLE_SUPER_ADMIN')) { @@ -239,11 +238,11 @@ class UserController extends AbstractController "Super Admin accessed user edit page", ); } + $this->addFlash('success', 'Information modifié avec success.'); $this->actionService->createAction("Edit user information", $actingUser, null, $user->getUserIdentifier()); return $this->redirectToRoute('user_show', ['id' => $user->getId()]); } - return $this->render('user/edit.html.twig', [ 'user' => $user, 'form' => $form->createView(), @@ -251,8 +250,10 @@ class UserController extends AbstractController ]); } $this->loggerService->logAccessDenied($actingUser->getId()); + $this->addFlash('error', "Accès non autorisé."); throw $this->createAccessDeniedException(self::ACCESS_DENIED); } catch (\Exception $e) { + $this->addFlash('error', 'Une erreur est survenue lors de la modification des informations utilisateur.'); $this->errorLogger->critical($e->getMessage()); } // Default deny access. shouldn't reach here normally. @@ -280,14 +281,17 @@ class UserController extends AbstractController $org = $this->organizationRepository->find($orgId); if (!$org) { $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); + $this->addFlash('error', "L'organisation n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } if($this->isGranted('ROLE_ADMIN') && !$this->userService->isAdminOfOrganization($org) && !$this->isGranted('ROLE_SUPER_ADMIN')) { $this->loggerService->logAccessDenied($actingUser->getId()); + $this->addFlash('error', "Accès non autorisé."); throw $this->createAccessDeniedException(self::ACCESS_DENIED); } }elseif($this->isGranted('ROLE_ADMIN')) { $this->loggerService->logAccessDenied($actingUser->getId()); + $this->addFlash('error', "Accès non autorisé."); throw $this->createAccessDeniedException(self::ACCESS_DENIED); } @@ -310,28 +314,31 @@ class UserController extends AbstractController $org->getId(), ); } + $this->addFlash('success', 'Utilisateur ajouté avec succès à l\'organisation. '); return $this->redirectToRoute('organization_show', ['id' => $orgId]); } + //Code semi-mort : On ne peut plus créer un utilisateur sans organisation // Case : User exists but NO organization context -> throw error on email field. - if ($existingUser) { - $this->loggerService->logError('Attempt to create user with existing email without organization', [ - 'target_user_email' => $user->getid(), - 'acting_user_id' => $actingUser->getId(), - ]); - $form->get('email')->addError( - new \Symfony\Component\Form\FormError( - 'This email is already in use. Add the user to an organization instead.' - ) - ); - - return $this->render('user/new.html.twig', [ - 'user' => $user, - 'form' => $form->createView(), - 'organizationId' => $orgId, - ]); - } +// if ($existingUser) { +// $this->loggerService->logError('Attempt to create user with existing email without organization', [ +// 'target_user_email' => $user->getid(), +// 'acting_user_id' => $actingUser->getId(), +// ]); +// +// $form->get('email')->addError( +// new \Symfony\Component\Form\FormError( +// 'This email is already in use. Add the user to an organization instead.' +// ) +// ); +// +// return $this->render('user/new.html.twig', [ +// 'user' => $user, +// 'form' => $form->createView(), +// 'organizationId' => $orgId, +// ]); +// } $picture = $form->get('pictureUrl')->getData(); $this->userService->createNewUser($user, $actingUser, $picture); @@ -361,10 +368,10 @@ class UserController extends AbstractController $org->getId() ); } - + $this->addFlash('success', 'Nouvel utilisateur créé et ajouté à l\'organisation avec succès. '); return $this->redirectToRoute('organization_show', ['id' => $orgId]); } - + $this->addFlash('success', 'Nouvel utilisateur créé avec succès. '); return $this->redirectToRoute('user_index'); } @@ -378,9 +385,10 @@ class UserController extends AbstractController $this->errorLogger->critical($e->getMessage()); if ($orgId) { + $this->addFlash('error', 'Une erreur est survenue lors de la création de l\'utilisateur pour l\'organisation .'); return $this->redirectToRoute('organization_show', ['id' => $orgId]); } - + $this->addFlash('error', 'Une erreur est survenue lors de la création de l\'utilisateur.'); return $this->redirectToRoute('user_index'); } } @@ -393,7 +401,6 @@ class UserController extends AbstractController $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); $status = $request->get('status'); - try { // Access control if (!$this->userService->hasAccessTo($actingUser, true)) { @@ -465,7 +472,7 @@ class UserController extends AbstractController 'target_user_id' => $id, ]); - return new JsonResponse(['error' => 'Invalid status'], Response::HTTP_BAD_REQUEST); + return new JsonResponse(['error' => 'Status invalide'], Response::HTTP_BAD_REQUEST); } catch (\Throwable $e) { // Application-level error logging → error.log (via error channel) @@ -476,7 +483,7 @@ class UserController extends AbstractController throw $e; } - return new JsonResponse(['error' => 'An error occurred'], Response::HTTP_INTERNAL_SERVER_ERROR); + return new JsonResponse(['error' => 'Une erreur est survenue'], Response::HTTP_INTERNAL_SERVER_ERROR); } } @@ -556,7 +563,7 @@ class UserController extends AbstractController if (!$user) { // Security/audit log for missing user $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); - + $this->addFlash('error', "L'utilisateur demandé n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } @@ -604,9 +611,8 @@ class UserController extends AbstractController 'target_user_id' => $id, 'acting_user_id' => $actingUser?->getId(), ]); - // No rethrow here: deletion succeeded; only notifications failed } - + $this->addFlash('success', 'Utilisateur supprimé avec succès.'); return $this->redirectToRoute('user_index'); } catch (\Exception $e) { @@ -619,7 +625,7 @@ class UserController extends AbstractController if ($e instanceof NotFoundHttpException) { throw $e; // keep 404 semantics } - + $this->addFlash('error', 'Erreur lors de la suppression de l\'utilisateur\.'); return $this->redirectToRoute('user_index'); } } @@ -634,11 +640,13 @@ class UserController extends AbstractController $uo = $this->entityManager->getRepository(UsersOrganizations::class)->find($id); if (!$uo) { $this->loggerService->logEntityNotFound('UsersOrganization', ['id' => $id], $actingUser->getId()); + $this->addFlash('error', "La liaison utilisateur-organisation n'existe pas."); throw new NotFoundHttpException("UserOrganization not found"); } $application = $this->entityManager->getRepository(Apps::class)->find($request->get('appId')); if (!$application) { $this->loggerService->logEntityNotFound('Application', ['id' => $request->get('appId')], $actingUser->getId()); + $this->addFlash('error', "L'application demandée n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } @@ -646,6 +654,7 @@ class UserController extends AbstractController $roleUser = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'USER']); if (!$roleUser) { $this->loggerService->logEntityNotFound('Role', ['name' => 'USER'], $actingUser->getId()); + $this->addFlash('error', "Le role de l'utilisateur n'existe pas."); throw $this->createNotFoundException('User role not found'); } @@ -667,6 +676,7 @@ class UserController extends AbstractController } $user = $uo->getUsers(); + $this->addFlash('success', 'Rôles mis à jour avec succès.'); return $this->redirectToRoute('user_show', [ 'user' => $user, 'id' => $user->getId(), diff --git a/src/Service/UserService.php b/src/Service/UserService.php index 211203e..3e7ae08 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -94,7 +94,7 @@ class UserService $userOrganizations = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $user]); if ($userOrganizations) { foreach ($userOrganizations as $uo) { - if ($this->isAdminOfOrganization($uo->getOrganization())) { + if ($this->isAdminOfOrganization($uo->getOrganization()) && $uo->getStatut() === "ACCEPTED" && $uo->isActive()) { return true; } } @@ -109,7 +109,7 @@ class UserService * entity role 'ROLE_ADMIN' in the UsersOrganizationsApp entity * (if he is admin for any application of the organization). * - * @param UsersOrganizations $usersOrganizations + * @param Organizations $organizations * @return bool * @throws Exception */ @@ -407,12 +407,11 @@ class UserService return $rolesArray; } - public function canEditRolesCheck(User $actingUser, User $user, $org, bool $isAdmin, UsersOrganizations $uo = null): bool + public function canEditRolesCheck(User $actingUser, User $user, bool $isAdmin, UsersOrganizations $uo = null, $org = null): bool { $userRoles = $user->getRoles(); $actingUserRoles = $actingUser->getRoles(); // if acting user is admin, he can´t edit super admin roles - if (!in_array('ROLE_SUPER_ADMIN', $actingUserRoles, true) && in_array('ROLE_SUPER_ADMIN', $userRoles, true)) { return false; } diff --git a/templates/organization/index.html.twig b/templates/organization/index.html.twig index 2d8ff2f..a8b1e71 100644 --- a/templates/organization/index.html.twig +++ b/templates/organization/index.html.twig @@ -4,6 +4,13 @@ {% block body %}