This commit is contained in:
parent
3d67eedf0c
commit
1b8be73219
@ -10,12 +10,74 @@ use App\Services\Course\CourseReviewService;
|
||||
use App\Services\Course\CourseService;
|
||||
use App\Services\Course\CourseSectionService;
|
||||
use App\Services\LiveClass\ZoomLiveService;
|
||||
use App\Models\Course\Course;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class PlayerController extends Controller
|
||||
{
|
||||
private function findCourseContentByIdAndType(Course $course, string $contentId, string $contentType): ?array
|
||||
{
|
||||
if (!in_array($contentType, ['lesson', 'quiz'], true)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($course->sections as $section) {
|
||||
if ($contentType === 'lesson') {
|
||||
foreach ($section->section_lessons as $lesson) {
|
||||
if ((string) $lesson->id === (string) $contentId) {
|
||||
return ['type' => 'lesson', 'id' => $lesson->id];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($section->section_quizzes as $quiz) {
|
||||
if ((string) $quiz->id === (string) $contentId) {
|
||||
return ['type' => 'quiz', 'id' => $quiz->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function findCourseContentById(Course $course, string $contentId): ?array
|
||||
{
|
||||
foreach ($course->sections as $section) {
|
||||
foreach ($section->section_lessons as $lesson) {
|
||||
if ((string) $lesson->id === (string) $contentId) {
|
||||
return ['type' => 'lesson', 'id' => $lesson->id];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($section->section_quizzes as $quiz) {
|
||||
if ((string) $quiz->id === (string) $contentId) {
|
||||
return ['type' => 'quiz', 'id' => $quiz->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function findFirstCourseContent(Course $course): ?array
|
||||
{
|
||||
foreach ($course->sections as $section) {
|
||||
$lesson = $section->section_lessons->first();
|
||||
if ($lesson) {
|
||||
return ['type' => 'lesson', 'id' => $lesson->id];
|
||||
}
|
||||
|
||||
$quiz = $section->section_quizzes->first();
|
||||
if ($quiz) {
|
||||
return ['type' => 'quiz', 'id' => $quiz->id];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
protected CourseService $courseService,
|
||||
protected CoursePlayerService $coursePlay,
|
||||
@ -37,6 +99,10 @@ class PlayerController extends Controller
|
||||
$user = Auth::user();
|
||||
$watchHistory = $this->sectionService->initWatchHistory($request->course_id, 'lesson', $user->id);
|
||||
|
||||
if (! $watchHistory) {
|
||||
return back()->with('error', 'Dieser Kurs hat noch keine Lektionen oder Quizze.');
|
||||
}
|
||||
|
||||
return redirect()->route('course.player', [
|
||||
'type' => $watchHistory->current_watching_type,
|
||||
'watch_history' => $watchHistory->id,
|
||||
@ -53,7 +119,47 @@ class PlayerController extends Controller
|
||||
$watching_type = in_array($type, ['lesson', 'quiz'], true) ? $type : ($watch_history->current_watching_type ?? 'lesson');
|
||||
|
||||
$course = $this->courseService->getUserCourseById($watch_history->course_id, $user);
|
||||
$watching = $this->coursePlay->getWatchingLesson($watching_id, $watching_type);
|
||||
|
||||
if (! $course) {
|
||||
return redirect()
|
||||
->route('category.courses', ['category' => 'all'])
|
||||
->with('error', 'Der Kurs konnte nicht gefunden werden.');
|
||||
}
|
||||
|
||||
// Fix wrong `type`/`lesson_id` combinations by resolving the content inside the course.
|
||||
$resolved = $this->findCourseContentByIdAndType($course, (string) $watching_id, $watching_type);
|
||||
if (! $resolved) {
|
||||
$resolved = $this->findCourseContentById($course, (string) $watching_id);
|
||||
}
|
||||
if (! $resolved) {
|
||||
$resolved = $this->findCourseContentByIdAndType($course, (string) $watch_history->current_watching_id, (string) $watch_history->current_watching_type);
|
||||
}
|
||||
if (! $resolved) {
|
||||
$resolved = $this->findCourseContentById($course, (string) $watch_history->current_watching_id);
|
||||
}
|
||||
if (! $resolved) {
|
||||
$resolved = $this->findFirstCourseContent($course);
|
||||
}
|
||||
|
||||
if (! $resolved) {
|
||||
return redirect()
|
||||
->route('course.details', ['slug' => $course->slug, 'id' => $course->id])
|
||||
->with('error', 'Dieser Kurs hat noch keine Lektionen oder Quizze.');
|
||||
}
|
||||
|
||||
$watching_id = (string) $resolved['id'];
|
||||
$watching_type = $resolved['type'];
|
||||
|
||||
// Canonicalize URL if it doesn’t match the resolved content.
|
||||
if ($type !== $watching_type || (string) $lesson_id !== (string) $watching_id) {
|
||||
return redirect()->route('course.player', [
|
||||
'type' => $watching_type,
|
||||
'watch_history' => $watch_history->id,
|
||||
'lesson_id' => $watching_id,
|
||||
]);
|
||||
}
|
||||
|
||||
$watching = $this->coursePlay->getWatchingLesson($watching_id, $watching_type, (string) $course->id);
|
||||
$reviews = $this->reviewService->getReviews(['course_id' => $course->id, ...$request->all()], true);
|
||||
$userReview = $this->reviewService->userReview($course->id, $user->id);
|
||||
$totalReviews = $this->reviewService->totalReviews($course->id);
|
||||
@ -74,7 +180,7 @@ class PlayerController extends Controller
|
||||
// }
|
||||
|
||||
return Inertia::render('course-player/index', [
|
||||
'type' => $type,
|
||||
'type' => $watching_type,
|
||||
'course' => $course,
|
||||
'section' => $section,
|
||||
'reviews' => $reviews,
|
||||
@ -86,29 +192,55 @@ class PlayerController extends Controller
|
||||
'zoomConfig' => $zoomConfig,
|
||||
]);
|
||||
} catch (ModelNotFoundException $th) {
|
||||
$fallbackId = $watch_history->current_watching_id;
|
||||
$fallbackType = $watch_history->current_watching_type;
|
||||
$user = Auth::user();
|
||||
$course = $this->courseService->getUserCourseById($watch_history->course_id, $user);
|
||||
|
||||
if ($course) {
|
||||
$watchHistoryForUser = WatchHistory::where('course_id', $course->id)
|
||||
->where('user_id', $user->id)
|
||||
->first();
|
||||
|
||||
$watchHistoryId = $watchHistoryForUser?->id ?? $watch_history->id;
|
||||
|
||||
$requestedId = $lesson_id;
|
||||
$requestedType = $watching_type ?? $type;
|
||||
|
||||
if ($fallbackId && in_array($fallbackType, ['lesson', 'quiz'], true)) {
|
||||
$isDifferentFromRequested = ((string) $fallbackId !== (string) $lesson_id) || ($fallbackType !== $requestedType);
|
||||
|
||||
if ($isDifferentFromRequested) {
|
||||
try {
|
||||
$this->coursePlay->getWatchingLesson((string) $fallbackId, $fallbackType);
|
||||
|
||||
// If the ID exists in the course but the type is wrong, redirect with the correct type.
|
||||
$resolved = $this->findCourseContentById($course, $requestedId);
|
||||
if ($resolved && $resolved['type'] !== $requestedType) {
|
||||
return redirect()->route('course.player', [
|
||||
'type' => $fallbackType,
|
||||
'watch_history' => $watch_history->id,
|
||||
'lesson_id' => $fallbackId,
|
||||
'type' => $resolved['type'],
|
||||
'watch_history' => $watchHistoryId,
|
||||
'lesson_id' => $resolved['id'],
|
||||
]);
|
||||
} catch (ModelNotFoundException $fallbackException) {
|
||||
// Fall through to generic error below.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('category.courses', ['category' => 'all'])->with('error', 'The requested content could not be found.');
|
||||
// If the watch history points to a valid item, jump there.
|
||||
$resolved = $this->findCourseContentById($course, (string) $watch_history->current_watching_id);
|
||||
if ($resolved && ((string) $resolved['id'] !== (string) $requestedId || $resolved['type'] !== $requestedType)) {
|
||||
return redirect()->route('course.player', [
|
||||
'type' => $resolved['type'],
|
||||
'watch_history' => $watchHistoryId,
|
||||
'lesson_id' => $resolved['id'],
|
||||
]);
|
||||
}
|
||||
|
||||
// Last resort: send the user to the first available content in the course.
|
||||
$first = $this->findFirstCourseContent($course);
|
||||
if ($first && ((string) $first['id'] !== (string) $requestedId || $first['type'] !== $requestedType)) {
|
||||
return redirect()->route('course.player', [
|
||||
'type' => $first['type'],
|
||||
'watch_history' => $watchHistoryId,
|
||||
'lesson_id' => $first['id'],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->route('course.details', ['slug' => $course->slug, 'id' => $course->id])
|
||||
->with('error', 'Dieser Kurs hat noch keine Lektionen oder Quizze.');
|
||||
}
|
||||
|
||||
return redirect()->route('category.courses', ['category' => 'all'])->with('error', 'Der angeforderte Inhalt konnte nicht gefunden werden.');
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->route('category.courses', ['category' => 'all'])->with('error', $th->getMessage());
|
||||
}
|
||||
|
||||
@ -26,11 +26,19 @@ class CheckEnroll
|
||||
}
|
||||
|
||||
$watchHistory = $request->route('watch_history');
|
||||
if (!WatchHistory::find($watchHistory)) {
|
||||
|
||||
if (!($watchHistory instanceof WatchHistory)) {
|
||||
$watchHistory = WatchHistory::find($watchHistory);
|
||||
}
|
||||
|
||||
if (!$watchHistory) {
|
||||
return back()->with('error', 'Invalid watch history');
|
||||
}
|
||||
|
||||
$course = Course::find($watchHistory->course_id);
|
||||
if (!$course) {
|
||||
return back()->with('error', 'Invalid course');
|
||||
}
|
||||
|
||||
if ($user->role == 'instructor' && $user->instructor_id == $course->instructor_id) {
|
||||
return $next($request);
|
||||
|
||||
@ -12,12 +12,12 @@ use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CoursePlayerService
|
||||
{
|
||||
function getWatchingLesson(string $lesson_id, string $watching_type): SectionLesson | SectionQuiz
|
||||
function getWatchingLesson(string $lesson_id, string $watching_type, ?string $course_id = null): SectionLesson | SectionQuiz
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if ($watching_type === 'lesson') {
|
||||
return SectionLesson::with([
|
||||
$query = SectionLesson::with([
|
||||
'resources',
|
||||
'forums' => function ($query) {
|
||||
$query->with([
|
||||
@ -27,15 +27,27 @@ class CoursePlayerService
|
||||
},
|
||||
]);
|
||||
},
|
||||
])->findOrFail($lesson_id);
|
||||
]);
|
||||
|
||||
if ($course_id) {
|
||||
$query->where('course_id', $course_id);
|
||||
}
|
||||
|
||||
return SectionQuiz::with([
|
||||
return $query->findOrFail($lesson_id);
|
||||
}
|
||||
|
||||
$query = SectionQuiz::with([
|
||||
'quiz_questions',
|
||||
'quiz_submissions' => function ($query) use ($user) {
|
||||
$query->where('user_id', $user->id);
|
||||
}
|
||||
])->findOrFail($lesson_id);
|
||||
]);
|
||||
|
||||
if ($course_id) {
|
||||
$query->where('course_id', $course_id);
|
||||
}
|
||||
|
||||
return $query->findOrFail($lesson_id);
|
||||
}
|
||||
|
||||
function getWatchHistory(string $course_id, ?string $user_id): ?WatchHistory
|
||||
|
||||
@ -289,21 +289,50 @@ class CourseSectionService extends MediaService
|
||||
|
||||
public function initWatchHistory(string $course_id, string $watching_type, string $user_id): ?WatchHistory
|
||||
{
|
||||
$lesson = SectionLesson::query()->where('course_id', $course_id);
|
||||
$history = WatchHistory::where('course_id', $course_id)
|
||||
->where('user_id', $user_id)
|
||||
->first();
|
||||
|
||||
if ($lesson->count() >= 0 && !$history) {
|
||||
$lesson = $lesson->orderBy('sort', 'asc')->first();
|
||||
|
||||
$coursePlay = new CoursePlayerService();
|
||||
$course = Course::where('id', $course_id)->with('sections')->first();
|
||||
|
||||
return $coursePlay->watchHistory($course, $lesson->id, $watching_type, $user_id);
|
||||
if ($history) {
|
||||
return $history;
|
||||
}
|
||||
|
||||
return $history;
|
||||
$course = Course::where('id', $course_id)->with([
|
||||
'sections.section_lessons',
|
||||
'sections.section_quizzes',
|
||||
])->first();
|
||||
|
||||
if (! $course) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$preferredTypes = $watching_type === 'quiz' ? ['quiz', 'lesson'] : ['lesson', 'quiz'];
|
||||
$firstItem = null;
|
||||
|
||||
foreach ($preferredTypes as $preferredType) {
|
||||
foreach ($course->sections as $section) {
|
||||
if ($preferredType === 'lesson') {
|
||||
$lesson = $section->section_lessons->first();
|
||||
if ($lesson) {
|
||||
$firstItem = ['type' => 'lesson', 'id' => $lesson->id];
|
||||
break 2;
|
||||
}
|
||||
} else {
|
||||
$quiz = $section->section_quizzes->first();
|
||||
if ($quiz) {
|
||||
$firstItem = ['type' => 'quiz', 'id' => $quiz->id];
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! $firstItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$coursePlay = new CoursePlayerService();
|
||||
return $coursePlay->watchHistory($course, (string) $firstItem['id'], $firstItem['type'], $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user