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 +54 -9 2.8.12.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
@@ -951,8 +965,11 @@
951 965
952 966 return apply_filters('fluent_community/admin_course_lesson_api_response', $data, $request->all());
953 967 }
954 968
969 + /**
970 + * Expects `title` and `section_id` at the top level of the request.
971 + */
955 972 public function createLesson(Request $request, $courseId)
956 973 {
957 974 $this->validate($request->all(), [
958 975 'title' => 'required',
@@ -986,8 +1003,10 @@
986 1003 $lesson = CourseLesson::create($lessonData);
987 1004
988 1005 $lesson = CourseLesson::findOrFail($lesson->id);
989 1006
1007 + do_action('fluent_community/lesson/created', $lesson, $topic);
1008 +
990 1009 return [
991 1010 'message' => __('Lesson has been created successfully.', 'fluent-community'),
992 1011 'lesson' => $lesson,
993 1012 ];
@@ -992,13 +1011,16 @@
992 1011 'lesson' => $lesson,
993 1012 ];
994 1013 }
995 1014
1015 + /**
1016 + * Expects the fields nested under `lesson`, referencing the section as `parent_id`.
1017 + */
996 1018 public function updateLesson(Request $request, $courseId, $lessionId)
997 1019 {
998 1020 Course::findOrFail($courseId);
999 1021
1000 - $lessonData = $request->get('lesson');
1022 + $lessonData = (array)$request->get('lesson');
1001 1023
1002 1024 $this->validate($lessonData, [
1003 1025 'title' => 'required',
1004 1026 'parent_id' => 'required',
@@ -1062,8 +1084,12 @@
1062 1084 if ($dirtyFields) {
1063 1085 $lesson->save();
1064 1086 $isNewlyPublished = $lesson->status === 'published' && $previousStatus !== 'published';
1065 1087 do_action('fluent_community/lesson/updated', $lesson, $dirtyFields, $isNewlyPublished);
1088 +
1089 + if ($isNewlyPublished) {
1090 + do_action('fluent_community/lesson/published', $lesson);
1091 + }
1066 1092 }
1067 1093
1068 1094 do_action('fluent_community/lesson/additional_media_updated', $request->all(), $lesson, $updateData);
1069 1095
@@ -1080,8 +1106,10 @@
1080 1106 })
1081 1107 ->where('id', $lessionId)
1082 1108 ->firstOrFail();
1083 1109
1110 + $previousStatus = $lesson->status;
1111 +
1084 1112 $acceptedFields = [ 'title', 'status', 'slug' ];
1085 1113
1086 1114 // empty title/slug/status must not overwrite, but a literal "0" is a valid value
1087 1115 // Request::only() is a plain array pick with no sanitization, so each field is
@@ -1095,9 +1123,16 @@
1095 1123 $lessonData['title'] = sanitize_text_field($lessonData['title']);
1096 1124 }
1097 1125
1098 1126 if (isset($lessonData['slug'])) {
1099 - $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 + );
1100 1135 }
1101 1136
1102 1137 if (isset($lessonData['status']) && !in_array($lessonData['status'], ['draft', 'published', 'archived'], true)) {
1103 1138 unset($lessonData['status']);
@@ -1115,10 +1150,19 @@
1115 1150 }
1116 1151
1117 1152 if (!empty($lessonData)) {
1118 1153 $lesson->fill($lessonData);
1119 - if ($lesson->isDirty()) {
1154 + $dirtyFields = $lesson->getDirty();
1155 +
1156 + if ($dirtyFields) {
1120 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 + }
1121 1165 }
1122 1166 }
1123 1167
1124 1168 return [
@@ -1193,8 +1237,9 @@
1193 1237 $newLesson = CourseLesson::findOrFail($newLesson->id);
1194 1238
1195 1239 CourseHelper::copyLessonDocuments($lesson, $newLesson);
1196 1240
1241 + do_action('fluent_community/lesson/created', $newLesson, $newLesson->topic);
1197 1242 do_action('fluent_community/lesson/duplicated', $newLesson, $lesson);
1198 1243
1199 1244 return [
1200 1245 'message' => __('Lesson has been duplicated successfully.', 'fluent-community'),