first(); if (! $user || ! in_array($user->type, [UserTypeEnum::ADMIN, UserTypeEnum::USER])) { return null; } if (! Auth::attempt(['email' => $email, 'password' => $password])) { return null; } // $user = User::where('email', $email)->first(); $deviceId = Str::uuid()->toString(); $accessToken = $user->createAccessToken($deviceId); $refreshToken = $user->createRefreshToken($deviceId); return [ 'payload' => [ 'access_token' => $accessToken, 'user' => $user, ], 'refreshToken' => $refreshToken, ]; } public function refresh(string $refreshToken): ?array { if (! $refreshToken) { return null; } $tokenModel = PersonalAccessToken::findToken($refreshToken); if ( ! $tokenModel || ! in_array('refresh', $tokenModel->abilities) || $tokenModel->expires_at < now() ) { return null; } $user = $tokenModel->tokenable; if (! $user) { return null; } $deviceId = Str::afterLast($tokenModel->name, '_'); $tokens = $this->refreshTokenTransaction($tokenModel, $user, $deviceId); return [ 'payload' => [ 'access_token' => $tokens['access_token'], 'user' => $user, ], 'refreshToken' => $tokens['refresh_token'], ]; } public function logout(): void { $user = Auth::user(); if (! $user) { return; } $tokenName = $user->currentAccessToken()->name; $deviceId = Str::afterLast($tokenName, '_'); $user ->tokens() ->where('name', 'like', "%_{$deviceId}") ->delete(); } protected function refreshTokenTransaction( PersonalAccessToken $tokenModel, User $user, string $deviceId, ): array { return DB::transaction(function () use ( $tokenModel, $user, $deviceId, ): array { $tokenModel->update(['expires_at' => Carbon::now()]); $accessToken = $user->createAccessToken($deviceId); $refreshToken = $user->createRefreshToken($deviceId); return [ 'access_token' => $accessToken, 'refresh_token' => $refreshToken, ]; }); } public function clientSendCode(array $data): bool|array|null { try { DB::beginTransaction(); $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT); $user = User::where(function ($query) use ($data) { $query->when(! empty($data['email']), function ($q) use ($data) { $q->where('email', $data['email']); }) ->when(! empty($data['phone']), function ($q) use ($data) { $q->where('phone', $data['phone']); }); }) ->first(); $isLogin = false; if ($user) { if ($user->type->value !== UserTypeEnum::CLIENT->value) { DB::rollBack(); return ['error' => 'wrong_user_type']; } $user->code = $code; $user->validated_code = false; $user->save(); $client = Client::where('user_id', $user->id)->first(); $hasAddress = $client && Address::where('source', 'client') ->where('source_id', $client->id) ->exists(); $isLogin = $client && $hasAddress; } else { $user = new User; $user->fill($data); $user->code = $code; $user->name = $data['name'] ?? 'Usuário'; $user->type = $data['type'] ?? UserTypeEnum::CLIENT->value; $user->save(); Client::create(['user_id' => $user->id]); } if (! empty($data['email'])) { $this->emailService->sendVerificationCode( email: $data['email'], code: $code, recipientName: $data['name'] ?? '', ); } elseif (! empty($data['phone'])) { Log::info('SMS: envio de código por telefone ainda não implementado.', [ 'phone' => $data['phone'], ]); } DB::commit(); return $isLogin; } catch (\Exception $e) { DB::rollBack(); Log::error('Erro ao enviar código de verificação.', [ 'error' => $e->getMessage(), 'data' => $data, ]); return false; } } public function providerSendCode(array $data): bool|array|null { try { DB::beginTransaction(); $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT); $user = User::where(function ($query) use ($data) { $query->when(! empty($data['email']), function ($q) use ($data) { $q->where('email', $data['email']); }) ->when(! empty($data['phone']), function ($q) use ($data) { $q->where('phone', $data['phone']); }); }) ->first(); $isLogin = false; if ($user) { if ($user->type->value !== UserTypeEnum::PROVIDER->value) { DB::rollBack(); return ['error' => 'wrong_user_type']; } $provider = Provider::where('user_id', $user->id)->first(); if ($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) { DB::rollBack(); return ['error' => 'provider_not_accepted']; } $user->code = $code; $user->validated_code = false; $user->save(); $isLogin = true; } else { $user = new User; $user->fill($data); $user->code = $code; $user->name = $data['name'] ?? 'Usuário'; $user->type = $data['type'] ?? UserTypeEnum::PROVIDER->value; $user->save(); } if (! empty($data['email'])) { $this->emailService->sendVerificationCode( email: $data['email'], code: $code, recipientName: $data['name'] ?? '', ); } elseif (! empty($data['phone'])) { Log::info('SMS: envio de código por telefone ainda não implementado.', [ 'phone' => $data['phone'], ]); } DB::commit(); return $isLogin; } catch (\Exception $e) { DB::rollBack(); Log::error('Erro ao enviar código de verificação.', [ 'error' => $e->getMessage(), 'data' => $data, ]); return false; } } public function validateCodeClient(array $data, bool $isLogin): bool|array { $email = $data['email'] ?? null; $phone = $data['phone'] ?? null; $code = $data['code'] ?? ''; $user = User::where(function ($query) use ($email, $phone) { $query->when($email, fn ($q) => $q->where('email', $email)) ->when($phone, fn ($q) => $q->where('phone', $phone)); }) ->where('code', $code) ->first(); if (! $user) { return false; } if ($isLogin) { return $this->loginWithEmail($user->email, $code); } return true; } public function validateCodeProvider(array $data, bool $isLogin): bool|array { $email = $data['email'] ?? null; $phone = $data['phone'] ?? null; $code = $data['code'] ?? ''; $user = User::where(function ($query) use ($email, $phone) { $query->when($email, fn ($q) => $q->where('email', $email)) ->when($phone, fn ($q) => $q->where('phone', $phone)); }) ->where('code', $code) ->first(); if (! $user) { return false; } if ($isLogin) { $user->load('provider'); $provider = $user->provider ?? null; if ($provider && $provider->approval_status === ApprovalStatusEnum::PENDING->value) { return ['error' => 'provider_pending']; } if ($provider && $provider->approval_status === ApprovalStatusEnum::REJECTED->value) { return ['error' => 'provider_rejected']; } return $this->loginWithEmail($user->email, $code); } return true; } public function validateCode(array $data, bool $isLogin): bool|array { $email = $data['email'] ?? null; $phone = $data['phone'] ?? null; $code = $data['code'] ?? ''; $user = User::where(function ($query) use ($email, $phone) { $query->when($email, function ($q) use ($email) { $q->where('email', $email); }) ->when($phone, function ($q) use ($phone) { $q->where('phone', $phone); }); }) ->where('code', $code) ->first(); if (! $user) { return false; } if ($isLogin) { $resultLogin = $this->loginWithEmail($user->email, $code); return $resultLogin; } return true; } public function loginWithEmail(string $email, string $code): ?array { $user = User::where('email', $email) ->where('code', $code) ->first(); if (! $user) { return null; } $deviceId = Str::uuid()->toString(); $accessToken = $user->createAccessTokenApp($deviceId); $refreshToken = $user->createRefreshTokenApp($deviceId); $user->validated_code = true; $user->code = null; $user->save(); return [ 'payload' => [ 'access_token' => $accessToken, 'user' => $user, ], 'refreshToken' => $refreshToken, ]; } }