- EnsureIsAdmin middleware: gates all admin routes on is_admin flag
- Apply admin middleware to entire admin route group
- Fix questionnaire resource route parameter name mismatch ({set})
- Audit log on questionnaire confirmation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
92 lines
3.0 KiB
PHP
92 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Program;
|
|
use App\Models\ProgramQuestionnaire;
|
|
use App\Models\QuestionnaireSet;
|
|
use App\Services\AuditLogService;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
|
|
class ProgramQuestionnaireController extends Controller
|
|
{
|
|
public function show(Program $program): View
|
|
{
|
|
$pq = $program->questionnaire()->with('questionnaireSet.questions')->first();
|
|
|
|
$availableSets = QuestionnaireSet::where('status', 'published')
|
|
->withCount('questions')
|
|
->orderBy('title')
|
|
->get();
|
|
|
|
return view('admin.programs.questionnaire.show', compact('program', 'pq', 'availableSets'));
|
|
}
|
|
|
|
public function attach(Request $request, Program $program): RedirectResponse
|
|
{
|
|
$data = $request->validate([
|
|
'questionnaire_set_id' => 'required|exists:questionnaire_sets,id',
|
|
]);
|
|
|
|
if ($program->questionnaire()->exists()) {
|
|
return back()->with('error', 'Program ini sudah ada soalselidik dilampirkan. Tanggalkan dahulu sebelum lampir yang baru.');
|
|
}
|
|
|
|
$set = QuestionnaireSet::findOrFail($data['questionnaire_set_id']);
|
|
|
|
if ($set->status !== 'published') {
|
|
return back()->with('error', 'Hanya soalselidik yang diterbitkan boleh dilampirkan.');
|
|
}
|
|
|
|
ProgramQuestionnaire::create([
|
|
'program_id' => $program->id,
|
|
'questionnaire_set_id' => $set->id,
|
|
'is_confirmed' => false,
|
|
]);
|
|
|
|
return back()->with('success', 'Soalselidik berjaya dilampirkan. Sila sahkan sebelum program bermula.');
|
|
}
|
|
|
|
public function confirm(Request $request, Program $program): RedirectResponse
|
|
{
|
|
$pq = $program->questionnaire;
|
|
|
|
if (! $pq) {
|
|
return back()->with('error', 'Tiada soalselidik untuk disahkan.');
|
|
}
|
|
|
|
$pq->update([
|
|
'is_confirmed' => true,
|
|
'confirmed_at' => now(),
|
|
'confirmed_by' => auth()->id(),
|
|
]);
|
|
|
|
AuditLogService::log('questionnaire.confirmed', $pq, [], ['program_id' => $program->id, 'questionnaire_set_id' => $pq->questionnaire_set_id]);
|
|
|
|
return back()->with('success', 'Soalselidik telah disahkan untuk program ini.');
|
|
}
|
|
|
|
public function detach(Program $program): RedirectResponse
|
|
{
|
|
$pq = $program->questionnaire;
|
|
|
|
if (! $pq) {
|
|
return back()->with('error', 'Tiada soalselidik untuk ditanggalkan.');
|
|
}
|
|
|
|
if ($pq->is_confirmed) {
|
|
$hasResponses = \App\Models\QuestionnaireResponse::where('program_id', $program->id)->exists();
|
|
if ($hasResponses) {
|
|
return back()->with('error', 'Soalselidik tidak boleh ditanggalkan kerana sudah ada respons diterima.');
|
|
}
|
|
}
|
|
|
|
$pq->delete();
|
|
|
|
return back()->with('success', 'Soalselidik berjaya ditanggalkan.');
|
|
}
|
|
}
|