<?php
namespace App\Auth\Application\UseCase;
use App\Auth\Application\Exception\BadLoginResponse;
use App\Auth\Application\Exception\InvalidCredentials;
use App\Auth\Application\Exception\LoginFailed;
use App\Auth\Application\UseCase\LoginUseCase;
use App\Entity\Idempiere\AdUser;
use App\Repository\Idempiere\AdUserRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
final class IdempiereTokenOnLoginSuccessSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly LoginUseCase $loginUseCase,
private readonly UrlGeneratorInterface $urlGenerator,
private readonly TokenStorageInterface $tokenStorage,
private readonly LoggerInterface $logger,
private readonly AdUserRepository $userRepository
) {
}
public static function getSubscribedEvents(): array
{
return [
LoginSuccessEvent::class => 'onLoginSuccess',
];
}
public function onLoginSuccess(LoginSuccessEvent $event): void
{
$request = $event->getRequest();
$route = (string) $request->attributes->get('_route', '');
// Solo para el login normal manejado por security form_login.
if ($route !== 'app_login') {
return;
}
if (!$request->hasSession()) {
return;
}
$session = $request->getSession();
$username = (string) $request->request->get('username', $request->request->get('_username', ''));
$password = (string) $request->request->get('password', $request->request->get('_password', ''));
if ($username === '' || $password === '') {
return;
}
try {
$roleId = $this->resolveRoleId($event);
$dto = $this->loginUseCase->execute($username, $password, $roleId);
$session->set('idempiere.token', $dto->token);
$session->set('idempiere.refresh_token', $dto->refreshtoken);
$session->set('idempiere.userId', $dto->userId);
$session->set('idempiere.language', $dto->language);
$session->set('idempiere.org', $dto->org);
$session->set('idempiere.client', $dto->client);
$session->set('idempiere.role', $dto->role);
$session->set('idempiere.warehouse_id', $dto->warehouse);
$session->set('idempiere.tree', $dto->tree);
} catch (InvalidCredentials | BadLoginResponse | LoginFailed $e) {
$this->logger->error('Idempiere token creation failed after successful app login.', [
'route' => $route,
'username' => $username,
'error' => $e->getMessage(),
'exception' => $e,
]);
$session->invalidate();
$this->tokenStorage->setToken(null);
if ($request->hasSession()) {
$request->getSession()->getFlashBag()->add('error', 'No se pudo crear token de iDempiere: ' . $e->getMessage());
}
$event->setResponse(new RedirectResponse($this->urlGenerator->generate('app_login')));
}
}
private function resolveRoleId(LoginSuccessEvent $event): int
{
$user = $event->getAuthenticatedToken()->getUser();
if (!$user instanceof AdUser) {
return 0;
}
$roles = $this->userRepository->findRoles($user->getId());
if (empty($roles)) {
return 0;
}
$vendorRoleId = (int)($_ENV['IDEMPIERE_ROLE_ID'] ?? 0);
// Si el usuario tiene el rol de vendedor, usarlo; si no, usar su primer rol
foreach ($roles as $role) {
if ((int)$role['ad_role_id'] === $vendorRoleId) {
return $vendorRoleId;
}
}
return (int)$roles[0]['ad_role_id'];
}
}