headless_lms_models/library/user_exercise_state_updater/
mod.rsmod data_loader;
mod state_deriver;
mod validation;
use crate::{
course_modules,
exercise_slide_submissions::ExerciseSlideSubmission,
exercises::Exercise,
peer_or_self_review_configs::PeerOrSelfReviewConfig,
peer_or_self_review_question_submissions::PeerOrSelfReviewQuestionSubmission,
peer_or_self_review_questions::PeerOrSelfReviewQuestion,
peer_or_self_review_submissions::PeerOrSelfReviewSubmission,
peer_review_queue_entries::PeerReviewQueueEntry,
prelude::*,
teacher_grading_decisions::TeacherGradingDecision,
user_exercise_slide_states::UserExerciseSlideStateGradingSummary,
user_exercise_states::{self, UserExerciseState, UserExerciseStateUpdate},
};
use std::default::Default;
#[derive(Debug)]
pub struct UserExerciseStateUpdateRequiredData {
pub exercise: Exercise,
pub current_user_exercise_state: UserExerciseState,
pub peer_or_self_review_information:
Option<UserExerciseStateUpdateRequiredDataPeerReviewInformation>,
pub latest_teacher_grading_decision: Option<TeacherGradingDecision>,
pub user_exercise_slide_state_grading_summary: UserExerciseSlideStateGradingSummary,
}
#[derive(Debug)]
pub struct UserExerciseStateUpdateRequiredDataPeerReviewInformation {
pub given_peer_or_self_review_submissions: Vec<PeerOrSelfReviewSubmission>,
pub given_self_review_submission: Option<PeerOrSelfReviewSubmission>,
pub latest_exercise_slide_submission_received_peer_or_self_review_question_submissions:
Vec<PeerOrSelfReviewQuestionSubmission>,
pub peer_review_queue_entry: Option<PeerReviewQueueEntry>,
pub peer_or_self_review_config: PeerOrSelfReviewConfig,
pub peer_or_self_review_questions: Vec<PeerOrSelfReviewQuestion>,
}
#[derive(Default)]
pub struct UserExerciseStateUpdateAlreadyLoadedRequiredData {
pub exercise: Option<Exercise>,
pub current_user_exercise_state: Option<UserExerciseState>,
pub peer_or_self_review_information:
Option<UserExerciseStateUpdateAlreadyLoadedRequiredDataPeerReviewInformation>,
pub latest_teacher_grading_decision: Option<Option<TeacherGradingDecision>>,
pub user_exercise_slide_state_grading_summary: Option<UserExerciseSlideStateGradingSummary>,
}
#[derive(Default)]
pub struct UserExerciseStateUpdateAlreadyLoadedRequiredDataPeerReviewInformation {
pub given_peer_or_self_review_submissions: Option<Vec<PeerOrSelfReviewSubmission>>,
pub given_self_review_submission: Option<Option<PeerOrSelfReviewSubmission>>,
pub latest_exercise_slide_submission: Option<ExerciseSlideSubmission>,
pub latest_exercise_slide_submission_received_peer_or_self_review_question_submissions:
Option<Vec<PeerOrSelfReviewQuestionSubmission>>,
pub peer_review_queue_entry: Option<Option<PeerReviewQueueEntry>>,
pub peer_or_self_review_config: Option<PeerOrSelfReviewConfig>,
pub peer_or_self_review_questions: Option<Vec<PeerOrSelfReviewQuestion>>,
}
pub async fn update_user_exercise_state(
conn: &mut PgConnection,
user_exercise_state_id: Uuid,
) -> ModelResult<UserExerciseState> {
update_user_exercise_state_with_some_already_loaded_data(
conn,
user_exercise_state_id,
Default::default(),
)
.await
}
#[instrument(skip(conn, already_loaded_internal_dependencies))]
pub async fn update_user_exercise_state_with_some_already_loaded_data(
conn: &mut PgConnection,
user_exercise_state_id: Uuid,
already_loaded_internal_dependencies: UserExerciseStateUpdateAlreadyLoadedRequiredData,
) -> ModelResult<UserExerciseState> {
let required_data = data_loader::load_required_data(
conn,
user_exercise_state_id,
already_loaded_internal_dependencies,
)
.await?;
let exercise_id = required_data.exercise.id;
let prev_user_exercise_state = required_data.current_user_exercise_state.clone();
let derived_user_exercise_state = state_deriver::derive_new_user_exercise_state(required_data)?;
if derived_user_exercise_state
== (UserExerciseStateUpdate {
id: prev_user_exercise_state.id,
score_given: prev_user_exercise_state.score_given,
activity_progress: prev_user_exercise_state.activity_progress,
reviewing_stage: prev_user_exercise_state.reviewing_stage,
grading_progress: prev_user_exercise_state.grading_progress,
})
{
info!("Update resulting in no changes, not updating the database.");
return Ok(prev_user_exercise_state);
}
let new_saved_user_exercise_state =
user_exercise_states::update(conn, derived_user_exercise_state).await?;
if let Some(course_instance_id) = new_saved_user_exercise_state.course_instance_id {
let course_module = course_modules::get_by_exercise_id(conn, exercise_id).await?;
super::progressing::update_automatic_completion_status_and_grant_if_eligible(
conn,
&course_module,
course_instance_id,
new_saved_user_exercise_state.user_id,
)
.await?;
}
Ok(new_saved_user_exercise_state)
}