feat: implement barangay system phases 2-14
Some checks failed
tests / PHP 8.2 (swoole-5.1.6) (push) Has been cancelled
tests / PHP 8.3 (swoole-5.1.6) (push) Has been cancelled
tests / PHP 8.4 (swoole-6.0) (push) Has been cancelled

Complete adaptation from BukidBountyApp to Philippine barangay governance:

- Barangay models: Resident, Household, HouseholdMember, Blotter, BlotterHearing,
  DocumentRequest, RequestPayment, RequestType, BarangayProject, BarangayBudget
- Controllers: ResidentController, HouseholdController, BlotterController,
  BlotterHearingController, DocumentRequestController, RequestTypeController,
  ProjectController, BudgetController, QRPHController, AdminConsoleController,
  UserController, FileController, ChapterController, LoginController
- Vue pages: Home, ManageResidents, ResidentProfile, ManageHouseholds, ManageBlotters,
  BlotterDetail, RequestDocument, ManageDocumentRequests, DocumentRequestDetail,
  ManageRequestTypes, ManageProjects, BudgetLedger, AdminConsole
- Barangay roles: PunongBarangay, Kagawad, Secretary, Treasurer, SK, Tanod, BHW, Staff, Resident
- UserPermissions matrix rewritten with barangay-specific permission mappings
- VueRouteMap replaced with barangay SPA routes
- UserActions enum references corrected across all controllers
- Removed all market/cooperative/POS/subscription code and models
This commit is contained in:
Jonathan Sykes
2026-06-07 03:09:09 +08:00
parent 19fec0933b
commit fbb7e3ff37
234 changed files with 5582 additions and 39457 deletions

View File

@@ -0,0 +1,184 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Auth;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Cache;
use Hypervel\Support\Facades\Response;
use Psr\Http\Message\ResponseInterface;
use Hypervel\Support\Facades\Auth;
use App\Models\User;
use Hypervel\Support\Facades\Hash;
use Hypervel\Support\Facades\Log;
use Hypervel\Support\Facades\Redis;
class LoginController
{
public function authenticate(Request $request): ResponseInterface
{
$credentials = $request->inputs(['mobile_number', 'password']);
$keepalive = $request->input('keepalive');
if (!$credentials['mobile_number'] || !$credentials['password']) {
return Response::json([
'success' => false,
'message' => 'Missing fields.',
], 422);
}
$candidates = self::phMobileVariants($credentials['mobile_number']);
$user = User::whereIn('mobile_number', $candidates)->first();
if (!$user) {
return Response::json([
'success' => false,
'message' => 'Account not found.',
], 401);
}
Log::info('Login attempt', [
'mobile_number' => $credentials['mobile_number'],
'candidates' => $candidates,
'user_found' => true,
'active' => $user->active,
'acct_type' => $user->acct_type->value ?? null,
]);
if (!$user->active) {
return Response::json([
'success' => false,
'message' => 'Account is inactive. Please contact support.',
], 401);
}
if ($user && Hash::check($credentials['password'], $user->password)) {
Auth::login($user); // or Auth::guard()->login($user)
$current_userHashkey = $user->hashkey;
$sessionId = session()->getId();
Redis::sadd("user_sessions:{$current_userHashkey}", $sessionId);
// $request->session()->regenerate();
Log::info('KeepAlive Value ' . $keepalive);
if ($keepalive === true || $keepalive === 'true') {
self::setSessiontoKeepAlive();
}
return Response::json([
'success' => true,
'message' => 'Login successful',
]);
}
return Response::json([
'success' => false,
'message' => 'Invalid credentials.',
], 401);
}
/**
* Set or extends current session auth<br>
* This Function is Not Working JWT Automatically sets based on config file ttl
* @param string|bool $sessionid if false then get current sessionID
* @param int|bool $aliveinseconds if true then consider it forever
* @return null|bool // Time To Live TTL
*/
public static function setSessiontoKeepAlive(string|false $sessionId = false, int|bool $aliveinseconds = true)
{
$sessionId = $sessionId ?: session()->getId();
if (!$sessionId) {
return false;
}
if ($aliveinseconds === true) {
$aliveinseconds = 7889472; // 3 months
}
if ($aliveinseconds === false) {
return false;
}
// The redis session driver stores the key under the Redis connection prefix.
// Cache::get/put uses a different prefix (cache store), so we use Redis::expire()
// directly to extend the TTL of the existing session key without reading its value.
$result = Redis::expire($sessionId, $aliveinseconds);
if (!$result) {
Log::warning('setSessiontoKeepAlive: session key not found in Redis, cannot extend TTL for: ' . $sessionId);
return false;
}
$ttl = Redis::ttl($sessionId);
Log::info('extended session: ' . $sessionId . ' for ' . $aliveinseconds . 's, TTL: ' . $ttl);
return $ttl;
}
/**
* Build all plausible stored forms of a Philippine mobile number so the
* caller can match whichever variant is in the DB. Variants returned:
* - 09XXXXXXXXX
* - 9XXXXXXXXX (no leading 0)
* - 639XXXXXXXXX
* - +639XXXXXXXXX
* plus the original raw input as a final fallback.
*/
public static function phMobileVariants(string $input): array
{
$digits = preg_replace('/\D+/', '', $input);
$core = null; // the 10-digit 9XXXXXXXXX portion
if (preg_match('/^639(\d{9})$/', $digits, $m)) {
$core = '9' . $m[1];
} elseif (preg_match('/^09(\d{9})$/', $digits, $m)) {
$core = '9' . $m[1];
} elseif (preg_match('/^9(\d{9})$/', $digits, $m)) {
$core = '9' . $m[1];
}
$variants = [$input];
if ($core) {
$variants[] = '0' . $core;
$variants[] = $core;
$variants[] = '63' . $core;
$variants[] = '+63' . $core;
}
return array_values(array_unique($variants));
}
/**
* Back-compat shim: still used by UserModifyAdminPageController to
* canonicalize on save (admin edit). Picks 09XXXXXXXXX when possible.
*/
public static function normalizePhMobile(string $input): string
{
$digits = preg_replace('/\D+/', '', $input);
if (preg_match('/^639(\d{9})$/', $digits, $m)) {
return '09' . $m[1];
}
if (preg_match('/^9(\d{9})$/', $digits, $m)) {
return '09' . $m[1];
}
if (preg_match('/^09\d{9}$/', $digits)) {
return $digits;
}
return $input;
}
public function extendcurrentSession()
{
$ttl = self::setSessiontoKeepAlive();
return Response::make('TTL is '.$ttl);
}
}