fix draft exam upload
This commit is contained in:
@@ -745,6 +745,9 @@ $routes->post('/administrator/teacher-submissions/notify', 'View\AdministratorCo
|
||||
$routes->get('/administrator/exam-drafts', 'View\ExamDraftController::adminIndex', ['filter' => 'auth:admin']);
|
||||
$routes->post('/administrator/exam-drafts/review', 'View\ExamDraftController::adminReview', ['filter' => 'auth:admin']);
|
||||
$routes->post('/administrator/exam-drafts/upload-legacy', 'View\ExamDraftController::adminUploadLegacy', ['filter' => 'auth:admin']);
|
||||
$routes->get('/principal/exam-drafts', 'View\ExamDraftController::principalIndex', ['filter' => 'auth:admin']);
|
||||
$routes->post('/principal/exam-drafts/review', 'View\ExamDraftController::principalReview', ['filter' => 'auth:admin']);
|
||||
$routes->post('/principal/exam-drafts/upload-legacy', 'View\ExamDraftController::principalUploadLegacy', ['filter' => 'auth:admin']);
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
|
||||
@@ -348,6 +348,16 @@ class ExamDraftController extends BaseController
|
||||
}
|
||||
|
||||
public function adminIndex()
|
||||
{
|
||||
return $this->reviewIndex();
|
||||
}
|
||||
|
||||
public function principalIndex()
|
||||
{
|
||||
return $this->reviewIndex();
|
||||
}
|
||||
|
||||
public function reviewIndex()
|
||||
{
|
||||
if ($this->reviewerIdColumn !== '') {
|
||||
$allDrafts = $this->examDraftModel
|
||||
@@ -487,10 +497,23 @@ class ExamDraftController extends BaseController
|
||||
'visibleClasses' => $visibleClasses,
|
||||
'classDraftGroups' => $classDraftGroups,
|
||||
'newSubmissionClasses' => $newSubmissionClasses,
|
||||
'reviewActionUrl' => base_url($this->reviewRoutePrefix() . '/exam-drafts/review'),
|
||||
'legacyUploadUrl' => base_url($this->reviewRoutePrefix() . '/exam-drafts/upload-legacy'),
|
||||
'reviewPortalLabel' => $this->reviewPortalLabel(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function adminUploadLegacy()
|
||||
{
|
||||
return $this->reviewUploadLegacy();
|
||||
}
|
||||
|
||||
public function principalUploadLegacy()
|
||||
{
|
||||
return $this->reviewUploadLegacy();
|
||||
}
|
||||
|
||||
public function reviewUploadLegacy()
|
||||
{
|
||||
$adminId = (int) (session()->get('user_id') ?? 0);
|
||||
if ($adminId <= 0) {
|
||||
@@ -571,13 +594,23 @@ class ExamDraftController extends BaseController
|
||||
}
|
||||
|
||||
if ($saved > 0) {
|
||||
return redirect()->to('/administrator/exam-drafts')->with('success', 'Old exam uploaded successfully.');
|
||||
return redirect()->to($this->reviewDashboardPath())->with('success', 'Old exam uploaded successfully.');
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('error', 'Unable to save the old exam.');
|
||||
}
|
||||
|
||||
public function adminReview()
|
||||
{
|
||||
return $this->reviewSubmission();
|
||||
}
|
||||
|
||||
public function principalReview()
|
||||
{
|
||||
return $this->reviewSubmission();
|
||||
}
|
||||
|
||||
public function reviewSubmission()
|
||||
{
|
||||
$draftId = (int) ($this->request->getPost('draft_id') ?? 0);
|
||||
if ($draftId <= 0) {
|
||||
@@ -690,11 +723,6 @@ class ExamDraftController extends BaseController
|
||||
if ($this->hasAcceptanceTypeColumn) {
|
||||
$newRow['acceptance_type'] = $status === 'accepted' ? $acceptanceType : null;
|
||||
}
|
||||
$teacherFile = $this->draftTeacherFile($draft);
|
||||
if (!empty($teacherFile)) {
|
||||
$newRow[$this->authorFileColumn] = $teacherFile;
|
||||
$newRow[$this->authorFilenameColumn] = $this->draftTeacherFilename($draft) ?? $teacherFile;
|
||||
}
|
||||
if ($this->hasIsLegacyColumn && !empty($draft['is_legacy'])) {
|
||||
$newRow['is_legacy'] = 1;
|
||||
}
|
||||
@@ -711,16 +739,6 @@ class ExamDraftController extends BaseController
|
||||
return redirect()->back()->with('success', 'Review saved successfully.');
|
||||
}
|
||||
return redirect()->back()->with('error', 'Unable to save the review.');
|
||||
} elseif (strtolower($status) === 'accepted' && !empty($this->draftTeacherFile($draft))) {
|
||||
$copied = $this->copyDraftToFinal($this->draftTeacherFile($draft));
|
||||
if ($copied !== null) {
|
||||
$update['final_file'] = $copied;
|
||||
$update['final_filename'] = $this->draftTeacherFilename($draft) ?? $this->draftTeacherFile($draft);
|
||||
$pdfName = $this->ensurePdfExists($copied, pathinfo($copied, PATHINFO_EXTENSION));
|
||||
if ($pdfName !== null && $this->hasFinalPdfColumn) {
|
||||
$update['final_pdf_file'] = $pdfName;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($status === 'legacy') {
|
||||
$this->prepareLegacyPdfVersion($update, $draft);
|
||||
@@ -1010,7 +1028,7 @@ class ExamDraftController extends BaseController
|
||||
. '<tr><td style="padding:4px 8px;"><strong>Status</strong></td><td style="padding:4px 8px;">' . esc((string) ($draft['status'] ?? 'submitted')) . '</td></tr>'
|
||||
. '<tr><td style="padding:4px 8px;"><strong>Submitted at</strong></td><td style="padding:4px 8px;">' . esc((string) $submittedAt) . '</td></tr>'
|
||||
. '</table>'
|
||||
. '<p>Review drafts: <a href="' . esc(base_url('administrator/exam-drafts')) . '">Admin exam drafts</a></p>';
|
||||
. '<p>Review drafts: <a href="' . esc(base_url($this->reviewRoutePrefix() . '/exam-drafts')) . '">' . esc($this->reviewPortalLabel()) . ' exam drafts</a></p>';
|
||||
|
||||
$mailer = \Config\Services::emailService();
|
||||
$mailer->send($principalEmail, $subject, $body, 'notifications');
|
||||
@@ -1019,6 +1037,38 @@ class ExamDraftController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
private function reviewDashboardPath(): string
|
||||
{
|
||||
return '/' . $this->reviewRoutePrefix() . '/exam-drafts';
|
||||
}
|
||||
|
||||
private function reviewRoutePrefix(): string
|
||||
{
|
||||
return $this->isPrincipalReviewer() ? 'principal' : 'administrator';
|
||||
}
|
||||
|
||||
private function reviewPortalLabel(): string
|
||||
{
|
||||
return $this->isPrincipalReviewer() ? 'Principal' : 'Administrator';
|
||||
}
|
||||
|
||||
private function isPrincipalReviewer(): bool
|
||||
{
|
||||
$roles = session()->get('roles');
|
||||
if (!is_array($roles)) {
|
||||
$roles = $roles === null ? [] : [$roles];
|
||||
}
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$normalized = strtolower(trim(str_replace([' ', '-'], '_', (string) $role)));
|
||||
if ($normalized === 'principal') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function nextDraftVersion(array $draft): int
|
||||
{
|
||||
$query = $this->examDraftModel
|
||||
@@ -1373,6 +1423,11 @@ class ExamDraftController extends BaseController
|
||||
$base = pathinfo($sourcePath, PATHINFO_FILENAME);
|
||||
$targetPath = $targetDir . '/' . $base . '.pdf';
|
||||
|
||||
if (!function_exists('exec')) {
|
||||
log_message('warning', 'ExamDraftController::convertDocToPdf skipped because exec() is unavailable.');
|
||||
return is_file($targetPath) ? basename($targetPath) : null;
|
||||
}
|
||||
|
||||
// Attempt conversion via LibreOffice if available
|
||||
$cmd = 'soffice --headless --convert-to pdf --outdir ' . escapeshellarg($targetDir) . ' ' . escapeshellarg($sourcePath) . ' 2>/dev/null';
|
||||
@\exec($cmd);
|
||||
|
||||
@@ -13,6 +13,9 @@ $schoolYear = $schoolYear ?? '';
|
||||
$semester = $semester ?? '';
|
||||
$maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
$allowedExtensions = $allowedExtensions ?? ['doc', 'docx', 'pdf'];
|
||||
$reviewActionUrl = $reviewActionUrl ?? base_url('administrator/exam-drafts/review');
|
||||
$legacyUploadUrl = $legacyUploadUrl ?? base_url('administrator/exam-drafts/upload-legacy');
|
||||
$reviewPortalLabel = $reviewPortalLabel ?? 'Administrator';
|
||||
|
||||
$renderBadge = static function (string $status, array $badges): string {
|
||||
$b = $badges[$status] ?? ['label' => $status, 'class' => 'bg-secondary text-white'];
|
||||
@@ -27,7 +30,7 @@ $fileAccept = implode(',', array_map(static fn ($x) => '.' . $x, $allowedExtensi
|
||||
<div>
|
||||
<h1 class="h3 mb-1">Exam draft submissions</h1>
|
||||
<p class="text-muted mb-0 small">
|
||||
<?= esc($semester ?: 'Semester') ?> <?= esc($schoolYear ?: '') ?>
|
||||
<?= esc($reviewPortalLabel) ?> review portal · <?= esc($semester ?: 'Semester') ?> <?= esc($schoolYear ?: '') ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-muted small d-flex flex-column align-items-lg-end">
|
||||
@@ -205,7 +208,7 @@ $fileAccept = implode(',', array_map(static fn ($x) => '.' . $x, $allowedExtensi
|
||||
</div>
|
||||
</td>
|
||||
<td style="min-width: 280px;">
|
||||
<?= form_open_multipart(base_url('administrator/exam-drafts/review'), ['class' => 'vstack gap-2', 'id' => $formId]) ?>
|
||||
<?= form_open_multipart($reviewActionUrl, ['class' => 'vstack gap-2', 'id' => $formId]) ?>
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="draft_id" value="<?= (int) ($draft['id'] ?? 0) ?>">
|
||||
<?php $selectedStatus = ''; ?>
|
||||
@@ -276,7 +279,7 @@ $fileAccept = implode(',', array_map(static fn ($x) => '.' . $x, $allowedExtensi
|
||||
<span class="badge bg-primary-subtle text-primary">Admin only</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= form_open_multipart(base_url('administrator/exam-drafts/upload-legacy'), ['class' => 'row g-3']) ?>
|
||||
<?= form_open_multipart($legacyUploadUrl, ['class' => 'row g-3']) ?>
|
||||
<?= csrf_field() ?>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small">Class sections</label>
|
||||
|
||||
Reference in New Issue
Block a user