940afe9319
API CI/CD / Validate (composer + pint) (push) Successful in 2m7s
API CI/CD / Test (PHPUnit) (push) Failing after 2m23s
API CI/CD / Build frontend assets (push) Successful in 2m18s
API CI/CD / Security audit (push) Successful in 31s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
166 lines
6.1 KiB
PHP
166 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Exams;
|
|
|
|
use App\Models\ExamDraft;
|
|
use App\Models\TeacherClass;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ExamDraftTeacherService
|
|
{
|
|
public function __construct(
|
|
private ExamDraftConfigService $configService,
|
|
private ExamDraftFileService $fileService
|
|
) {}
|
|
|
|
public function listForTeacher(int $teacherId): array
|
|
{
|
|
$context = $this->configService->context();
|
|
$schoolYear = (string) ($context['school_year'] ?? '');
|
|
$teacherUserColumn = (string) ($context['teacher_user_column'] ?? '');
|
|
|
|
$assignments = TeacherClass::getClassAssignmentsByUserId($teacherId, $schoolYear);
|
|
$classSectionIds = array_map(static fn ($a) => (int) $a['class_section_id'], $assignments);
|
|
|
|
$drafts = [];
|
|
if ($teacherUserColumn !== '') {
|
|
$drafts = ExamDraft::query()
|
|
->where($teacherUserColumn, $teacherId)
|
|
->orderByDesc('created_at')
|
|
->get()
|
|
->toArray();
|
|
}
|
|
|
|
$legacyExams = [];
|
|
if (($context['has_legacy'] ?? false) && ! empty($classSectionIds)) {
|
|
$legacyExams = DB::table('exam_drafts as ed')
|
|
->select('ed.*', 'cs.class_section_name')
|
|
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'ed.class_section_id')
|
|
->whereIn('ed.class_section_id', $classSectionIds)
|
|
->where('ed.is_legacy', 1)
|
|
->whereNotNull('ed.final_file')
|
|
->orderBy('cs.class_section_name')
|
|
->orderByDesc('ed.created_at')
|
|
->get()
|
|
->map(fn ($r) => (array) $r)
|
|
->all();
|
|
}
|
|
|
|
return [
|
|
'assignments' => $assignments,
|
|
'drafts' => $drafts,
|
|
'legacyExams' => $legacyExams,
|
|
'examTypes' => ExamDraftConfigService::EXAM_TYPES,
|
|
'statusOptions' => ExamDraftConfigService::STATUS_OPTIONS,
|
|
'schoolYear' => $schoolYear,
|
|
'semester' => (string) ($context['semester'] ?? ''),
|
|
];
|
|
}
|
|
|
|
public function store(int $teacherId, array $payload, ?UploadedFile $file): array
|
|
{
|
|
$context = $this->configService->context();
|
|
$schoolYear = (string) ($context['school_year'] ?? '');
|
|
$semester = (string) ($context['semester'] ?? '');
|
|
|
|
$classSectionId = (int) ($payload['class_section_id'] ?? 0);
|
|
$examType = trim((string) ($payload['exam_type'] ?? ''));
|
|
$description = trim((string) ($payload['description'] ?? ''));
|
|
|
|
if ($classSectionId <= 0) {
|
|
return ['ok' => false, 'message' => 'Select a class section before submitting.'];
|
|
}
|
|
|
|
$assignment = TeacherClass::query()
|
|
->where('teacher_id', $teacherId)
|
|
->where('class_section_id', $classSectionId)
|
|
->first();
|
|
|
|
if (! $assignment) {
|
|
return ['ok' => false, 'message' => 'You are not assigned to the selected class section.'];
|
|
}
|
|
|
|
$teacherFile = null;
|
|
$teacherFilename = null;
|
|
if ($file) {
|
|
$stored = $this->fileService->storeUploadedFile(
|
|
$file,
|
|
ExamDraftConfigService::TEACHER_UPLOAD_DIR,
|
|
ExamDraftConfigService::ALLOWED_EXTENSIONS,
|
|
ExamDraftConfigService::MAX_UPLOAD_BYTES
|
|
);
|
|
if ($stored === null) {
|
|
return ['ok' => false, 'message' => 'Failed to store the uploaded file.'];
|
|
}
|
|
$teacherFile = $stored['stored'];
|
|
$teacherFilename = $stored['original'];
|
|
}
|
|
|
|
$existingDraft = ExamDraft::query()
|
|
->where('class_section_id', $classSectionId)
|
|
->where('semester', $semester)
|
|
->where('school_year', $schoolYear)
|
|
->orderByDesc('version')
|
|
->when(
|
|
(string) ($context['teacher_user_column'] ?? '') !== '',
|
|
fn ($query) => $query->where((string) $context['teacher_user_column'], $teacherId)
|
|
)
|
|
->first();
|
|
|
|
$nextVersion = 1;
|
|
$previousId = null;
|
|
if ($existingDraft) {
|
|
$nextVersion = ((int) ($existingDraft->version ?? 1)) + 1;
|
|
$previousId = (int) ($existingDraft->id ?? 0) ?: null;
|
|
}
|
|
|
|
$title = $examType !== '' ? $examType : 'Exam Draft';
|
|
|
|
$createPayload = [
|
|
'class_section_id' => $classSectionId,
|
|
'semester' => $semester,
|
|
'school_year' => $schoolYear,
|
|
'exam_type' => $title,
|
|
'draft_title' => $title,
|
|
'status' => 'submitted',
|
|
'version' => $nextVersion,
|
|
];
|
|
|
|
if (($context['teacher_user_column'] ?? null) === 'teacher_id') {
|
|
$createPayload['teacher_id'] = $teacherId;
|
|
}
|
|
if (($context['teacher_user_column'] ?? null) === 'author_id') {
|
|
$createPayload['author_id'] = $teacherId;
|
|
}
|
|
if (($context['teacher_comment_column'] ?? null) === 'description') {
|
|
$createPayload['description'] = $description !== '' ? $description : null;
|
|
}
|
|
if (($context['teacher_comment_column'] ?? null) === 'author_comment') {
|
|
$createPayload['author_comment'] = $description !== '' ? $description : null;
|
|
}
|
|
if (($context['teacher_file_column'] ?? null) === 'teacher_file') {
|
|
$createPayload['teacher_file'] = $teacherFile;
|
|
}
|
|
if (($context['teacher_file_column'] ?? null) === 'author_file') {
|
|
$createPayload['author_file'] = $teacherFile;
|
|
}
|
|
if (($context['teacher_filename_column'] ?? null) === 'teacher_filename') {
|
|
$createPayload['teacher_filename'] = $teacherFilename;
|
|
}
|
|
if (($context['teacher_filename_column'] ?? null) === 'author_filename') {
|
|
$createPayload['author_filename'] = $teacherFilename;
|
|
}
|
|
if ($context['has_previous_draft_id'] ?? false) {
|
|
$createPayload['previous_draft_id'] = $previousId;
|
|
}
|
|
|
|
$draft = ExamDraft::query()->create($createPayload);
|
|
|
|
return [
|
|
'ok' => true,
|
|
'draft' => $draft->toArray(),
|
|
];
|
|
}
|
|
}
|