diff --git a/services/headless-lms/models/.sqlx/query-c223a006ab760c7242112d5cdc386e041e1a10e53255ca20b378e4661f8d7186.json b/services/headless-lms/models/.sqlx/query-c223a006ab760c7242112d5cdc386e041e1a10e53255ca20b378e4661f8d7186.json new file mode 100644 index 00000000000..8c97fcd81ee --- /dev/null +++ b/services/headless-lms/models/.sqlx/query-c223a006ab760c7242112d5cdc386e041e1a10e53255ca20b378e4661f8d7186.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n CASE\n WHEN ues.score_given IS NULL THEN 0\n ELSE 1\n END AS exercise_attempts\nFROM\nuser_exercise_states AS ues\nWHERE ues.deleted_at IS NULL\n AND ues.exercise_id IN (\n SELECT UNNEST($1::uuid [])\n )\n AND ues.course_instance_id = $2\n AND ues.user_id = $3;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exercise_attempts", + "type_info": "Int4" + } + ], + "parameters": { + "Left": ["UuidArray", "Uuid", "Uuid"] + }, + "nullable": [null] + }, + "hash": "c223a006ab760c7242112d5cdc386e041e1a10e53255ca20b378e4661f8d7186" +} diff --git a/services/headless-lms/models/src/chapter_completion_requirements.rs b/services/headless-lms/models/src/chapter_completion_requirements.rs index 4768a486299..cee3db6ee61 100644 --- a/services/headless-lms/models/src/chapter_completion_requirements.rs +++ b/services/headless-lms/models/src/chapter_completion_requirements.rs @@ -46,6 +46,25 @@ RETURNING id Ok(res.id) } +pub async fn get_requirements_by_chapter_id( + conn: &mut PgConnection, + chapter_id: Uuid, +) -> ModelResult { + let completion_requirements = sqlx::query_as!( + ChapterCompletionRequirements, + " + SELECT * + FROM chapter_completion_requirements + WHERE chapter_id = $1 + AND deleted_at IS NULL; + ", + chapter_id + ) + .fetch_one(conn) + .await?; + Ok(completion_requirements) +} + pub async fn delete_chapter_completion_requirements( conn: &mut PgConnection, id: Uuid, diff --git a/services/headless-lms/models/src/library/progressing.rs b/services/headless-lms/models/src/library/progressing.rs index 08932463c25..84b27383df4 100644 --- a/services/headless-lms/models/src/library/progressing.rs +++ b/services/headless-lms/models/src/library/progressing.rs @@ -17,7 +17,6 @@ use crate::{ user_course_settings, user_details::UserDetail, user_exercise_states, - user_exercise_states::UserCourseInstanceChapterExerciseProgress, users::{self, User}, }; use headless_lms_utils::numbers::option_f32_to_f32_two_decimals_with_none_as_zero; @@ -113,16 +112,25 @@ pub async fn check_and_insert_suspected_cheaters( Ok(()) } +pub struct TotalScoreInChapter { + pub total_score: f32, +} + +pub struct TotalAttemptsInChapter { + pub total_attempts: i32, +} + // Get the total score given to a student in a chapter pub async fn get_total_score_in_a_chapter( conn: &mut PgConnection, user_id: Uuid, course_instance_id: Uuid, chapter_id: Uuid, -) -> ModelResult> { +) -> ModelResult { let chapter_exercises = exercises::get_exercises_by_chapter_id(conn, chapter_id).await?; let exercise_ids: Vec = chapter_exercises.into_iter().map(|e| e.id).collect(); + // Fetch user exercise progress let user_course_instance_exercise_progress = user_exercise_states::get_user_course_instance_chapter_exercises_progress( conn, @@ -131,15 +139,15 @@ pub async fn get_total_score_in_a_chapter( user_id, ) .await?; - let rounded_score_given_instances: Vec = - user_course_instance_exercise_progress - .into_iter() - .map(|i| UserCourseInstanceChapterExerciseProgress { - score_given: option_f32_to_f32_two_decimals_with_none_as_zero(i.score_given), - exercise_id: i.exercise_id, - }) - .collect(); - Ok(rounded_score_given_instances) + + // Calculate the total score + let total_score: f32 = user_course_instance_exercise_progress + .into_iter() + .map(|i| option_f32_to_f32_two_decimals_with_none_as_zero(i.score_given)) + .sum(); + + // Return the total score + Ok(TotalScoreInChapter { total_score }) } // Get the total score given to a student in a chapter @@ -148,7 +156,7 @@ pub async fn get_total_exercise_attempt_in_a_chapter( user_id: Uuid, course_instance_id: Uuid, chapter_id: Uuid, -) -> ModelResult<()> { +) -> ModelResult { let chapter_exercises = exercises::get_exercises_by_chapter_id(conn, chapter_id).await?; let exercise_ids: Vec = chapter_exercises.into_iter().map(|e| e.id).collect(); @@ -160,16 +168,15 @@ pub async fn get_total_exercise_attempt_in_a_chapter( user_id, ) .await?; - // let rounded_score_given_instances: Vec = - // user_course_instance_exercise_progress - // .into_iter() - // .map(|i| UserCourseInstanceChapterExerciseProgress { - // score_given: option_f32_to_f32_two_decimals_with_none_as_zero(i.score_given), - // exercise_id: i.exercise_id, - // }) - // .collect(); - // Ok(rounded_score_given_instances) - Ok(()) + + // Calculate the exercise attempts in a chapter + let total_attempts: i32 = user_course_instance_exercises_attempted + .into_iter() + .map(|i| i.exercise_attempts.unwrap_or(0)) + .sum(); + + // Return the total score + Ok(TotalAttemptsInChapter { total_attempts }) } /// Creates completion for the user if eligible and previous one doesn't exist. Returns an Option containing diff --git a/services/headless-lms/models/src/user_exercise_states.rs b/services/headless-lms/models/src/user_exercise_states.rs index 4e299c28e6e..9e70fbaac1e 100644 --- a/services/headless-lms/models/src/user_exercise_states.rs +++ b/services/headless-lms/models/src/user_exercise_states.rs @@ -467,7 +467,7 @@ WHERE ues.deleted_at IS NULL } pub struct ChapterExerciseAttempts { - pub exercise_attempt: Option, + pub exercise_attempts: Option, } pub async fn get_user_course_instance_chapter_exercises_attempts( @@ -481,9 +481,9 @@ pub async fn get_user_course_instance_chapter_exercises_attempts( r#" SELECT CASE - WHEN ues.score_given IS NULL THEN FALSE - ELSE TRUE - END AS exercise_attempt + WHEN ues.score_given IS NULL THEN 0 + ELSE 1 + END AS exercise_attempts FROM user_exercise_states AS ues WHERE ues.deleted_at IS NULL