Browse Source

feat: retorna token para prestador criado porem restringe endpoints antes da aprovacao do mesmo

Gustavo Mantovani 1 week ago
parent
commit
b9c80cb22c

+ 5 - 0
app/Http/Controllers/ProviderController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Http\Requests\ProviderBankAccountRequest;
 use App\Http\Requests\ProviderRequest;
 use App\Http\Requests\RegisterProviderRequest;
+use App\Http\Resources\AuthResource;
 use App\Http\Resources\ProviderResource;
 use App\Services\ProviderService;
 use Illuminate\Http\JsonResponse;
@@ -117,6 +118,10 @@ class ProviderController extends Controller
         }
 
         return $this->successResponse(
+            payload: new AuthResource([
+                ...$result['payload'],
+                'refresh_token' => $result['refreshToken'],
+            ]),
             message: __('messages.provider_registered_pending'),
             code: 201,
         );

+ 46 - 0
app/Http/Middleware/EnsureProviderIsAccepted.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use App\Enums\ApprovalStatusEnum;
+use App\Enums\UserTypeEnum;
+use Closure;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class EnsureProviderIsAccepted
+{
+    public function handle(Request $request, Closure $next): Response
+    {
+        $user = $request->user();
+
+        if (! $user || $user->type !== UserTypeEnum::PROVIDER) {
+            return $next($request);
+        }
+
+        $provider = $user->provider;
+
+        if (! $provider) {
+            return $this->forbidden(__('auth.registration_incomplete'));
+        }
+
+        if ($provider->approval_status === ApprovalStatusEnum::PENDING) {
+            return response()->json([
+                'payload' => ['approval_status' => ApprovalStatusEnum::PENDING->value],
+                'message' => __('auth.provider_pending'),
+            ], 202);
+        }
+
+        if ($provider->approval_status === ApprovalStatusEnum::REJECTED) {
+            return $this->forbidden(__('auth.provider_rejected'));
+        }
+
+        return $next($request);
+    }
+
+    private function forbidden(string $message): JsonResponse
+    {
+        return response()->json(['message' => $message], 403);
+    }
+}

+ 67 - 47
app/Services/AuthService.php

@@ -34,7 +34,7 @@ class AuthService
 
         $deviceId = Str::uuid()->toString();
 
-        $accessToken = $user->createAccessToken($deviceId);
+        $accessToken  = $user->createAccessToken($deviceId);
         $refreshToken = $user->createRefreshToken($deviceId);
 
         return [
@@ -42,6 +42,7 @@ class AuthService
                 'access_token' => $accessToken,
                 'user'         => $user,
             ],
+
             'refreshToken' => $refreshToken,
         ];
     }
@@ -63,6 +64,7 @@ class AuthService
         }
 
         $user = $tokenModel->tokenable;
+
         if (! $user) {
             return null;
         }
@@ -76,6 +78,7 @@ class AuthService
                 'access_token' => $tokens['access_token'],
                 'user'         => $user,
             ],
+
             'refreshToken' => $tokens['refresh_token'],
         ];
     }
@@ -83,24 +86,25 @@ class AuthService
     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();
+        $user->tokens()->where('name', 'like', "%_{$deviceId}")->delete();
     }
 
+    //
+
     protected function refreshTokenTransaction(
         PersonalAccessToken $tokenModel,
-        User $user,
-        string $deviceId,
-        bool $isApp = false,
+        User                $user,
+        string              $deviceId,
+        bool                $isApp = false,
     ): array {
         return DB::transaction(function () use (
             $tokenModel,
@@ -113,6 +117,7 @@ class AuthService
             $accessToken = $isApp
                 ? $user->createAccessTokenApp($deviceId)
                 : $user->createAccessToken($deviceId);
+
             $refreshToken = $isApp
                 ? $user->createRefreshTokenApp($deviceId)
                 : $user->createRefreshToken($deviceId);
@@ -124,22 +129,22 @@ class AuthService
         });
     }
 
