Refactor for monolog in user controller
This commit is contained in:
parent
659eb08d6e
commit
5f4336d824
|
|
@ -98,7 +98,7 @@ class SecurityController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route('/password_reset/{id}', name: 'password_reset', methods: ['POST'])]
|
||||
public function password_reset(int $id): Response
|
||||
public function password_reset(int $id, Request $request): Response
|
||||
{
|
||||
$user = $this->userRepository->find($id);
|
||||
if (!$user) {
|
||||
|
|
@ -127,7 +127,10 @@ class SecurityController extends AbstractController
|
|||
$uo->setIsActive(true);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->entityManager->flush();
|
||||
$data = ['user' => $user, 'organization' => $uo->getOrganization()];
|
||||
$data = ['user' => $user,
|
||||
'organization' => $uo->getOrganization(),
|
||||
'ip' => $request->getClientIp(),
|
||||
];
|
||||
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, "USER_ACCEPTED");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,18 +22,14 @@ use App\Service\UserOrganizationAppService;
|
|||
use App\Service\UserOrganizationService;
|
||||
use App\Service\UserService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use mysql_xdevapi\Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Mailer\Mailer;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Mime\Email;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
|
||||
#[Route(path: '/user', name: 'user_')]
|
||||
class UserController extends AbstractController
|
||||
|
|
@ -76,6 +72,7 @@ class UserController extends AbstractController
|
|||
|
||||
// Vérification des droits d'accès supplémentaires
|
||||
if (!$this->userService->hasAccessTo($actingUser)) {
|
||||
$this->loggerService->logAccessDenied($actingUser->getId());
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +101,10 @@ class UserController extends AbstractController
|
|||
]);
|
||||
|
||||
if (!$uoList) {
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization', [
|
||||
'user_id' => $user->getId(),
|
||||
'organization_id' => $orgId],
|
||||
$actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +118,13 @@ class UserController extends AbstractController
|
|||
'users' => $user,
|
||||
'isActive' => true,
|
||||
]);
|
||||
if (!$uoList) {
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization', [
|
||||
'user_id' => $user->getId(),
|
||||
'organization_id' => $orgId],
|
||||
$actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
// Charger les liens UserOrganizationApp (UOA) actifs pour les UO trouvées
|
||||
|
|
@ -127,6 +135,13 @@ 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
|
||||
|
|
@ -171,17 +186,11 @@ class UserController extends AbstractController
|
|||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||
try {
|
||||
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
if ($this->userService->hasAccessTo($actingUser)) {
|
||||
$user = $this->userRepository->find($id);
|
||||
if (!$user) {
|
||||
$this->userManagementLogger->notice('User not found for edit', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $request->getClientIp(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$form = $this->createForm(UserForm::class, $user);
|
||||
|
|
@ -190,64 +199,70 @@ class UserController extends AbstractController
|
|||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
// Handle user edit
|
||||
$picture = $form->get('pictureUrl')->getData();
|
||||
$this->userService->formatNewUserData($user, $picture);
|
||||
$this->userService->formatUserData($user, $picture);
|
||||
$user->setModifiedAt(new \DateTimeImmutable('now'));
|
||||
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
|
||||
//log and action
|
||||
$this->userManagementLogger->notice('User information edited', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'organization_id' => $request->get('organizationId'),
|
||||
'ip' => $request->getClientIp(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
if ($request->get('organizationId')) {
|
||||
$org = $this->organizationRepository->find($request->get('organizationId'));
|
||||
$this->loggerService->logUserAction($user->getId(), $actingUser->getId(), 'User information edited');
|
||||
$orgId = $request->get('organizationId');
|
||||
if ($orgId) {
|
||||
$org = $this->organizationRepository->find($orgId);
|
||||
if ($org) {
|
||||
$this->actionService->createAction("Edit user information", $actingUser, $org, $user->getUserIdentifier());
|
||||
$this->organizationManagementLogger->info('User edited within organization context', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'acting_user' => $actingUser->getUserIdentifier(),
|
||||
'ip' => $request->getClientIp(),
|
||||
]);
|
||||
return $this->redirectToRoute('user_show', ['id' => $user->getId(), 'organizationId' => $request->get('organizationId')]);
|
||||
$this->loggerService->logUserAction($user->getId(), $actingUser->getId(), 'User information edited');
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
"Super Admin accessed user edit page",
|
||||
);
|
||||
}
|
||||
return $this->redirectToRoute('user_show', ['id' => $user->getId(), 'organizationId' => $orgId]);
|
||||
}
|
||||
} else {
|
||||
$this->actionService->createAction("Edit user information", $actingUser, null, $user->getUserIdentifier());
|
||||
return $this->redirectToRoute('user_show', ['id' => $user->getId()]);
|
||||
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
"Super Admin accessed user edit page",
|
||||
);
|
||||
}
|
||||
$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(),
|
||||
'organizationId' => $request->get('organizationId')
|
||||
]);
|
||||
}
|
||||
$this->loggerService->logAccessDenied($actingUser->getId());
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
} catch (\Exception $e) {
|
||||
$this->errorLogger->critical($e->getMessage());
|
||||
}
|
||||
$this->securityLogger->warning('Access denied on user edit', [
|
||||
'target_user_id' => $id,
|
||||
'acting_user' => $actingUser?->getId(),
|
||||
'ip' => $request->getClientIp(),
|
||||
]);
|
||||
// Default deny access. shouldn't reach here normally.
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
|
||||
}
|
||||
|
||||
#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
|
||||
public function new(Request $request): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
||||
|
||||
try {
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
|
||||
if (!$this->userService->hasAccessTo($actingUser)) {
|
||||
$this->loggerService->logAccessDenied($actingUser->getId());
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
|
|
@ -256,15 +271,12 @@ class UserController extends AbstractController
|
|||
$form->handleRequest($request);
|
||||
|
||||
$orgId = $request->get('organizationId');
|
||||
$org = $orgId ? $this->organizationRepository->find($orgId) : null;
|
||||
|
||||
if (!$org && $orgId) {
|
||||
$this->loggerService->logCritical('Organization not found for user creation', [
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $request->getClientIp(),
|
||||
]);
|
||||
throw $this->createNotFoundException('Organization not found');
|
||||
if ($orgId) {
|
||||
$org = $this->organizationRepository->find($orgId);
|
||||
if (!$org) {
|
||||
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
|
|
@ -276,7 +288,6 @@ class UserController extends AbstractController
|
|||
$existingUser,
|
||||
$org,
|
||||
$actingUser,
|
||||
$request->getClientIp()
|
||||
);
|
||||
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
|
|
@ -284,20 +295,17 @@ class UserController extends AbstractController
|
|||
$existingUser->getId(),
|
||||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
$request->getClientIp(),
|
||||
"Super Admin linked user to organization",
|
||||
);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('organization_show', ['id' => $orgId]);
|
||||
}
|
||||
|
||||
// Case : User exists but NO organization context → error
|
||||
// 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(),
|
||||
'ip' => $request->getClientIp(),
|
||||
]);
|
||||
|
||||
$form->get('email')->addError(
|
||||
|
|
@ -314,26 +322,24 @@ class UserController extends AbstractController
|
|||
}
|
||||
|
||||
$picture = $form->get('pictureUrl')->getData();
|
||||
$this->userService->createNewUser($user, $actingUser, $picture, $request->getClientIp());
|
||||
$this->userService->createNewUser($user, $actingUser, $picture);
|
||||
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
$request->getClientIp(),
|
||||
"Super Admin created new user",
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
// Link to organization if provided
|
||||
// Case : Organization provided and user doesn't already exist
|
||||
if ($org) {
|
||||
$this->userService->linkUserToOrganization(
|
||||
$user,
|
||||
$org,
|
||||
$actingUser,
|
||||
$request->getClientIp()
|
||||
);
|
||||
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
|
|
@ -341,8 +347,7 @@ class UserController extends AbstractController
|
|||
$user->getId(),
|
||||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
$request->getClientIp(),
|
||||
"Super Admin linked user to organization",
|
||||
"Super Admin linked user to organization during creation",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -359,11 +364,9 @@ class UserController extends AbstractController
|
|||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error on user creation route: " . $e->getMessage(), [
|
||||
'ip' => $request->getClientIp(),
|
||||
]);
|
||||
$this->errorLogger->critical($e->getMessage());
|
||||
|
||||
if ($orgId ?? null) {
|
||||
if ($orgId) {
|
||||
return $this->redirectToRoute('organization_show', ['id' => $orgId]);
|
||||
}
|
||||
|
||||
|
|
@ -378,32 +381,19 @@ class UserController extends AbstractController
|
|||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
||||
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
$ip = $request->getClientIp();
|
||||
$status = $request->get('status');
|
||||
|
||||
try {
|
||||
// Access control
|
||||
if (!$this->userService->hasAccessTo($actingUser, true)) {
|
||||
$this->securityLogger->warning('Access denied on user status change', [
|
||||
'target_user_id' => $id,
|
||||
'acting_user_id' => $actingUser?->getId(),
|
||||
'acting_identifier' => $actingUser?->getId(),
|
||||
'requested_status' => $status,
|
||||
'ip' => $ip,
|
||||
]);
|
||||
|
||||
$this->loggerService->logAccessDenied($actingUser->getId());
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
// Load target user
|
||||
$user = $this->userRepository->find($id);
|
||||
if (!$user) {
|
||||
$this->securityLogger->warning('User not found for status change', [
|
||||
'target_user_id' => $id,
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'requested_status' => $status,
|
||||
'ip' => $ip,
|
||||
]);
|
||||
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
|
||||
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
|
|
@ -416,31 +406,18 @@ class UserController extends AbstractController
|
|||
|
||||
if ($this->userService->isUserConnected($user->getUserIdentifier())) {
|
||||
$this->userService->revokeUserTokens($user->getUserIdentifier());
|
||||
|
||||
$this->securityLogger->info('User tokens revoked due to deactivation', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'target_identifier' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
}
|
||||
|
||||
$user->setModifiedAt(new \DateTimeImmutable('now'));
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->userManagementLogger->notice('User deactivated', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'target_identifier' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
$this->loggerService->logUserAction($user->getId(), $actingUser->getId(), 'User deactivated');
|
||||
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
$ip,
|
||||
'Super admin deactivated user'
|
||||
);
|
||||
}
|
||||
|
|
@ -454,21 +431,16 @@ class UserController extends AbstractController
|
|||
if ($status === 'activate') {
|
||||
$user->setIsActive(true);
|
||||
$user->setModifiedAt(new \DateTimeImmutable('now'));
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
$this->loggerService->logUserAction($user->getId(), $actingUser->getId(), 'User activated');
|
||||
|
||||
$this->userManagementLogger->notice('User activated', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'target_identifier' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
$ip,
|
||||
'Super admin activated user'
|
||||
);
|
||||
}
|
||||
|
|
@ -479,25 +451,16 @@ class UserController extends AbstractController
|
|||
}
|
||||
|
||||
// Invalid status
|
||||
$this->errorLogger->warning('Invalid status passed to activeStatus', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
$this->loggerService->logError('Invalid status provided for activeStatus', [
|
||||
'requested_status' => $status,
|
||||
'ip' => $ip,
|
||||
'target_user_id' => $id,
|
||||
]);
|
||||
|
||||
return new JsonResponse(['error' => 'Invalid status'], Response::HTTP_BAD_REQUEST);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
// Application-level error logging → error.log (via error channel)
|
||||
$this->errorLogger->error('Error in activeStatus', [
|
||||
'exception_message' => $e->getMessage(),
|
||||
'exception_class' => get_class($e),
|
||||
'target_user_id' => $id,
|
||||
'acting_user_id' => $actingUser?->getId(),
|
||||
'requested_status' => $status,
|
||||
'ip' => $ip,
|
||||
]);
|
||||
$this->errorLogger->critical($e->getMessage());
|
||||
|
||||
// Preserve 403/404 semantics, 500 for everything else
|
||||
if ($e instanceof NotFoundHttpException || $e instanceof AccessDeniedException) {
|
||||
|
|
@ -508,34 +471,152 @@ class UserController extends AbstractController
|
|||
}
|
||||
}
|
||||
|
||||
//TODO : MONOLOG + remove picture from bucket
|
||||
#[Route('/organization/activateStatus/{id}', name: 'activate_organization', methods: ['GET', 'POST'])]
|
||||
public function activateStatusOrganization(int $id, Request $request): JsonResponse
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
try {
|
||||
if ($this->userService->hasAccessTo($actingUser, true)) {
|
||||
$orgId = $request->get('organizationId');
|
||||
$org = $this->organizationRepository->find($orgId);
|
||||
if (!$org) {
|
||||
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
|
||||
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,
|
||||
'organization' => $org]);
|
||||
if (!$uo) {
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization', ['user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId()], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$status = $request->get('status');
|
||||
if ($status === 'deactivate') {
|
||||
$uo->setIsActive(false);
|
||||
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->entityManager->flush();
|
||||
$data = ['user' => $user,
|
||||
'organization' => $org];
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, "USER_DEACTIVATED");
|
||||
$this->loggerService->logOrganizationInformation($org->getId(), $actingUser->getId(), "UO link deactivated with uo id : {$uo->getId()}");
|
||||
$this->actionService->createAction("Deactivate user in organization", $actingUser, $org, $org->getName() . " for user " . $user->getUserIdentifier());
|
||||
return new JsonResponse(['status' => 'deactivated'], Response::HTTP_OK);
|
||||
}
|
||||
if ($status === "activate") {
|
||||
$uo->setIsActive(true);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->entityManager->flush();
|
||||
$this->loggerService->logOrganizationInformation($orgId, $actingUser->getId(), "UO link activated with uo id : {$uo->getId()}");
|
||||
$this->actionService->createAction("Activate user in organization", $actingUser, $org, $org->getName() . " for user " . $user->getUserIdentifier());
|
||||
$data = ['user' => $user,
|
||||
'organization' => $org];
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, "USER_ACTIVATED");
|
||||
return new JsonResponse(['status' => 'activated'], Response::HTTP_OK);
|
||||
}
|
||||
//invalid status
|
||||
$this->loggerService->logError('Invalid status provided for activateStatusOrganization', [
|
||||
'requested_status' => $status,
|
||||
'target_user_id' => $id,
|
||||
'organization_id' => $orgId,
|
||||
]);
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->loggerService->logCritical($exception->getMessage());
|
||||
}
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
|
||||
//TODO :remove picture from bucket
|
||||
#[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($actingUser, $user);
|
||||
$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());
|
||||
$data = ['user' => $user,
|
||||
'organization' => null];
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, "USER_DELETED");
|
||||
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT); //204
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
|
||||
try {
|
||||
$user = $this->userRepository->find($id);
|
||||
|
||||
if (!$user) {
|
||||
// Security/audit log for missing user
|
||||
$this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId());
|
||||
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
|
||||
// Soft delete the user
|
||||
$user->setIsActive(false);
|
||||
$user->setIsDeleted(true);
|
||||
$user->setModifiedAt(new \DateTimeImmutable('now'));
|
||||
|
||||
// Deactivate all org links
|
||||
$this->userOrganizationService->deactivateAllUserOrganizationLinks($actingUser, $user);
|
||||
$this->loggerService->logOrganizationInformation($user->getId(), $actingUser->getId(), 'All user organization links deactivated');
|
||||
|
||||
// Revoke tokens if connected
|
||||
if ($this->userService->isUserConnected($user->getUserIdentifier())) {
|
||||
$this->userService->revokeUserTokens($user->getUserIdentifier());
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
// User management log
|
||||
$this->loggerService->logUserAction($user->getId(), $actingUser->getId(), 'User deleted');
|
||||
|
||||
// Super admin log (standardized style)
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$this->loggerService->logSuperAdmin(
|
||||
$user->getId(),
|
||||
null,
|
||||
$actingUser->getId(),
|
||||
'Super admin deleted user'
|
||||
);
|
||||
}
|
||||
|
||||
$this->actionService->createAction('Delete user', $actingUser, null, $user->getUserIdentifier());
|
||||
|
||||
// Notify organization admins (user may belong to multiple organizations)
|
||||
try {
|
||||
$data = [
|
||||
'user' => $user,
|
||||
'organization' => null,
|
||||
];
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, 'USER_DELETED');
|
||||
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$this->loggerService->logCritical($e->getMessage(), [
|
||||
'target_user_id' => $id,
|
||||
'acting_user_id' => $actingUser?->getId(),
|
||||
]);
|
||||
// No rethrow here: deletion succeeded; only notifications failed
|
||||
}
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT); // 204
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Route-level error logging → error.log
|
||||
$this->loggerService->logCritical('error while deleting user', [
|
||||
'target_user_id' => $id,
|
||||
'acting_user_id' => $actingUser?->getId(),
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
if ($e instanceof NotFoundHttpException) {
|
||||
throw $e; // keep 404 semantics
|
||||
}
|
||||
|
||||
return new Response('', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO : MONOLOG
|
||||
#[Route(path: '/application/roles/{id}', name: 'application_role', methods: ['GET', 'POST'])]
|
||||
public function applicationRole(int $id, Request $request): Response
|
||||
{
|
||||
|
|
@ -543,19 +624,26 @@ class UserController extends AbstractController
|
|||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
|
||||
if ($this->userService->hasAccessTo($actingUser, true)) {
|
||||
$uo = $this->userOrganizationService->getByIdOrFail($id);
|
||||
$uo = $this->entityManager->getRepository(UsersOrganizations::class)->find($id);
|
||||
if (!$uo) {
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization', ['id' => $id], $actingUser->getId());
|
||||
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());
|
||||
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');
|
||||
$this->loggerService->logEntityNotFound('Role', ['name' => 'USER'], $actingUser->getId());
|
||||
throw $this->createNotFoundException('User role not found');
|
||||
}
|
||||
|
||||
if (!empty($selectedRolesIds)) {
|
||||
// Si le role User n'est pas sélectionné, on désactive tous les liens (affiché comme 'accès' dans l'UI)
|
||||
if (!in_array((string)$roleUser->getId(), $selectedRolesIds, true)) {
|
||||
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo, $application);
|
||||
} else {
|
||||
|
|
@ -651,6 +739,7 @@ class UserController extends AbstractController
|
|||
#[Route(path: '/', name: 'index', methods: ['GET'])]
|
||||
public function index(): Response
|
||||
{
|
||||
$this->isGranted('ROLE_SUPER_ADMIN');
|
||||
$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]);
|
||||
|
|
@ -658,6 +747,9 @@ class UserController extends AbstractController
|
|||
'users' => $totalUsers
|
||||
]);
|
||||
}
|
||||
|
||||
//shouldn't be reached normally
|
||||
$this->loggerService->logAccessDenied($actingUser->getId());
|
||||
throw $this->createAccessDeniedException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
|
|
@ -811,16 +903,21 @@ class UserController extends AbstractController
|
|||
$orgId = $request->get('organizationId');
|
||||
$org = $this->organizationRepository->find($orgId);
|
||||
if (!$org) {
|
||||
$this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$user = $this->userRepository->find($userId);
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User', ['id' => $user->getId()], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$uo = $this->uoRepository->findOneBy(['users' => $user,
|
||||
'organization' => $org,
|
||||
'statut' => "INVITED"]);
|
||||
if (!$uo) {
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization', [
|
||||
'user_id' => $user->getId(),
|
||||
'organization_id' => $orgId], $actingUser->getId());
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$uo->setModifiedAt(new \DateTimeImmutable());
|
||||
|
|
@ -832,7 +929,12 @@ class UserController extends AbstractController
|
|||
$this->organizationsService->notifyOrganizationAdmins($data, 'USER_INVITED');
|
||||
return $this->json(['message' => 'Invitation envoyée avec success.'], Response::HTTP_OK);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error("Error resending invitation email to user " . $user->getUserIdentifier() . " for organization " . $org->getName() . ": " . $e->getMessage());
|
||||
$this->loggerService->logCritical('Error while resending invitation', [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
return $this->json(['message' => 'Erreur lors de l\'envoie du mail.'], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
|
@ -846,20 +948,35 @@ class UserController extends AbstractController
|
|||
$userId = $request->get('id');
|
||||
|
||||
if (!$token || !$userId) {
|
||||
$this->loggerService->logEntityNotFound('Token or UserId missing in accept invitation', [
|
||||
'token' => $token,
|
||||
'user_id' => $userId
|
||||
],
|
||||
null);
|
||||
throw $this->createNotFoundException('Invalid invitation link.');
|
||||
}
|
||||
$user = $this->userRepository->find($userId);
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User not found in accept invitation', [
|
||||
'user_id' => $userId
|
||||
],null);
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
if (!$this->userService->isPasswordTokenValid($user, $token)) {
|
||||
$this->loggerService->logError('Token or UserId mismatch in accept invitation', [
|
||||
'token' => $token,
|
||||
'user_id' => $userId
|
||||
]);
|
||||
throw $this->createNotFoundException('Invalid or expired invitation token.');
|
||||
}
|
||||
$orgId = $this->userService->getOrgFromToken($token);
|
||||
if ($orgId) {
|
||||
$uo = $this->uoRepository->findOneBy(['users' => $user, 'organization' => $orgId]);
|
||||
if (!$uo || $uo->getStatut() !== 'INVITED') {
|
||||
$this->logger->warning("User " . $user->getUserIdentifier() . " tried to accept an invitation but no pending invitation was found for organization ID " . $orgId);
|
||||
$this->loggerService->logEntityNotFound('UsersOrganization not found or not in INVITED status in accept invitation', [
|
||||
'user_id' => $user->getId(),
|
||||
'organization_id' => $orgId
|
||||
], null);
|
||||
throw $this->createNotFoundException('No pending invitation found for this user and organization.');
|
||||
}
|
||||
$uo->setModifiedAt(new \DateTimeImmutable());
|
||||
|
|
@ -867,7 +984,8 @@ class UserController extends AbstractController
|
|||
$uo->setIsActive(true);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->entityManager->flush();
|
||||
$this->logger->info("User " . $user->getUserIdentifier() . " accepted invitation for organization ID " . $orgId);
|
||||
$this->loggerService->logUserAction($user->getId(), null, "User accepted invitation for organization id : {$orgId}");
|
||||
$this->loggerService->logOrganizationInformation($orgId, $user->getId(), "User accepted invitation with uo id : {$uo->getId()}");
|
||||
}
|
||||
return $this->render('security/login.html.twig');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Service;
|
|||
|
||||
use App\Entity\Organizations;
|
||||
use App\Entity\User;
|
||||
use App\Service\LoggerService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
|
|
@ -15,7 +16,7 @@ class EmailService
|
|||
public function __construct(
|
||||
private readonly MailerInterface $mailer,
|
||||
private readonly LoggerInterface $logger,
|
||||
private UrlGeneratorInterface $urlGenerator
|
||||
private UrlGeneratorInterface $urlGenerator, private readonly LoggerService $loggerService
|
||||
) {}
|
||||
|
||||
public function sendPasswordSetupEmail(User $user, string $token): void
|
||||
|
|
@ -43,7 +44,9 @@ class EmailService
|
|||
]);
|
||||
|
||||
try {
|
||||
$orgId = $this->getOrgFromToken($token);
|
||||
$this->mailer->send($email);
|
||||
$this->loggerService->logEmailSent($user->getId(), $orgId, 'Password setup email sent.');
|
||||
} catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) {
|
||||
$this->logger->error('Failed to send password setup email: ' . $e->getMessage());
|
||||
}
|
||||
|
|
@ -69,10 +72,26 @@ class EmailService
|
|||
]);
|
||||
|
||||
try{
|
||||
$orgId = $org->getId();
|
||||
$this->loggerService->logEmailSent($existingUser->getId(), $orgId, 'Existing user notification email sent.');
|
||||
$this->mailer->send($email);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Failed to send existing user notification email: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getOrgFromToken(string $token): ?int
|
||||
{
|
||||
if (str_starts_with($token, 'o')) {
|
||||
$parts = explode('@', $token);
|
||||
if (count($parts) === 2) {
|
||||
$orgPart = substr($parts[0], 1); // Remove the leading 'o'
|
||||
if (is_numeric($orgPart)) {
|
||||
return (int)$orgPart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,106 +4,99 @@ namespace App\Service;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
readonly class LoggerService
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $userManagementLogger,
|
||||
private LoggerInterface $organizationManagementLogger,
|
||||
private LoggerInterface $accessControlLogger,
|
||||
private LoggerInterface $emailNotificationLogger,
|
||||
private LoggerInterface $adminActionsLogger,
|
||||
private LoggerInterface $securityLogger,
|
||||
private LoggerInterface $errorLogger,
|
||||
private LoggerInterface $userManagementLogger,
|
||||
private LoggerInterface $organizationManagementLogger,
|
||||
private LoggerInterface $accessControlLogger,
|
||||
private LoggerInterface $emailNotificationLogger,
|
||||
private LoggerInterface $adminActionsLogger,
|
||||
private LoggerInterface $securityLogger,
|
||||
private LoggerInterface $errorLogger,
|
||||
private RequestStack $requestStack,
|
||||
) {}
|
||||
|
||||
|
||||
|
||||
// User Management Logs
|
||||
public function logUserCreated(int $userId, int $actingUserId, ?string $ip): void
|
||||
public function logUserCreated(int $userId, int $actingUserId): void
|
||||
{
|
||||
$this->userManagementLogger->notice("New user created: $userId", [
|
||||
'target_user_id' => $userId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logUserEdited(int $userId, int $actingUserId, ?int $orgId, ?string $ip): void
|
||||
{
|
||||
$this->userManagementLogger->notice('User information edited', [
|
||||
'target_user_id' => $userId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'organization_id' => $orgId,
|
||||
'ip' => $ip,
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Organization Management Logs
|
||||
public function logUserOrganizationLinkCreated(int $userId, int $orgId, int $actingUserId, ?int $uoId, ?string $ip): void
|
||||
public function logUserOrganizationLinkCreated(int $userId, int $orgId, int $actingUserId, ?int $uoId): void
|
||||
{
|
||||
$this->organizationManagementLogger->notice('User-Organization link created', [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'uo_id' => $uoId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logExistingUserAddedToOrg(int $userId, int $orgId, int $actingUserId, int $uoId, ?string $ip): void
|
||||
public function logExistingUserAddedToOrg(int $userId, int $orgId, int $actingUserId, int $uoId): void
|
||||
{
|
||||
$this->organizationManagementLogger->notice('Existing user added to organization', [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'uo_id' => $uoId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Email Notification Logs
|
||||
public function logPasswordSetupEmailSent(int $userId, ?int $orgId, ?string $ip): void
|
||||
public function logEmailSent(int $userId, ?int $orgId, string $message): void
|
||||
{
|
||||
$this->emailNotificationLogger->notice("Password setup email sent to $userId", [
|
||||
$this->emailNotificationLogger->notice($message, [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $orgId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logExistingUserNotificationSent(int $userId, int $orgId, ?string $ip): void
|
||||
public function logExistingUserNotificationSent(int $userId, int $orgId): void
|
||||
{
|
||||
$this->emailNotificationLogger->notice("Existing user notification email sent to $userId", [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $orgId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logAdminNotified(int $adminUserId, int $targetUserId, int $orgId, int $actingUserId, ?string $ip): void
|
||||
public function logAdminNotified(int $adminUserId, int $targetUserId, int $orgId, int $actingUserId): void
|
||||
{
|
||||
$this->emailNotificationLogger->notice('Organization admin notified', [
|
||||
'admin_user_id' => $adminUserId,
|
||||
'target_user_id' => $targetUserId,
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logSuperAdmin(int $userId, ?int $orgId = null, int $actingUserId, ?string $ip, string $message): void
|
||||
public function logSuperAdmin(int $userId, ?int $orgId = null, int $actingUserId, string $message): void
|
||||
{
|
||||
$this->adminActionsLogger->notice($message, [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
|
@ -113,6 +106,7 @@ readonly class LoggerService
|
|||
{
|
||||
$this->errorLogger->error($message, array_merge($context, [
|
||||
'timestamp' => $this->now(),
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
]));
|
||||
}
|
||||
|
||||
|
|
@ -120,17 +114,18 @@ readonly class LoggerService
|
|||
{
|
||||
$this->errorLogger->critical($message, array_merge($context, [
|
||||
'timestamp' => $this->now(),
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
]));
|
||||
}
|
||||
|
||||
// Security Logs
|
||||
public function logAccessDenied(int $targetId, ?int $actingUserId, ?string $ip): void
|
||||
public function logAccessDenied(?int $actingUserId): void
|
||||
{
|
||||
$this->securityLogger->warning('Access denied', [
|
||||
'target_id' => $targetId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $ip,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
'page_accessed' => $_SERVER['REQUEST_URI'] ?? 'unknown',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -139,4 +134,94 @@ readonly class LoggerService
|
|||
{
|
||||
return (new \DateTimeImmutable('now'))->format(DATE_ATOM);
|
||||
}
|
||||
|
||||
|
||||
public function logUserAction(int $targetId, int $actingUserId, string $message): void
|
||||
{
|
||||
$this->userManagementLogger->notice($message, [
|
||||
'target_user_id'=> $targetId,
|
||||
'acting_user_id'=> $actingUserId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logAdminAction(int $targetId, int $actingUserId, int $organizationId, string $message): void
|
||||
{
|
||||
$this->adminActionsLogger->notice($message, [
|
||||
'target_id' => $targetId,
|
||||
'acting_user_id'=> $actingUserId,
|
||||
'organization_id'=> $organizationId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logEntityNotFound(string $entityType, array $criteria, ?int $actingUserId): void
|
||||
{
|
||||
$this->errorLogger->warning('Entity not found', [
|
||||
'entity_type' => $entityType,
|
||||
'criteria' => $criteria,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logAWSAction(string $action, array $details): void
|
||||
{
|
||||
$this->securityLogger->info("AWS action performed: $action", array_merge($details, [
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]));
|
||||
}
|
||||
|
||||
public function logTokenRevocation(string $message, array $array): void
|
||||
{
|
||||
$this->securityLogger->notice($message, array_merge($array, [
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]));
|
||||
}
|
||||
|
||||
public function logUOALinkDeactivated(int $uoaId, int $appId, int $roleId): void
|
||||
{
|
||||
$this->securityLogger->notice('UOA link deactivated', [
|
||||
'uoa_id' => $uoaId,
|
||||
'app_id' => $appId,
|
||||
'role_id' => $roleId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logOrganizationInformation(int $organizationId, int $actingUserId, string $message): void
|
||||
{
|
||||
$this->organizationManagementLogger->info($message, [
|
||||
'organization_id' => $organizationId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logRoleEntityAssignment(int $userId, int $organizationId, int $roleId, int $actingUserId, string $message): void
|
||||
{
|
||||
$this->accessControlLogger->info($message, [
|
||||
'target_user_id' => $userId,
|
||||
'organization_id' => $organizationId,
|
||||
'role_id' => $roleId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
public function logRoleAssignment(string $message, array $context): void
|
||||
{
|
||||
$this->accessControlLogger->info($message, [
|
||||
'context' => $context,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use App\Entity\Roles;
|
|||
use App\Entity\UserOrganizatonApp;
|
||||
use App\Entity\UsersOrganizations;
|
||||
use App\Repository\UsersOrganizationsRepository;
|
||||
use App\Service\LoggerService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
|
||||
class OrganizationsService
|
||||
|
|
@ -16,10 +18,11 @@ class OrganizationsService
|
|||
private string $logoDirectory;
|
||||
|
||||
public function __construct(
|
||||
string $logoDirectory, private readonly AwsService $awsService,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
string $logoDirectory, private readonly AwsService $awsService,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly UsersOrganizationsRepository $uoRepository,
|
||||
private readonly NotificationService $notificationService
|
||||
private readonly NotificationService $notificationService,
|
||||
private readonly LoggerInterface $emailNotificationLogger, private readonly LoggerService $loggerService,
|
||||
)
|
||||
{
|
||||
$this->logoDirectory = $logoDirectory;
|
||||
|
|
@ -33,8 +36,18 @@ class OrganizationsService
|
|||
|
||||
try {
|
||||
$this->awsService->PutDocObj($_ENV['S3_PORTAL_BUCKET'], $logoFile, $customFilename, $extension, 'logo/');
|
||||
$this->loggerService->logAWSAction('Upload organization logo', [
|
||||
'organization_id' => $organization->getId(),
|
||||
'filename' => $customFilename,
|
||||
'bucket' => $_ENV['S3_PORTAL_BUCKET'],
|
||||
]);
|
||||
$organization->setLogoUrl('logo/' . $customFilename);
|
||||
} catch (FileException $e) {
|
||||
$this->loggerService->logError('Failed to upload organization logo to S3', [
|
||||
'organization_id' => $organization->getId(),
|
||||
'error' => $e->getMessage(),
|
||||
'bucket' => $_ENV['S3_PORTAL_BUCKET'],
|
||||
]);
|
||||
throw new FileException('Failed to upload logo to S3: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -87,6 +100,13 @@ class OrganizationsService
|
|||
$data['organization']
|
||||
);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of new user accept', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $newUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_INVITED':
|
||||
if ($uoa) {
|
||||
|
|
@ -97,6 +117,13 @@ class OrganizationsService
|
|||
$data['organization']
|
||||
);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of new user invited', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $invitedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_DEACTIVATED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -107,6 +134,13 @@ class OrganizationsService
|
|||
$data['organization']
|
||||
);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user deactivated', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $removedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_DELETED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -117,6 +151,13 @@ class OrganizationsService
|
|||
$data['organization']
|
||||
);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user deleted', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $removedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_ACTIVATED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -127,6 +168,13 @@ class OrganizationsService
|
|||
$data['organization']
|
||||
);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user activated', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $activatedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,15 @@ use App\Entity\User;
|
|||
use App\Entity\UserOrganizatonApp;
|
||||
use App\Entity\UsersOrganizations;
|
||||
use App\Service\ActionService;
|
||||
use App\Service\LoggerService;
|
||||
use App\Service\UserService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
class UserOrganizationAppService
|
||||
{
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly ActionService $actionService, private readonly Security $security, private readonly UserService $userService)
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly ActionService $actionService, private readonly Security $security, private readonly UserService $userService, private readonly LoggerInterface $logger, private readonly LoggerService $loggerService)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -79,10 +81,20 @@ class UserOrganizationAppService
|
|||
$uoas = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy(['userOrganization' => $userOrganization, 'isActive' => true]);
|
||||
}
|
||||
foreach ($uoas as $uoa) {
|
||||
$uoa->setIsActive(false);
|
||||
$this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(),
|
||||
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName() . ", Role: " . $uoa->getRole()->getName());
|
||||
$this->entityManager->persist($uoa);
|
||||
try{
|
||||
$uoa->setIsActive(false);
|
||||
$this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(),
|
||||
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName() . ", Role: " . $uoa->getRole()->getName());
|
||||
$this->entityManager->persist($uoa);
|
||||
$this->loggerService->logUOALinkDeactivated($uoa->getId(), $uoa->getApplication()->getId(), $uoa->getRole()->getId());
|
||||
}catch (\Exception $exception){
|
||||
$this->loggerService->logCritical("Error deactivating UOA link", [
|
||||
'uoa_id' => $uoa->getId(),
|
||||
'app_id' => $uoa->getApplication()->getId(),
|
||||
'role_id' => $uoa->getRole()->getId(),
|
||||
'exception_message' => $exception->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +140,11 @@ class UserOrganizationAppService
|
|||
if (!$uoa->isActive()) {
|
||||
$uoa->setIsActive(true);
|
||||
$this->entityManager->persist($uoa);
|
||||
$this->loggerService->logOrganizationInformation(
|
||||
$uo->getOrganization()->getId(),
|
||||
$actingUser->getId(),
|
||||
"Re-activated role '$roleName' for user '{$uo->getUsers()->getId()}' in application '{$application->getName()} with UOA ID {$uoa->getId()}'"
|
||||
);
|
||||
$this->actionService->createAction(
|
||||
"Re-activate user role for application",
|
||||
$actingUser,
|
||||
|
|
@ -148,7 +165,11 @@ class UserOrganizationAppService
|
|||
if ($uoa->isActive()) {
|
||||
$uoa->setIsActive(false);
|
||||
$this->entityManager->persist($uoa);
|
||||
|
||||
$this->loggerService->logOrganizationInformation(
|
||||
$uo->getOrganization()->getId(),
|
||||
$actingUser->getId(),
|
||||
"Deactivated role '$roleName' for user '{$uo->getUsers()->getId()}' in application '{$application->getName()}' with UOA ID {$uoa->getId()}'"
|
||||
);
|
||||
$this->actionService->createAction(
|
||||
"Deactivate user role for application",
|
||||
$actingUser,
|
||||
|
|
@ -185,6 +206,11 @@ class UserOrganizationAppService
|
|||
$this->ensureAdminRoleForSuperAdmin($newUoa);
|
||||
}
|
||||
$this->entityManager->persist($newUoa);
|
||||
$this->loggerService->logOrganizationInformation(
|
||||
$uo->getOrganization()->getId(),
|
||||
$actingUser->getId(),
|
||||
"Created new role '{$role->getName()}' for user '{$uo->getUsers()->getId()}' in application '{$application->getName()}' with UOA ID {$newUoa->getId()}'"
|
||||
);
|
||||
$this->actionService->createAction("New user role for application",
|
||||
$actingUser,
|
||||
$uo->getOrganization(),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use App\Entity\Organizations;
|
|||
use App\Entity\User;
|
||||
use App\Entity\UsersOrganizations;
|
||||
use App\Service\ActionService;
|
||||
use App\Service\LoggerService;
|
||||
use \App\Service\UserOrganizationAppService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
|
@ -19,7 +20,7 @@ readonly class UserOrganizationService
|
|||
{
|
||||
|
||||
public function __construct(
|
||||
private userOrganizationAppService $userOrganizationAppService, private EntityManagerInterface $entityManager, private ActionService $actionService,
|
||||
private userOrganizationAppService $userOrganizationAppService, private EntityManagerInterface $entityManager, private ActionService $actionService, private LoggerService $loggerService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -43,20 +44,14 @@ readonly class UserOrganizationService
|
|||
//deactivate all UO links
|
||||
foreach ($uos as $uo) {
|
||||
$this->userOrganizationAppService->deactivateAllUserOrganizationsAppLinks($uo);
|
||||
$this->loggerService->logOrganizationInformation($uo->getOrganization()->getId(), $actingUser->getId(),
|
||||
'Uo link deactivated');
|
||||
$uo->setIsActive(false);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->actionService->createAction("Deactivate UO link", $actingUser, $uo->getOrganization(), $uo->getOrganization()->getName() );
|
||||
}
|
||||
}
|
||||
|
||||
public function getByIdOrFail(int $id): UsersOrganizations
|
||||
{
|
||||
$uo = $this->entityManager->getRepository(UsersOrganizations::class)->find($id);
|
||||
if (!$uo) {
|
||||
throw new NotFoundHttpException("UserOrganization not found");
|
||||
}
|
||||
return $uo;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ class UserService
|
|||
*/
|
||||
public function hasAccessTo(User $user, bool $skipSelfCheck = false): bool
|
||||
{
|
||||
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
return true;
|
||||
}
|
||||
if (!$skipSelfCheck && $user->getUserIdentifier() === $this->security->getUser()->getUserIdentifier()) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -106,9 +109,6 @@ class UserService
|
|||
}
|
||||
}
|
||||
}
|
||||
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
|
@ -151,6 +151,7 @@ class UserService
|
|||
{
|
||||
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $userIdentifier]);
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User', ['user_identifier' => $userIdentifier], null);
|
||||
throw new EntityNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
return $user;
|
||||
|
|
@ -182,18 +183,20 @@ class UserService
|
|||
return ['none' => $group];
|
||||
}
|
||||
|
||||
//TODO: reset function
|
||||
public function handleProfilePicture(User $user, $picture): void
|
||||
{
|
||||
// Get file extension
|
||||
$extension = $picture->guessExtension();
|
||||
|
||||
// Create custom filename: userNameUserSurname_ddmmyyhhmmss
|
||||
// Create custom filename: userNameUserSurname_dmyHis
|
||||
$customFilename = $user->getName() . $user->getSurname() . '_' . date('dmyHis') . '.' . $extension;
|
||||
// $customFilename = $user->getName() . $user->getSurname() . "." .$extension;
|
||||
try {
|
||||
$this->awsService->PutDocObj($_ENV['S3_PORTAL_BUCKET'], $picture, $customFilename, $extension, 'profile/');
|
||||
|
||||
$this->loggerService->logAWSAction(
|
||||
'Profile picture uploaded to S3',[
|
||||
'user_id' => $user->getId(),
|
||||
'filename' => $customFilename,
|
||||
]);
|
||||
$user->setPictureUrl('profile/' . $customFilename);
|
||||
} catch (FileException $e) {
|
||||
// Handle upload error
|
||||
|
|
@ -249,12 +252,18 @@ class UserService
|
|||
if ($roleFormatted === 'ROLE_SUPER_ADMIN' && !in_array('ROLE_ADMIN', $user->getRoles(), true)) {
|
||||
$user->setRoles(array_merge($user->getRoles(), ['ROLE_ADMIN']));
|
||||
}
|
||||
$this->loggerService->logRoleAssignment(
|
||||
'Role assigned to user',
|
||||
[
|
||||
'user_id' => $user->getId(),
|
||||
'role' => $roleFormatted,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// Remove the role if present and not used elsewhere
|
||||
if (in_array($roleFormatted, $user->getRoles(), true)) {
|
||||
$uos = $this->entityManager->getRepository(UsersOrganizations::class)
|
||||
->findBy(['users' => $user, 'isActive' => true]);
|
||||
|
||||
$hasRole = false;
|
||||
foreach ($uos as $uo) {
|
||||
$uoa = $this->entityManager->getRepository(UserOrganizatonApp::class)
|
||||
|
|
@ -264,7 +273,6 @@ class UserService
|
|||
'role' => $this->entityManager->getRepository(Roles::class)
|
||||
->findOneBy(['name' => $role]),
|
||||
]);
|
||||
|
||||
if ($uoa) {
|
||||
$hasRole = true;
|
||||
break;
|
||||
|
|
@ -300,9 +308,26 @@ class UserService
|
|||
'userIdentifier' => $userIdentifier,
|
||||
'revoked' => false
|
||||
]);
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
$token->revoke();
|
||||
try{
|
||||
$token->revoke();
|
||||
$this->loggerService->logTokenRevocation(
|
||||
'Access token revoked for user',
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}catch (\Exception $e){
|
||||
$this->loggerService->logError(
|
||||
'Error revoking access token: ' . $e->getMessage(),
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,7 +494,7 @@ class UserService
|
|||
* @param User $user
|
||||
* @return void
|
||||
*/
|
||||
public function formatNewUserData(User $user, $picture, bool $setPassword = false): void
|
||||
public function formatUserData(User $user, $picture, bool $setPassword = false): void
|
||||
{
|
||||
// capitalize name and surname
|
||||
$user->setName(ucfirst(strtolower($user->getName())));
|
||||
|
|
@ -496,7 +521,6 @@ class UserService
|
|||
User $existingUser,
|
||||
Organizations $org,
|
||||
User $actingUser,
|
||||
?string $ip
|
||||
): int {
|
||||
try {
|
||||
$uoId = $this->handleExistingUser($existingUser, $org);
|
||||
|
|
@ -506,17 +530,14 @@ class UserService
|
|||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
$uoId,
|
||||
$ip
|
||||
);
|
||||
|
||||
$this->actionService->createAction(
|
||||
"Add existing user to organization",
|
||||
$actingUser,
|
||||
$org,
|
||||
"Added user {$existingUser->getUserIdentifier()} to {$org->getName()}"
|
||||
);
|
||||
|
||||
$this->sendExistingUserNotifications($existingUser, $org, $actingUser, $ip);
|
||||
$this->sendExistingUserNotifications($existingUser, $org, $actingUser);
|
||||
|
||||
return $uoId;
|
||||
} catch (\Exception $e) {
|
||||
|
|
@ -524,7 +545,6 @@ class UserService
|
|||
'target_user_id' => $existingUser->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
|
|
@ -533,14 +553,14 @@ class UserService
|
|||
/**
|
||||
* Create a brand-new user
|
||||
*/
|
||||
public function createNewUser(User $user, User $actingUser, $picture, ?string $ip): void
|
||||
public function createNewUser(User $user, User $actingUser, $picture): void
|
||||
{
|
||||
try {
|
||||
$this->formatNewUserData($user, $picture, true);
|
||||
$this->formatUserData($user, $picture, true);
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->loggerService->logUserCreated($user->getId(), $actingUser->getId(), $ip);
|
||||
$this->loggerService->logUserCreated($user->getId(), $actingUser->getId());
|
||||
$token = $this->generatePasswordToken($user);
|
||||
$this->emailService->sendPasswordSetupEmail($user, $token);
|
||||
$this->actionService->createAction("Create new user", $actingUser, null, $user->getUserIdentifier());
|
||||
|
|
@ -548,7 +568,6 @@ class UserService
|
|||
$this->loggerService->logError('Error creating new user: ' . $e->getMessage(), [
|
||||
'target_user_email' => $user->getEmail(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
|
|
@ -561,7 +580,6 @@ class UserService
|
|||
User $user,
|
||||
Organizations $org,
|
||||
User $actingUser,
|
||||
?string $ip
|
||||
): UsersOrganizations {
|
||||
try {
|
||||
$uo = new UsersOrganizations();
|
||||
|
|
@ -578,7 +596,7 @@ class UserService
|
|||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
$uo->getId(),
|
||||
$ip
|
||||
|
||||
);
|
||||
|
||||
$this->actionService->createAction(
|
||||
|
|
@ -588,7 +606,7 @@ class UserService
|
|||
"Added {$user->getUserIdentifier()} to {$org->getName()}"
|
||||
);
|
||||
|
||||
$this->sendNewUserNotifications($user, $org, $actingUser, $ip);
|
||||
$this->sendNewUserNotifications($user, $org, $actingUser);
|
||||
|
||||
return $uo;
|
||||
} catch (\Exception $e) {
|
||||
|
|
@ -596,51 +614,47 @@ class UserService
|
|||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'acting_user_id' => $actingUser->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Private helpers for email notifications
|
||||
private function sendExistingUserNotifications(User $user, Organizations $org, User $actingUser, ?string $ip): void
|
||||
private function sendExistingUserNotifications(User $user, Organizations $org, User $actingUser): void
|
||||
{
|
||||
try {
|
||||
$token = $this->generatePasswordToken($user, $org->getId());
|
||||
$this->emailService->sendExistingUserNotificationEmail($user, $org, $token);
|
||||
$this->loggerService->logExistingUserNotificationSent($user->getId(), $org->getId(), $ip);
|
||||
$this->loggerService->logExistingUserNotificationSent($user->getId(), $org->getId());
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error sending existing user notification: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser, $ip);
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser,);
|
||||
}
|
||||
|
||||
private function sendNewUserNotifications(User $user, Organizations $org, User $actingUser, ?string $ip): void
|
||||
private function sendNewUserNotifications(User $user, Organizations $org, User $actingUser): void
|
||||
{
|
||||
try {
|
||||
$token = $this->generatePasswordToken($user, $org->getId());
|
||||
$this->emailService->sendPasswordSetupEmail($user, $token);
|
||||
$this->loggerService->logPasswordSetupEmailSent($user->getId(), $org->getId(), $ip);
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error sending password setup email: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser, $ip);
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser);
|
||||
}
|
||||
|
||||
private function notifyOrgAdmins(User $user, Organizations $org, User $actingUser, ?string $ip): void
|
||||
private function notifyOrgAdmins(User $user, Organizations $org, User $actingUser): void
|
||||
{
|
||||
try {
|
||||
$data = ['user' => $user, 'organization' => $org];
|
||||
$data = ['user' => $user,
|
||||
'organization' => $org];
|
||||
$adminsUos = $this->organizationsService->notifyOrganizationAdmins($data, 'USER_INVITED');
|
||||
|
||||
foreach ($adminsUos as $adminUo) {
|
||||
|
|
@ -649,14 +663,12 @@ class UserService
|
|||
$user->getId(),
|
||||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
$ip
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error notifying organization admins: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
'ip' => $ip,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue