Files

126 lines
3.8 KiB
PHP

<?php
namespace App\Http\Controllers\API\v1\Voter;
use Illuminate\Http\Request;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Util;
use App\Services\PhysicalAttendanceGateCode;
use App\Voter;
class AttendanceController extends Controller
{
//
public function __invoke(Request $request, $id)
{
$this->validateRequest($request, $id);
$this->assertPhysicalGateCode($request);
$this->updateAttendance($request, $id);
return response()->json([
'status' => 'success',
'message' => 'Kehadiran anda telah disahkan.'
]);
}
private function validateRequest($request, $id)
{
$rules = [
'name' => [
'required',
Rule::unique('voter')->ignore($id)->where(function($query){
$query->where('election_id', Util::getCurrentElection());
})
],
'no_kp' => [
'required',
Rule::unique('voter')->ignore($id)->where(function($query){
$query->where('election_id', Util::getCurrentElection());
})
],
'unit' => 'required',
'no_anggota' => [
'required',
Rule::unique('voter')->ignore($id)->where(function($query){
$query->where('election_id', Util::getCurrentElection());
})
],
'kehadiran' => 'required',
];
if (config('physical_attendance_gate.enabled')) {
$rules['physical_gate_code'] = 'required_if:kehadiran,1|string|max:64';
}
$this->validate($request, $rules);
}
/**
* When gate is enabled, Fizikal (kehadiran = 1) must match the rotating counter code.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
private function assertPhysicalGateCode(Request $request)
{
if (!config('physical_attendance_gate.enabled')) {
return;
}
if ((int) $request->input('kehadiran') !== 1) {
return;
}
$gate = app(PhysicalAttendanceGateCode::class);
if (!$gate->isConfigured()) {
throw new HttpResponseException(response()->json([
'status' => 'failed',
'message' => 'Pengesahan kod fizikal tidak dikonfigurasi dengan betul.',
], 503));
}
if (!$gate->validates(Util::getCurrentElection(), (string) $request->input('physical_gate_code'))) {
throw new HttpResponseException(response()->json([
'status' => 'failed',
'message' => 'Kod kaunter tidak sah atau telah tamat tempoh. Sila semak skrin pendaftaran dan cuba lagi.',
], 422));
}
}
private function updateAttendance($request, $id)
{
$voter = Voter::findOrFail($id);
$voter->fill($request->only(['name', 'no_kp', 'no_anggota', 'unit', 'kehadiran']));
// Skip admin verification phase for Fizikal.
// When Fizikal is selected and (optionally) the counter gate code is valid, we auto-verify.
// For non-Fizikal attendance, keep this field cleared.
if ((int) $voter->kehadiran === 1) {
$voter->fizikal_registration_verified_at = now();
} else {
$voter->fizikal_registration_verified_at = null;
}
$voter->save();
$mode = ((int) $voter->kehadiran === 1) ? 'physical' : 'online';
activity()
->performedOn($voter)
->withProperties([
'voter_id' => $voter->id,
'voter_name' => $voter->name,
'election_id' => Util::getCurrentElection(),
'attendance_mode' => $mode,
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
])
->log("confirm attendance ({$mode}): {$voter->name}");
}
}