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 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 courses::set_cheater_detection_enabled(&mut conn, suspected_cheaters_course_id, true).await?;
331
332 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}