Files
alrahma_sunday_school_api/app/Http/Controllers/Api/Auth/AuthController.php
T
2026-04-25 00:00:23 -04:00

140 lines
4.4 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Auth;
use App\Http\Controllers\Api\Core\BaseApiController;
use App\Models\User;
use App\Services\Auth\ApiLoginSecurityService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use PHPOpenSourceSaver\JWTAuth\Facades\JWTAuth;
class AuthController extends BaseApiController
{
public function login(Request $request, ApiLoginSecurityService $security): JsonResponse
{
$payload = $request->all();
if ($request->isJson() && ($payload === [] || $payload === null)) {
$decoded = json_decode((string) $request->getContent(), true);
$payload = is_array($decoded) ? $decoded : [];
}
// Match CodeIgniter apiLogin: raw email/password (no trim); empty check is identical to CI `!$email || !$password`.
$email = (string) ($payload['email'] ?? '');
$password = (string) ($payload['password'] ?? '');
if ($email === '' || $password === '') {
return response()->json([
'status' => false,
'message' => 'Email and password are required.',
], 400);
}
$ip = $request->ip();
if ($security->isIpBlocked((string) $ip)) {
return response()->json([
'status' => false,
'message' => 'Too many failed attempts from your IP. Please try again later.',
], 429);
}
$user = User::query()->where('email', $email)->first();
if (!$user) {
$security->logIpAttempt((string) $ip);
return response()->json([
'status' => false,
'message' => 'Invalid email or password.',
], 401);
}
if ($user->is_suspended) {
return response()->json([
'status' => false,
'message' => 'Account suspended. Please reset your password.',
], 403);
}
if (! ci_password_verify($password, (string) $user->password)) {
$security->handleFailedLogin($user, $email, (string) $ip);
return response()->json([
'status' => false,
'message' => 'Invalid email or password.',
], 401);
}
$security->resetFailedAttempts($user);
$security->logSuccessfulLogin($user->fresh(), $request);
$fresh = $user->fresh();
if (!$fresh) {
return response()->json([
'status' => false,
'message' => 'Invalid email or password.',
], 401);
}
$jwtToken = JWTAuth::fromUser($fresh);
return response()->json($security->buildLoginResponse($fresh, $jwtToken));
}
public function refresh(Request $request): JsonResponse
{
try {
$newToken = JWTAuth::parseToken()->refresh();
} catch (\Throwable $e) {
return $this->respondError('Token refresh failed.', 401);
}
return $this->respondSuccess([
'access_token' => $newToken,
'token_type' => 'bearer',
'expires_in' => (int) config('jwt.ttl') * 60,
], 'Token refreshed.');
}
public function me(): JsonResponse
{
$user = Auth::user();
if (!$user) {
return $this->respondError('Unauthorized.', 401);
}
$teacherContext = $user->teacherSessionContext();
return $this->respondSuccess([
'id' => (int) $user->id,
'firstname' => $user->firstname,
'lastname' => $user->lastname,
'email' => $user->email,
'class_section_id' => $teacherContext['class_section_id'],
'class_section_name' => $teacherContext['class_section_name'],
], 'OK');
}
public function logout(Request $request): JsonResponse
{
$token = $request->bearerToken();
if ($token && substr_count($token, '.') === 2) {
try {
JWTAuth::setToken($token)->invalidate();
} catch (\Throwable $e) {
// ignore invalidation errors
}
}
$user = $request->user();
if ($user && method_exists($user, 'currentAccessToken')) {
$current = $user->currentAccessToken();
if ($current) {
$current->delete();
}
}
return $this->respondSuccess(null, 'Logged out.');
}
}