PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.11.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.11.0
2.11.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 All 78 releases
← All changes | Modules/Course/Http/Controllers/CourseAdminController.php +47 -8 2.9.02.11.0 View file →
@@ -85,9 +85,9 @@
85 85 $courseData = [
86 86 'parent_id' => $request->get('parent_id') ?: null, // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
87 87 'title' => $request->getSafe('title', 'sanitize_text_field'),
88 88 'privacy' => $request->get('privacy'),
89 - 'description' => wp_kses_post($request->get('description')),
89 + 'description' => wp_kses_post((string) $request->get('description', '')),
90 90 'status' => $request->get('status', 'draft'),
91 91 'settings' => [
92 92 'course_type' => $request->get('course_type'),
93 93 'emoji' => CustomSanitizer::sanitizeEmoji($request->get('settings.emoji', '')),
@@ -94,9 +94,9 @@
94 94 'shape_svg' => CustomSanitizer::sanitizeSvg($request->get('settings.shape_svg', '')),
95 95 'disable_comments' => $request->get('settings.disable_comments') === 'yes' ? 'yes' : 'no',
96 96 'hide_members_count' => $request->get('settings.hide_members_count') === 'yes' ? 'yes' : 'no',
97 97 'course_layout' => $request->get('settings.course_layout') === 'modern' ? 'modern' : 'classic',
98 - 'course_details' => CustomSanitizer::unslashMarkdown(trim($request->get('settings.course_details'))),
98 + 'course_details' => CustomSanitizer::unslashMarkdown(trim((string) $request->get('settings.course_details', ''))),
99 99 'hide_instructor_view' => $request->get('settings.hide_instructor_view') === 'yes' ? 'yes' : 'no',
100 100 'show_instructor_students_count' => $request->get('settings.show_instructor_students_count') === 'yes' ? 'yes' : 'no',
101 101 'sequential_lesson_order' => $request->get('settings.sequential_lesson_order') === 'yes' ? 'yes' : 'no',
102 102 ],
@@ -229,9 +229,9 @@
229 229
230 230 $courseData = [
231 231 'title' => $request->getSafe('title', 'sanitize_text_field'),
232 232 'privacy' => $request->get('privacy'),
233 - 'description' => wp_kses_post($request->get('description')),
233 + 'description' => wp_kses_post((string) $request->get('description', '')),
234 234 'status' => $request->get('status'),
235 235 'cover_photo' => $request->getSafe('cover_photo', 'sanitize_url'),
236 236 'parent_id' => $request->get('parent_id') ?: null, // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
237 237 ];
@@ -303,9 +303,9 @@
303 303 $existingSettings['show_instructor_students_count'] = $request->get('settings.show_instructor_students_count') === 'yes' ? 'yes' : 'no';
304 304 $existingSettings['show_paywalls'] = $request->get('settings.show_paywalls') === 'yes' ? 'yes' : 'no';
305 305 $existingSettings['show_welcome_banner'] = $request->get('settings.show_welcome_banner') === 'yes' ? 'yes' : 'no';
306 306 $existingSettings['course_layout'] = $request->get('settings.course_layout') === 'modern' ? 'modern' : 'classic';
307 - $existingSettings['course_details'] = CustomSanitizer::unslashMarkdown(trim($request->get('settings.course_details')));
307 + $existingSettings['course_details'] = CustomSanitizer::unslashMarkdown(trim((string) $request->get('settings.course_details', '')));
308 308 $existingSettings['sequential_lesson_order'] = $request->get('settings.sequential_lesson_order') === 'yes' ? 'yes' : 'no';
309 309
310 310 if ($request->get('privacy') == 'public' && $existingSettings['course_type'] == 'self_paced') {
311 311 $existingSettings['public_lesson_view'] = $request->get('settings.public_lesson_view') == 'yes' ? 'yes' : 'no';
@@ -383,8 +383,10 @@
383 383 $newTopic = $topic->replicate();
384 384 $newTopic->space_id = $newCourse->id;
385 385 $newTopic->save();
386 386
387 + do_action('fluent_community/section/created', $newTopic, $newCourse);
388 +
387 389 foreach ($topic->lessons as $lesson) {
388 390 /** @var CourseLesson $lesson */
389 391 $newLesson = $lesson->replicate();
390 392 $newLesson->space_id = $newCourse->id;
@@ -390,8 +392,10 @@
390 392 $newLesson->space_id = $newCourse->id;
391 393 $newLesson->parent_id = $newTopic->id;
392 394 $newLesson->save();
393 395 CourseHelper::copyLessonDocuments($lesson, $newLesson);
396 +
397 + do_action('fluent_community/lesson/created', $newLesson, $newTopic);
394 398 }
395 399 }
396 400
397 401 do_action('fluent_community/course/created', $newCourse);
@@ -603,9 +607,13 @@
603 607 'message' => __('This student is not enrolled in this course.', 'fluent-community'),
604 608 ]);
605 609 }
606 610
607 - CourseHelper::resetCourseProgress($courseId, (int) $studentId);
611 + if (!CourseHelper::resetCourseProgress($courseId, (int) $studentId)) {
612 + return $this->sendError([
613 + 'message' => __("Student's progress could not be reset. Please try again.", 'fluent-community'),
614 + ]);
615 + }
608 616
609 617 return [
610 618 'message' => __("Student's progress has been reset.", 'fluent-community'),
611 619 ];
@@ -735,9 +743,9 @@
735 743 'space_id' => $courseId,
736 744 'status' => 'published',
737 745 ];
738 746
739 - Course::findOrFail($courseId);
747 + $course = Course::findOrFail($courseId);
740 748
741 749 $latestPriority = CourseTopic::where('type', 'course_section')->where('space_id', $courseId)->max('priority');
742 750
743 751 $sectionData['priority'] = (int) $latestPriority + 1;
@@ -745,8 +753,10 @@
745 753 $section = CourseTopic::create($sectionData);
746 754
747 755 $section->load('lessons');
748 756
757 + do_action('fluent_community/section/created', $section, $course);
758 +
749 759 return [
750 760 'message' => __('Section has been created successfully.', 'fluent-community'),
751 761 'section' => $section,
752 762 ];
@@ -868,8 +878,10 @@
868 878 $newSection->space_id = $toCourse->id;
869 879 $newSection->priority = (int) $latestPriority + 1;
870 880 $newSection->save();
871 881
882 + do_action('fluent_community/section/created', $newSection, $toCourse);
883 +
872 884 $originalLessons = CourseLesson::where('parent_id', $originalSection->id)->get();
873 885 foreach ($originalLessons as $lesson) {
874 886 /** @var CourseLesson $lesson */
875 887 $newLesson = $lesson->replicate();
@@ -876,8 +888,10 @@
876 888 $newLesson->space_id = $toCourse->id;
877 889 $newLesson->parent_id = $newSection->id;
878 890 $newLesson->save();
879 891 CourseHelper::copyLessonDocuments($lesson, $newLesson);
892 +
893 + do_action('fluent_community/lesson/created', $newLesson, $newSection);
880 894 }
881 895
882 896 $newSection->load('lessons');
883 897
@@ -989,8 +1003,10 @@
989 1003 $lesson = CourseLesson::create($lessonData);
990 1004
991 1005 $lesson = CourseLesson::findOrFail($lesson->id);
992 1006
1007 + do_action('fluent_community/lesson/created', $lesson, $topic);
1008 +
993 1009 return [
994 1010 'message' => __('Lesson has been created successfully.', 'fluent-community'),
995 1011 'lesson' => $lesson,
996 1012 ];
@@ -1068,8 +1084,12 @@
1068 1084 if ($dirtyFields) {
1069 1085 $lesson->save();
1070 1086 $isNewlyPublished = $lesson->status === 'published' && $previousStatus !== 'published';
1071 1087 do_action('fluent_community/lesson/updated', $lesson, $dirtyFields, $isNewlyPublished);
1088 +
1089 + if ($isNewlyPublished) {
1090 + do_action('fluent_community/lesson/published', $lesson);
1091 + }
1072 1092 }
1073 1093
1074 1094 do_action('fluent_community/lesson/additional_media_updated', $request->all(), $lesson, $updateData);
1075 1095
@@ -1086,8 +1106,10 @@
1086 1106 })
1087 1107 ->where('id', $lessionId)
1088 1108 ->firstOrFail();
1089 1109
1110 + $previousStatus = $lesson->status;
1111 +
1090 1112 $acceptedFields = [ 'title', 'status', 'slug' ];
1091 1113
1092 1114 // empty title/slug/status must not overwrite, but a literal "0" is a valid value
1093 1115 // Request::only() is a plain array pick with no sanitization, so each field is
@@ -1101,9 +1123,16 @@
1101 1123 $lessonData['title'] = sanitize_text_field($lessonData['title']);
1102 1124 }
1103 1125
1104 1126 if (isset($lessonData['slug'])) {
1105 - $lessonData['slug'] = sanitize_title($lessonData['slug']);
1127 + // sanitize_title() alone let an author set a slug already taken by a
1128 + // sibling lesson, which getLessonBySlug() then resolves arbitrarily.
1129 + $lessonData['slug'] = CourseLesson::uniqueSlug(
1130 + $lessonData['slug'],
1131 + $lesson->space_id,
1132 + $lesson->id,
1133 + Arr::get($lessonData, 'title', $lesson->title)
1134 + );
1106 1135 }
1107 1136
1108 1137 if (isset($lessonData['status']) && !in_array($lessonData['status'], ['draft', 'published', 'archived'], true)) {
1109 1138 unset($lessonData['status']);
@@ -1121,10 +1150,19 @@
1121 1150 }
1122 1151
1123 1152 if (!empty($lessonData)) {
1124 1153 $lesson->fill($lessonData);
1125 - if ($lesson->isDirty()) {
1154 + $dirtyFields = $lesson->getDirty();
1155 +
1156 + if ($dirtyFields) {
1126 1157 $lesson->save();
1158 +
1159 + $isNewlyPublished = $lesson->status === 'published' && $previousStatus !== 'published';
1160 + do_action('fluent_community/lesson/updated', $lesson, $dirtyFields, $isNewlyPublished);
1161 +
1162 + if ($isNewlyPublished) {
1163 + do_action('fluent_community/lesson/published', $lesson);
1164 + }
1127 1165 }
1128 1166 }
1129 1167
1130 1168 return [
@@ -1199,8 +1237,9 @@
1199 1237 $newLesson = CourseLesson::findOrFail($newLesson->id);
1200 1238
1201 1239 CourseHelper::copyLessonDocuments($lesson, $newLesson);
1202 1240
1241 + do_action('fluent_community/lesson/created', $newLesson, $newLesson->topic);
1203 1242 do_action('fluent_community/lesson/duplicated', $newLesson, $lesson);
1204 1243
1205 1244 return [
1206 1245 'message' => __('Lesson has been duplicated successfully.', 'fluent-community'),