PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.4.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.4.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
fluent-community / Modules / Course / Http / Controllers / CourseController.php

CourseController.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.4.01, at Modules/Course/Http/Controllers/CourseController.php

460 lines 17.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Modules\Course\Http\Controllers;
4
5 use FluentCommunity\App\Http\Controllers\Controller;
6 use FluentCommunity\App\Models\SpaceUserPivot;
7 use FluentCommunity\App\Services\Helper;
8 use FluentCommunity\App\Services\LockscreenService;
9 use FluentCommunity\Framework\Http\Request\Request;
10 use FluentCommunity\Framework\Support\Arr;
11 use FluentCommunity\Modules\Course\Model\Course;
12 use FluentCommunity\Modules\Course\Model\CourseLesson;
13 use FluentCommunity\Modules\Course\Model\CourseTopic;
14 use FluentCommunity\App\Services\FeedsHelper;
15 use FluentCommunity\Modules\Course\Services\CourseHelper;
16
17 class CourseController extends Controller
18 {
19 public function getCourses(Request $request)
20 {
21 $user = $this->getUser();
22 $isCourseCreator = $user && $user->hasCourseCreatorAccess();
23 $enrolledIds = CourseHelper::getEnrolledCourseIds();
24
25 $search = $request->getSafe('search');
26 $topicSlug = $request->getSafe('topic_slug');
27 $isEnrolled = $request->getSafe('type') == 'enrolled';
28 $sortBy = $request->getSafe('sort_by', 'sanitize_text_field', 'alphabetical');
29
30 $courses = Course::searchBy($search)
31 ->where(function ($q) use ($isCourseCreator, $isEnrolled, $user) {
32 if ($isCourseCreator && !$isEnrolled) {
33 $q->where('status', 'published')
34 ->orWhere('created_by', $user->ID);
35 } else {
36 $q->where('status', 'published');
37 }
38 })
39 ->byPostTopic($topicSlug)
40 ->where(function ($q) use ($enrolledIds) {
41 $q->whereIn('privacy', ['public', 'private']);
42 $q->orWhereIn('id', $enrolledIds);
43 })
44 ->when($isEnrolled, function ($q) use ($enrolledIds) {
45 $q->whereIn('id', $enrolledIds);
46 })
47 ->when($sortBy == 'alphabetical', function ($q) {
48 $q->orderBy('title', 'ASC');
49 })
50 ->when($sortBy == 'oldest', function ($q) {
51 $q->orderBy('created_at', 'ASC');
52 })
53 ->when($sortBy == 'latest', function ($q) {
54 $q->orderBy('created_at', 'DESC');
55 })
56 ->paginate();
57
58 foreach ($courses as $course) {
59 $course->isEnrolled = CourseHelper::isEnrolled($course->id);
60 if ($course->isEnrolled) {
61 $course->progress = CourseHelper::getCourseProgress($course->id);
62 }
63
64 if (!$course->cover_photo) {
65 $course->cover_photo = FLUENT_COMMUNITY_PLUGIN_URL . 'assets/images/course-placeholder.jpg';
66 }
67
68 $course->sectionsCount = CourseTopic::where('space_id', $course->id)->count();
69 $course->lessonsCount = CourseLesson::where('space_id', $course->id)->count();
70 if (Arr::get($course->settings, 'hide_members_count') != 'yes') {
71 $course->studentsCount = SpaceUserPivot::where('space_id', $course->id)->count();
72 } else {
73 $course->studentsCount = 0;
74 }
75 }
76
77 $data = [
78 'courses' => $courses,
79 'course_categories' => $request->get('with_categories') ? CourseHelper::getCourseCategories() : []
80 ];
81
82 return apply_filters('fluent_community/courses_api_response', $data, $request->all());
83 }
84
85 public function getCourse(Request $request, $courseId)
86 {
87 $user = $this->getUser();
88
89 $course = Course::findOrFail($courseId);
90
91 $isCourseCreator = $course->isCourseAdmin($user);
92
93 if ($course->status !== 'published' && !$isCourseCreator) {
94 return $this->sendError([
95 'message' => __('Course not found. maybe the course is not published yet!', 'fluent-community')
96 ]);
97 }
98
99 $intendtedLessonSlug = $request->get('intended_lesson_slug');
100
101 $data = $this->processCourse($course, $isCourseCreator, $intendtedLessonSlug);
102
103 return apply_filters('fluent_community/get_course_api_response', $data, $request->all());
104 }
105
106 public function getCourseBySlug(Request $request, $slug)
107 {
108 $user = $this->getUser();
109
110 $course = Course::where('slug', $slug)->firstOrFail();
111
112 $isCourseCreator = $course->isCourseAdmin($user);
113
114 if ($course->status !== 'published' && !$isCourseCreator) {
115 return $this->sendError([
116 'message' => __('Course not found. maybe the course is not published yet!', 'fluent-community')
117 ]);
118 }
119
120 $hideInstructorView = Arr::get($course->settings, 'hide_instructor_view') == 'yes';
121 $showStudentCount = Arr::get($course->settings, 'show_instructor_students_count') == 'yes';
122 if (!$hideInstructorView) {
123 $course->load(['creator']);
124 if ($course->creator) {
125 $creatorCourseIds = Course::where('created_by', $course->creator->user_id)->pluck('id');
126 $course->creator->total_courses = count($creatorCourseIds);
127 if ($showStudentCount) {
128 $course->creator->total_students = SpaceUserPivot::whereIn('space_id', $creatorCourseIds)->distinct('user_id')->count('user_id');
129 }
130 if ($course->creator->short_description) {
131 $course->creator->short_description_rendered = wp_kses_post(FeedsHelper::mdToHtml($course->creator->short_description));
132 }
133 }
134 }
135
136 $intendtedLessonSlug = $request->get('intended_lesson_slug');
137
138 $data = $this->processCourse($course, $isCourseCreator, $intendtedLessonSlug);
139
140 return apply_filters('fluent_community/course_api_response', $data, $request->all());
141 }
142
143 public function getLessonBySlug(Request $request, $courseSlug, $lessonSlug)
144 {
145 $user = $this->getUser();
146
147 $course = Course::where('slug', $courseSlug)->firstOrFail();
148
149 $isCourseCreator = $course->isCourseAdmin($user);
150
151 if ($course->status !== 'published' && !$isCourseCreator) {
152 return $this->sendError([
153 'message' => __('Course not found. maybe the course is not published yet!', 'fluent-community')
154 ]);
155 }
156
157 $lesson = CourseLesson::where('space_id', $course->id)
158 ->where('slug', $lessonSlug)
159 ->when(!$isCourseCreator, function ($q) {
160 $q->where('status', 'published');
161 })
162 ->with(['topic'])
163 ->firstOrFail();
164
165 if (!$lesson || !$lesson->topic) {
166 return $this->sendError([
167 'message' => __('Lesson not found. maybe the lesson is not published yet!', 'fluent-community')
168 ]);
169 }
170
171 $enrollment = CourseHelper::getCourseEnrollment($course->id);
172
173 if ($course->privacy == 'secret' && !$enrollment && !$isCourseCreator) {
174 return $this->sendError([
175 'message' => __('You must need to be invited to view this course', 'fluent-community')
176 ]);
177 }
178
179 $section = $lesson->topic;
180 $hasAcessSectionAcess = !!$enrollment;
181 $unlockDate = '';
182 $courseType = $course->getCourseType();
183 $hasPublicViewAccess = $course->privacy == 'public' && Arr::get($course->settings, 'public_lesson_view') == 'yes' && $courseType == 'self_paced';
184 if ($hasAcessSectionAcess) {
185 $unlockDate = CourseHelper::getSectionAccessDate($section, $courseType, $enrollment);
186 if ($unlockDate && strtotime($unlockDate) > current_time('timestamp')) {
187 $hasAcessSectionAcess = false;
188 } else {
189 $unlockDate = null;
190 }
191 }
192
193 $canViewLesson = $hasAcessSectionAcess || $isCourseCreator || $hasPublicViewAccess;
194 $canViewLesson = apply_filters('fluent_community/course/can_view_lesson', $canViewLesson, $lesson, $course, $this->getUser());
195
196 $formattedLesson = CourseHelper::formatLessonData($course, $lesson, $user, [
197 'can_view' => $canViewLesson,
198 'parse_content' => $canViewLesson,
199 'is_locked' => !$hasAcessSectionAcess && !$isCourseCreator,
200 'unclock_date' => $unlockDate
201 ]);
202
203 $data = [
204 'lesson' => $formattedLesson
205 ];
206
207 return apply_filters('fluent_community/course_lesson_api_response', $data, $request->all());
208 }
209
210 private function processCourse(Course $course, $isCourseCreator, $intendtedLessonSlug = '')
211 {
212 $sections = CourseTopic::where('space_id', $course->id)
213 ->orderBy('priority', 'ASC')
214 ->with(['lessons' => function ($query) use ($isCourseCreator) {
215 if (!$isCourseCreator) {
216 $query->where('status', 'published');
217 }
218 }])
219 ->get();
220
221 $enrollment = CourseHelper::getCourseEnrollment($course->id);
222
223 $currentUser = Helper::getCurrentUser();
224
225 if ($course->privacy == 'private' && !$enrollment) {
226 $course->lockscreen_config = LockscreenService::getLockscreenConfig($course, null, true);
227 }
228
229 if ($course->privacy == 'secret' && !$enrollment && !$isCourseCreator) {
230 return $this->sendError([
231 'message' => __('You must need to be invited to view this course', 'fluent-community')
232 ]);
233 }
234
235 $course->is_course_admin = $isCourseCreator;
236
237 $courseSettings = $course->settings;
238 if (Arr::get($courseSettings, 'course_details')) {
239 $courseSettings['course_details_rendered'] = wp_kses_post(FeedsHelper::mdToHtml($courseSettings['course_details']));
240 $course->settings = $courseSettings;
241 }
242
243 $courseType = $course->getCourseType();
244
245 $hasPublicViewAccess = $course->privacy == 'public' && Arr::get($course->settings, 'public_lesson_view') == 'yes' && $courseType == 'self_paced';
246
247 $formattedSections = [];
248
249 foreach ($sections as $section) {
250 if ($section->lessons->isEmpty()) {
251 continue;
252 }
253
254 $hasAcessSectionAcess = !!$enrollment;
255 $unlockDate = '';
256
257 if ($hasAcessSectionAcess) {
258 $unlockDate = CourseHelper::getSectionAccessDate($section, $courseType, $enrollment);
259 if ($unlockDate && strtotime($unlockDate) > current_time('timestamp')) {
260 $hasAcessSectionAcess = false;
261 } else {
262 $unlockDate = null;
263 }
264 }
265
266 $formattedLessons = [];
267 foreach ($section->lessons as $lesson) {
268 $canViewLesson = $hasAcessSectionAcess || $isCourseCreator || $hasPublicViewAccess;
269 $canViewLesson = apply_filters('fluent_community/course/can_view_lesson', $canViewLesson, $lesson, $course, $this->getUser());
270
271 $parseContent = $intendtedLessonSlug === $lesson->slug && $canViewLesson;
272
273 $formattedLesson = CourseHelper::formatLessonData($course, $lesson, $currentUser, [
274 'can_view' => $canViewLesson,
275 'parse_content' => $parseContent,
276 'is_locked' => !$hasAcessSectionAcess && !$isCourseCreator,
277 'unclock_date' => $unlockDate
278 ]);
279
280 $isLazyLoad = !$parseContent;
281 if(!$canViewLesson) {
282 $isLazyLoad = false;
283 }
284
285 $formattedLesson['lazy_load'] = $isLazyLoad;
286
287 $formattedLessons[] = $formattedLesson;
288 }
289
290 $formattedSections[] = [
291 'id' => $section->id,
292 'title' => $section->title,
293 'lessons' => $formattedLessons,
294 'created_at' => $section->created_at,
295 'slug' => $section->slug,
296 'type' => 'section',
297 'is_locked' => !$hasAcessSectionAcess && !$isCourseCreator,
298 'unlock_date' => $unlockDate
299 ];
300 }
301
302 return [
303 'course' => $course,
304 'sections' => $formattedSections,
305 'track' => CourseHelper::getCourseProgressTrack($course->id)
306 ];
307 }
308
309 public function enrollCourse(Request $request, $courseId)
310 {
311 $user = $this->getUser();
312
313 if (!$user) {
314 return $this->sendError([
315 'message' => __('You need to login to enroll in this course.', 'fluent-community')
316 ]);
317 }
318
319 $course = Course::findOrFail($courseId);
320
321 $isCourseCreator = $course->isCourseAdmin($user);
322
323 if ($course->status !== 'published' && !$isCourseCreator) {
324 return $this->sendError([
325 'message' => __('Course not found. maybe the course is not published yet!', 'fluent-community')
326 ]);
327 }
328
329 if (!$isCourseCreator && $course->privacy != 'public') {
330 return $this->sendError([
331 'message' => __('You are not allowed to enroll in this course.', 'fluent-community')
332 ]);
333 }
334
335 $enrolled = CourseHelper::enrollCourse($course, get_current_user_id());
336
337 if (!$enrolled) {
338 return [
339 'message' => __('You are already enrolled in this course.', 'fluent-community'),
340 'track' => CourseHelper::getCourseProgressTrack($courseId)
341 ];
342 }
343
344 return [
345 'message' => __('You have been enrolled in this course.', 'fluent-community'),
346 'track' => CourseHelper::getCourseProgressTrack($courseId)
347 ];
348 }
349
350 public function updateCompletionLesson(Request $request, $courseId, $lessonId)
351 {
352 $course = Course::findOrFail($courseId);
353
354 if ($course->status != 'published') {
355 return $this->sendError([
356 'message' => __('Course is not in published state.', 'fluent-community')
357 ]);
358 }
359
360
361 if (!CourseHelper::isEnrolled($courseId)) {
362 return $this->sendError([
363 'message' => __('Please enroll this course first', 'fluent-community')
364 ]);
365 }
366
367 $lesson = CourseLesson::where('space_id', $courseId)
368 ->where('status', 'published')
369 ->where('id', $lessonId)
370 ->first();
371
372 if (!$lesson) {
373 return $this->sendError([
374 'message' => __('Lesson is not on published state.', 'fluent-community')
375 ]);
376 }
377
378 $state = $request->get('state');
379
380 if (!in_array($state, ['completed', 'incomplete'])) {
381 return $this->sendError([
382 'message' => __('Invalid state.', 'fluent-community')
383 ]);
384 }
385
386 $isAllowed = apply_filters('fluent_community/is_allowed_to_complete_lesson', true, $lesson);
387
388 if (!$isAllowed) {
389 return $this->sendError([
390 'message' => __('You are not allowed to complete this lesson.', 'fluent-community')
391 ]);
392 }
393
394 CourseHelper::updateLessonCompletion($lesson, get_current_user_id(), $state);
395 $track = CourseHelper::getCourseProgressTrack($courseId);
396 $isCompleted = $track['progress'] == 100;
397
398 if ($isCompleted) {
399 CourseHelper::completeCourse($course, $lesson, get_current_user_id());
400 }
401
402 return [
403 'message' => __('Lesson completion state updated.', 'fluent-community'),
404 'track' => $track,
405 'is_completed' => $isCompleted
406 ];
407 }
408
409 public function getAllCourses(Request $request)
410 {
411 $user = $this->getUser();
412 $isCourseCreator = $user && $user->hasCourseCreatorAccess();
413
414 $courses = Course::where(function ($q) use ($isCourseCreator, $user) {
415 if ($isCourseCreator) {
416 $q->where('status', 'published')
417 ->orWhere('created_by', $user->ID);
418 } else {
419 $q->where('status', 'published');
420 }
421 })
422 ->with(['creator'])
423 ->paginate();
424
425 $formattedCourses = [];
426 foreach ($courses as $course) {
427 $course->sectionsCount = CourseTopic::where('space_id', $course->id)->count();
428 $course->lessonsCount = CourseLesson::where('space_id', $course->id)->count();
429
430 if (Arr::get($course->settings, 'hide_members_count') != 'yes') {
431 $course->studentsCount = SpaceUserPivot::where('space_id', $course->id)->count();
432 } else {
433 $course->studentsCount = 0;
434 }
435
436 $showInstructorView = Arr::get($course->settings, 'hide_instructor_view') != 'yes';
437 $showStudentCount = Arr::get($course->settings, 'show_instructor_students_count') == 'yes';
438 if ($showInstructorView) {
439 if ($course->creator) {
440 $creatorCourseIds = Course::where('created_by', $course->creator->user_id)->pluck('id');
441 $course->creator->total_courses = count($creatorCourseIds);
442 if ($showStudentCount) {
443 $course->creator->total_students = SpaceUserPivot::whereIn('space_id', $creatorCourseIds)->distinct('user_id')->count('user_id');
444 }
445 if ($course->creator->short_description) {
446 $course->creator->short_description_rendered = wp_kses_post(FeedsHelper::mdToHtml($course->creator->short_description));
447 }
448 }
449 }
450
451 $formattedCourses[] = $this->processCourse($course, $course->isCourseAdmin($user));
452 }
453
454 return apply_filters('fluent_community/all_courses_api_response', [
455 'courses' => $formattedCourses,
456 'total' => $courses->total()
457 ], $request->all());
458 }
459 }
460