+    //
+
     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']);
-                    });
-            })
-                ->where('type', UserTypeEnum::CLIENT->value)
-                ->first();
+                })->when(! empty($data['phone']), function ($q) use ($data) {
+                    $q->where('phone', $data['phone']);
+                });
+            })->where('type', UserTypeEnum::CLIENT->value)->first();
 
             $isLogin = false;
 
@@ -188,6 +193,7 @@ class AuthService
             return $isLogin;
         } catch (\Exception $e) {
             DB::rollBack();
+
             Log::error('Erro ao enviar código de verificação.', [
                 'error' => $e->getMessage(),
                 'data'  => $data,
@@ -201,37 +207,43 @@ class AuthService
     {
         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']);
-                    });
-            })
-                ->where('type', UserTypeEnum::PROVIDER->value)
-                ->first();
+                })->when(! empty($data['phone']), function ($q) use ($data) {
+                    $q->where('phone', $data['phone']);
+                });
+            })->where('type', UserTypeEnum::PROVIDER->value)->first();
+
             $isLogin = false;
+
             if ($user) {
                 $provider = Provider::where('user_id', $user->id)->first();
+
                 if ($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) {
                     DB::rollBack();
 
                     return ['error' => 'provider_not_accepted'];
                 }
+
                 $isLogin = $provider !== null;
 
-                $user->code = $code;
+                $user->code           = $code;
                 $user->validated_code = false;
+
                 $user->save();
             } 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();
             }
 
@@ -252,6 +264,7 @@ class AuthService
             return $isLogin;
         } catch (\Exception $e) {
             DB::rollBack();
+
             Log::error('Erro ao enviar código de verificação.', [
                 'error' => $e->getMessage(),
                 'data'  => $data,
@@ -261,19 +274,18 @@ class AuthService
         }
     }
 
+    //
+
     public function validateCodeClient(array $data, bool $isLogin): bool|array
     {
         $email = $data['email'] ?? null;
         $phone = $data['phone'] ?? null;
-        $code = $data['code'] ?? '';
+        $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('type', UserTypeEnum::CLIENT->value)
-            ->where('code', $code)
-            ->first();
+        })->where('type', UserTypeEnum::CLIENT->value)->where('code', $code)->first();
 
         if (! $user) {
             return false;
@@ -281,7 +293,9 @@ class AuthService
 
         if ($isLogin) {
             $user->load('client');
+
             $client = $user->client;
+
             $hasAddress = $client && Address::where('source', 'client')
                 ->where('source_id', $client->id)
                 ->exists();
@@ -300,15 +314,12 @@ class AuthService
     {
         $email = $data['email'] ?? null;
         $phone = $data['phone'] ?? null;
-        $code = $data['code'] ?? '';
+        $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('type', UserTypeEnum::PROVIDER->value)
-            ->where('code', $code)
-            ->first();
+        })->where('type', UserTypeEnum::PROVIDER->value)->where('code', $code)->first();
 
         if (! $user) {
             return false;
@@ -316,6 +327,7 @@ class AuthService
 
         if ($isLogin) {
             $user->load('provider');
+
             $provider = $user->provider ?? null;
 
             if (! $provider) {
@@ -336,22 +348,21 @@ class AuthService
         return true;
     }
 
+    //
+
     public function validateCode(array $data, bool $isLogin): bool|array
     {
         $email = $data['email'] ?? null;
         $phone = $data['phone'] ?? null;
-        $code = $data['code'] ?? '';
+        $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();
+            })->when($phone, function ($q) use ($phone) {
+                $q->where('phone', $phone);
+            });
+        })->where('code', $code)->first();
 
         if (! $user) {
             return false;
@@ -377,22 +388,31 @@ class AuthService
             return null;
         }
 
-        $deviceId = Str::uuid()->toString();
+        $user->validated_code = true;
+        $user->code           = null;
 
