diff --git a/app/Config/Filters.php b/app/Config/Filters.php index c9431b94..6c031ae7 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -20,6 +20,8 @@ use App\Filters\SecurityInputFilter; use App\Filters\GlobalPostFileUploadGuard; use App\Filters\AclFilter; use App\Filters\RateLimitFilter; +use App\Filters\JwtApiRateLimitFilter; +use App\Filters\AuthApiRateLimitFilter; use App\Filters\AuthJWT; @@ -51,6 +53,8 @@ class Filters extends BaseConfig 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, 'AclFilter' => AclFilter::class, 'ratelimit' => RateLimitFilter::class, + 'AuthApiRateLimitFilter' => AuthApiRateLimitFilter::class, + 'JwtApiRateLimitFilter' => JwtApiRateLimitFilter::class, ]; diff --git a/app/Config/Routes.php b/app/Config/Routes.php index f659dfb9..8ed2579c 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -10,6 +10,15 @@ $routes->options('(:any)', function() { // But having this route ensures OPTIONS isn't rejected as 404 }); +$routes->group('sheet', function ($routes) { + $routes->get('(:any)', 'GoogleSheetController::editor/$1'); + $routes->get('(:any)/fetch', 'GoogleSheetController::fetch/$1'); + $routes->post('(:any)/save', 'GoogleSheetController::save/$1'); + $routes->get('(:any)/download', 'GoogleSheetController::download/$1'); +}); + + + /** * @var RouteCollection $routes */ diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index e4a04375..1ecc8dde 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -3669,7 +3669,7 @@ class EmployeeController extends AdminController "policyStartDate" => $policyStartDate, "policyEndDate" => $policyEndDate, "plan" => $primary["wellness_plan_id"] ?? null, - "source" => $primary['short_name'] ?? null, + "source" => 'NHANCE', "employer" => $primary['short_name'] ?? null, "employeeCode" => $empCode, "accountNumber" => "", // Fill from DB if available @@ -3690,8 +3690,8 @@ class EmployeeController extends AdminController "name" => $row["name"], "phone" => $row["mobile"], "email" => $row["email_corporate"], - "relationshipName" => strtoupper($row["relationship"] ?? ''), - "gender" => $row["gender"], + "relationshipName" => $this->mapRelationship($row["relationship"],$row["gender"]), + "gender" => $row["gender"] == 'M' ? 'Male' : 'Female', "dob" => $row["dob"] ]; } @@ -3700,6 +3700,42 @@ class EmployeeController extends AdminController } + function mapRelationship(string $relationship, ?string $gender = null): string + { + // Normalize input + $key = strtolower(trim($relationship)); + $key = str_replace(['-', '_'], ' ', $key); + $key = preg_replace('/\s+/', ' ', $key); + + // Base mapping + $map = [ + 'self' => 'self', + 'son' => 'son', + 'daughter' => 'daughter', + 'father' => 'father', + 'mother' => 'mother', + 'father in law' => 'father in law', + 'father-in-law' => 'father in law', + 'mother in law' => 'mother in law', + 'mother-in-law' => 'mother in law', + ]; + + // Special handling for spouse + if ($key === 'spouse') { + if ($gender === 'M') { + return 'husband'; + } + if ($gender === 'F') { + return 'wife'; + } + + // fallback if gender missing (better to throw error) + throw new Exception("Gender required to map 'Spouse'"); + } + + return $map[$key] ?? ''; + } + /** * Send each family payload to API and attach the response diff --git a/app/Helpers/HttpRequestHelper.php b/app/Helpers/HttpRequestHelper.php index 3e072e8a..53268b39 100755 --- a/app/Helpers/HttpRequestHelper.php +++ b/app/Helpers/HttpRequestHelper.php @@ -15,6 +15,7 @@ class HttpRequestHelper $data = [ 'ip' => $request->getIPAddress(), + 'real_ip' => getRealClientIP(), 'platform' => $platform, 'browser' => $browser, 'method' => strtoupper($request->getMethod()), diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index 178ec18a..63351544 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -1069,23 +1069,40 @@ function getRealClientIP() return $request->getIPAddress(); } -function generateFingerprint() +function generateFingerprint(): string { $request = service('request'); $ua = $request->getUserAgent()->getAgentString(); $ip = getRealClientIP(); - // Use only subnet (first 3 blocks) to tolerate IP change - $ipParts = explode('.', $ip); - $ipSubnet = $ipParts[0] . '.' . $ipParts[1] . '.' . $ipParts[2]; + // Normalize localhost + if ($ip === '127.0.0.1' || $ip === '::1') { + $ipGroup = 'localhost'; + } + // IPv4 handling + elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + $parts = explode('.', $ip); + // Use /24 subnet (first 3 octets) + $ipGroup = $parts[0] . '.' . $parts[1] . '.' . $parts[2]; + } + // IPv6 handling + elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + // Use first 4 blocks of IPv6 (rough /64 grouping) + $blocks = explode(':', $ip); + $ipGroup = implode(':', array_slice($blocks, 0, 4)); + } + // Fallback + else { + $ipGroup = 'unknown'; + } - // $secret = env('app.sessionFingerprintSalt'); - - // return hash('sha256', $ua . '|' . $ipSubnet . '|' . $secret); - return hash('sha256', $ua . '|' . $ipSubnet ); + return hash('sha256', $ua . '|' . $ipGroup); } + + + if (!function_exists('convertGoogleDriveToDownloadLink')) { function convertGoogleDriveToDownloadLink(?string $url): ?string {