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