-        $accessToken = $user->createAccessTokenApp($deviceId);
-        $refreshToken = $user->createRefreshTokenApp($deviceId);
+        $user->save();
 
-        $user->validated_code = true;
+        return $this->createAppSession($user);
+    }
 
-        $user->code = null;
+    //
 
-        $user->save();
+    public function createAppSession(User $user): array
+    {
+        $user->loadMissing(['provider.profileMedia', 'client.profileMedia']);
+
+        $deviceId = Str::uuid()->toString();
+
+        $accessToken  = $user->createAccessTokenApp($deviceId);
+        $refreshToken = $user->createRefreshTokenApp($deviceId);
 
         return [
             'payload' => [
                 'access_token' => $accessToken,
                 'user'         => $user,
             ],
+
             'refreshToken' => $refreshToken,
         ];
     }

+ 8 - 3
app/Services/ProviderService.php

@@ -21,6 +21,7 @@ use Illuminate\Support\Facades\Log;
 class ProviderService
 {
     public function __construct(
+        private readonly AuthService $authService,
         private readonly PagarmeRecipientService $pagarmeRecipientService,
         private readonly MediaService $mediaService,
         private readonly EmailService $emailService,
@@ -138,7 +139,7 @@ class ProviderService
 
     //
 
-    public function register(array $data): bool
+    public function register(array $data): array
     {
         try {
             DB::beginTransaction();
@@ -182,6 +183,7 @@ class ProviderService
 
             if (! $provider) {
                 $provider = new Provider;
+
                 $provider->user_id = $user->id;
             } elseif ($provider->trashed()) {
                 $provider->restore();
@@ -256,7 +258,7 @@ class ProviderService
 
             $this->createProviderWorkingDays($provider->id, $data);
 
-            if (empty($user->email) || empty($user->code)) {
+            if ((empty($user->email) && empty($user->phone)) || empty($user->code)) {
                 throw new \Exception(__('messages.user_not_found_or_code_not_validated'));
             }
 
@@ -267,9 +269,11 @@ class ProviderService
 
             $user->save();
 
+            $result = $this->authService->createAppSession($user);
+
             DB::commit();
 
-            return true;
+            return $result;
         } catch (\Exception $e) {
             DB::rollBack();
 
@@ -311,6 +315,7 @@ class ProviderService
     {
         [$provider, $wasAccepted] = DB::transaction(function () use ($id) {
             $provider = Provider::findOrFail($id);
+
             $wasAccepted = $provider->approval_status === ApprovalStatusEnum::ACCEPTED;
 
             $provider->update(['approval_status' => ApprovalStatusEnum::ACCEPTED->value]);

+ 4 - 2
bootstrap/app.php

@@ -1,6 +1,7 @@
 <?php
 
 use App\Http\Middleware\CheckPermission;
+use App\Http\Middleware\EnsureProviderIsAccepted;
 use App\Http\Middleware\PerformanceMonitor;
 use App\Http\Middleware\SetUserLanguage;
 use App\Tasks\DeleteExpiredTokens;
@@ -22,8 +23,9 @@ return Application::configure(basePath: dirname(__DIR__))
         // $middleware->statefulApi();
         $middleware->append([SetUserLanguage::class, PerformanceMonitor::class]);
         $middleware->alias([
-            'permission' => CheckPermission::class,
-            'ability'    => CheckForAnyAbility::class,
+            'permission'        => CheckPermission::class,
+            'ability'           => CheckForAnyAbility::class,
+            'provider.accepted' => EnsureProviderIsAccepted::class,
         ]);
     })
     ->withSchedule(function (Schedule $schedule) {

+ 11 - 11
lang/pt/auth.php

@@ -13,17 +13,17 @@ return [
     |
     */
 
-    'failed'             => 'Essas credenciais não correspondem aos nossos registros.',
-    'password'           => 'A senha fornecida está incorreta.',
-    'throttle'           => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.',
-    'logout'             => 'Desconectado com sucesso',
-    'logged_in'          => 'Conectado com sucesso',
-    'already_logged_out' => 'Usuário já desconectado',
-    'unauthorized'       => 'Não autorizado',
-    'session_expired'    => 'Sessão expirada',
-    'invalid_code'       => 'Código inválido',
-    'valid_code'         => 'O código fornecido é válido.',
-    'wrong_user_type'    => 'Este e-mail não pode acessar esse aplicativo. Entre em contato com o suporte para mais informações.',
+    'failed'                   => 'Essas credenciais não correspondem aos nossos registros.',
+    'password'                 => 'A senha fornecida está incorreta.',
+    'throttle'                 => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.',
+    'logout'                   => 'Desconectado com sucesso',
+    'logged_in'                => 'Conectado com sucesso',
+    'already_logged_out'       => 'Usuário já desconectado',
+    'unauthorized'             => 'Não autorizado',
+    'session_expired'          => 'Sessão expirada',
+    'invalid_code'             => 'Código inválido',
+    'valid_code'               => 'O código fornecido é válido.',
+    'wrong_user_type'          => 'Este e-mail não pode acessar esse aplicativo. Entre em contato com o suporte para mais informações.',
     'provider_pending'         => 'Seu cadastro está aguardando aprovação. Em breve entraremos em contato.',
     'provider_rejected'        => 'Seu cadastro foi recusado. Entre em contato com o suporte.',
     'provider_not_accepted'    => 'Seu cadastro ainda não foi aprovado. Por favor, aguarde ou entre em contato com o suporte para mais informações.',

+ 3 - 1
routes/api.php

@@ -4,13 +4,15 @@ use Illuminate\Support\Facades\Route;
 
 Route::middleware([])->group(function () {
     $noAuthRoutes = glob(__DIR__ . "/noAuthRoutes/*.php");
+
     foreach ($noAuthRoutes as $noAuthRoute) {
         Route::group([], $noAuthRoute);
     }
 });
 
-Route::middleware(['auth:sanctum', 'ability:access'])->group(function () {
+Route::middleware(['auth:sanctum', 'ability:access', 'provider.accepted'])->group(function () {
     $authRoutes = glob(__DIR__ . "/authRoutes/*.php");
+
     foreach ($authRoutes as $authRoute) {
         Route::group([], $authRoute);
     }

+ 1 - 1
routes/authRoutes/auth.php

@@ -3,4 +3,4 @@
 use App\Http\Controllers\AuthController;
 use Illuminate\Support\Facades\Route;
 
-Route::post('/logout', [AuthController::class, 'logout']);
+Route::post('/logout', [AuthController::class, 'logout'])->withoutMiddleware('provider.accepted');

+ 2 - 2
routes/authRoutes/device_token.php

@@ -3,5 +3,5 @@
 use App\Http\Controllers\DeviceTokenController;
 use Illuminate\Support\Facades\Route;
 
-Route::post('/device-tokens',           [DeviceTokenController::class, 'store']);
-Route::delete('/device-tokens/{token}', [DeviceTokenController::class, 'destroy']);
+Route::post('/device-tokens',           [DeviceTokenController::class, 'store'])->withoutMiddleware('provider.accepted');
+Route::delete('/device-tokens/{token}', [DeviceTokenController::class, 'destroy'])->withoutMiddleware('provider.accepted');

+ 1 - 1
routes/authRoutes/user.php

@@ -3,7 +3,7 @@
 use App\Http\Controllers\UserController;
 use Illuminate\Support\Facades\Route;
 
-Route::get('/user/me',               [UserController::class, 'me']);
+Route::get('/user/me',               [UserController::class, 'me'])->withoutMiddleware('provider.accepted');
 Route::match(['put', 'post'], '/me', [UserController::class, 'updateMe'])->middleware('permission:config.user,edit');
 Route::get('/user',                  [UserController::class, 'index'])->middleware('permission:config.user,view');
 Route::post('/user',                 [UserController::class, 'store'])->middleware('permission:config.user,add');