Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.00% covered (warning)
75.00%
45 / 60
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
LoginTokenService
75.00% covered (warning)
75.00%
45 / 60
0.00% covered (danger)
0.00%
0 / 1
14.25
0.00% covered (danger)
0.00%
0 / 1
 generate
75.00% covered (warning)
75.00%
45 / 60
0.00% covered (danger)
0.00%
0 / 1
14.25
1<?php
2
3namespace Domain\Login\Services;
4
5use Domain\Shared\Integrations\Senior\Exceptions\IntegrationSoapSeniorException;
6use Domain\Shared\Integrations\Senior\SeniorCredentialResolver;
7use SoapFault;
8use function config;
9
10use Carbon\Carbon;
11use Laravel\Sanctum\NewAccessToken;
12
13use Illuminate\Auth\AuthenticationException;
14use Illuminate\Support\Facades\Auth;
15use Illuminate\Support\Facades\Cache;
16use Illuminate\Support\Facades\Crypt;
17use Illuminate\Support\Facades\Log;
18
19use App\Models\User;
20
21use Domain\Login\DTOs\LoginDTO;
22use Domain\User\Services\UpdateUserExpoTokenService;
23use Domain\Login\Integrations\AuthenticateSenior;
24use Domain\Shared\Enums\SectorEnum;
25use Domain\User\Enums\AccessLevel;
26
27readonly class LoginTokenService
28{
29    /**
30     * @param LoginDTO $loginDTO
31     * @return NewAccessToken
32     * @throws AuthenticationException
33     * @throws IntegrationSoapSeniorException
34     * @throws SoapFault
35     */
36    public static function generate(LoginDTO $loginDTO): NewAccessToken
37    {
38        $sector = $loginDTO->toArray()['sector'] ?? null;
39        $accessLevel = $loginDTO->toArray()['access_level'] ?? null;
40        $email = $loginDTO->toArray()['email'] ?? null;
41        $password = $loginDTO->toArray()['password'] ?? null;
42        $usedSeniorCredentials = false;
43
44        /** @var User|null $user */
45        $user = User::where('email', $email)->first();
46
47        if (!$user) {
48            throw new AuthenticationException(
49                __('This access does not match our records.')
50            );
51        }
52
53        $hasWarehouseErpAccess = $user->hasAccessLevel(
54            AccessLevel::REQUESTER->value,
55            SectorEnum::WAREHOUSE->value
56        ) || $user->hasAccessLevel(
57            AccessLevel::SEPARATOR->value,
58            SectorEnum::WAREHOUSE->value
59        );
60
61        // Reaplica a validacao do ERP para requisitante sem quebrar regra atual:
62        // se nao houver usuario ERP preenchido, cai no login padrao do sistema.
63        if ($hasWarehouseErpAccess) {
64            $seniorUser = (new SeniorCredentialResolver())->resolveUsername($user);
65
66            if (!is_null($seniorUser)) {
67                AuthenticateSenior::login($seniorUser, $password);
68                Auth::login($user);
69                $usedSeniorCredentials = true;
70            } elseif (!Auth::attempt($loginDTO->getKey())) {
71                throw new AuthenticationException(
72                    __('This access does not match our records.')
73                );
74            }
75        } elseif (!Auth::attempt($loginDTO->getKey())) {
76            throw new AuthenticationException(
77                __('This access does not match our records.')
78            );
79        }
80
81        /** @var User $user */
82        $user = Auth::user();
83        $accesses = $user->getAttribute('access_level');
84
85        if (!(isset($accesses[$sector]) && in_array($accessLevel, $accesses[$sector]))) {
86            throw new AuthenticationException(
87                __('The user is not associated with the access level: :accessLevel or with the sector: :sector.', [
88                    'accessLevel' => $loginDTO->toArray()['access_level'],
89                    'sector' => $loginDTO->toArray()['sector']
90                ])
91            );
92        }
93
94        $expiresAt = Carbon::now()->addMinutes(config('sanctum.expiration'));
95
96        $token = $user->createToken(
97            $user->getKey(),
98            [$sector => $loginDTO->toArray()['access_level']],
99            expiresAt: $expiresAt
100        );
101
102        // Mantem a senha usada no login ERP atrelada ao token atual
103        // para que a exportacao da requisicao utilize o mesmo contexto do usuario logado.
104        if ($usedSeniorCredentials && !empty($password)) {
105            Cache::put(
106                "erp_password_{$token->accessToken->id}",
107                Crypt::encryptString($password),
108                $expiresAt
109            );
110        }
111
112        if(!is_null($loginDTO->expo_token)){
113            (new UpdateUserExpoTokenService(
114                $loginDTO->expo_token, $user, $user)
115            )->update();
116        }
117
118        Log::channel('access')->info(
119            "Login efetuado: #{$user->getKey()} {$user->getAttribute('name')}"
120        );
121
122        return $token;
123    }
124}