pdo = $connection->getPdo(); $aiConfig = require __DIR__ . '/../../../config/ai.php'; $this->jwtConfig = $aiConfig['jwt']; } /** * Register a new user. */ public function register(string $name, string $email, string $password): array { // Check for duplicates $stmt = $this->pdo->prepare("SELECT id FROM users WHERE email = ?"); $stmt->execute([$email]); if ($stmt->fetch()) { throw new Exception("Email already registered."); } $passwordHash = password_hash($password, PASSWORD_BCRYPT); $this->pdo->beginTransaction(); try { $stmt = $this->pdo->prepare("INSERT INTO users (name, email, password_hash, status) VALUES (?, ?, ?, 'active')"); $stmt->execute([$name, $email, $passwordHash]); $userId = (int)$this->pdo->lastInsertId(); // Count users to assign role: first user gets Admin, others get Member $stmt = $this->pdo->query("SELECT COUNT(*) FROM users"); $count = (int)$stmt->fetchColumn(); $roleCode = $count === 1 ? 'admin' : 'member'; $stmt = $this->pdo->prepare("SELECT id FROM roles WHERE code = ?"); $stmt->execute([$roleCode]); $roleId = $stmt->fetchColumn(); if ($roleId) { $stmt = $this->pdo->prepare("INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)"); $stmt->execute([$userId, $roleId]); } $this->pdo->commit(); return [ 'id' => $userId, 'name' => $name, 'email' => $email, 'status' => 'active' ]; } catch (Throwable $e) { $this->pdo->rollBack(); throw new Exception("Registration failed: " . $e->getMessage()); } } /** * Authenticate a user by email and password. */ public function login(string $email, string $password): array { $stmt = $this->pdo->prepare("SELECT id, name, email, password_hash, status FROM users WHERE email = ? AND deleted_at IS NULL"); $stmt->execute([$email]); $user = $stmt->fetch(); if (!$user || !password_verify($password, $user['password_hash'])) { throw new Exception("Invalid email or password."); } if ($user['status'] !== 'active') { throw new Exception("User account is inactive."); } unset($user['password_hash']); return $user; } /** * Get active user by ID. */ public function getUserById(int $id): ?array { $stmt = $this->pdo->prepare("SELECT id, name, email, status FROM users WHERE id = ? AND deleted_at IS NULL"); $stmt->execute([$id]); $user = $stmt->fetch(); return $user ?: null; } /** * Generate JWT for APIs. */ public function generateJwt(array $user): string { $issuedAt = time(); $expire = $issuedAt + $this->jwtConfig['expires_in']; $payload = [ 'iss' => $_ENV['APP_URL'] ?? 'https://scoutiq.intaleqapp.com', 'aud' => $_ENV['APP_URL'] ?? 'https://scoutiq.intaleqapp.com', 'iat' => $issuedAt, 'exp' => $expire, 'sub' => $user['id'], 'user' => [ 'id' => $user['id'], 'name' => $user['name'], 'email' => $user['email'] ] ]; return JWT::encode($payload, $this->jwtConfig['secret'], $this->jwtConfig['algorithm']); } /** * Decode and verify JWT. */ public function verifyJwt(string $token): ?array { try { $decoded = JWT::decode($token, new Key($this->jwtConfig['secret'], $this->jwtConfig['algorithm'])); $payload = (array)$decoded; if (isset($payload['user'])) { return (array)$payload['user']; } return $this->getUserById((int)$payload['sub']); } catch (Throwable $e) { return null; } } }