142 خطوط
6.5 KiB
PHP
142 خطوط
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Modules\Publishing\Http;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Modules\Assignments\Application\AssignmentResolver;
|
|
use App\Modules\Assignments\Domain\Assignment;
|
|
use App\Modules\Courses\Domain\Course;
|
|
use App\Modules\Courses\Domain\CourseVersion;
|
|
use App\Modules\Identity\Application\RolePermissions;
|
|
use App\Modules\Identity\Domain\Enums\Permission;
|
|
use App\Modules\Publishing\Application\CoursePublication;
|
|
use App\Modules\Tenancy\Application\TenantContext;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
final class CoursePublicationController extends Controller
|
|
{
|
|
public function __construct(private readonly TenantContext $tenant, private readonly RolePermissions $permissions, private readonly CoursePublication $publication, private readonly AssignmentResolver $resolver) {}
|
|
|
|
public function readiness(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
|
|
return response()->json(['data' => $this->publication->readiness($this->version($course, $version))]);
|
|
}
|
|
|
|
public function configure(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
$data = $request->validate([
|
|
'mode' => ['required', Rule::in(['all', 'any'])], 'rules' => ['required', 'array', 'min:1', 'max:8'],
|
|
'rules.*.type' => ['required', Rule::in(['all_required_lessons', 'minimum_lesson_percentage', 'assessment_passed', 'minimum_score', 'required_interaction'])],
|
|
'rules.*.value' => ['nullable', 'numeric', 'between:0,100'],
|
|
]);
|
|
$model = $this->publication->configure($this->version($course, $version), $data);
|
|
|
|
return response()->json(['data' => $this->payload($model)]);
|
|
}
|
|
|
|
public function submitReview(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
|
|
return response()->json(['data' => $this->payload($this->publication->submitReview($this->version($course, $version)))]);
|
|
}
|
|
|
|
public function returnDraft(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
|
|
return response()->json(['data' => $this->payload($this->publication->returnToDraft($this->version($course, $version)))]);
|
|
}
|
|
|
|
public function publish(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
$data = $request->validate(['reassignMode' => ['required', Rule::in(['none', 'everyone', 'selected'])], 'assignmentIds' => ['nullable', 'array'], 'assignmentIds.*' => ['string']]);
|
|
$model = $this->version($course, $version);
|
|
$published = $this->publication->publish($model, (string) $request->user()->getKey());
|
|
$created = $this->reassign($request, $published, $data['reassignMode'], $data['assignmentIds'] ?? []);
|
|
|
|
return response()->json(['data' => [...$this->payload($published), 'reassignmentsCreated' => $created]]);
|
|
}
|
|
|
|
public function schedule(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
$data = $request->validate(['scheduledPublishAt' => ['required', 'date', 'after:now'], 'scheduledUnpublishAt' => ['nullable', 'date', 'after:scheduledPublishAt']]);
|
|
$model = $this->publication->schedule($this->version($course, $version), new \DateTimeImmutable($data['scheduledPublishAt']), isset($data['scheduledUnpublishAt']) ? new \DateTimeImmutable($data['scheduledUnpublishAt']) : null);
|
|
|
|
return response()->json(['data' => $this->payload($model)]);
|
|
}
|
|
|
|
public function cancelSchedule(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
|
|
return response()->json(['data' => $this->payload($this->publication->cancelSchedule($this->version($course, $version)))]);
|
|
}
|
|
|
|
public function unpublish(Request $request, string $course, string $version): JsonResponse
|
|
{
|
|
$this->authorize($request);
|
|
$this->publication->unpublish($this->version($course, $version));
|
|
|
|
return response()->json(status: 204);
|
|
}
|
|
|
|
/** @param list<string> $selected */
|
|
private function reassign(Request $request, CourseVersion $published, string $mode, array $selected): int
|
|
{
|
|
if ($mode === 'none' || ! $published->source_version_id) {
|
|
return 0;
|
|
}
|
|
$query = Assignment::query()->where('organization_id', $this->tenant->id())->where('assignable_type', 'course')->where('assignable_id', $published->source_version_id)->where('status', 'active');
|
|
if ($mode === 'selected') {
|
|
$query->whereIn('id', $selected);
|
|
}
|
|
|
|
return DB::transaction(function () use ($query, $request, $published): int {
|
|
$count = 0;
|
|
foreach ($query->get() as $source) {
|
|
$copy = $source->replicate(['cancelled_at']);
|
|
$copy->assignable_id = $published->getKey();
|
|
$copy->assigned_by = $request->user()->getKey();
|
|
$copy->source = 'version_reassignment';
|
|
$copy->save();
|
|
$this->resolver->sync($copy);
|
|
$count++;
|
|
}
|
|
|
|
return $count;
|
|
});
|
|
}
|
|
|
|
private function version(string $course, string $version): CourseVersion
|
|
{
|
|
Course::query()->where('organization_id', $this->tenant->id())->findOrFail($course);
|
|
|
|
return CourseVersion::query()->where('organization_id', $this->tenant->id())->where('course_id', $course)->findOrFail($version);
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
private function payload(CourseVersion $version): array
|
|
{
|
|
return [
|
|
'id' => $version->getKey(), 'status' => $version->status->value, 'completionRules' => $version->completion_rules,
|
|
'reviewSubmittedAt' => $version->review_submitted_at?->toISOString(), 'publishedAt' => $version->published_at?->toISOString(),
|
|
'scheduledPublishAt' => $version->scheduled_publish_at?->toISOString(), 'scheduledUnpublishAt' => $version->scheduled_unpublish_at?->toISOString(),
|
|
'unpublishedAt' => $version->unpublished_at?->toISOString(), 'taxonomySnapshotCount' => count($version->taxonomy_snapshot ?? []),
|
|
];
|
|
}
|
|
|
|
private function authorize(Request $request): void
|
|
{
|
|
abort_unless($this->permissions->allows($request->user(), Permission::CoursesPublish), 403);
|
|
}
|
|
}
|