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