PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.10.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.10.01
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
← All changes | Modules/Course/Http/Controllers/CourseController.php +119 -9 2.6.02.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();