48 lines
1.8 KiB
PHP
48 lines
1.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Certificate;
|
|
use App\Models\Scopes\OwnedByUserScope;
|
|
use App\Rules\Turnstile;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Session;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\View\View;
|
|
|
|
/**
|
|
* Public, unauthenticated page where anyone can check whether a certificate
|
|
* number and holder last name match a genuine, currently valid certificate.
|
|
* Deliberately returns nothing beyond "valid"/"invalid" — no certificate
|
|
* details are ever exposed here.
|
|
*/
|
|
class VerifyController extends Controller
|
|
{
|
|
public function show(): View
|
|
{
|
|
return view('verify.show', ['result' => Session::get('verify.result')]);
|
|
}
|
|
|
|
public function check(Request $request): RedirectResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'certificate_number' => ['required', 'string', 'max:255'],
|
|
'holder_last_name' => ['required', 'string', 'max:255'],
|
|
'cf-turnstile-response' => [new Turnstile],
|
|
]);
|
|
|
|
$isValid = Certificate::query()
|
|
// Verification checks across every account's certificates, not
|
|
// just the caller's — bypass the owner scope explicitly since a
|
|
// staff member checking a certificate may be logged in too.
|
|
->withoutGlobalScope(OwnedByUserScope::class)
|
|
->whereRaw('LOWER(certificate_number) = ?', [Str::lower(trim($validated['certificate_number']))])
|
|
->whereRaw('LOWER(holder_last_name) = ?', [Str::lower(trim($validated['holder_last_name']))])
|
|
->where('expires_at', '>=', today())
|
|
->exists();
|
|
|
|
return redirect()->route('verify.show')
|
|
->with('verify.result', $isValid ? 'valid' : 'invalid');
|
|
}
|
|
}
|