c366614fcd
Task 0.5+0.6: SalesAuthController (login 200/422/403, me, logout) + маршруты /api/sales/auth и зона данных. Порядок middleware admin-db ДО auth:sales. Тест SalesAuthTest 7/7, весь sales-набор 25/25. Logout инвалидирует токен (в тесте Auth::forgetGuards() — артефакт мульти-запросов; в бою каждый запрос свежий). Larastan baseline: Pest false-pos SalesAuthTest. Заодно pint-канон моделей/трейта/SalesModelsTest. Один эскейп на сессию. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
105 lines
3.3 KiB
PHP
105 lines
3.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Http\Controllers\Api\Sales;
|
||
|
||
use App\Models\SalesUser;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Routing\Controller;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\Hash;
|
||
|
||
/**
|
||
* Аутентификация портала отдела продаж.
|
||
*
|
||
* Все маршруты идут через middleware admin-db (UseAdminConnection),
|
||
* который переключает default-соединение на pgsql_admin (crm_admin_user).
|
||
* Это необходимо, потому что sales_users и personal_access_tokens доступны
|
||
* crm_admin_user, а Sanctum читает токены ДО контроллера — в middleware auth:sales.
|
||
*
|
||
* guard: 'sales' (Sanctum, provider sales_users) — см. config/auth.php.
|
||
*
|
||
* Spec: docs/superpowers/plans/2026-06-30-sales-portal.md (Task 0.5)
|
||
*/
|
||
class SalesAuthController extends Controller
|
||
{
|
||
/**
|
||
* Вход менеджера / руководителя продаж.
|
||
*
|
||
* Валидация: email (required, email) + password (required, string).
|
||
* Ошибки: 422 неверные учётные данные, 403 аккаунт отключён.
|
||
* Успех: 200 {token, user: {id, name, email, role}}.
|
||
*/
|
||
public function login(Request $request): JsonResponse
|
||
{
|
||
$request->validate([
|
||
'email' => ['required', 'email'],
|
||
'password' => ['required', 'string'],
|
||
]);
|
||
|
||
$user = SalesUser::where('email', $request->email)->first();
|
||
|
||
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||
return response()->json(
|
||
['message' => 'Неверный логин или пароль.'],
|
||
422
|
||
);
|
||
}
|
||
|
||
if (! $user->is_active) {
|
||
return response()->json(
|
||
['message' => 'Аккаунт отключён, обратитесь к начальнику.'],
|
||
403
|
||
);
|
||
}
|
||
|
||
$token = $user->createToken('sales')->plainTextToken;
|
||
|
||
return response()->json([
|
||
'token' => $token,
|
||
'user' => [
|
||
'id' => $user->id,
|
||
'name' => $user->name,
|
||
'email' => $user->email,
|
||
'role' => $user->role,
|
||
],
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Текущий авторизованный менеджер.
|
||
*
|
||
* Guard: auth:sales — Sanctum Bearer-токен.
|
||
* Возвращает: {id, name, email, role}.
|
||
*/
|
||
public function me(Request $request): JsonResponse
|
||
{
|
||
/** @var SalesUser $user */
|
||
$user = $request->user('sales');
|
||
|
||
return response()->json([
|
||
'id' => $user->id,
|
||
'name' => $user->name,
|
||
'email' => $user->email,
|
||
'role' => $user->role,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Выход — инвалидирует текущий токен.
|
||
*
|
||
* Guard: auth:sales.
|
||
* Возвращает: 200 {message}.
|
||
*/
|
||
public function logout(Request $request): JsonResponse
|
||
{
|
||
/** @var SalesUser $user */
|
||
$user = $request->user('sales');
|
||
$user->currentAccessToken()->delete();
|
||
|
||
return response()->json(['message' => 'Вы вышли.']);
|
||
}
|
||
}
|