PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.10.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.10.0
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 +123 -9 2.5.02.10.0 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,9 +247,14 @@
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
253 + $course = apply_filters('fluent_community/course/processed', $course, [
254 + 'is_enrolled' => !!$enrollment,
255 + ]);
256 +
245 257 $courseSettings = $course->settings;
246 258 if (Arr::get($courseSettings, 'course_details')) {
247 259 $courseSettings['course_details_rendered'] = wp_kses_post(FeedsHelper::mdToHtml($courseSettings['course_details']));
248 260 $course->settings = $courseSettings;
@@ -290,9 +302,9 @@
290 302 $formattedLesson = CourseHelper::formatLessonData($course, $lesson, $currentUser, [
291 303 'can_view' => $canViewLesson,
292 304 'parse_content' => $parseContent,
293 305 'is_locked' => !$canViewLesson && !$isCourseCreator,
294 - 'unclock_date' => $unlockDate,
306 + 'unlock_date' => $unlockDate,
295 307 'lock_type' => $lockType
296 308 ]);
297 309
298 310 $isLazyLoad = !$parseContent;
@@ -334,8 +346,9 @@
334 346 ]);
335 347 }
336 348
337 349 $course = Course::findOrFail($courseId);
350 + /** @var Course $course */
338 351
339 352 $isCourseCreator = $course->isCourseAdmin($user);
340 353
341 354 if ($course->status !== 'published' && !$isCourseCreator) {
@@ -400,14 +413,21 @@
400 413 'message' => __('Invalid state.', 'fluent-community')
401 414 ]);
402 415 }
403 416
404 - $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);
405 418
406 419 if (!$isAllowed) {
407 - return $this->sendError([
420 + $errorData = [
408 421 'message' => __('You are not allowed to complete this lesson.', 'fluent-community')
409 - ]);
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);
410 430 }
411 431
412 432 CourseHelper::updateLessonCompletion($lesson, get_current_user_id(), $state);
413 433 $track = CourseHelper::getCourseProgressTrack($courseId);
@@ -423,14 +443,96 @@
423 443 'is_completed' => $isCompleted
424 444 ];
425 445 }
426 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 +
427 529 public function getAllCourses(Request $request)
428 530 {
429 531 $user = $this->getUser();
430 532 $isCourseCreator = $user && $user->hasCourseCreatorAccess();
431 533
432 - $courses = Course::where(function ($q) use ($isCourseCreator, $user) {
534 + $coursesQuery = Course::where(function ($q) use ($isCourseCreator, $user) {
433 535 if ($isCourseCreator) {
434 536 $q->where('status', 'published')
435 537 ->orWhere('created_by', $user->ID);
436 538 } else {
@@ -435,11 +537,23 @@
435 537 ->orWhere('created_by', $user->ID);
436 538 } else {
437 539 $q->where('status', 'published');
438 540 }
439 - })
440 - ->with(['creator'])
441 - ->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();
442 556
443 557 $formattedCourses = [];
444 558 foreach ($courses as $course) {
445 559 $course->sectionsCount = CourseTopic::where('space_id', $course->id)->count();