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::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_courses::{
21            CommonCourseData, seed_sample_course, seed_switching_course_instances_course,
22        },
23        seed_file_storage::SeedFileStorageResult,
24        seed_helpers::get_seed_spec_fetcher,
25    },
26};
27
28use super::super::seed_users::SeedUsersResult;
29
30pub async fn seed_organization_uh_mathstat(
31    db_pool: Pool<Postgres>,
32    seed_users_result: SeedUsersResult,
33    base_url: String,
34    jwt_key: Arc<JwtKey>,
35    // 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
36    seed_file_storage_result: SeedFileStorageResult,
37) -> anyhow::Result<Uuid> {
38    info!("seeding organization uh-mathstat");
39
40    let SeedUsersResult {
41        teacher_user_id,
42        admin_user_id: _,
43        language_teacher_user_id: _,
44        material_viewer_user_id,
45        assistant_user_id: _,
46        course_or_exam_creator_user_id: _,
47        example_normal_user_ids,
48        teaching_and_learning_services_user_id: _,
49        student_without_research_consent: _,
50        student_without_country: _,
51        user_user_id: _,
52        student_1_user_id: _,
53        student_2_user_id: _,
54        student_3_user_id,
55        student_4_user_id: _,
56        student_5_user_id: _,
57        student_6_user_id: _,
58        langs_user_id,
59        sign_up_user: _,
60    } = seed_users_result;
61    let _ = seed_file_storage_result;
62
63    let mut conn = db_pool.acquire().await?;
64
65    let uh_mathstat_id = organizations::insert(
66        &mut conn,
67        PKeyPolicy::Fixed(Uuid::parse_str("269d28b2-a517-4572-9955-3ed5cecc69bd")?),
68        "University of Helsinki, Department of Mathematics and Statistics",
69        "uh-mathstat",
70        Some("Organization for Mathematics and Statistics courses. This organization creates courses that do require prior experience in mathematics, such as integration and induction."),
71        false,
72    )
73    .await?;
74
75    roles::insert(
76        &mut conn,
77        material_viewer_user_id,
78        UserRole::MaterialViewer,
79        RoleDomain::Organization(uh_mathstat_id),
80    )
81    .await?;
82
83    let new_course = NewCourse {
84        name: "Introduction to Statistics".to_string(),
85        slug: "introduction-to-statistics".to_string(),
86        organization_id: uh_mathstat_id,
87        language_code: "en-US".to_string(),
88        teacher_in_charge_name: "admin".to_string(),
89        teacher_in_charge_email: "admin@example.com".to_string(),
90        description: "Introduces you to the wonderful world of statistics!".to_string(),
91        is_draft: false,
92        is_test_mode: false,
93        is_unlisted: false,
94        copy_user_permissions: false,
95        is_joinable_by_code_only: false,
96        join_code: None,
97        ask_marketing_consent: false,
98        flagged_answers_threshold: Some(3),
99        can_add_chatbot: false,
100    };
101    let (
102        statistics_course,
103        _statistics_front_page,
104        _statistics_default_course_instancem,
105        _statistics_default_course_module,
106    ) = library::content_management::create_new_course(
107        &mut conn,
108        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
109            course_id: Uuid::parse_str("f307d05f-be34-4148-bb0c-21d6f7a35cdb")?,
110            default_course_instance_id: Uuid::parse_str("8e4aeba5-1958-49bc-9b40-c9f0f0680911")?,
111        }),
112        new_course,
113        teacher_user_id,
114        get_seed_spec_fetcher(),
115        models_requests::fetch_service_info,
116    )
117    .await?;
118    let _statistics_course_instance = course_instances::insert(
119        &mut conn,
120        PKeyPolicy::Fixed(Uuid::parse_str("c4a99a18-fd43-491a-9500-4673cb900be0")?),
121        NewCourseInstance {
122            course_id: statistics_course.id,
123            name: Some("Non-default instance"),
124            description: Some("This appears to be a non-default instance"),
125            support_email: Some("contact@example.com"),
126            teacher_in_charge_name: "admin",
127            teacher_in_charge_email: "admin@example.com",
128            opening_time: None,
129            closing_time: None,
130        },
131    )
132    .await?;
133
134    let draft_course = NewCourse {
135        name: "Introduction to Drafts".to_string(),
136        slug: "introduction-to-drafts".to_string(),
137        organization_id: uh_mathstat_id,
138        language_code: "en-US".to_string(),
139        teacher_in_charge_name: "admin".to_string(),
140        teacher_in_charge_email: "admin@example.com".to_string(),
141        description: "Just a draft.".to_string(),
142        is_draft: true,
143        is_test_mode: false,
144        is_unlisted: false,
145        copy_user_permissions: false,
146        is_joinable_by_code_only: false,
147        join_code: None,
148        ask_marketing_consent: false,
149        flagged_answers_threshold: Some(3),
150        can_add_chatbot: false,
151    };
152    library::content_management::create_new_course(
153        &mut conn,
154        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
155            course_id: Uuid::parse_str("963a9caf-1e2d-4560-8c88-9c6d20794da3")?,
156            default_course_instance_id: Uuid::parse_str("5cb4b4d6-4599-4f81-ab7e-79b415f8f584")?,
157        }),
158        draft_course,
159        teacher_user_id,
160        get_seed_spec_fetcher(),
161        models_requests::fetch_service_info,
162    )
163    .await?;
164
165    let (cody_only_course, _, _, _) = library::content_management::create_new_course(
166        &mut conn,
167        PKeyPolicy::Fixed(CreateNewCourseFixedIds {
168            course_id: Uuid::parse_str("39a52e8c-ebbf-4b9a-a900-09aa344f3691")?,
169            default_course_instance_id: Uuid::parse_str("5b7286ce-22c5-4874-ade1-262949c4a604")?,
170        }),
171        NewCourse {
172            name: "Joinable by code only".to_string(),
173            slug: "joinable-by-code-only".to_string(),
174            organization_id: uh_mathstat_id,
175            language_code: "en-US".to_string(),
176            teacher_in_charge_name: "admin".to_string(),
177            teacher_in_charge_email: "admin@example.com".to_string(),
178            description: "Just a draft.".to_string(),
179            is_draft: false,
180            is_test_mode: false,
181            is_unlisted: false,
182            copy_user_permissions: false,
183            is_joinable_by_code_only: true,
184            join_code: Some(
185                "zARvZARjYhESMPVceEgZyJGQZZuUHVVgcUepyzEqzSqCMdbSCDrTaFhkJTxBshWU".to_string(),
186            ),
187            ask_marketing_consent: false,
188            flagged_answers_threshold: Some(3),
189            can_add_chatbot: false,
190        },
191        teacher_user_id,
192        get_seed_spec_fetcher(),
193        models_requests::fetch_service_info,
194    )
195    .await?;
196
197    roles::insert(
198        &mut conn,
199        teacher_user_id,
200        UserRole::Teacher,
201        RoleDomain::Course(cody_only_course.id),
202    )
203    .await?;
204
205    let uh_data = CommonCourseData {
206        db_pool: db_pool.clone(),
207        organization_id: uh_mathstat_id,
208        teacher_user_id,
209        student_user_id: student_3_user_id,
210        langs_user_id,
211        example_normal_user_ids: Arc::new(example_normal_user_ids.to_vec()),
212        jwt_key: Arc::clone(&jwt_key),
213        base_url,
214    };
215    let introduction_to_citations = seed_sample_course(
216        Uuid::parse_str("049061ba-ac30-49f1-aa9d-b7566dc22b78")?,
217        "Introduction to citations",
218        "introduction-to-citations",
219        uh_data.clone(),
220        false,
221        seed_users_result,
222    )
223    .await?;
224
225    copy_course(
226        &mut conn,
227        introduction_to_citations,
228        &NewCourse {
229            name: "Johdatus sitaatioihin".to_string(),
230            slug: "johdatus-sitaatioihin".to_string(),
231            organization_id: uh_mathstat_id,
232            language_code: "fi-FI".to_string(),
233            teacher_in_charge_name: "admin".to_string(),
234            teacher_in_charge_email: "admin@example.com".to_string(),
235            description: "Just a draft.".to_string(),
236            is_draft: false,
237            is_test_mode: false,
238            is_unlisted: false,
239            copy_user_permissions: false,
240            is_joinable_by_code_only: false,
241            join_code: None,
242            ask_marketing_consent: false,
243            flagged_answers_threshold: Some(3),
244            can_add_chatbot: false,
245        },
246        true,
247        teacher_user_id,
248    )
249    .await?;
250
251    let _preview_unopened_chapters = seed_sample_course(
252        Uuid::parse_str("dc276e05-6152-4a45-b31d-97a0c2700a68")?,
253        "Preview unopened chapters",
254        "preview-unopened-chapters",
255        uh_data.clone(),
256        false,
257        seed_users_result,
258    )
259    .await?;
260
261    let _reset_progress = seed_sample_course(
262        Uuid::parse_str("841ea3f5-0269-4146-a4c6-4fd2f51e4150")?,
263        "Reset progress",
264        "reset-progress",
265        uh_data.clone(),
266        false,
267        seed_users_result,
268    )
269    .await?;
270
271    let _change_path = seed_sample_course(
272        Uuid::parse_str("c783777b-426e-4cfd-9a5f-4a36b2da503a")?,
273        "Change path",
274        "change-path",
275        uh_data.clone(),
276        false,
277        seed_users_result,
278    )
279    .await?;
280
281    let _self_review = seed_sample_course(
282        Uuid::parse_str("3cbaac48-59c4-4e31-9d7e-1f51c017390d")?,
283        "Self review",
284        "self-review",
285        uh_data.clone(),
286        false,
287        seed_users_result,
288    )
289    .await?;
290
291    let _audio_course = seed_sample_course(
292        Uuid::parse_str("2b80a0cb-ae0c-4f4b-843e-0322a3d18aff")?,
293        "Audio course",
294        "audio-course",
295        uh_data.clone(),
296        false,
297        seed_users_result,
298    )
299    .await?;
300
301    let suspected_cheaters_course_id = seed_sample_course(
302        Uuid::parse_str("060c272f-8c68-4d90-946f-2d431114ed56")?,
303        "Course for Suspected Cheaters",
304        "course-for-suspected-cheaters",
305        uh_data.clone(),
306        false,
307        seed_users_result,
308    )
309    .await?;
310
311    // configure automatic completions
312    let automatic_default_module =
313        course_modules::get_default_by_course_id(&mut conn, suspected_cheaters_course_id).await?;
314    let automatic_default_module = course_modules::update_automatic_completion_status(
315        &mut conn,
316        automatic_default_module.id,
317        &CompletionPolicy::Automatic(AutomaticCompletionRequirements {
318            course_module_id: automatic_default_module.id,
319            number_of_exercises_attempted_treshold: Some(1),
320            number_of_points_treshold: Some(1),
321            requires_exam: false,
322        }),
323    )
324    .await?;
325    course_modules::update_uh_course_code(
326        &mut conn,
327        automatic_default_module.id,
328        Some("CHEATER123".to_string()),
329    )
330    .await?;
331
332    let chatbot_course_id = seed_sample_course(
333        Uuid::parse_str("c7753361-5b78-4307-aad6-f139ea3865d4")?,
334        "Chatbot",
335        "chatbot",
336        uh_data.clone(),
337        true,
338        seed_users_result,
339    )
340    .await?;
341
342    chatbot_configurations::insert(
343        &mut conn,
344        NewChatbotConf {
345            course_id: chatbot_course_id,
346            enabled_to_students: true,
347            chatbot_name: "Genetic Lifeform and Disk Operating System".to_string(),
348            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(),
349            initial_message: "Oh... It's you.".to_string(),
350            weekly_tokens_per_user: 3000,
351            daily_tokens_per_user: 1000,
352            temperature: 0.5,
353            top_p: 1.0,
354            frequency_penalty: 0.0,
355            presence_penalty: 0.0,
356            response_max_tokens: 500,
357            use_azure_search: false,
358            maintain_azure_search_index: false,
359            hide_citations: false,
360            use_semantic_reranking: false,
361            default_chatbot: true,
362        },
363    )
364    .await?;
365
366    let _giveaway_course_id = seed_sample_course(
367        Uuid::parse_str("f118ce1e-3511-4b5e-ba92-9ab91b81de22")?,
368        "Giveaway",
369        "giveaway",
370        uh_data.clone(),
371        false,
372        seed_users_result,
373    )
374    .await?;
375
376    let _custom_points_course_id = seed_sample_course(
377        Uuid::parse_str("db5cd9c7-1658-4214-896e-8213678d3534")?,
378        "Custom points",
379        "custom-points",
380        uh_data.clone(),
381        false,
382        seed_users_result,
383    )
384    .await?;
385
386    let _closed_course_id = seed_sample_course(
387        Uuid::parse_str("7622eb8e-15a5-40c8-8136-0956d9f25b16")?,
388        "Closed course",
389        "closed-course",
390        uh_data.clone(),
391        false,
392        seed_users_result,
393    )
394    .await?;
395
396    let _changing_course_instance_id = seed_switching_course_instances_course(
397        Uuid::parse_str("813ce3c6-acbc-47a5-9d95-47ade9d09a74")?,
398        "Changing course instance",
399        "changing-course-instance",
400        uh_data.clone(),
401        false,
402        seed_users_result,
403    )
404    .await?;
405
406    Ok(uh_mathstat_id)
407}