180 lines
5.8 KiB
PHP
180 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
|
|
use App\Core\Request;
|
|
use App\Core\Response;
|
|
use App\Core\Security;
|
|
use App\Models\User;
|
|
use App\Models\Company;
|
|
|
|
class AuthController extends BaseController
|
|
{
|
|
/**
|
|
* Register a new company and admin user
|
|
*/
|
|
public function register(Request $request, Response $response): void
|
|
{
|
|
$errors = $this->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
|
|
]
|
|
]);
|
|
}
|
|
}
|