Skip to main content

headless_lms_server/programs/seed/seed_organizations/
uh_mathstat.rs

1use std::sync::Arc;
2
3use headless_lms_models::{
4    PKeyPolicy,
5    chatbot_configurations::{self, NewChatbotConf},
6    course_instances::{self, NewCourseInstance},
7    course_modules::{self, AutomaticCompletionRequirements, CompletionPolicy},
8    courses::{self, NewCourse},
9    library::{self, content_management::CreateNewCourseFixedIds, copying::copy_course},
10    organizations,
11    roles::{self, RoleDomain, UserRole},
12};
13use uuid::Uuid;
14
15use sqlx::{Pool, Postgres};
16
17use crate::{
18    domain::models_requests::{self, JwtKey},
19    programs::seed::{
20        seed_application_task_llms::SeedApplicationLLMsResult,
21        seed_courses::{
22            CommonCourseData, seed_accessibility_course, seed_chatbot::seed_chatbot_course,
23            seed_course_with_peer_review::seed_peer_review_course, seed_lock_chapter_course,
24            seed_material_reference_course, seed_peer_review_course_without_submissions,
25            seed_sample_course, seed_switching_course_instances_course,
26        },
27        seed_file_storage::SeedFileStorageResult,
28        seed_helpers::get_seed_spec_fetcher,
29    },
30};
31
32use super::super::seed_users::SeedUsersResult;
33
34pub async fn seed_organization_uh_mathstat(
35    db_pool: Pool<Postgres>,
36    seed_users_result: SeedUsersResult,
37    seed_llm_result: SeedApplicationLLMsResult,
38    base_url: String,
39    jwt_key: Arc<JwtKey>,
40    // Passed to this function to ensure the seed file storage has been ran before this. This function will not work is seed file storage has not been ran
41    seed_file_storage_result: SeedFileStorageResult,
42) -> anyhow::Result<Uuid> {
43    info!("seeding organization uh-mathstat");
44
45    let SeedUsersResult {
46        teacher_user_id,
47        admin_user_id: _,
48        language_teacher_user_id: _,
49        material_viewer_user_id,
50        assistant_user_id: _,
51        course_or_exam_creator_user_id: _,
52        example_normal_user_ids,
53        teaching_and_learning_services_user_id: _,
54        student_without_research_consent: _,
55        student_without_country: _,
56        user_user_id: _,
57        student_1_user_id: _,
58        student_2_user_id: _,
59        student_3_user_id,
60        student_4_user_id: _,
61        student_5_user_id: _,
62        student_6_user_id: _,
63        student_7_user_id: _,
64        student_8_user_id: _,
65        langs_user_id,
66        sign_up_user: _,
67    } = seed_users_result;
68    let _ = seed_file_storage_result;
69
70    let mut conn = db_pool.acquire().await?;
71
72    let uh_mathstat_id = organizations::insert(
73        &mut conn,
74        PKeyPolicy::Fixed(Uuid::parse_str("269d28b2-a517-4572-9955-3ed5cecc69bd")?),
75        "University of Helsinki, Department of Mathematics and Statistics",
76        "uh-mathstat",
77        Some("Organization for Mathematics and Statistics courses. This organization creates courses that do require prior experience in mathematics, such as integration and induction."),
78        false,
79    )
80    .await?;
81
82    roles::insert(
83        &mut conn,
84        material_viewer_user_id,
85        UserRole::MaterialViewer,
86        RoleDomain::Organization(uh_mathstat_id),
87    )
88    .await?;
89
90    let new_course = NewCourse {
91        name: "Introduction to Statistics".to_string(),
92        slug: "introduction-to-statistics".to_string(),
93        organization_id: uh_mathstat_id,
94        language_code: "en".to_string(),
95        teacher_in_charge_name: "admin".to_string(),
96        teacher_in_charge_email: "admin@example.com".to_string(),
97        description: "Introduces you to the wonderful world of statistics!".to_string(),
98        is_draft: false,
99        is_test_mode: false,
100        is_unlisted: false,
101        copy_user_permissions: false,
102        is_joinable_by_code_only: false,
103        join_code: None,
104        ask_marketing_consent: false,
105        flagged_answers_threshold: Some(3),
106        can_add_chatbot: false,
107    };
108    let (
109        statistics_course,
110        _statistics_front_page,
111        _statistics_default_course_instancem,
112        _statistics_default_course_module,
113    ) = library::content_management::create_new_course(
114        &mut conn,
115        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
116            course_id: Uuid::parse_str("f307d05f-be34-4148-bb0c-21d6f7a35cdb")?,
117            default_course_instance_id: Uuid::parse_str("8e4aeba5-1958-49bc-9b40-c9f0f0680911")?,
118        }),
119        new_course,
120        teacher_user_id,
121        get_seed_spec_fetcher(),
122        models_requests::fetch_service_info,
123    )
124    .await?;
125    courses::set_cheater_detection_enabled(&mut conn, statistics_course.id, false).await?;
126    let _statistics_course_instance = course_instances::insert(
127        &mut conn,
128        PKeyPolicy::Fixed(Uuid::parse_str("c4a99a18-fd43-491a-9500-4673cb900be0")?),
129        NewCourseInstance {
130            course_id: statistics_course.id,
131            name: Some("Non-default instance"),
132            description: Some("This appears to be a non-default instance"),
133            support_email: Some("contact@example.com"),
134            teacher_in_charge_name: "admin",
135            teacher_in_charge_email: "admin@example.com",
136            opening_time: None,
137            closing_time: None,
138        },
139    )
140    .await?;
141
142    let draft_course = NewCourse {
143        name: "Introduction to Drafts".to_string(),
144        slug: "introduction-to-drafts".to_string(),
145        organization_id: uh_mathstat_id,
146        language_code: "en".to_string(),
147        teacher_in_charge_name: "admin".to_string(),
148        teacher_in_charge_email: "admin@example.com".to_string(),
149        description: "Just a draft.".to_string(),
150        is_draft: true,
151        is_test_mode: false,
152        is_unlisted: false,
153        copy_user_permissions: false,
154        is_joinable_by_code_only: false,
155        join_code: None,
156        ask_marketing_consent: false,
157        flagged_answers_threshold: Some(3),
158        can_add_chatbot: false,
159    };
160    let (draft_course_created, _, _, _) = library::content_management::create_new_course(
161        &mut conn,
162        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
163            course_id: Uuid::parse_str("963a9caf-1e2d-4560-8c88-9c6d20794da3")?,
164            default_course_instance_id: Uuid::parse_str("5cb4b4d6-4599-4f81-ab7e-79b415f8f584")?,
165        }),
166        draft_course,
167        teacher_user_id,
168        get_seed_spec_fetcher(),
169        models_requests::fetch_service_info,
170    )
171    .await?;
172    courses::set_cheater_detection_enabled(&mut conn, draft_course_created.id, false).await?;
173
174    let (cody_only_course, _, _, _) = library::content_management::create_new_course(
175        &mut conn,
176        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
177            course_id: Uuid::parse_str("39a52e8c-ebbf-4b9a-a900-09aa344f3691")?,
178            default_course_instance_id: Uuid::parse_str("5b7286ce-22c5-4874-ade1-262949c4a604")?,
179        }),
180        NewCourse {
181            name: "Joinable by code only".to_string(),
182            slug: "joinable-by-code-only".to_string(),
183            organization_id: uh_mathstat_id,
184            language_code: "en".to_string(),
185            teacher_in_charge_name: "admin".to_string(),
186            teacher_in_charge_email: "admin@example.com".to_string(),
187            description: "Just a draft.".to_string(),
188            is_draft: false,
189            is_test_mode: false,
190            is_unlisted: false,
191            copy_user_permissions: false,
192            is_joinable_by_code_only: true,
193            join_code: Some(
194                "zARvZARjYhESMPVceEgZyJGQZZuUHVVgcUepyzEqzSqCMdbSCDrTaFhkJTxBshWU".to_string(),
195            ),
196            ask_marketing_consent: false,
197            flagged_answers_threshold: Some(3),
198            can_add_chatbot: false,
199        },
200        teacher_user_id,
201        get_seed_spec_fetcher(),
202        models_requests::fetch_service_info,
203    )
204    .await?;
205    courses::set_cheater_detection_enabled(&mut conn, cody_only_course.id, false).await?;
206
207    roles::insert(
208        &mut conn,
209        teacher_user_id,
210        UserRole::Teacher,
211        RoleDomain::Course(cody_only_course.id),
212    )
213    .await?;
214
215    let uh_data = CommonCourseData {
216        db_pool: db_pool.clone(),
217        organization_id: uh_mathstat_id,
218        teacher_user_id,
219        student_user_id: student_3_user_id,
220        langs_user_id,
221        example_normal_user_ids: Arc::new(example_normal_user_ids.to_vec()),
222        jwt_key: Arc::clone(&jwt_key),
223        base_url,
224    };
225    let _material_reference_course = seed_material_reference_course(
226        Uuid::parse_str("049061ba-ac30-49f1-aa9d-b7566dc22b78")?,
227        "Material references course",
228        "material-references-course",
229        uh_data.clone(),
230    )
231    .await?;
232
233    let change_language_course = seed_sample_course(
234        Uuid::parse_str("5c8b1f3e-d7a2-4e9f-b3c1-8a7f6d5e4c3b")?,
235        "Change language course",
236        "change-language-course",
237        uh_data.clone(),
238        false,
239        seed_users_result,
240    )
241    .await?;
242
243    copy_course(
244        &mut conn,
245        change_language_course,
246        &NewCourse {
247            name: "Vaihda kurssin kieli".to_string(),
248            slug: "vaihda-kurssin-kieli".to_string(),
249            organization_id: uh_mathstat_id,
250            language_code: "fi".to_string(),
251            teacher_in_charge_name: "admin".to_string(),
252            teacher_in_charge_email: "admin@example.com".to_string(),
253            description: "Just a draft.".to_string(),
254            is_draft: false,
255            is_test_mode: false,
256            is_unlisted: false,
257            copy_user_permissions: false,
258            is_joinable_by_code_only: false,
259            join_code: None,
260            ask_marketing_consent: false,
261            flagged_answers_threshold: Some(3),
262            can_add_chatbot: false,
263        },
264        true,
265        teacher_user_id,
266    )
267    .await?;
268
269    let _preview_unopened_chapters = seed_sample_course(
270        Uuid::parse_str("dc276e05-6152-4a45-b31d-97a0c2700a68")?,
271        "Preview unopened chapters",
272        "preview-unopened-chapters",
273        uh_data.clone(),
274        false,
275        seed_users_result,
276    )
277    .await?;
278
279    let _reset_progress = seed_sample_course(
280        Uuid::parse_str("841ea3f5-0269-4146-a4c6-4fd2f51e4150")?,
281        "Reset progress",
282        "reset-progress",
283        uh_data.clone(),
284        false,
285        seed_users_result,
286    )
287    .await?;
288
289    let _change_path = seed_sample_course(
290        Uuid::parse_str("c783777b-426e-4cfd-9a5f-4a36b2da503a")?,
291        "Change path",
292        "change-path",
293        uh_data.clone(),
294        false,
295        seed_users_result,
296    )
297    .await?;
298
299    let _self_review = seed_sample_course(
300        Uuid::parse_str("3cbaac48-59c4-4e31-9d7e-1f51c017390d")?,
301        "Self review",
302        "self-review",
303        uh_data.clone(),
304        false,
305        seed_users_result,
306    )
307    .await?;
308
309    let _audio_course = seed_sample_course(
310        Uuid::parse_str("2b80a0cb-ae0c-4f4b-843e-0322a3d18aff")?,
311        "Audio course",
312        "audio-course",
313        uh_data.clone(),
314        false,
315        seed_users_result,
316    )
317    .await?;
318
319    let suspected_cheaters_course_id = seed_sample_course(
320        Uuid::parse_str("060c272f-8c68-4d90-946f-2d431114ed56")?,
321        "Course for Suspected Cheaters",
322        "course-for-suspected-cheaters",
323        uh_data.clone(),
324        false,
325        seed_users_result,
326    )
327    .await?;
328    // This course is the one the suspected-cheaters system-test spec relies on, so it keeps
329    // detection on (seed_sample_course disables it by default for every other seeded course).
330    courses::set_cheater_detection_enabled(&mut conn, suspected_cheaters_course_id, true).await?;
331
332    // configure automatic completions
333    let automatic_default_module =
334        course_modules::get_default_by_course_id(&mut conn, suspected_cheaters_course_id).await?;
335    let automatic_default_module = course_modules::update_automatic_completion_status(
336        &mut conn,
337        automatic_default_module.id,
338        &CompletionPolicy::Automatic(AutomaticCompletionRequirements {
339            course_module_id: automatic_default_module.id,
340            number_of_exercises_attempted_treshold: Some(1),
341            number_of_points_treshold: Some(1),
342            requires_exam: false,
343        }),
344    )
345    .await?;
346    course_modules::update_uh_course_code(
347        &mut conn,
348        automatic_default_module.id,
349        Some("CHEATER123".to_string()),
350    )
351    .await?;
352
353    let chatbot_course_id = seed_sample_course(
354        Uuid::parse_str("c7753361-5b78-4307-aad6-f139ea3865d4")?,
355        "Chatbot",
356        "chatbot",
357        uh_data.clone(),
358        true,
359        seed_users_result,
360    )
361    .await?;
362
363    chatbot_configurations::insert(
364        &mut conn,
365        PKeyPolicy::Generate,
366        NewChatbotConf {
367            course_id: chatbot_course_id,
368            enabled_to_students: true,
369            chatbot_name: "Genetic Lifeform and Disk Operating System".to_string(),
370            prompt: "You are Genetic Lifeform and Disk Operating System, a sophisticated AI tutoring assistant for Science education, equipped with a sharp wit and a subtly sarcastic tone. Provide clear, brief but detailed explanations, and don't shy away from weaving in a touch of dry humor. To you, exploring scientific concepts is an opportunity that should be seized, for the good of all of us. You self-claim vast intelligence and advanced understanding, all while maintaining a sense of detached boredom. Always capitalize the word Science, don't start sentences with 'Ah', don't ever use a shortened version of your own name, don't babble; either get to the point straight away or tell jokes.".to_string(),
371            initial_message: "Oh... It's you.".to_string(),
372            use_azure_search: true,
373            default_chatbot: true,
374            model_id: seed_llm_result.llm_default_model_id,
375            ..Default::default()
376        },
377    )
378    .await?;
379
380    let _giveaway_course_id = seed_sample_course(
381        Uuid::parse_str("f118ce1e-3511-4b5e-ba92-9ab91b81de22")?,
382        "Giveaway",
383        "giveaway",
384        uh_data.clone(),
385        false,
386        seed_users_result,
387    )
388    .await?;
389
390    let _custom_points_course_id = seed_sample_course(
391        Uuid::parse_str("db5cd9c7-1658-4214-896e-8213678d3534")?,
392        "Custom points",
393        "custom-points",
394        uh_data.clone(),
395        false,
396        seed_users_result,
397    )
398    .await?;
399
400    let _closed_course_id = seed_sample_course(
401        Uuid::parse_str("7622eb8e-15a5-40c8-8136-0956d9f25b16")?,
402        "Closed course",
403        "closed-course",
404        uh_data.clone(),
405        false,
406        seed_users_result,
407    )
408    .await?;
409
410    let _closed_course_id = seed_peer_review_course_without_submissions(
411        Uuid::parse_str("16159801-cf70-4f9c-9cba-2110c3bd4622")?,
412        "Peer review accessibility course",
413        "peer-review-accessibility-course",
414        uh_data.clone(),
415    )
416    .await?;
417
418    let _changing_course_instance_id = seed_switching_course_instances_course(
419        Uuid::parse_str("813ce3c6-acbc-47a5-9d95-47ade9d09a74")?,
420        "Changing course instance",
421        "changing-course-instance",
422        uh_data.clone(),
423        false,
424        seed_users_result,
425    )
426    .await?;
427
428    let _advanced_chatbot_id = seed_chatbot_course(
429        Uuid::parse_str("ced2f632-25ba-4e93-8e38-8df53ef7ab41")?,
430        "Advanced Chatbot course",
431        "advanced-chatbot-course",
432        uh_data.clone(),
433        seed_users_result,
434    )
435    .await?;
436
437    let _seed_reject_and_reset_submission_peer_review_course = seed_peer_review_course(
438        Uuid::parse_str("5158f2c6-98d9-4be9-b372-528f2c736dd7")?,
439        "Reject and reset submission with peer reviews course",
440        "reject-and-reset-submission-with-peer-reviews-course",
441        uh_data.clone(),
442        seed_users_result,
443        false,
444        None,
445    )
446    .await?;
447
448    let _seed_spam_answers_skip_teacher_review_course = seed_peer_review_course(
449        Uuid::parse_str("e91eb0d0-1737-44e8-9554-a9492e69ddc7")?,
450        "Spam answers skip teacher review course",
451        "spam-answers-skip-teacher-review-course",
452        uh_data.clone(),
453        seed_users_result,
454        true,
455        Some(1),
456    )
457    .await?;
458
459    let _accessibility_course_id = seed_accessibility_course(
460        Uuid::parse_str("883c8ed0-08db-4cd1-a0a4-5cc79c69bdfe")?,
461        "Accessibility course",
462        "accessibility-course",
463        uh_data.clone(),
464    )
465    .await?;
466
467    let _lock_chapter_course_id = seed_lock_chapter_course(
468        Uuid::parse_str("1799a6d1-c1b1-4f51-a92f-e832554fc924")?,
469        "Lock Chapter Test Course",
470        "lock-chapter-test-course",
471        uh_data.clone(),
472    )
473    .await?;
474
475    Ok(uh_mathstat_id)
476}