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