headless_lms_server/programs/seed/seed_courses/
seed_course_with_peer_review.rs

1use 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}