New role logic to activate/deactive user in organization

This commit is contained in:
Charles 2026-02-11 11:50:47 +01:00
parent 7d1e2ee4e7
commit e64afa87db
4 changed files with 51 additions and 137 deletions

View File

@ -182,7 +182,7 @@ class OrganizationController extends AbstractController
#[Route(path: '/view/{id}', name: 'show', methods: ['GET'])] #[Route(path: '/view/{id}', name: 'show', methods: ['GET'])]
public function view($id): Response public function view($id): Response
{ {
$this->denyAccessUnlessGranted('ROLE_ADMIN'); $this->denyAccessUnlessGranted('ROLE_USER');
$organization = $this->organizationsRepository->find($id); $organization = $this->organizationsRepository->find($id);
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
if (!$organization) { if (!$organization) {
@ -304,7 +304,7 @@ class OrganizationController extends AbstractController
#[Route(path: '/data', name: 'data', methods: ['GET'])] #[Route(path: '/data', name: 'data', methods: ['GET'])]
public function data(Request $request): JsonResponse public function data(Request $request): JsonResponse
{ {
$this->denyAccessUnlessGranted('ROLE_ADMIN'); $this->denyAccessUnlessGranted('ROLE_USER');
$page = max(1, (int)$request->query->get('page', 1)); $page = max(1, (int)$request->query->get('page', 1));

View File

@ -369,21 +369,22 @@ class UserController extends AbstractController
#[Route('/organization/activateStatus/{id}', name: 'activate_organization', methods: ['GET', 'POST'])] #[Route('/organization/activateStatus/{id}', name: 'activate_organization', methods: ['GET', 'POST'])]
public function activateStatusOrganization(int $id, Request $request): JsonResponse public function activateStatusOrganization(int $id, Request $request): JsonResponse
{ {
$this->denyAccessUnlessGranted('ROLE_ADMIN'); $this->denyAccessUnlessGranted('ROLE_USER');
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
try { try {
if ($this->userService->hasAccessTo($actingUser, true)) { $user = $this->userRepository->find($id);
if (!$user) {
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
throw $this->createNotFoundException(self::NOT_FOUND);
}
if ($this->userService->isAdminOfUser($user)) {
$orgId = $request->get('organizationId'); $orgId = $request->get('organizationId');
$org = $this->organizationRepository->find($orgId); $org = $this->organizationRepository->find($orgId);
if (!$org) { if (!$org) {
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
throw $this->createNotFoundException(self::NOT_FOUND); throw $this->createNotFoundException(self::NOT_FOUND);
} }
$user = $this->userRepository->find($id);
if (!$user) {
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
throw $this->createNotFoundException(self::NOT_FOUND);
}
$uo = $this->uoRepository->findOneBy(['users' => $user, $uo = $this->uoRepository->findOneBy(['users' => $user,
'organization' => $org]); 'organization' => $org]);
if (!$uo) { if (!$uo) {

View File

@ -19,121 +19,32 @@ class UsersOrganizationsRepository extends ServiceEntityRepository
} }
/** /**
* Returns active user-organization mappings with joined User and Organization. * Checks if an acting user has administrative rights over a target user
* Only active and non-deleted users and organizations are included. * based on shared organizational memberships.
*
* @return UsersOrganizations[]
*/ */
public function findUsersWithOrganization(array $organizationIds = null): array public function isUserAdminOfTarget(User $actingUser, User $targetUser, $adminRole): bool
{ {
$qb = $this->createQueryBuilder('uo') $qb = $this->createQueryBuilder('uo_acting');
->addSelect('u', 'o')
->leftJoin('uo.users', 'u')
->leftJoin('uo.organization', 'o')
->andWhere('u.isActive = :uActive')
->andWhere('u.isDeleted = :uDeleted')
->andWhere('o.isActive = :oActive')
->andWhere('o.isDeleted = :oDeleted')
->orderBy('o.name', 'ASC')
->addOrderBy('u.surname', 'ASC')
->setParameter('uActive', true)
->setParameter('uDeleted', false)
->setParameter('oActive', true)
->setParameter('oDeleted', false);
if (!empty($organizationIds)) {
$qb->andWhere('o.id IN (:orgIds)')
->setParameter('orgIds', $organizationIds);
}
return $qb->getQuery()->getResult(); return (bool) $qb
} ->select('COUNT(uo_acting.id)')
// We join the same table again to find the target user in the same organization
/** ->innerJoin(
* Same as above, filtered by a list of organization IDs. UsersOrganizations::class,
* 'uo_target',
* @param int[] $organizationIds 'WITH',
* @return UsersOrganizations[] 'uo_target.organization = uo_acting.organization'
*/ )
public function findActiveWithUserAndOrganizationByOrganizationIds(array $organizationIds): array ->where('uo_acting.users = :actingUser')
{ ->andWhere('uo_acting.role = :role')
if (empty($organizationIds)) { ->andWhere('uo_acting.isActive = true')
return []; ->andWhere('uo_target.users = :targetUser')
} ->andWhere('uo_target.statut = :status')
->setParameter('actingUser', $actingUser)
$qb = $this->createQueryBuilder('uo') ->setParameter('targetUser', $targetUser)
->addSelect('u', 'o') ->setParameter('role', $adminRole)
->leftJoin('uo.users', 'u') ->setParameter('status', 'ACCEPTED')
->leftJoin('uo.organization', 'o') ->getQuery()
->where('uo.isActive = :uoActive') ->getSingleScalarResult() > 0;
->andWhere('u.isActive = :uActive')
->andWhere('u.isDeleted = :uDeleted')
->andWhere('o.isActive = :oActive')
->andWhere('o.isDeleted = :oDeleted')
->andWhere('o.id IN (:orgIds)')
->orderBy('o.name', 'ASC')
->addOrderBy('u.surname', 'ASC')
->setParameter('uoActive', true)
->setParameter('uActive', true)
->setParameter('uDeleted', false)
->setParameter('oActive', true)
->setParameter('oDeleted', false)
->setParameter('orgIds', $organizationIds);
return $qb->getQuery()->getResult();
}
/**
* Find 10 newest Users in an Organization.
*
* @param Organizations $organization
* @return User[]
*/
public function findNewestUO(Organizations $organization): array
{
$qb = $this->createQueryBuilder('uo')
->select('uo', 'u')
->leftJoin('uo.users', 'u')
->where('uo.organization = :org')
->andWhere('uo.isActive = :uoActive')
->andWhere('u.isActive = :uActive')
->andWhere('u.isDeleted = :uDeleted')
->orderBy('u.createdAt', 'DESC')
->setMaxResults(10)
->setParameter('org', $organization)
->setParameter('uoActive', true)
->setParameter('uActive', true)
->setParameter('uDeleted', false);
return $qb->getQuery()->getResult();
}
/**
* Find all the admins of an Organization.
* limited to 10 results.
*
* @param Organizations $organization
* @return User[]
*/
public function findAdminsInOrganization(Organizations $organization): array
{
$qb = $this->createQueryBuilder('uo')
->select('uo', 'u')
->leftJoin('uo.users', 'u')
->leftJoin('uo.userOrganizatonApps', 'uoa')
->leftJoin('uoa.role', 'r')
->where('uo.organization = :org')
->andWhere('uo.isActive = :uoActive')
->andWhere('u.isActive = :uActive')
->andWhere('u.isDeleted = :uDeleted')
->andWhere('r.name = :roleAdmin')
->orderBy('u.surname', 'ASC')
->setMaxResults(10)
->setParameter('org', $organization)
->setParameter('uoActive', true)
->setParameter('uActive', true)
->setParameter('uDeleted', false)
->setParameter('roleAdmin', 'ADMIN');
return $qb->getQuery()->getResult();
} }
} }

View File

@ -134,21 +134,23 @@ class UserService
*/ */
public function isAdminOfUser(User $user): bool public function isAdminOfUser(User $user): bool
{ {
$actingUser = $this->getUserByIdentifier($this->security->getUser()->getUserIdentifier()); $actingUser = $this->security->getUser();
$roleAdmin = $this->rolesRepository->findOneBy(['name' => 'ADMIN']);
$adminUOs = $this->entityManager->getRepository(UsersOrganizations::class)->findBy([ if (!$actingUser instanceof User) {
'users' => $actingUser, return false;
'isActive' => true,
'role'=> $roleAdmin]);
$userOrganizations = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $user, 'statut' => 'ACCEPTED', 'isActive' => true]);
if ($userOrganizations) {
foreach ($userOrganizations as $uo) {
if (in_array($uo, $adminUOs, true)) {
return true;
}
}
} }
return false;
// Reuse the cached/fetched role
$adminRole = $this->rolesRepository->findOneBy(['name' => 'ADMIN']);
if (!$adminRole) {
return false;
}
// Call the optimized repository method
return $this->entityManager
->getRepository(UsersOrganizations::class)
->isUserAdminOfTarget($actingUser, $user, $adminRole);
} }
/** /**
@ -161,7 +163,7 @@ class UserService
*/ */
public function isAdminOfOrganization(Organizations $organizations): bool public function isAdminOfOrganization(Organizations $organizations): bool
{ {
$actingUser = $this->getUserByIdentifier($this->security->getUser()->getUserIdentifier()); $actingUser =$this->security->getUser();
$roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']); $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']);
$uoAdmin = $this->entityManager->getRepository(UsersOrganizations::class)->findOneBy(['users' => $actingUser, $uoAdmin = $this->entityManager->getRepository(UsersOrganizations::class)->findOneBy(['users' => $actingUser,
'organization' => $organizations, 'organization' => $organizations,