refactor user service
This commit is contained in:
parent
87ecf70d95
commit
271c2e31d1
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Event;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Symfony\Contracts\EventDispatcher\Event;
|
||||||
|
|
||||||
|
class UserCreatedEvent extends Event
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly User $newUser,
|
||||||
|
private readonly User $actingUser
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewUser(): User
|
||||||
|
{
|
||||||
|
return $this->newUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActingUser(): User
|
||||||
|
{
|
||||||
|
return $this->actingUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventSubscriber;
|
||||||
|
|
||||||
|
use App\Event\UserCreatedEvent;
|
||||||
|
use App\Service\ActionService;
|
||||||
|
use App\Service\EmailService;
|
||||||
|
use App\Service\LoggerService;
|
||||||
|
use App\Service\UserService; // Only if you need helper methods, otherwise avoid to prevent circular ref
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
|
class UserSubscriber implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly EmailService $emailService,
|
||||||
|
private readonly LoggerService $loggerService,
|
||||||
|
private readonly ActionService $actionService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
UserCreatedEvent::class => 'onUserCreated',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUserCreated(UserCreatedEvent $event): void
|
||||||
|
{
|
||||||
|
$user = $event->getNewUser();
|
||||||
|
$actingUser = $event->getActingUser();
|
||||||
|
|
||||||
|
// 1. Generate Token (If logic was moved here, otherwise assume UserService set it)
|
||||||
|
// If the token generation logic is still in UserService, just send the email here.
|
||||||
|
// If you moved generating the token here, do it now.
|
||||||
|
|
||||||
|
// 2. Send Email
|
||||||
|
// Note: You might need to pass the token in the Event if it's not stored in the DB entity
|
||||||
|
// or generate a new one here if appropriate.
|
||||||
|
if ($user->getPasswordToken()) {
|
||||||
|
$this->emailService->sendPasswordSetupEmail($user, $user->getPasswordToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Log the creation
|
||||||
|
$this->loggerService->logUserCreated($user->getId(), $actingUser->getId());
|
||||||
|
|
||||||
|
// 4. Create the Audit Action
|
||||||
|
$this->actionService->createAction(
|
||||||
|
"Create new user",
|
||||||
|
$actingUser,
|
||||||
|
null,
|
||||||
|
$user->getUserIdentifier()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ use App\Entity\Roles;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Entity\UserOrganizatonApp;
|
use App\Entity\UserOrganizatonApp;
|
||||||
use App\Entity\UsersOrganizations;
|
use App\Entity\UsersOrganizations;
|
||||||
use App\Service\AwsService;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
@ -17,25 +16,24 @@ use Exception;
|
||||||
use League\Bundle\OAuth2ServerBundle\Model\AccessToken;
|
use League\Bundle\OAuth2ServerBundle\Model\AccessToken;
|
||||||
use Random\RandomException;
|
use Random\RandomException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use SebastianBergmann\CodeCoverage\Util\DirectoryCouldNotBeCreatedException;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use App\Event\UserCreatedEvent;
|
||||||
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
|
|
||||||
class UserService
|
class UserService
|
||||||
{
|
{
|
||||||
|
|
||||||
public const NOT_FOUND = 'Entity not found';
|
public const NOT_FOUND = 'Entity not found';
|
||||||
|
|
||||||
public function __construct(private readonly EntityManagerInterface $entityManager,
|
public function __construct(private readonly EntityManagerInterface $entityManager,
|
||||||
private readonly Security $security,
|
private readonly Security $security,
|
||||||
private readonly AwsService $awsService,
|
private readonly AwsService $awsService,
|
||||||
private readonly LoggerService $loggerService,
|
private readonly LoggerService $loggerService,
|
||||||
private readonly ActionService $actionService,
|
private readonly ActionService $actionService,
|
||||||
private readonly EmailService $emailService,
|
private readonly EmailService $emailService,
|
||||||
private readonly OrganizationsService $organizationsService,
|
private readonly OrganizationsService $organizationsService,
|
||||||
|
private readonly EventDispatcherInterface $eventDispatcher
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -185,9 +183,9 @@ class UserService
|
||||||
try {
|
try {
|
||||||
$this->awsService->PutDocObj($_ENV['S3_PORTAL_BUCKET'], $picture, $customFilename, $extension, 'profile/');
|
$this->awsService->PutDocObj($_ENV['S3_PORTAL_BUCKET'], $picture, $customFilename, $extension, 'profile/');
|
||||||
$this->loggerService->logAWSAction(
|
$this->loggerService->logAWSAction(
|
||||||
'Profile picture uploaded to S3',[
|
'Profile picture uploaded to S3', [
|
||||||
'user_id' => $user->getId(),
|
'user_id' => $user->getId(),
|
||||||
'filename' => $customFilename,
|
'filename' => $customFilename,
|
||||||
]);
|
]);
|
||||||
$user->setPictureUrl('profile/' . $customFilename);
|
$user->setPictureUrl('profile/' . $customFilename);
|
||||||
} catch (FileException $e) {
|
} catch (FileException $e) {
|
||||||
|
|
@ -468,7 +466,7 @@ class UserService
|
||||||
$user->setName(trim($user->getName()));
|
$user->setName(trim($user->getName()));
|
||||||
$user->setSurname(trim($user->getSurname()));
|
$user->setSurname(trim($user->getSurname()));
|
||||||
$user->setEmail(trim($user->getEmail()));
|
$user->setEmail(trim($user->getEmail()));
|
||||||
if($setPassword) {
|
if ($setPassword) {
|
||||||
//FOR SETTING A DEFAULT RANDOM PASSWORD OF 50 CHARACTERS until user set his own password
|
//FOR SETTING A DEFAULT RANDOM PASSWORD OF 50 CHARACTERS until user set his own password
|
||||||
try {
|
try {
|
||||||
$user->setPassword(bin2hex(random_bytes(50)));
|
$user->setPassword(bin2hex(random_bytes(50)));
|
||||||
|
|
@ -480,7 +478,7 @@ class UserService
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if($picture) {
|
if ($picture) {
|
||||||
$this->handleProfilePicture($user, $picture);
|
$this->handleProfilePicture($user, $picture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -489,10 +487,11 @@ class UserService
|
||||||
* Handle existing user being added to an organization
|
* Handle existing user being added to an organization
|
||||||
*/
|
*/
|
||||||
public function addExistingUserToOrganization(
|
public function addExistingUserToOrganization(
|
||||||
User $existingUser,
|
User $existingUser,
|
||||||
Organizations $org,
|
Organizations $org,
|
||||||
User $actingUser,
|
User $actingUser,
|
||||||
): int {
|
): int
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$uoId = $this->handleExistingUser($existingUser, $org);
|
$uoId = $this->handleExistingUser($existingUser, $org);
|
||||||
|
|
||||||
|
|
@ -513,9 +512,9 @@ class UserService
|
||||||
return $uoId;
|
return $uoId;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->loggerService->logError('Error linking existing user to organization: ' . $e->getMessage(), [
|
$this->loggerService->logError('Error linking existing user to organization: ' . $e->getMessage(), [
|
||||||
'target_user_id' => $existingUser->getId(),
|
'target_user_id' => $existingUser->getId(),
|
||||||
'organization_id' => $org->getId(),
|
'organization_id' => $org->getId(),
|
||||||
'acting_user_id' => $actingUser->getId(),
|
'acting_user_id' => $actingUser->getId(),
|
||||||
]);
|
]);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
@ -528,17 +527,20 @@ class UserService
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->formatUserData($user, $picture, true);
|
$this->formatUserData($user, $picture, true);
|
||||||
|
|
||||||
|
// Generate token here if it's part of the user persistence flow
|
||||||
|
$token = $this->generatePasswordToken($user);
|
||||||
|
|
||||||
$this->entityManager->persist($user);
|
$this->entityManager->persist($user);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(new UserCreatedEvent($user, $actingUser));
|
||||||
|
|
||||||
$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());
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
// Error logging remains here because the event won't fire if exception occurs
|
||||||
$this->loggerService->logError('Error creating new user: ' . $e->getMessage(), [
|
$this->loggerService->logError('Error creating new user: ' . $e->getMessage(), [
|
||||||
'target_user_email' => $user->getEmail(),
|
'target_user_email' => $user->getEmail(),
|
||||||
'acting_user_id' => $actingUser->getId(),
|
'acting_user_id' => $actingUser->getId(),
|
||||||
]);
|
]);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
@ -548,10 +550,11 @@ class UserService
|
||||||
* Link newly created user to an organization
|
* Link newly created user to an organization
|
||||||
*/
|
*/
|
||||||
public function linkUserToOrganization(
|
public function linkUserToOrganization(
|
||||||
User $user,
|
User $user,
|
||||||
Organizations $org,
|
Organizations $org,
|
||||||
User $actingUser,
|
User $actingUser,
|
||||||
): UsersOrganizations {
|
): UsersOrganizations
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$uo = new UsersOrganizations();
|
$uo = new UsersOrganizations();
|
||||||
$uo->setUsers($user);
|
$uo->setUsers($user);
|
||||||
|
|
@ -567,7 +570,7 @@ class UserService
|
||||||
$org->getId(),
|
$org->getId(),
|
||||||
$actingUser->getId(),
|
$actingUser->getId(),
|
||||||
$uo->getId(),
|
$uo->getId(),
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->actionService->createAction(
|
$this->actionService->createAction(
|
||||||
|
|
@ -582,9 +585,9 @@ class UserService
|
||||||
return $uo;
|
return $uo;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->loggerService->logError('Error linking user to organization: ' . $e->getMessage(), [
|
$this->loggerService->logError('Error linking user to organization: ' . $e->getMessage(), [
|
||||||
'target_user_id' => $user->getId(),
|
'target_user_id' => $user->getId(),
|
||||||
'organization_id' => $org->getId(),
|
'organization_id' => $org->getId(),
|
||||||
'acting_user_id' => $actingUser->getId(),
|
'acting_user_id' => $actingUser->getId(),
|
||||||
]);
|
]);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
@ -597,11 +600,11 @@ class UserService
|
||||||
$token = $this->generatePasswordToken($user, $org->getId());
|
$token = $this->generatePasswordToken($user, $org->getId());
|
||||||
$this->emailService->sendExistingUserNotificationEmail($user, $org, $token);
|
$this->emailService->sendExistingUserNotificationEmail($user, $org, $token);
|
||||||
$this->loggerService->logExistingUserNotificationSent($user->getId(), $org->getId());
|
$this->loggerService->logExistingUserNotificationSent($user->getId(), $org->getId());
|
||||||
$this->organizationsService->notifyOrganizationAdmins(['user'=> $user, 'acting_user_id'=>$actingUser->getId(),
|
$this->organizationsService->notifyOrganizationAdmins(['user' => $user, 'acting_user_id' => $actingUser->getId(),
|
||||||
'organization'=> $org], 'USER_INVITED');
|
'organization' => $org], 'USER_INVITED');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->loggerService->logError("Error sending existing user notification: " . $e->getMessage(), [
|
$this->loggerService->logError("Error sending existing user notification: " . $e->getMessage(), [
|
||||||
'target_user_id' => $user->getId(),
|
'target_user_id' => $user->getId(),
|
||||||
'organization_id' => $org->getId(),
|
'organization_id' => $org->getId(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -612,11 +615,11 @@ class UserService
|
||||||
try {
|
try {
|
||||||
$token = $this->generatePasswordToken($user, $org->getId());
|
$token = $this->generatePasswordToken($user, $org->getId());
|
||||||
$this->emailService->sendPasswordSetupEmail($user, $token);
|
$this->emailService->sendPasswordSetupEmail($user, $token);
|
||||||
$this->organizationsService->notifyOrganizationAdmins(['user'=> $user, 'acting_user_id'=>$actingUser->getId(),
|
$this->organizationsService->notifyOrganizationAdmins(['user' => $user, 'acting_user_id' => $actingUser->getId(),
|
||||||
'organization'=> $org], 'USER_INVITED');
|
'organization' => $org], 'USER_INVITED');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->loggerService->logError("Error sending password setup email: " . $e->getMessage(), [
|
$this->loggerService->logError("Error sending password setup email: " . $e->getMessage(), [
|
||||||
'target_user_id' => $user->getId(),
|
'target_user_id' => $user->getId(),
|
||||||
'organization_id' => $org->getId(),
|
'organization_id' => $org->getId(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue