Allowance check

This commit is contained in:
ISMAIL MASSERAN
2026-04-14 02:34:00 +00:00
parent 0c4d200839
commit 3775c4a876
100 changed files with 81493 additions and 3226 deletions
@@ -0,0 +1,57 @@
<?php
namespace App\Http\Middleware;
use Closure;
/**
* Role 3 = Jawatankuasa Kehadiran: only counter/kehadiran-related APIs.
* Other roles pass through unchanged.
*/
class AttendanceCommitteeRoleMiddleware
{
public function handle($request, Closure $next)
{
$user = $request->user();
if (!$user || (int) $user->role !== 3) {
return $next($request);
}
if ($this->attendanceCommitteeMayAccess($request)) {
return $next($request);
}
return response()->json([
'status' => 'failed',
'message' => 'Akses ditolak. Akaun ini hanya untuk halaman kehadiran.',
], 403);
}
/**
* @param \Illuminate\Http\Request $request
* @return bool
*/
private function attendanceCommitteeMayAccess($request)
{
if ($request->isMethod('get') && $request->is('api/v1/admin/information')) {
return true;
}
if ($request->isMethod('get') && $request->is('api/v1/admin/logout')) {
return true;
}
if ($request->isMethod('post') && $request->is('api/v1/admin/impersonate/leave')) {
return true;
}
if ($request->isMethod('get') && $request->is('api/v1/voter')) {
return true;
}
if ($request->isMethod('post') && $request->is('api/v1/voter/*/verify-fizikal-registration')) {
return true;
}
if ($request->is('api/v1/allowance/*')) {
return true;
}
return false;
}
}
+17 -2
View File
@@ -20,7 +20,7 @@ class ElectionMiddleware
if ($this->isElection($request)) {
return response()->json([
'status' => 'failed',
'message' => 'You can not add, update, or delete during the election.'
'message' => 'Anda tidak boleh menambah, mengemas kini, atau menghapus semasa sesi mengundi.'
]);
}
@@ -29,6 +29,21 @@ class ElectionMiddleware
private function isElection($request)
{
return !$request->isMethod('get') && Util::getElectionStatus() == 2 && !$request->is('api/v1/election/*');
return
!$request->isMethod('get')
&& Util::getElectionStatus() == 2
&& !$request->is('api/v1/election/*')
// Allow paperless allowance flows during election (cash counter needs this)
&& !$request->is('api/v1/allowance/*')
// Allow admin to update voter info during election (edit screen uses PUT /api/v1/voter/{id})
&& !($request->is('api/v1/voter/*') && $request->isMethod('put'))
// Allow admin to add voter during election (manual add uses POST /api/v1/voter)
&& !($request->is('api/v1/voter') && $request->isMethod('post'))
// Allow updating applicable voters list during election (add page uses POST /api/v1/voter/sync-applicable)
&& !($request->is('api/v1/voter/sync-applicable') && $request->isMethod('post'))
&& !$request->is('api/v1/voter/*/verify-fizikal-registration')
// Pentadbir utama: urus akaun (tambah/kemaskini/padam) semasa mengundi
&& !$request->is('api/v1/admin')
&& !$request->is('api/v1/admin/*');
}
}
@@ -0,0 +1,34 @@
<?php
namespace App\Http\Middleware;
use App\Voter;
use Closure;
use Illuminate\Support\Facades\Auth;
class FizikalRegistrationVerifiedMiddleware
{
/**
* Block voting until fizikal attendance is confirmed by admin (kehadiran = 1 + verified_at set).
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if (!$user instanceof Voter) {
return response()->json([
'status' => 'failed',
'message' => 'Sesi tidak sah.',
], 401);
}
if (!$user->isFizikalRegistrationVerifiedForVoting()) {
return response()->json([
'status' => 'failed',
'message' => 'Pendaftaran fizikal anda belum disahkan oleh pentadbir. Sila tunggu pengesahan di kaunter.',
], 403);
}
return $next($request);
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Http\Middleware;
use Closure;
class PhysicalGateDisplayKeyMiddleware
{
/**
* Only clients that know the display key may read the current gate code.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (!config('physical_attendance_gate.enabled')) {
return response()->json([
'status' => 'failed',
'message' => 'Ciri kod kaunter fizikal tidak diaktifkan.',
], 404);
}
$expected = (string) config('physical_attendance_gate.display_key');
if ($expected === '') {
return response()->json([
'status' => 'failed',
'message' => 'Kod paparan kaunter belum dikonfigurasi.',
], 503);
}
$provided = (string) $request->header('X-Physical-Gate-Display-Key', '');
if ($provided === '' && $request->bearerToken()) {
$provided = (string) $request->bearerToken();
}
if ($provided === '' || !hash_equals($expected, $provided)) {
return response()->json([
'status' => 'failed',
'message' => 'Akses ditolak.',
], 403);
}
$service = app(\App\Services\PhysicalAttendanceGateCode::class);
if (!$service->isConfigured()) {
return response()->json([
'status' => 'failed',
'message' => 'PHYSICAL_ATTENDANCE_GATE_SECRET belum ditetapkan.',
], 503);
}
return $next($request);
}
}