add class progress and fix endpoints

This commit is contained in:
root
2026-03-12 17:27:49 -04:00
parent 0f39dbee62
commit 33be0c9a0d
40 changed files with 2086 additions and 438 deletions
@@ -0,0 +1,180 @@
<?php
namespace App\Services\ClassProgress;
use App\Models\ClassProgressReport;
use App\Models\TeacherClass;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ClassProgressMutationService
{
public function __construct(
private ClassProgressRuleService $rules,
private ClassProgressAttachmentService $attachments
) {}
public function createReports(User $user, array $payload, array $filesBySubject): Collection
{
$subjectSections = (array) config('progress.subject_sections', []);
$classSectionId = (int) ($payload['class_section_id'] ?? 0);
$this->assertTeacherAssignment($user, $classSectionId);
$weekStart = (string) ($payload['week_start'] ?? '');
$weekEnd = $this->rules->ensureWeekEnd($weekStart, $payload['week_end'] ?? null);
if (!$this->rules->isWeekEndValid($weekStart, $weekEnd)) {
throw new \InvalidArgumentException('Week end must be the same as or after the week start.');
}
$reports = DB::transaction(function () use ($user, $payload, $subjectSections, $classSectionId, $weekStart, $weekEnd, $filesBySubject) {
$created = collect();
foreach ($subjectSections as $slug => $section) {
$covered = trim((string) ($payload["covered_{$slug}"] ?? ''));
if ($covered === '') {
continue;
}
$homework = trim((string) ($payload["homework_{$slug}"] ?? ''));
$unitValues = (array) ($payload["unit_{$slug}"] ?? []);
$chapterValues = (array) ($payload["chapter_{$slug}"] ?? []);
$unitTitle = $this->rules->buildUnitChapterSummary($unitValues, $chapterValues);
$report = ClassProgressReport::query()->create([
'teacher_id' => $user->id,
'class_section_id' => $classSectionId,
'week_start' => $weekStart,
'week_end' => $weekEnd,
'subject' => $section['db_subject'] ?? $section['label'] ?? $slug,
'unit_title' => $unitTitle,
'covered' => $covered,
'homework' => $homework !== '' ? $homework : null,
'status' => $this->rules->defaultStatus(),
'support_needed' => $payload['support_needed'] ?? null,
'flags_json' => $this->rules->normalizeFlags($payload['flags'] ?? null),
]);
$attachments = $filesBySubject[$slug] ?? [];
$stored = $this->attachments->storeAttachments($report->id, $attachments);
if ($stored !== []) {
$report->update(['attachment_path' => $stored[0]['file_path'] ?? null]);
}
$created->push($report);
}
if ($created->isEmpty()) {
throw new \InvalidArgumentException('Please provide progress for at least one subject.');
}
return $created;
});
Log::info('Class progress reports created.', [
'teacher_id' => $user->id,
'class_section_id' => $classSectionId,
'count' => $reports->count(),
]);
return $reports;
}
public function updateReport(ClassProgressReport $report, array $payload, array $attachments): ClassProgressReport
{
return DB::transaction(function () use ($report, $payload, $attachments) {
$weekStart = $payload['week_start'] ?? $report->week_start?->format('Y-m-d');
$weekEnd = $this->rules->ensureWeekEnd((string) $weekStart, $payload['week_end'] ?? null);
if ($weekStart && $weekEnd && !$this->rules->isWeekEndValid((string) $weekStart, (string) $weekEnd)) {
throw new \InvalidArgumentException('Week end must be the same as or after the week start.');
}
$data = [];
if ($weekStart) {
$data['week_start'] = $weekStart;
}
if ($weekEnd) {
$data['week_end'] = $weekEnd;
}
if (array_key_exists('covered', $payload)) {
$data['covered'] = $payload['covered'];
}
if (array_key_exists('homework', $payload)) {
$data['homework'] = $payload['homework'];
}
if (array_key_exists('unit_title', $payload)) {
$data['unit_title'] = $payload['unit_title'];
}
if (array_key_exists('status', $payload)) {
$data['status'] = $payload['status'];
}
if (array_key_exists('support_needed', $payload)) {
$data['support_needed'] = $payload['support_needed'];
}
if (array_key_exists('flags', $payload)) {
$data['flags_json'] = $this->rules->normalizeFlags($payload['flags']);
}
if ($data !== []) {
$report->fill($data);
$report->save();
}
if ($attachments !== []) {
$stored = $this->attachments->storeAttachments($report->id, $attachments);
if ($stored !== []) {
$report->update(['attachment_path' => $stored[0]['file_path'] ?? $report->attachment_path]);
}
}
return $report->fresh(['classSection', 'attachments']);
});
}
public function deleteReport(ClassProgressReport $report): void
{
DB::transaction(function () use ($report) {
$report->attachments()->delete();
$report->delete();
});
}
private function assertTeacherAssignment(User $user, int $classSectionId): void
{
if ($classSectionId <= 0) {
throw new \InvalidArgumentException('No class assignment found for this report.');
}
if ($this->isAdmin($user)) {
return;
}
$assigned = TeacherClass::query()
->where('teacher_id', $user->id)
->where('class_section_id', $classSectionId)
->exists();
if (!$assigned) {
throw new \InvalidArgumentException('No class assignment found for this report.');
}
}
private function isAdmin(User $user): bool
{
$roles = $user->roles()
->pluck('roles.name')
->map(fn ($name) => strtolower((string) $name))
->toArray();
foreach (['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] as $role) {
if (in_array($role, $roles, true)) {
return true;
}
}
return false;
}
}