headless_lms_server/programs/seed/seed_courses/
seed_course_with_peer_review.rs1use crate::programs::seed::builder::chapter::ChapterBuilder;
2use crate::programs::seed::builder::context::SeedContext;
3use crate::programs::seed::builder::course::{CourseBuilder, CourseInstanceConfig};
4use crate::programs::seed::builder::exercise::{ExerciseBuilder, ExerciseIds};
5use crate::programs::seed::builder::module::ModuleBuilder;
6use crate::programs::seed::builder::page::PageBuilder;
7use crate::programs::seed::seed_courses::CommonCourseData;
8use crate::programs::seed::seed_helpers::paragraph;
9use anyhow::Result;
10use chrono::Utc;
11
12use headless_lms_models::peer_or_self_review_configs::{
13 CmsPeerOrSelfReviewConfig, PeerReviewProcessingStrategy,
14};
15use headless_lms_models::peer_or_self_review_questions::CmsPeerOrSelfReviewQuestion;
16use headless_lms_models::roles::UserRole;
17use serde_json::json;
18use tracing::info;
19use uuid::Uuid;
20
21use super::super::seed_users::SeedUsersResult;
22
23pub async fn seed_peer_review_course(
24 course_id: Uuid,
25 course_name: &str,
26 course_slug: &str,
27 common_course_data: CommonCourseData,
28 seed_users_result: SeedUsersResult,
29 flagged_answers_skip_manual_review_and_allow_retry: bool,
30 flagged_answers_threshold: Option<i32>,
31) -> Result<Uuid> {
32 let CommonCourseData {
33 db_pool,
34 organization_id: org,
35 teacher_user_id,
36 student_user_id: _student,
37 langs_user_id: _langs_user_id,
38 example_normal_user_ids: _users,
39 jwt_key: _jwt_key,
40 base_url: _base_url,
41 } = common_course_data;
42
43 let mut conn = db_pool.acquire().await?;
44 let cx = SeedContext {
45 teacher: teacher_user_id,
46 org,
47 base_course_ns: course_id,
48 };
49
50 info!("Inserting sample course {}", course_name);
51 let course = CourseBuilder::new(course_name, course_slug)
52 .desc("Sample course for testing reject and reset-feature in manual review after peer review.")
53 .chatbot(false)
54 .course_id(course_id)
55 .flagged_answers_skip_manual_review_and_allow_retry(flagged_answers_skip_manual_review_and_allow_retry)
56 .flagged_answers_threshold(flagged_answers_threshold)
57 .instance(CourseInstanceConfig {
58 name: None,
59 description: None,
60 support_email: None,
61 teacher_in_charge_name: "admin".to_string(),
62 teacher_in_charge_email: "admin@example.com".to_string(),
63 opening_time: None,
64 closing_time: None,
65 instance_id: Some(cx.v5(b"instance:default")),
66 })
67 .role(seed_users_result.teacher_user_id, UserRole::Teacher)
68 .module(
69 ModuleBuilder::new()
70 .order(0)
71 .register_to_open_university(false)
72 .automatic_completion(Some(1), Some(1), false)
73 .chapter(
74 ChapterBuilder::new(1, "The Basics")
75 .opens(Utc::now())
76 .fixed_ids(cx.v5(b"chapter:1"), cx.v5(b"chapter:1:instance"))
77 .page(
78 PageBuilder::new("/chapter-1/page-1", "Page One")
79 .block(paragraph(
80 "This is a simple introduction to the basics.",
81 cx.v5(b"page:1:1:block:intro"),
82 ))
83 .exercise(ExerciseBuilder::example_exercise(
84 "Simple multiple choice with peer review",
85 ExerciseIds {
86 exercise_id: cx.v5(b"exercise:1:1:e"),
87 slide_id: cx.v5(b"exercise:1:1:s"),
88 task_id: cx.v5(b"exercise:1:1:t"),
89 block_id: cx.v5(b"exercise:1:1:b"),
90 },
91 vec![paragraph(
92 "What is 2 + 2?",
93 cx.v5(b"exercise:1:1:prompt"),
94 )],
95 json!([
96 {
97 "name": "3",
98 "correct": false,
99 "id": cx.v5(b"exercise:1:1:option:1")
100 },
101 {
102 "name": "4",
103 "correct": true,
104 "id": cx.v5(b"exercise:1:1:option:2")
105 },
106 {
107 "name": "5",
108 "correct": false,
109 "id": cx.v5(b"exercise:1:1:option:3")
110 }
111 ]),
112 true,
113 Some(CmsPeerOrSelfReviewConfig {
114 id: cx.v5(b"peer-review:1"),
115 course_id,
116 exercise_id: Some(cx.v5(b"exercise:1:1:e")),
117 peer_reviews_to_give: 2,
118 peer_reviews_to_receive: 1,
119 accepting_threshold: 2.1,
120 processing_strategy:
121 PeerReviewProcessingStrategy::AutomaticallyGradeOrManualReviewByAverage,
122 reset_answer_if_zero_points_from_review: false,
123 points_are_all_or_nothing: true,
124 review_instructions: None,
125 }),
126 Some(vec![CmsPeerOrSelfReviewQuestion {
127 id: cx.v5(b"peer-review:1:q1"),
128 peer_or_self_review_config_id: cx.v5(b"peer-review:1"),
129 order_number: 1,
130 question: "Good answer?".to_string(),
131 question_type:
132 headless_lms_models::peer_or_self_review_questions::PeerOrSelfReviewQuestionType::Scale,
133 answer_required: true,
134 weight: 0.0,
135 }]),
136 ))
137 .exercise(ExerciseBuilder::example_exercise(
138 "Simple multiple choice with automatic reset on zero score",
139 ExerciseIds {
140 exercise_id: cx.v5(b"exercise:2:1:e"),
141 slide_id: cx.v5(b"exercise:2:1:s"),
142 task_id: cx.v5(b"exercise:2:1:t"),
143 block_id: cx.v5(b"exercise:2:1:b"),
144 },
145 vec![paragraph(
146 "What is 2 + 2?",
147 cx.v5(b"exercise:2:1:prompt"),
148 )],
149 json!([
150 {
151 "name": "3",
152 "correct": false,
153 "id": cx.v5(b"exercise:2:1:option:1")
154 },
155 {
156 "name": "4",
157 "correct": true,
158 "id": cx.v5(b"exercise:2:1:option:2")
159 },
160 {
161 "name": "5",
162 "correct": false,
163 "id": cx.v5(b"exercise:2:1:option:3")
164 }
165 ]),
166 true,
167 Some(CmsPeerOrSelfReviewConfig {
168 id: cx.v5(b"peer-review:2"),
169 course_id,
170 exercise_id: Some(cx.v5(b"exercise:2:1:e")),
171 peer_reviews_to_give: 2,
172 peer_reviews_to_receive: 1,
173 accepting_threshold: 2.1,
174 processing_strategy:
175 PeerReviewProcessingStrategy::AutomaticallyGradeByAverage,
176 reset_answer_if_zero_points_from_review: true,
177 points_are_all_or_nothing: true,
178 review_instructions: None,
179 }),
180 Some(vec![CmsPeerOrSelfReviewQuestion {
181 id: cx.v5(b"peer-review:2:q1"),
182 peer_or_self_review_config_id: cx.v5(b"peer-review:2"),
183 order_number: 1,
184 question: "Good answer?".to_string(),
185 question_type:
186 headless_lms_models::peer_or_self_review_questions::PeerOrSelfReviewQuestionType::Scale,
187 answer_required: true,
188 weight: 0.0,
189 }]),
190 )),
191 ),
192 ),
193 );
194 let (course, _default_instance, _last_module) = course.seed(&mut conn, &cx).await?;
195 Ok(course.id)
196}