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