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 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 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}