Files
eCert-MBIP/app/Http/Controllers/Public/CertificateController.php
Saufi 2ddc7e3caf feat: certificate template management and generation (Fasa 7)
- CertificateService: Intervention Image v3 text overlay on template
- GenerateCertificateJob: queued generation with retry logic
- SendCertificateEmailJob: stub (implemented in Fasa 8)
- CertificateTemplateController: upload, config editor, preview, test generate
- Admin/CertificateController: list, generate-all, email-all
- Public/CertificateController: show with questionnaire gate, download
- DejaVuSans fonts bundled under resources/fonts
- Views: admin template/certificate management, public certificate download

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 22:18:23 +08:00

89 lines
3.1 KiB
PHP

<?php
namespace App\Http\Controllers\Public;
use App\Http\Controllers\Controller;
use App\Models\Certificate;
use App\Models\QuestionnaireResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
class CertificateController extends Controller
{
public function show(string $cert_token): View|RedirectResponse
{
$certificate = Certificate::where('token', $cert_token)
->with(['participant', 'program', 'template'])
->firstOrFail();
$program = $certificate->program;
$participant = $certificate->participant;
// Check questionnaire gate
$pq = $program->questionnaire()->first();
$needsQuestionnaire = $pq && $pq->is_confirmed;
$hasAnswered = false;
if ($needsQuestionnaire) {
$hasAnswered = QuestionnaireResponse::where('program_id', $program->id)
->where('participant_id', $participant->id)
->exists();
}
// Find active QR code for questionnaire redirect
$qrCode = $program->qrCode;
return view('public.certificate.show', compact(
'certificate', 'program', 'participant', 'pq',
'needsQuestionnaire', 'hasAnswered', 'qrCode'
));
}
public function download(string $cert_token): Response|RedirectResponse
{
$certificate = Certificate::where('token', $cert_token)
->with(['participant', 'program'])
->firstOrFail();
if (! $certificate->isGenerated()) {
return back()->with('error', 'Sijil belum sedia untuk dimuat turun.');
}
if (! $certificate->file_path || ! Storage::disk('local')->exists($certificate->file_path)) {
return back()->with('error', 'Fail sijil tidak dijumpai. Sila hubungi penganjur.');
}
// Check questionnaire gate
$program = $certificate->program;
$pq = $program->questionnaire()->first();
if ($pq && $pq->is_confirmed) {
$hasAnswered = QuestionnaireResponse::where('program_id', $program->id)
->where('participant_id', $certificate->participant_id)
->exists();
if (! $hasAnswered) {
$qrCode = $program->qrCode;
$redirectTo = $qrCode
? route('public.questionnaire.show', [$qrCode->token, $certificate->participant->uuid])
: back();
return redirect($redirectTo)->with('info', 'Sila jawab borang penilaian terlebih dahulu.');
}
}
$certificate->recordDownload();
$content = Storage::disk('local')->get($certificate->file_path);
$filename = 'Sijil-' . str($certificate->participant->name)->slug() . '.jpg';
return response($content, 200, [
'Content-Type' => 'image/jpeg',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
'Content-Length' => strlen($content),
]);
}
}