validate($request, [ 'company_name' => 'required|min:3', 'user_name' => 'required|min:3', 'email' => 'required|email', 'password' => 'required|strong_password' ]); if (!empty($errors)) { $response->json(['errors' => $errors], 400); return; } $data = $request->getBody(); // Check if user already exists securely via Blind Index $existingUser = User::findByEmail($data['email']); if ($existingUser) { $response->json(['errors' => ['email' => ['This email is already registered.']]], 409); return; } try { // Create Company $companyId = Company::create([ 'name' => $data['company_name'] ]); // Create Admin User for this Company $userId = User::createSecure([ 'company_id' => $companyId, 'name' => $data['user_name'], 'email' => strtolower(trim($data['email'])), 'password' => $data['password'], 'role' => 'admin' ]); // Automatically Assign 14-Day Free Trial (Plan ID: 4) $startsAt = date('Y-m-d H:i:s'); $endsAt = date('Y-m-d H:i:s', strtotime('+14 days')); \App\Models\CompanySubscription::subscribeCompany( $companyId, 4, // Trial Plan ID 14, // Duration in days 'auto_trial', 'system' ); $response->json([ 'message' => 'Company and Admin user registered successfully. 14-Day Free Trial activated.', 'company_id' => $companyId, 'user_id' => $userId ], 201); } catch (\Exception $e) { error_log("Registration Error: " . $e->getMessage()); $response->json(['error' => 'An error occurred during registration.'], 500); } } /** * Login existing user and return JWT */ public function login(Request $request, Response $response): void { $errors = $this->validate($request, [ 'email' => 'required|email', 'password' => 'required' ]); if (!empty($errors)) { $response->json(['errors' => $errors], 400); return; } $data = $request->getBody(); // Find user by email blind index $user = User::findByEmail($data['email']); if (!$user) { $response->json(['error' => 'Invalid email or password'], 401); return; } // Verify password hash if (!Security::verifyPassword($data['password'], $user['password'])) { $response->json(['error' => 'Invalid email or password'], 401); return; } if ($user['status'] !== 'active') { $response->json(['error' => 'Your account is inactive or suspended.'], 403); return; } // Generate standard JWT token with full required payload $payload = [ 'user_id' => $user['id'], 'company_id' => $user['company_id'], 'role' => $user['role'] ]; $token = Security::generateJWT($payload); $response->json([ 'message' => 'Login successful', 'token' => $token, 'user' => [ 'id' => $user['id'], 'company_id' => $user['company_id'], 'name' => $user['name'], 'role' => $user['role'], 'is_super_admin' => (int)$user['company_id'] === 1 ] ], 200); } /** * Get current logged in user details * (Protected by AuthMiddleware) */ public function me(Request $request, Response $response): void { $user = User::find($request->user_id); if (!$user || (int)$user['company_id'] !== (int)$request->company_id) { $response->json(['error' => 'User not found'], 404); return; } $isSuperAdmin = (int)$user['company_id'] === 1; // Fetch subscription info for the UI $subscription = \App\Models\CompanySubscription::findActiveByCompany($user['company_id']); $subStatus = $subscription ? $subscription['status'] : 'expired'; $trialDaysLeft = 0; if ($subscription && $subscription['status'] === 'active' && strpos((string)$subscription['payment_gateway'], 'auto_trial') !== false) { $subStatus = 'trialing'; // Treat as trialing } if ($subStatus === 'trialing' || ($subscription && $subscription['plan_id'] == 4)) { $endsAt = strtotime($subscription['ends_at']); $now = time(); $trialDaysLeft = max(0, ceil(($endsAt - $now) / 86400)); } $response->json([ 'user' => [ 'id' => $user['id'], 'company_id' => $user['company_id'], 'name' => $user['name'], 'email' => Security::decrypt($user['email']), 'role' => $user['role'], 'status' => $user['status'], 'created_at' => $user['created_at'], 'is_super_admin' => $isSuperAdmin, 'subscription_status' => $subStatus, 'trial_days_left' => $trialDaysLeft ] ]); } }