← All changes
|
Modules/Course/Http/Controllers/CourseController.php
+119
-9
2.6.0
→
2.10.01
View file →
| @@ -12,8 +12,9 @@ | ||
| 12 | 12 | use FluentCommunity\Modules\Course\Model\CourseLesson; |
| 13 | 13 | use FluentCommunity\Modules\Course\Model\CourseTopic; |
| 14 | 14 | use FluentCommunity\App\Services\FeedsHelper; |
| 15 | 15 | use FluentCommunity\Modules\Course\Services\CourseHelper; |
| 16 | +use FluentCommunity\Modules\Course\Services\LessonVideoGateService; | |
| 16 | 17 | |
| 17 | 18 | class CourseController extends Controller |
| 18 | 19 | { |
| 19 | 20 | public function getCourses(Request $request) |
| @@ -71,8 +72,10 @@ | ||
| 71 | 72 | $course->studentsCount = SpaceUserPivot::where('space_id', $course->id)->count(); |
| 72 | 73 | } else { |
| 73 | 74 | $course->studentsCount = 0; |
| 74 | 75 | } |
| 76 | + | |
| 77 | + do_action_ref_array('fluent_community/course', [&$course]); | |
| 75 | 78 | } |
| 76 | 79 | |
| 77 | 80 | $data = [ |
| 78 | 81 | 'courses' => $courses, |
| @@ -86,8 +89,9 @@ | ||
| 86 | 89 | { |
| 87 | 90 | $user = $this->getUser(); |
| 88 | 91 | |
| 89 | 92 | $course = Course::findOrFail($courseId); |
| 93 | + /** @var Course $course */ | |
| 90 | 94 | |
| 91 | 95 | $isCourseCreator = $course->isCourseAdmin($user); |
| 92 | 96 | |
| 93 | 97 | if ($course->status !== 'published' && !$isCourseCreator) { |
| @@ -107,8 +111,9 @@ | ||
| 107 | 111 | { |
| 108 | 112 | $user = $this->getUser(); |
| 109 | 113 | |
| 110 | 114 | $course = Course::where('slug', $slug)->firstOrFail(); |
| 115 | + /** @var Course $course */ | |
| 111 | 116 | |
| 112 | 117 | $isCourseCreator = $course->isCourseAdmin($user); |
| 113 | 118 | |
| 114 | 119 | if ($course->status !== 'published' && !$isCourseCreator) { |
| @@ -143,8 +148,9 @@ | ||
| 143 | 148 | public function getLessonBySlug(Request $request, $courseSlug, $lessonSlug) |
| 144 | 149 | { |
| 145 | 150 | $user = $this->getUser(); |
| 146 | 151 | |
| 152 | + /** @var Course $course */ | |
| 147 | 153 | $course = Course::where('slug', $courseSlug)->firstOrFail(); |
| 148 | 154 | |
| 149 | 155 | $isCourseCreator = $course->isCourseAdmin($user); |
| 150 | 156 | |
| @@ -203,9 +209,9 @@ | ||
| 203 | 209 | $formattedLesson = CourseHelper::formatLessonData($course, $lesson, $user, [ |
| 204 | 210 | 'can_view' => $canViewLesson, |
| 205 | 211 | 'parse_content' => $canViewLesson, |
| 206 | 212 | 'is_locked' => !$canViewLesson && !$isCourseCreator, |
| 207 | - 'unclock_date' => $unlockDate, | |
| 213 | + 'unlock_date' => $unlockDate, | |
| 208 | 214 | 'lock_type' => $lockType |
| 209 | 215 | ]); |
| 210 | 216 | |
| 211 | 217 | $data = [ |
| @@ -218,8 +224,9 @@ | ||
| 218 | 224 | private function processCourse(Course $course, $isCourseCreator, $intendtedLessonSlug = '') |
| 219 | 225 | { |
| 220 | 226 | $sections = CourseTopic::where('space_id', $course->id) |
| 221 | 227 | ->orderBy('priority', 'ASC') |
| 228 | + ->orderBy('id', 'ASC') | |
| 222 | 229 | ->with(['lessons' => function ($query) use ($isCourseCreator) { |
| 223 | 230 | if (!$isCourseCreator) { |
| 224 | 231 | $query->where('status', 'published'); |
| 225 | 232 | } |
| @@ -240,8 +247,9 @@ | ||
| 240 | 247 | ]); |
| 241 | 248 | } |
| 242 | 249 | |
| 243 | 250 | $course->is_course_admin = $isCourseCreator; |
| 251 | + $course->can_self_enroll = $isCourseCreator || ($course->status === 'published' && $course->privacy === 'public'); | |
| 244 | 252 | |
| 245 | 253 | $course = apply_filters('fluent_community/course/processed', $course, [ |
| 246 | 254 | 'is_enrolled' => !!$enrollment, |
| 247 | 255 | ]); |
| @@ -294,9 +302,9 @@ | ||
| 294 | 302 | $formattedLesson = CourseHelper::formatLessonData($course, $lesson, $currentUser, [ |
| 295 | 303 | 'can_view' => $canViewLesson, |
| 296 | 304 | 'parse_content' => $parseContent, |
| 297 | 305 | 'is_locked' => !$canViewLesson && !$isCourseCreator, |
| 298 | - 'unclock_date' => $unlockDate, | |
| 306 | + 'unlock_date' => $unlockDate, | |
| 299 | 307 | 'lock_type' => $lockType |
| 300 | 308 | ]); |
| 301 | 309 | |
| 302 | 310 | $isLazyLoad = !$parseContent; |
| @@ -338,8 +346,9 @@ | ||
| 338 | 346 | ]); |
| 339 | 347 | } |
| 340 | 348 | |
| 341 | 349 | $course = Course::findOrFail($courseId); |
| 350 | + /** @var Course $course */ | |
| 342 | 351 | |
| 343 | 352 | $isCourseCreator = $course->isCourseAdmin($user); |
| 344 | 353 | |
| 345 | 354 | if ($course->status !== 'published' && !$isCourseCreator) { |
| @@ -404,14 +413,21 @@ | ||
| 404 | 413 | 'message' => __('Invalid state.', 'fluent-community') |
| 405 | 414 | ]); |
| 406 | 415 | } |
| 407 | 416 | |
| 408 | - $isAllowed = apply_filters('fluent_community/is_allowed_to_complete_lesson', true, $lesson); | |
| 417 | + $isAllowed = apply_filters('fluent_community/is_allowed_to_complete_lesson', true, $lesson, $state); | |
| 409 | 418 | |
| 410 | 419 | if (!$isAllowed) { |
| 411 | - return $this->sendError([ | |
| 420 | + $errorData = [ | |
| 412 | 421 | 'message' => __('You are not allowed to complete this lesson.', 'fluent-community') |
| 413 | - ]); | |
| 422 | + ]; | |
| 423 | + | |
| 424 | + if (LessonVideoGateService::isCompletionBlockedFor($lesson, Helper::getCurrentUser())) { | |
| 425 | + $errorData['code'] = 'video_watch_required'; | |
| 426 | + $errorData['threshold'] = LessonVideoGateService::getThreshold($lesson); | |
| 427 | + } | |
| 428 | + | |
| 429 | + return $this->sendError($errorData); | |
| 414 | 430 | } |
| 415 | 431 | |
| 416 | 432 | CourseHelper::updateLessonCompletion($lesson, get_current_user_id(), $state); |
| 417 | 433 | $track = CourseHelper::getCourseProgressTrack($courseId); |
| @@ -427,14 +443,96 @@ | ||
| 427 | 443 | 'is_completed' => $isCompleted |
| 428 | 444 | ]; |
| 429 | 445 | } |
| 430 | 446 | |
| 447 | + public function markLessonVideoWatched(Request $request, $courseId, $lessonId) | |
| 448 | + { | |
| 449 | + $course = Course::findOrFail($courseId); | |
| 450 | + | |
| 451 | + if ($course->status != 'published') { | |
| 452 | + return $this->sendError([ | |
| 453 | + 'message' => __('Course is not in published state.', 'fluent-community') | |
| 454 | + ]); | |
| 455 | + } | |
| 456 | + | |
| 457 | + if (!CourseHelper::isEnrolled($courseId)) { | |
| 458 | + return $this->sendError([ | |
| 459 | + 'message' => __('Please enroll this course first', 'fluent-community') | |
| 460 | + ]); | |
| 461 | + } | |
| 462 | + | |
| 463 | + $lesson = CourseLesson::where('space_id', $courseId) | |
| 464 | + ->where('status', 'published') | |
| 465 | + ->where('id', $lessonId) | |
| 466 | + ->first(); | |
| 467 | + | |
| 468 | + if (!$lesson) { | |
| 469 | + return $this->sendError([ | |
| 470 | + 'message' => __('Lesson is not on published state.', 'fluent-community') | |
| 471 | + ]); | |
| 472 | + } | |
| 473 | + | |
| 474 | + if (!LessonVideoGateService::isGatedLesson($lesson)) { | |
| 475 | + return [ | |
| 476 | + 'message' => __('This lesson does not require video completion.', 'fluent-community'), | |
| 477 | + 'is_gated' => false, | |
| 478 | + 'watched' => false | |
| 479 | + ]; | |
| 480 | + } | |
| 481 | + | |
| 482 | + $watchedPercent = min(100, absint($request->get('watched_percent'))); | |
| 483 | + $threshold = LessonVideoGateService::getThreshold($lesson); | |
| 484 | + | |
| 485 | + if ($watchedPercent < $threshold) { | |
| 486 | + return $this->sendError([ | |
| 487 | + /* translators: %d is the watched percentage required to complete the lesson */ | |
| 488 | + 'message' => sprintf(__('Please watch at least %d%% of the video.', 'fluent-community'), $threshold) | |
| 489 | + ]); | |
| 490 | + } | |
| 491 | + | |
| 492 | + LessonVideoGateService::markWatched($lesson, get_current_user_id()); | |
| 493 | + | |
| 494 | + return [ | |
| 495 | + 'message' => __('Video watch progress has been recorded.', 'fluent-community'), | |
| 496 | + 'is_gated' => true, | |
| 497 | + 'watched' => true | |
| 498 | + ]; | |
| 499 | + } | |
| 500 | + | |
| 501 | + public function resetMyProgress(Request $request, $courseId) | |
| 502 | + { | |
| 503 | + $course = Course::findOrFail($courseId); | |
| 504 | + | |
| 505 | + if ($course->status !== 'published') { | |
| 506 | + return $this->sendError([ | |
| 507 | + 'message' => __('Course is not in published state.', 'fluent-community') | |
| 508 | + ]); | |
| 509 | + } | |
| 510 | + | |
| 511 | + if (!CourseHelper::isEnrolled($courseId)) { | |
| 512 | + return $this->sendError([ | |
| 513 | + 'message' => __('Please enroll this course first', 'fluent-community') | |
| 514 | + ]); | |
| 515 | + } | |
| 516 | + | |
| 517 | + CourseHelper::resetCourseProgress($courseId, get_current_user_id()); | |
| 518 | + | |
| 519 | + return [ | |
| 520 | + 'message' => __('Your course progress has been reset.', 'fluent-community'), | |
| 521 | + 'track' => [ | |
| 522 | + 'completed_lessons' => [], | |
| 523 | + 'isEnrolled' => true, | |
| 524 | + 'progress' => 0 | |
| 525 | + ] | |
| 526 | + ]; | |
| 527 | + } | |
| 528 | + | |
| 431 | 529 | public function getAllCourses(Request $request) |
| 432 | 530 | { |
| 433 | 531 | $user = $this->getUser(); |
| 434 | 532 | $isCourseCreator = $user && $user->hasCourseCreatorAccess(); |
| 435 | 533 | |
| 436 | - $courses = Course::where(function ($q) use ($isCourseCreator, $user) { | |
| 534 | + $coursesQuery = Course::where(function ($q) use ($isCourseCreator, $user) { | |
| 437 | 535 | if ($isCourseCreator) { |
| 438 | 536 | $q->where('status', 'published') |
| 439 | 537 | ->orWhere('created_by', $user->ID); |
| 440 | 538 | } else { |
| @@ -439,11 +537,23 @@ | ||
| 439 | 537 | ->orWhere('created_by', $user->ID); |
| 440 | 538 | } else { |
| 441 | 539 | $q->where('status', 'published'); |
| 442 | 540 | } |
| 443 | - }) | |
| 444 | - ->with(['creator']) | |
| 445 | - ->paginate(); | |
| 541 | + }); | |
| 542 | + | |
| 543 | + if (!($user && $user->isCommunityModerator())) { | |
| 544 | + $userId = get_current_user_id(); | |
| 545 | + $coursesQuery->where(function ($q) use ($userId) { | |
| 546 | + $q->whereIn('privacy', ['public', 'private']) | |
| 547 | + ->orWhereHas('space_pivot', function ($sub) use ($userId) { | |
| 548 | + $sub->where('user_id', $userId) | |
| 549 | + ->where('role', 'student'); | |
| 550 | + }) | |
| 551 | + ->orWhere('created_by', $userId); | |
| 552 | + }); | |
| 553 | + } | |
| 554 | + | |
| 555 | + $courses = $coursesQuery->with(['creator'])->paginate(); | |
| 446 | 556 | |
| 447 | 557 | $formattedCourses = []; |
| 448 | 558 | foreach ($courses as $course) { |
| 449 | 559 | $course->sectionsCount = CourseTopic::where('space_id', $course->id)->count(); |