156 lines
5.7 KiB
PHP
156 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\PairingLookupRequest;
|
|
use App\Http\Requests\PairingOtpRequest;
|
|
use App\Http\Requests\PairingOtpVerifyRequest;
|
|
use App\Models\Registration;
|
|
use App\Services\OtpService;
|
|
use App\Services\PairingTokenService;
|
|
use Illuminate\Http\Request;
|
|
|
|
class PairingController extends Controller
|
|
{
|
|
public function lookup(PairingLookupRequest $request)
|
|
{
|
|
$code = $request->validated()['registration_code'];
|
|
|
|
$registration = Registration::where('registration_code', $code)
|
|
->with('player', 'flightMember.flight.members.registration.player')
|
|
->firstOrFail();
|
|
|
|
$flightMember = $registration->flightMember;
|
|
$flight = $flightMember?->flight;
|
|
|
|
$members = [];
|
|
if ($flight) {
|
|
foreach ($flight->members as $m) {
|
|
$members[] = [
|
|
'seat' => (int) $m->seat_no,
|
|
'name' => $m->registration?->player?->name,
|
|
'band' => $m->registration?->handicap_band,
|
|
'hcp' => $m->registration?->handicap_value,
|
|
'is_you' => $m->registration_id === $registration->id,
|
|
];
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'registration' => [
|
|
'status' => $registration->status,
|
|
'player' => [
|
|
'name' => $registration->player->name,
|
|
'band' => $registration->handicap_band,
|
|
'handicap' => $registration->handicap_value,
|
|
],
|
|
'preferences' => [
|
|
'pairing_mode' => $registration->pairing_mode,
|
|
'pairing_mode_label' => strtolower($registration->pairing_mode) === 'LEVEL' ? 'level' : (strtolower($registration->pairing_mode) === 'RANDOM' ? 'random' : 'balanced'),
|
|
],
|
|
],
|
|
'flight' => $flight ? [
|
|
'code' => $flight->code,
|
|
'course' => $flight->course,
|
|
'start_hole' => (int) $flight->start_hole,
|
|
'start_tee' => $flight->start_tee,
|
|
'is_final' => $flight->status === 'FINAL',
|
|
] : null,
|
|
'members' => $members,
|
|
]);
|
|
}
|
|
|
|
|
|
public function requestOtp(PairingOtpRequest $request, OtpService $otpService)
|
|
{
|
|
$registrationId = $request->validated()['registration_id'];
|
|
$registration = Registration::with('player')->findOrFail($registrationId);
|
|
|
|
$otpService->sendPairingOtp($registration);
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function verifyOtp(PairingOtpVerifyRequest $request, OtpService $otpService, PairingTokenService $tokenService)
|
|
{
|
|
$data = $request->validated();
|
|
$registration = Registration::with('player')->findOrFail($data['registration_id']);
|
|
|
|
$otpService->verifyPairingOtp($registration, $data['otp']);
|
|
|
|
$token = $tokenService->issue($registration->id);
|
|
|
|
return response()->json([
|
|
'pairing_token' => $token,
|
|
]);
|
|
}
|
|
|
|
public function me(Request $request, PairingTokenService $tokenService)
|
|
{
|
|
$auth = $request->header('Authorization', '');
|
|
if (!str_starts_with($auth, 'Bearer ')) {
|
|
return response()->json(['message' => 'Unauthorized'], 401);
|
|
}
|
|
$token = trim(substr($auth, 7));
|
|
|
|
$registrationId = $tokenService->verify($token);
|
|
if (!$registrationId) {
|
|
return response()->json(['message' => 'Unauthorized'], 401);
|
|
}
|
|
|
|
$registration = Registration::with('player', 'flightMember.flight.members.registration.player')
|
|
->findOrFail($registrationId);
|
|
|
|
$flightMember = $registration->flightMember;
|
|
$flight = $flightMember?->flight;
|
|
|
|
// Build members array for diagram (seat 1..4)
|
|
$members = [];
|
|
if ($flight) {
|
|
foreach ($flight->members as $m) {
|
|
$members[] = [
|
|
'seat' => (int) $m->seat_no,
|
|
'name' => $m->registration?->player?->name,
|
|
'band' => $m->registration?->handicap_band,
|
|
'hcp' => $m->registration?->handicap_value,
|
|
'is_you' => $m->registration_id === $registration->id,
|
|
];
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'registration' => [
|
|
'status' => $registration->status,
|
|
'player' => [
|
|
'name' => $registration->player->name,
|
|
'band' => $registration->handicap_band,
|
|
'handicap' => $registration->handicap_value,
|
|
],
|
|
// Optional for UI copy; can be expanded later:
|
|
'preferences' => [
|
|
'pairing_mode' => $registration->pairing_mode,
|
|
'pairing_mode_label' => strtolower($registration->pairing_mode) === 'LEVEL' ? 'level' : (strtolower($registration->pairing_mode) === 'RANDOM' ? 'random' : 'balanced'),
|
|
],
|
|
],
|
|
'flight' => $flight ? [
|
|
'code' => $flight->code,
|
|
'course' => $flight->course,
|
|
'start_hole' => (int) $flight->start_hole,
|
|
'start_tee' => $flight->start_tee,
|
|
'is_final' => $flight->status === 'FINAL',
|
|
] : null,
|
|
'members' => $members,
|
|
]);
|
|
}
|
|
|
|
private function maskPhone(string $phone): string
|
|
{
|
|
// crude masking; adjust as needed for E164 normalization
|
|
$digits = preg_replace('/\D+/', '', $phone);
|
|
if (strlen($digits) <= 4) return '+**' . $digits;
|
|
$last4 = substr($digits, -4);
|
|
return '+'.substr($digits, 0, 2) . '***' . $last4;
|
|
}
|
|
}
|