From 9cba627d450b8bfa682f1b7a4d4b7578c7265025 Mon Sep 17 00:00:00 2001 From: Dmitry Merkushin Date: Wed, 27 Sep 2023 18:20:53 -0600 Subject: [PATCH] Use repository instead of comments directly, complete lesson/quiz properly --- includes/class-sensei-course.php | 4 +- includes/class-sensei-grading.php | 29 +++++++------ includes/class-sensei-quiz.php | 19 +++++---- includes/class-sensei-utils.php | 70 ++++++++++++++++++++----------- 4 files changed, 74 insertions(+), 48 deletions(-) diff --git a/includes/class-sensei-course.php b/includes/class-sensei-course.php index 190b06aa3f4..0e54f60847e 100755 --- a/includes/class-sensei-course.php +++ b/includes/class-sensei-course.php @@ -1551,11 +1551,11 @@ public function course_count( $post_status = 'publish' ) { /** - * course_lessons function. + * Get course lessons. * * @access public * - * @param int $course_id (default: 0). The course id. + * @param int|WP_Post $course_id (default: 0). The course id. * @param string|array $post_status (default: 'publish'). The post status. * @param string $fields (default: 'all'). WP only allows 3 types, but we will limit it to only 'ids' or 'all'. * @param array $query_args Base arguments for the WP query. diff --git a/includes/class-sensei-grading.php b/includes/class-sensei-grading.php index 2b16bbb8a72..60477941a88 100755 --- a/includes/class-sensei-grading.php +++ b/includes/class-sensei-grading.php @@ -688,6 +688,11 @@ public function admin_process_grading_submission() { // store the feedback from grading Sensei()->quiz->save_user_answers_feedback( $all_answers_feedback, $quiz_lesson_id, $user_id ); + $lesson_progress = Sensei()->lesson_progress_repository->get( $quiz_lesson_id, $user_id ); + if ( ! $lesson_progress ) { + $lesson_progress = Sensei()->lesson_progress_repository->create( $quiz_lesson_id, $user_id ); + } + $quiz_progress = Sensei()->quiz_progress_repository->get( $quiz_id, $user_id ); if ( ! $quiz_progress ) { return false; @@ -712,6 +717,9 @@ public function admin_process_grading_submission() { if ( $pass_required ) { // Student has reached the pass mark and lesson is complete. if ( $quiz_passmark <= $grade ) { + // Due to our internal logic, we need to complete the lesson first. + // This is because in the comments-based version the lesson status is used for both the lesson and the quiz. + $lesson_progress->complete(); $lesson_status = 'passed'; $quiz_progress->pass(); } else { @@ -722,11 +730,17 @@ public function admin_process_grading_submission() { // Student only has to partake the quiz. else { + $lesson_progress->complete(); $lesson_status = 'graded'; $quiz_progress->grade(); } } + // Due to our internal logic, we need to save the lesson progress first. + // This is because in the comments-based version the lesson status is used for both the lesson and the quiz. + // And in this context the quiz status should be preserved in the comments-based version. + // For the tables-based version the order does not matter. + Sensei()->lesson_progress_repository->save( $lesson_progress ); Sensei()->quiz_progress_repository->save( $quiz_progress ); if ( count( $lesson_metadata ) ) { foreach ( $lesson_metadata as $key => $value ) { @@ -734,22 +748,13 @@ public function admin_process_grading_submission() { } } - if ( in_array( $lesson_status, [ 'passed', 'graded' ], true ) ) { + if ( $lesson_progress->is_complete() ) { - /** - * Fires when a user completes a lesson. - * - * This hook is fired when a user passes a quiz or their quiz submission was graded. - * Therefore the corresponding lesson is marked as complete. - * - * @since 1.7.0 - * - * @param int $user_id - * @param int $quiz_lesson_id - */ + /* The action is documented in includes/class-sensei-utils.php */ do_action( 'sensei_user_lesson_end', $user_id, $quiz_lesson_id ); } + if ( isset( $_POST['sensei_grade_next_learner'] ) && strlen( $_POST['sensei_grade_next_learner'] ) > 0 ) { $load_url = add_query_arg( array( 'message' => 'graded' ) ); diff --git a/includes/class-sensei-quiz.php b/includes/class-sensei-quiz.php index 56b286afbe4..d97dd225cf4 100755 --- a/includes/class-sensei-quiz.php +++ b/includes/class-sensei-quiz.php @@ -920,6 +920,11 @@ public static function submit_answers_for_grading( $quiz_answers, $files = array Sensei_Utils::user_start_lesson( $user_id, $lesson_id ); } + $lesson_progress = Sensei()->lesson_progress_repository->get( $lesson_id, $user_id ); + if ( ! $lesson_progress ) { + $lesson_progress = Sensei()->lesson_progress_repository->create( $lesson_id, $user_id ); + } + $quiz_progress = Sensei()->quiz_progress_repository->get( $quiz_id, $user_id ); if ( ! $quiz_progress ) { // Even after starting a lesson we can't find the progress. Leave immediately. @@ -948,6 +953,7 @@ public static function submit_answers_for_grading( $quiz_answers, $files = array // Student has reached the pass mark and lesson is complete. if ( $quiz_pass_percentage <= $grade ) { + $lesson_progress->complete(); $quiz_progress->pass(); $lesson_status = 'passed'; } else { @@ -956,26 +962,21 @@ public static function submit_answers_for_grading( $quiz_answers, $files = array } } else { // Student only has to partake the quiz. + $lesson_progress->complete(); $quiz_progress->grade(); $lesson_status = 'graded'; } } + Sensei()->lesson_progress_repository->save( $lesson_progress ); Sensei()->quiz_progress_repository->save( $quiz_progress ); foreach ( $lesson_metadata as $key => $value ) { update_comment_meta( $quiz_progress->get_id(), $key, $value ); } - if ( 'passed' === $lesson_status || 'graded' === $lesson_status ) { + if ( $lesson_progress->is_complete() ) { - /** - * Lesson end action hook - * - * This hook is fired after a lesson quiz has been graded and the lesson status is 'passed' OR 'graded' - * - * @param int $user_id - * @param int $lesson_id - */ + /* The action is documented in includes/class-sensei-utils.php */ do_action( 'sensei_user_lesson_end', $user_id, $lesson_id ); } diff --git a/includes/class-sensei-utils.php b/includes/class-sensei-utils.php index 0d0197c0981..ca0c1e47e9a 100644 --- a/includes/class-sensei-utils.php +++ b/includes/class-sensei-utils.php @@ -516,7 +516,15 @@ public static function sensei_start_lesson( $lesson_id = 0, $user_id = 0, $compl } } - // Note: When this action runs the lesson status may not yet exist. + /** + * Fires when a user starts a lesson. + * When this action runs the lesson status may not yet exist. + * + * @hook sensei_user_lesson_start + * + * @param {int} $user_id ID of user starting lesson. + * @param {int} $lesson_id ID of lesson being started. + */ do_action( 'sensei_user_lesson_start', $user_id, $lesson_id ); $lesson_progress = Sensei()->lesson_progress_repository->get( $lesson_id, $user_id ); @@ -534,7 +542,17 @@ public static function sensei_start_lesson( $lesson_id = 0, $user_id = 0, $compl } if ( $complete ) { - // Run this *after* the lesson status has been created/updated. + /** + * Fires when a user completes a lesson. + * + * This hook is fired when a user completes a lesson, passes a quiz or their quiz submission was graded. + * Therefore the corresponding lesson is marked as complete. + * + * @since 1.7.0 + * + * @param int $user_id + * @param int $lesson_id + */ do_action( 'sensei_user_lesson_end', $user_id, $lesson_id ); } @@ -1394,7 +1412,6 @@ public static function user_complete_course( $course_id = 0, $user_id = 0, $trig $course_progress->start(); } - $course_completion = Sensei()->settings->settings['course_completion']; $lessons_completed = 0; $lesson_status_args = array( 'user_id' => $user_id, @@ -1415,29 +1432,17 @@ public static function user_complete_course( $course_id = 0, $user_id = 0, $trig // ...if all lessons 'passed' then update the course status to complete // The below checks if a lesson is fully completed, though maybe should be Utils::user_completed_lesson() $lesson_status_args['post__in'] = $lesson_ids; - $all_lesson_statuses = self::sensei_check_for_activity( $lesson_status_args, true ); - // Need to always return an array, even with only 1 item. - if ( ! is_array( $all_lesson_statuses ) ) { - $all_lesson_statuses = array( $all_lesson_statuses ); - } - - foreach ( $all_lesson_statuses as $lesson_status ) { - // If lessons are complete without needing quizzes to be passed - if ( 'passed' !== $course_completion ) { - // A user cannot 'complete' a course if a lesson... - // ...is still in progress - // ...hasn't yet been graded. - $lesson_not_complete_stati = array( 'in-progress', 'ungraded' ); - if ( ! in_array( $lesson_status->comment_approved, $lesson_not_complete_stati, true ) ) { - $lessons_completed++; - } - } else { - $lesson_complete_stati = array( 'complete', 'graded', 'passed' ); - if ( in_array( $lesson_status->comment_approved, $lesson_complete_stati, true ) ) { - $lessons_completed++; - } + $lesson_progress_args = array( + 'user_id' => $user_id, + 'lesson_id' => $lesson_ids, + ); + $all_lesson_progress = Sensei()->lesson_progress_repository->find( $lesson_progress_args ); + + foreach ( $all_lesson_progress as $lesson_progress ) { + if ( $lesson_progress->is_complete() ) { + $lessons_completed++; } - } // Each lesson + } if ( $lessons_completed === $total_lessons ) { $course_progress->complete(); @@ -1674,6 +1679,8 @@ public static function user_completed_lesson( $lesson = 0, $user_id = 0 ): bool * Returns the requested course status * * @since 1.7.0 + * @deprecated $$next-version$$ Use course progress repository instead. + * * @param int $course_id * @param int $user_id * @return object @@ -1729,6 +1736,12 @@ public static function user_lesson_status( $lesson_id = 0, $user_id = 0 ) { return false; } + /** + * Returns if a lesson is a preview lesson or not. + * + * @param int $lesson_id Lesson ID. + * @return bool + */ public static function is_preview_lesson( $lesson_id ) { $is_preview = false; @@ -1742,6 +1755,13 @@ public static function is_preview_lesson( $lesson_id ) { return $is_preview; } + /** + * Returns if a user has passed a quiz or not. + * + * @param int $quiz_id Quiz ID. + * @param int $user_id User ID. + * @return bool + */ public static function user_passed_quiz( $quiz_id = 0, $user_id = 0 ) { if ( ! $quiz_id ) {