From 90173f4dc375f5d860fe235a1de576c2d342eaa4 Mon Sep 17 00:00:00 2001 From: Heliozoa Date: Tue, 11 Jul 2023 21:01:03 +0300 Subject: [PATCH 1/4] Improve seed structure --- services/headless-lms/Cargo.lock | 1 + services/headless-lms/entrypoint/Cargo.toml | 2 + services/headless-lms/entrypoint/src/main.rs | 47 +- .../server/src/programs/seed/mod.rs | 20 +- .../server/src/programs/seed/seed_courses.rs | 387 ++++++++------ .../server/src/programs/seed/seed_helpers.rs | 63 ++- .../programs/seed/seed_organizations/uh_cs.rs | 478 +++++------------- .../seed/seed_organizations/uh_mathstat.rs | 24 +- services/headless-lms/utils/src/futures.rs | 3 +- 9 files changed, 476 insertions(+), 549 deletions(-) diff --git a/services/headless-lms/Cargo.lock b/services/headless-lms/Cargo.lock index 600a93afa3fd..ab33abb7034f 100644 --- a/services/headless-lms/Cargo.lock +++ b/services/headless-lms/Cargo.lock @@ -1480,6 +1480,7 @@ dependencies = [ "actix-web", "anyhow", "headless-lms-server", + "tokio", ] [[package]] diff --git a/services/headless-lms/entrypoint/Cargo.toml b/services/headless-lms/entrypoint/Cargo.toml index ffcbfd22c763..69284ba877a1 100644 --- a/services/headless-lms/entrypoint/Cargo.toml +++ b/services/headless-lms/entrypoint/Cargo.toml @@ -16,3 +16,5 @@ headless-lms-server = { path = "../server" } actix-web = "4.3.1" # Flexible concrete Error type built on std::error::Error anyhow = "1.0.71" +# A runtime for writing reliable network applications without compromising speed. +tokio = "1.29.1" diff --git a/services/headless-lms/entrypoint/src/main.rs b/services/headless-lms/entrypoint/src/main.rs index 6794002c3d46..2578ea4fb43f 100644 --- a/services/headless-lms/entrypoint/src/main.rs +++ b/services/headless-lms/entrypoint/src/main.rs @@ -1,29 +1,50 @@ +use std::future::Future; + use headless_lms_server::programs; /// The entrypoint to all the binaries provided by the project. /// Expects program name as the first argument. -#[actix_web::main] -async fn main() -> anyhow::Result<()> { +fn main() -> anyhow::Result<()> { let program_name = std::env::args() .nth(1) .expect("No program name provided as the first argument."); match program_name.as_str() { - "doc-file-generator" => programs::doc_file_generator::main().await?, - "email-deliver" => programs::email_deliver::main().await?, - "ended-exams-processor" => programs::ended_exams_processor::main().await?, + "doc-file-generator" => tokio_run(programs::doc_file_generator::main())?, + "email-deliver" => tokio_run(programs::email_deliver::main())?, + "ended-exams-processor" => tokio_run(programs::ended_exams_processor::main())?, "open-university-registration-link-fetcher" => { - programs::open_university_registration_link_fetcher::main().await? + tokio_run(programs::open_university_registration_link_fetcher::main())? } - "regrader" => programs::regrader::main().await?, - "seed" => programs::seed::main().await?, - "service-info-fetcher" => programs::service_info_fetcher::main().await?, - "peer-review-updater" => programs::peer_review_updater::main().await?, - "start-server" => programs::start_server::main().await?, + "regrader" => tokio_run(programs::regrader::main())?, + "seed" => tokio_run(programs::seed::main())?, + "service-info-fetcher" => tokio_run(programs::service_info_fetcher::main())?, + "peer-review-updater" => tokio_run(programs::peer_review_updater::main())?, + "start-server" => actix_run(programs::start_server::main())?, "sorter" => programs::sorter::sort()?, - "sync-tmc-users" => programs::sync_tmc_users::main().await?, - "calculate-page-visit-stats" => programs::calculate_page_visit_stats::main().await?, + "sync-tmc-users" => tokio_run(programs::sync_tmc_users::main())?, + "calculate-page-visit-stats" => tokio_run(programs::calculate_page_visit_stats::main())?, _ => panic!("Unknown program name: {}", program_name), }; Ok(()) } + +fn actix_run(f: F) -> anyhow::Result<()> +where + F: Future>, +{ + let rt = actix_web::rt::Runtime::new()?; + rt.block_on(f)?; + Ok(()) +} + +// tokio's default runtime can use multiple threads, so it's less prone to stack overflows when spawning lots of tasks +// making it better suited for non-actix-web tasks +fn tokio_run(f: F) -> anyhow::Result<()> +where + F: Future>, +{ + let rt = tokio::runtime::Runtime::new()?; + rt.block_on(f)?; + Ok(()) +} diff --git a/services/headless-lms/server/src/programs/seed/mod.rs b/services/headless-lms/server/src/programs/seed/mod.rs index 522f5b531866..3eec2ecffd14 100644 --- a/services/headless-lms/server/src/programs/seed/mod.rs +++ b/services/headless-lms/server/src/programs/seed/mod.rs @@ -1,5 +1,3 @@ -#![allow(clippy::too_many_arguments)] - pub mod seed_certificate_fonts; pub mod seed_courses; pub mod seed_exercise_services; @@ -28,26 +26,28 @@ pub async fn main() -> anyhow::Result<()> { let (_, seed_users_result, _) = try_join!( run_parallelly(seed_exercise_services::seed_exercise_services( db_pool.clone() - ),), + )), run_parallelly(seed_users::seed_users(db_pool.clone())), run_parallelly(seed_playground_examples::seed_playground_examples( db_pool.clone() - ),), + )), )?; let (uh_cs_organization_result, _uh_mathstat_organization_id) = try_join!( - run_parallelly(seed_organizations::uh_cs::seed_organization_uh_cs( - db_pool.clone(), - seed_users_result.clone(), - Arc::clone(&jwt_key), + Box::pin(run_parallelly( + seed_organizations::uh_cs::seed_organization_uh_cs( + db_pool.clone(), + seed_users_result.clone(), + Arc::clone(&jwt_key), + ) )), - run_parallelly( + Box::pin(run_parallelly( seed_organizations::uh_mathstat::seed_organization_uh_mathstat( db_pool.clone(), seed_users_result.clone(), Arc::clone(&jwt_key), ) - ) + )) )?; seed_roles::seed_roles(&db_pool, &seed_users_result, &uh_cs_organization_result).await?; diff --git a/services/headless-lms/server/src/programs/seed/seed_courses.rs b/services/headless-lms/server/src/programs/seed/seed_courses.rs index c6c1289bb84c..7cd6917baf26 100644 --- a/services/headless-lms/server/src/programs/seed/seed_courses.rs +++ b/services/headless-lms/server/src/programs/seed/seed_courses.rs @@ -41,20 +41,32 @@ use sqlx::{Pool, Postgres}; use tracing::info; use uuid::Uuid; -use super::seed_helpers::heading; +use super::seed_helpers::{heading, CommonExerciseData}; + +#[derive(Clone)] +pub struct CommonCourseData { + pub db_pool: Pool, + pub organization_id: Uuid, + pub admin_user_id: Uuid, + pub student_user_id: Uuid, + pub example_normal_user_ids: Arc>, + pub jwt_key: Arc, +} -#[allow(clippy::too_many_arguments)] pub async fn seed_sample_course( - db_pool: &Pool, - org: Uuid, course_id: Uuid, course_name: &str, course_slug: &str, - admin: Uuid, - student: Uuid, - users: &[Uuid], - jwt_key: Arc, + common_course_data: CommonCourseData, ) -> Result { + let CommonCourseData { + db_pool, + organization_id: org, + admin_user_id: admin, + student_user_id: student, + example_normal_user_ids: users, + jwt_key, + } = common_course_data; let spec_fetcher = models_requests::make_spec_fetcher(Uuid::new_v4(), Arc::clone(&jwt_key)); info!("inserting sample course {}", course_name); let mut conn = db_pool.acquire().await?; @@ -359,15 +371,17 @@ pub async fn seed_sample_course( Uuid::new_v5(&course_id, b"4027d508-4fad-422e-bb7f-15c613a02cc6"); let (exercise_block_1, exercise_1, slide_1, task_1) = create_best_exercise( - exercise_1_id, - exercise_1_slide_1_id, - exercise_1_slide_1_task_1_id, - block_id_2, block_id_3, exercise_1_slide_1_task_1_spec_1_id, exercise_1_slide_1_task_1_spec_2_id, exercise_1_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_1_id, + exercise_slide_id: exercise_1_slide_1_id, + exercise_task_id: exercise_1_slide_1_task_1_id, + block_id: block_id_2, + }, ); let page_c1_1 = create_page( &mut conn, @@ -424,37 +438,43 @@ pub async fn seed_sample_course( let exercise_4_slide_1_task_1_spec_3_id = Uuid::new_v5(&course_id, b"fca5a8ba-50e0-4375-8d4b-9d02762d908c"); let (exercise_block_2, exercise_2, slide_2, task_2) = create_best_exercise( - exercise_2_id, - exercise_2_slide_1_id, - exercise_2_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"2dbb4649-bcac-47ab-a817-ca17dcd70378"), Uuid::new_v5(&course_id, b"c0986981-c8ae-4c0b-b558-1163a16760ec"), exercise_2_slide_1_task_1_spec_1_id, exercise_2_slide_1_task_1_spec_2_id, exercise_2_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_2_id, + exercise_slide_id: exercise_2_slide_1_id, + exercise_task_id: exercise_2_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"2dbb4649-bcac-47ab-a817-ca17dcd70378"), + }, ); let (exercise_block_3, exercise_3, slide_3, task_3) = create_best_exercise( - exercise_3_id, - exercise_3_slide_1_id, - exercise_3_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"fb26489d-ca49-4f76-a1c2-f759ed3146c0"), Uuid::new_v5(&course_id, b"c0986981-c8ae-4c0b-b558-1163a16760ec"), exercise_3_slide_1_task_1_spec_1_id, exercise_3_slide_1_task_1_spec_2_id, exercise_3_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_3_id, + exercise_slide_id: exercise_3_slide_1_id, + exercise_task_id: exercise_3_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"fb26489d-ca49-4f76-a1c2-f759ed3146c0"), + }, ); let (exercise_block_4, exercise_4, slide_4, task_4_1) = create_best_exercise( - exercise_4_id, - exercise_4_slide_1_id, - exercise_4_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"334593ad-8ba5-4589-b1f7-b159e754bdc5"), Uuid::new_v5(&course_id, b"389e80bd-5f91-40c7-94ff-7dda1eeb96fb"), exercise_4_slide_1_task_1_spec_1_id, exercise_4_slide_1_task_1_spec_2_id, exercise_4_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_4_id, + exercise_slide_id: exercise_4_slide_1_id, + exercise_task_id: exercise_4_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"334593ad-8ba5-4589-b1f7-b159e754bdc5"), + }, ); let page2_id = create_page( @@ -499,10 +519,6 @@ pub async fn seed_sample_course( quizzes_exercise_task_1, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"a6ee42d0-2200-43b7-9981-620753a9b5c0"), - Uuid::new_v5(&course_id, b"8d01d9b3-87d1-4e24-bee2-2726d3853ec6"), - Uuid::new_v5(&course_id, b"00dd984d-8651-404e-80b8-30fae9cf32ed"), - Uuid::new_v5(&course_id, b"a66c2552-8123-4287-bd8b-b49a29204870"), Uuid::new_v5(&course_id, b"f6f63ff0-c119-4141-922b-bc04cbfa0a31"), true, serde_json::json!({ @@ -551,6 +567,12 @@ pub async fn seed_sample_course( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"a6ee42d0-2200-43b7-9981-620753a9b5c0"), + exercise_slide_id: Uuid::new_v5(&course_id, b"8d01d9b3-87d1-4e24-bee2-2726d3853ec6"), + exercise_task_id: Uuid::new_v5(&course_id, b"00dd984d-8651-404e-80b8-30fae9cf32ed"), + block_id: Uuid::new_v5(&course_id, b"a66c2552-8123-4287-bd8b-b49a29204870"), + }, ); let ( @@ -560,10 +582,6 @@ pub async fn seed_sample_course( quizzes_exercise_task_2, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"949b548f-a87f-4dc6-aafc-9f1e1abe34a7"), - Uuid::new_v5(&course_id, b"39c36d3f-017e-4c36-a97e-908e25b3678b"), - Uuid::new_v5(&course_id, b"8ae8971c-95dd-4d8c-b38f-152ad89c6b20"), - Uuid::new_v5(&course_id, b"d05b1d9b-f270-4e5e-baeb-a904ea29dc90"), Uuid::new_v5(&course_id, b"1057f91c-9dac-4364-9d6a-fa416abc540b"), false, serde_json::json!({ @@ -613,6 +631,12 @@ pub async fn seed_sample_course( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"949b548f-a87f-4dc6-aafc-9f1e1abe34a7"), + exercise_slide_id: Uuid::new_v5(&course_id, b"39c36d3f-017e-4c36-a97e-908e25b3678b"), + exercise_task_id: Uuid::new_v5(&course_id, b"8ae8971c-95dd-4d8c-b38f-152ad89c6b20"), + block_id: Uuid::new_v5(&course_id, b"d05b1d9b-f270-4e5e-baeb-a904ea29dc90"), + }, ); let ( @@ -622,10 +646,6 @@ pub async fn seed_sample_course( quizzes_exercise_task_3, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"9bcf634d-584c-4fef-892c-3c0e97dab1d5"), - Uuid::new_v5(&course_id, b"984457f6-bc9b-4604-b54c-80fb4adfab76"), - Uuid::new_v5(&course_id, b"e4230b3a-1db8-49c4-9554-1f96f7f3d015"), - Uuid::new_v5(&course_id, b"52939561-af36-4ab6-bffa-be97e94d3314"), Uuid::new_v5(&course_id, b"8845b17e-2320-4384-97f8-24e42457cb5e"), false, serde_json::json!({ @@ -694,6 +714,12 @@ pub async fn seed_sample_course( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"9bcf634d-584c-4fef-892c-3c0e97dab1d5"), + exercise_slide_id: Uuid::new_v5(&course_id, b"984457f6-bc9b-4604-b54c-80fb4adfab76"), + exercise_task_id: Uuid::new_v5(&course_id, b"e4230b3a-1db8-49c4-9554-1f96f7f3d015"), + block_id: Uuid::new_v5(&course_id, b"52939561-af36-4ab6-bffa-be97e94d3314"), + }, ); let ( @@ -703,10 +729,6 @@ pub async fn seed_sample_course( quizzes_exercise_task_4, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"854a4e05-6575-4d27-8feb-6ee01f662d8a"), - Uuid::new_v5(&course_id, b"6a8e65be-f5cd-4c87-b4f9-9522cb37bbcb"), - Uuid::new_v5(&course_id, b"b5e1e7e87-0678-4296-acf7-a8ac926ff94b"), - Uuid::new_v5(&course_id, b"50e26d7f-f11f-4a8a-990d-fb17c3371d1d"), Uuid::new_v5(&course_id, b"7ca39a36-2dcd-4521-bbf6-bfc5849874e3"), false, serde_json::json!({ @@ -796,6 +818,12 @@ pub async fn seed_sample_course( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"854a4e05-6575-4d27-8feb-6ee01f662d8a"), + exercise_slide_id: Uuid::new_v5(&course_id, b"6a8e65be-f5cd-4c87-b4f9-9522cb37bbcb"), + exercise_task_id: Uuid::new_v5(&course_id, b"b5e1e7e87-0678-4296-acf7-a8ac926ff94b"), + block_id: Uuid::new_v5(&course_id, b"50e26d7f-f11f-4a8a-990d-fb17c3371d1d"), + }, ); let ( @@ -805,10 +833,6 @@ pub async fn seed_sample_course( quizzes_exercise_task_5, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"981623c8-baa3-4d14-bb8a-963e167da9ca"), - Uuid::new_v5(&course.id, b"b1a6d7e4-00b2-43fb-bf39-863f4ef49d09"), - Uuid::new_v5(&course.id, b"1a2f2c9f-9552-440e-8dd3-1e3703bd0fab"), - Uuid::new_v5(&course.id, b"6b568812-f752-4d9f-a60a-48257822d21e"), Uuid::new_v5(&course.id, b"b2f7d8d5-f3c0-4cac-8eb7-89a7b88c2236"), false, serde_json::json!({ @@ -881,6 +905,12 @@ pub async fn seed_sample_course( "updatedAt": "2022-05-04T09:03:06.271Z" }), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"981623c8-baa3-4d14-bb8a-963e167da9ca"), + exercise_slide_id: Uuid::new_v5(&course.id, b"b1a6d7e4-00b2-43fb-bf39-863f4ef49d09"), + exercise_task_id: Uuid::new_v5(&course.id, b"1a2f2c9f-9552-440e-8dd3-1e3703bd0fab"), + block_id: Uuid::new_v5(&course.id, b"6b568812-f752-4d9f-a60a-48257822d21e"), + }, ); let ( @@ -890,16 +920,18 @@ pub async fn seed_sample_course( quizzes_exercise_task_6, ) = quizzes_exercise( "Multiple choice with feedback".to_string(), - Uuid::new_v5(&course.id, b"f7fa3a08-e287-44de-aea8-32133af89d31"), - Uuid::new_v5(&course.id, b"31820133-579a-4d9f-8b0c-2120f76d1390"), - Uuid::new_v5(&course.id, b"55f929c7-30ab-441d-a0ad-6cd115857b3b"), - Uuid::new_v5(&course.id, b"d7a91d07-9bd9-449c-9862-fbacb0b402b0"), Uuid::new_v5(&course.id, b"664ea614-4af4-4ad0-9855-eae1881568e6"), false, serde_json::from_str(include_str!( "../../assets/quizzes-multiple-choice-feedback.json" ))?, Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"f7fa3a08-e287-44de-aea8-32133af89d31"), + exercise_slide_id: Uuid::new_v5(&course.id, b"31820133-579a-4d9f-8b0c-2120f76d1390"), + exercise_task_id: Uuid::new_v5(&course.id, b"55f929c7-30ab-441d-a0ad-6cd115857b3b"), + block_id: Uuid::new_v5(&course.id, b"d7a91d07-9bd9-449c-9862-fbacb0b402b0"), + }, ); let ( @@ -909,14 +941,16 @@ pub async fn seed_sample_course( quizzes_exercise_task_7, ) = quizzes_exercise( "Scale".to_string(), - Uuid::new_v5(&course.id, b"212132eb-b108-4027-b312-2275cf0b7473"), - Uuid::new_v5(&course.id, b"6172a36a-b65d-463c-81d0-7f7fce07615c"), - Uuid::new_v5(&course.id, b"0dcfc4ca-c2f7-40b0-8654-14c6893a1fd9"), - Uuid::new_v5(&course.id, b"b64d7bd2-a216-494e-a23c-7a975fb1a415"), Uuid::new_v5(&course.id, b"05fa1188-4653-4904-bf1c-a93363225841"), false, serde_json::from_str(include_str!("../../assets/scale.json"))?, Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"212132eb-b108-4027-b312-2275cf0b7473"), + exercise_slide_id: Uuid::new_v5(&course.id, b"6172a36a-b65d-463c-81d0-7f7fce07615c"), + exercise_task_id: Uuid::new_v5(&course.id, b"0dcfc4ca-c2f7-40b0-8654-14c6893a1fd9"), + block_id: Uuid::new_v5(&course.id, b"b64d7bd2-a216-494e-a23c-7a975fb1a415"), + }, ); let ( @@ -926,14 +960,16 @@ pub async fn seed_sample_course( quizzes_exercise_task_8, ) = quizzes_exercise( "Vector exercise".to_string(), - Uuid::new_v5(&course.id, b"80373dc3-ceba-45b4-a114-161d60228c0c"), - Uuid::new_v5(&course.id, b"08f0da90-9080-4cdd-adc7-66173cd5b833"), - Uuid::new_v5(&course.id, b"ea24c875-1a3c-403e-8272-b1249a475c89"), - Uuid::new_v5(&course.id, b"38ed716f-5d4f-4ddd-9f5a-700ef124b934"), Uuid::new_v5(&course.id, b"0c271345-6934-4489-8164-2cc4dc8974bb"), false, serde_json::from_str(include_str!("../../assets/vector-exercise.json"))?, None, + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"80373dc3-ceba-45b4-a114-161d60228c0c"), + exercise_slide_id: Uuid::new_v5(&course.id, b"08f0da90-9080-4cdd-adc7-66173cd5b833"), + exercise_task_id: Uuid::new_v5(&course.id, b"ea24c875-1a3c-403e-8272-b1249a475c89"), + block_id: Uuid::new_v5(&course.id, b"38ed716f-5d4f-4ddd-9f5a-700ef124b934"), + }, ); let page_3 = create_page( @@ -1243,15 +1279,17 @@ pub async fn seed_sample_course( let exercise_5_slide_1_task_1_spec_3_id = Uuid::new_v5(&course_id, b"d77fb97d-322c-4c5f-a405-8978a8cfb0a9"); let (exercise_block_5, exercise_5, exercise_slide_5, exercise_task_5) = create_best_exercise( - exercise_5_id, - exercise_5_slide_1_id, - exercise_5_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"e869c471-b1b7-42a0-af05-dffd1d86a7bb"), Uuid::new_v5(&course_id, b"fe464d17-2365-4e65-8b33-e0ebb5a67836"), exercise_5_slide_1_task_1_spec_1_id, exercise_5_slide_1_task_1_spec_2_id, exercise_5_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_5_id, + exercise_slide_id: exercise_5_slide_1_id, + exercise_task_id: exercise_5_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"e869c471-b1b7-42a0-af05-dffd1d86a7bb"), + }, ); create_page( &mut conn, @@ -1564,7 +1602,7 @@ pub async fn seed_sample_course( // enrollments, user exercise states, submissions, grades info!("sample enrollments, user exercise states, submissions, grades"); - for &user_id in users { + for user_id in users.iter().copied() { course_instance_enrollments::insert_enrollment_and_set_as_current( &mut conn, NewCourseInstanceEnrollment { @@ -1848,12 +1886,17 @@ pub async fn seed_sample_course( } pub async fn create_glossary_course( - db_pool: &Pool, - org_id: Uuid, - admin: Uuid, course_id: Uuid, - jwt_key: Arc, + common_course_data: CommonCourseData, ) -> Result { + let CommonCourseData { + db_pool, + organization_id: org_id, + admin_user_id: admin, + student_user_id: _, + example_normal_user_ids: _, + jwt_key, + } = common_course_data; let mut conn = db_pool.acquire().await?; // Create new course @@ -2008,10 +2051,6 @@ pub async fn seed_cs_course_material( quizzes_exercise_task_5, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"cd3aa815-620e-43b3-b291-0fb10beca030"), - Uuid::new_v5(&course.id, b"0b1bbfb0-df56-4e40-92f1-df0a33f1fc70"), - Uuid::new_v5(&course.id, b"7f011d0e-1cbf-4870-bacf-1873cf360c15"), - Uuid::new_v5(&course.id, b"b9446b94-0edf-465c-9a9a-57708b7ef180"), Uuid::new_v5(&course.id, b"58e71279-81e1-4679-83e6-8f5f23ec055a"), false, serde_json::json!({ @@ -2077,6 +2116,12 @@ pub async fn seed_cs_course_material( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"cd3aa815-620e-43b3-b291-0fb10beca030"), + exercise_slide_id: Uuid::new_v5(&course.id, b"0b1bbfb0-df56-4e40-92f1-df0a33f1fc70"), + exercise_task_id: Uuid::new_v5(&course.id, b"7f011d0e-1cbf-4870-bacf-1873cf360c15"), + block_id: Uuid::new_v5(&course.id, b"b9446b94-0edf-465c-9a9a-57708b7ef180"), + }, ); let ( @@ -2086,16 +2131,18 @@ pub async fn seed_cs_course_material( quizzes_exercise_task_6, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"925d4a89-0f25-4e8e-bc11-350393d8d894"), - Uuid::new_v5(&course.id, b"ff92ca4a-aa9c-11ec-ac56-475e57747ad3"), - Uuid::new_v5(&course.id, b"9037cb17-3841-4a79-8f50-bbe595a4f785"), - Uuid::new_v5(&course.id, b"d6d80ae0-97a1-4db1-8a3b-2bdde3cfbe9a"), Uuid::new_v5(&course.id, b"085b60ec-aa9d-11ec-b500-7b1e176646f8"), false, serde_json::from_str(include_str!( "../../assets/quizzes-multiple-choice-additional-feedback.json" ))?, Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"925d4a89-0f25-4e8e-bc11-350393d8d894"), + exercise_slide_id: Uuid::new_v5(&course.id, b"ff92ca4a-aa9c-11ec-ac56-475e57747ad3"), + exercise_task_id: Uuid::new_v5(&course.id, b"9037cb17-3841-4a79-8f50-bbe595a4f785"), + block_id: Uuid::new_v5(&course.id, b"d6d80ae0-97a1-4db1-8a3b-2bdde3cfbe9a"), + }, ); let ( @@ -2105,10 +2152,6 @@ pub async fn seed_cs_course_material( quizzes_exercise_task_7, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"57905c8a-aa9d-11ec-92d4-47ab996cb70c"), - Uuid::new_v5(&course.id, b"5b058552-aa9d-11ec-bc36-57e1c5f8407a"), - Uuid::new_v5(&course.id, b"5d953894-aa9d-11ec-97e7-2ff4d73f69f1"), - Uuid::new_v5(&course.id, b"604dae7c-aa9d-11ec-8df1-575042832340"), Uuid::new_v5(&course.id, b"6365746e-aa9d-11ec-8718-0b5628cbe29f"), false, serde_json::json!({ @@ -2174,6 +2217,12 @@ pub async fn seed_cs_course_material( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"57905c8a-aa9d-11ec-92d4-47ab996cb70c"), + exercise_slide_id: Uuid::new_v5(&course.id, b"5b058552-aa9d-11ec-bc36-57e1c5f8407a"), + exercise_task_id: Uuid::new_v5(&course.id, b"5d953894-aa9d-11ec-97e7-2ff4d73f69f1"), + block_id: Uuid::new_v5(&course.id, b"604dae7c-aa9d-11ec-8df1-575042832340"), + }, ); let ( @@ -2183,10 +2232,6 @@ pub async fn seed_cs_course_material( quizzes_exercise_task_8, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"c1a4831c-cc78-4f42-be18-2a35a7f3b506"), - Uuid::new_v5(&course.id, b"75045b18-aa9d-11ec-b3d1-6f64c2d6d46d"), - Uuid::new_v5(&course.id, b"712fd37c-e3d7-4569-8a64-371d7dda9c19"), - Uuid::new_v5(&course.id, b"6799021d-ff0c-4e4d-b5db-c2c19fba7fb9"), Uuid::new_v5(&course.id, b"01b69776-3e82-4694-98a9-5ce53f2a4ab5"), false, serde_json::json!({ @@ -2252,6 +2297,12 @@ pub async fn seed_cs_course_material( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"c1a4831c-cc78-4f42-be18-2a35a7f3b506"), + exercise_slide_id: Uuid::new_v5(&course.id, b"75045b18-aa9d-11ec-b3d1-6f64c2d6d46d"), + exercise_task_id: Uuid::new_v5(&course.id, b"712fd37c-e3d7-4569-8a64-371d7dda9c19"), + block_id: Uuid::new_v5(&course.id, b"6799021d-ff0c-4e4d-b5db-c2c19fba7fb9"), + }, ); pages::update_page( @@ -2688,6 +2739,7 @@ pub async fn seed_cs_course_material( Ok(course.id) } +#[allow(clippy::too_many_arguments)] pub async fn seed_course_without_submissions( db_pool: &Pool, org: Uuid, @@ -2996,15 +3048,17 @@ pub async fn seed_course_without_submissions( Uuid::new_v5(&course_id, b"4027d508-4fad-422e-bb7f-15c613a02cc6"); let (exercise_block_1, exercise_1, slide_1, task_1) = create_best_exercise( - exercise_1_id, - exercise_1_slide_1_id, - exercise_1_slide_1_task_1_id, - block_id_2, block_id_3, exercise_1_slide_1_task_1_spec_1_id, exercise_1_slide_1_task_1_spec_2_id, exercise_1_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_1_id, + exercise_slide_id: exercise_1_slide_1_id, + exercise_task_id: exercise_1_slide_1_task_1_id, + block_id: block_id_2, + }, ); let page_c1_1 = create_page( &mut conn, @@ -3069,37 +3123,43 @@ pub async fn seed_course_without_submissions( let exercise_4_slide_1_task_1_spec_3_id = Uuid::new_v5(&course_id, b"fca5a8ba-50e0-4375-8d4b-9d02762d908c"); let (exercise_block_2, exercise_2, slide_2, task_2) = create_best_exercise( - exercise_2_id, - exercise_2_slide_1_id, - exercise_2_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"2dbb4649-bcac-47ab-a817-ca17dcd70378"), Uuid::new_v5(&course_id, b"c0986981-c8ae-4c0b-b558-1163a16760ec"), exercise_2_slide_1_task_1_spec_1_id, exercise_2_slide_1_task_1_spec_2_id, exercise_2_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_2_id, + exercise_slide_id: exercise_2_slide_1_id, + exercise_task_id: exercise_2_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"2dbb4649-bcac-47ab-a817-ca17dcd70378"), + }, ); let (exercise_block_3, exercise_3, slide_3, task_3) = create_best_exercise( - exercise_3_id, - exercise_3_slide_1_id, - exercise_3_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"fb26489d-ca49-4f76-a1c2-f759ed3146c0"), Uuid::new_v5(&course_id, b"c0986981-c8ae-4c0b-b558-1163a16760ec"), exercise_3_slide_1_task_1_spec_1_id, exercise_3_slide_1_task_1_spec_2_id, exercise_3_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_3_id, + exercise_slide_id: exercise_3_slide_1_id, + exercise_task_id: exercise_3_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"fb26489d-ca49-4f76-a1c2-f759ed3146c0"), + }, ); let (exercise_block_4, exercise_4, slide_4, task_4_1) = create_best_exercise( - exercise_4_id, - exercise_4_slide_1_id, - exercise_4_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"334593ad-8ba5-4589-b1f7-b159e754bdc5"), Uuid::new_v5(&course_id, b"389e80bd-5f91-40c7-94ff-7dda1eeb96fb"), exercise_4_slide_1_task_1_spec_1_id, exercise_4_slide_1_task_1_spec_2_id, exercise_4_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_4_id, + exercise_slide_id: exercise_4_slide_1_id, + exercise_task_id: exercise_4_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"334593ad-8ba5-4589-b1f7-b159e754bdc5"), + }, ); let page2_id = create_page( @@ -3162,10 +3222,6 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_1, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"a6ee42d0-2200-43b7-9981-620753a9b5c0"), - Uuid::new_v5(&course_id, b"8d01d9b3-87d1-4e24-bee2-2726d3853ec6"), - Uuid::new_v5(&course_id, b"00dd984d-8651-404e-80b8-30fae9cf32ed"), - Uuid::new_v5(&course_id, b"a66c2552-8123-4287-bd8b-b49a29204870"), Uuid::new_v5(&course_id, b"f6f63ff0-c119-4141-922b-bc04cbfa0a31"), true, serde_json::json!({ @@ -3214,6 +3270,12 @@ pub async fn seed_course_without_submissions( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"a6ee42d0-2200-43b7-9981-620753a9b5c0"), + exercise_slide_id: Uuid::new_v5(&course_id, b"8d01d9b3-87d1-4e24-bee2-2726d3853ec6"), + exercise_task_id: Uuid::new_v5(&course_id, b"00dd984d-8651-404e-80b8-30fae9cf32ed"), + block_id: Uuid::new_v5(&course_id, b"a66c2552-8123-4287-bd8b-b49a29204870"), + }, ); let ( @@ -3223,10 +3285,6 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_2, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"949b548f-a87f-4dc6-aafc-9f1e1abe34a7"), - Uuid::new_v5(&course_id, b"39c36d3f-017e-4c36-a97e-908e25b3678b"), - Uuid::new_v5(&course_id, b"8ae8971c-95dd-4d8c-b38f-152ad89c6b20"), - Uuid::new_v5(&course_id, b"d05b1d9b-f270-4e5e-baeb-a904ea29dc90"), Uuid::new_v5(&course_id, b"1057f91c-9dac-4364-9d6a-fa416abc540b"), false, serde_json::json!({ @@ -3276,6 +3334,12 @@ pub async fn seed_course_without_submissions( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"949b548f-a87f-4dc6-aafc-9f1e1abe34a7"), + exercise_slide_id: Uuid::new_v5(&course_id, b"39c36d3f-017e-4c36-a97e-908e25b3678b"), + exercise_task_id: Uuid::new_v5(&course_id, b"8ae8971c-95dd-4d8c-b38f-152ad89c6b20"), + block_id: Uuid::new_v5(&course_id, b"d05b1d9b-f270-4e5e-baeb-a904ea29dc90"), + }, ); let ( @@ -3285,10 +3349,6 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_3, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"9bcf634d-584c-4fef-892c-3c0e97dab1d5"), - Uuid::new_v5(&course_id, b"984457f6-bc9b-4604-b54c-80fb4adfab76"), - Uuid::new_v5(&course_id, b"e4230b3a-1db8-49c4-9554-1f96f7f3d015"), - Uuid::new_v5(&course_id, b"52939561-af36-4ab6-bffa-be97e94d3314"), Uuid::new_v5(&course_id, b"8845b17e-2320-4384-97f8-24e42457cb5e"), false, serde_json::json!({ @@ -3357,6 +3417,12 @@ pub async fn seed_course_without_submissions( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"9bcf634d-584c-4fef-892c-3c0e97dab1d5"), + exercise_slide_id: Uuid::new_v5(&course_id, b"984457f6-bc9b-4604-b54c-80fb4adfab76"), + exercise_task_id: Uuid::new_v5(&course_id, b"e4230b3a-1db8-49c4-9554-1f96f7f3d015"), + block_id: Uuid::new_v5(&course_id, b"52939561-af36-4ab6-bffa-be97e94d3314"), + }, ); let ( @@ -3366,10 +3432,6 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_4, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course_id, b"854a4e05-6575-4d27-8feb-6ee01f662d8a"), - Uuid::new_v5(&course_id, b"6a8e65be-f5cd-4c87-b4f9-9522cb37bbcb"), - Uuid::new_v5(&course_id, b"b5e1e7e87-0678-4296-acf7-a8ac926ff94b"), - Uuid::new_v5(&course_id, b"50e26d7f-f11f-4a8a-990d-fb17c3371d1d"), Uuid::new_v5(&course_id, b"7ca39a36-2dcd-4521-bbf6-bfc5849874e3"), false, serde_json::json!({ @@ -3459,6 +3521,12 @@ pub async fn seed_course_without_submissions( "grantPointsPolicy": "grant_whenever_possible", "awardPointsEvenIfWrong": false}), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"854a4e05-6575-4d27-8feb-6ee01f662d8a"), + exercise_slide_id: Uuid::new_v5(&course_id, b"6a8e65be-f5cd-4c87-b4f9-9522cb37bbcb"), + exercise_task_id: Uuid::new_v5(&course_id, b"b5e1e7e87-0678-4296-acf7-a8ac926ff94b"), + block_id: Uuid::new_v5(&course_id, b"50e26d7f-f11f-4a8a-990d-fb17c3371d1d"), + }, ); let ( @@ -3468,10 +3536,6 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_5, ) = quizzes_exercise( "Best quizzes exercise".to_string(), - Uuid::new_v5(&course.id, b"981623c8-baa3-4d14-bb8a-963e167da9ca"), - Uuid::new_v5(&course.id, b"b1a6d7e4-00b2-43fb-bf39-863f4ef49d09"), - Uuid::new_v5(&course.id, b"1a2f2c9f-9552-440e-8dd3-1e3703bd0fab"), - Uuid::new_v5(&course.id, b"6b568812-f752-4d9f-a60a-48257822d21e"), Uuid::new_v5(&course.id, b"b2f7d8d5-f3c0-4cac-8eb7-89a7b88c2236"), false, serde_json::json!({ @@ -3544,6 +3608,12 @@ pub async fn seed_course_without_submissions( "updatedAt": "2022-05-04T09:03:06.271Z" }), Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"981623c8-baa3-4d14-bb8a-963e167da9ca"), + exercise_slide_id: Uuid::new_v5(&course.id, b"b1a6d7e4-00b2-43fb-bf39-863f4ef49d09"), + exercise_task_id: Uuid::new_v5(&course.id, b"1a2f2c9f-9552-440e-8dd3-1e3703bd0fab"), + block_id: Uuid::new_v5(&course.id, b"6b568812-f752-4d9f-a60a-48257822d21e"), + }, ); let ( @@ -3553,16 +3623,18 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_6, ) = quizzes_exercise( "Multiple choice with feedback".to_string(), - Uuid::new_v5(&course.id, b"f7fa3a08-e287-44de-aea8-32133af89d31"), - Uuid::new_v5(&course.id, b"31820133-579a-4d9f-8b0c-2120f76d1390"), - Uuid::new_v5(&course.id, b"55f929c7-30ab-441d-a0ad-6cd115857b3b"), - Uuid::new_v5(&course.id, b"d7a91d07-9bd9-449c-9862-fbacb0b402b0"), Uuid::new_v5(&course.id, b"664ea614-4af4-4ad0-9855-eae1881568e6"), false, serde_json::from_str(include_str!( "../../assets/quizzes-multiple-choice-feedback.json" ))?, Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"f7fa3a08-e287-44de-aea8-32133af89d31"), + exercise_slide_id: Uuid::new_v5(&course.id, b"31820133-579a-4d9f-8b0c-2120f76d1390"), + exercise_task_id: Uuid::new_v5(&course.id, b"55f929c7-30ab-441d-a0ad-6cd115857b3b"), + block_id: Uuid::new_v5(&course.id, b"d7a91d07-9bd9-449c-9862-fbacb0b402b0"), + }, ); let ( @@ -3572,14 +3644,16 @@ pub async fn seed_course_without_submissions( quizzes_exercise_task_7, ) = quizzes_exercise( "Scale".to_string(), - Uuid::new_v5(&course.id, b"212132eb-b108-4027-b312-2275cf0b7473"), - Uuid::new_v5(&course.id, b"6172a36a-b65d-463c-81d0-7f7fce07615c"), - Uuid::new_v5(&course.id, b"0dcfc4ca-c2f7-40b0-8654-14c6893a1fd9"), - Uuid::new_v5(&course.id, b"b64d7bd2-a216-494e-a23c-7a975fb1a415"), Uuid::new_v5(&course.id, b"05fa1188-4653-4904-bf1c-a93363225841"), false, serde_json::from_str(include_str!("../../assets/scale.json"))?, Some(Utc.with_ymd_and_hms(2125, 1, 1, 23, 59, 59).unwrap()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course.id, b"212132eb-b108-4027-b312-2275cf0b7473"), + exercise_slide_id: Uuid::new_v5(&course.id, b"6172a36a-b65d-463c-81d0-7f7fce07615c"), + exercise_task_id: Uuid::new_v5(&course.id, b"0dcfc4ca-c2f7-40b0-8654-14c6893a1fd9"), + block_id: Uuid::new_v5(&course.id, b"b64d7bd2-a216-494e-a23c-7a975fb1a415"), + }, ); let page_3 = create_page( @@ -3865,15 +3939,17 @@ pub async fn seed_course_without_submissions( let exercise_5_slide_1_task_1_spec_3_id = Uuid::new_v5(&course_id, b"d77fb97d-322c-4c5f-a405-8978a8cfb0a9"); let (exercise_block_5, exercise_5, exercise_slide_5, exercise_task_5) = create_best_exercise( - exercise_5_id, - exercise_5_slide_1_id, - exercise_5_slide_1_task_1_id, - Uuid::new_v5(&course_id, b"e869c471-b1b7-42a0-af05-dffd1d86a7bb"), Uuid::new_v5(&course_id, b"fe464d17-2365-4e65-8b33-e0ebb5a67836"), exercise_5_slide_1_task_1_spec_1_id, exercise_5_slide_1_task_1_spec_2_id, exercise_5_slide_1_task_1_spec_3_id, Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: exercise_5_id, + exercise_slide_id: exercise_5_slide_1_id, + exercise_task_id: exercise_5_slide_1_task_1_id, + block_id: Uuid::new_v5(&course_id, b"e869c471-b1b7-42a0-af05-dffd1d86a7bb"), + }, ); create_page( &mut conn, @@ -4058,14 +4134,19 @@ pub async fn seed_course_without_submissions( } pub async fn seed_peer_review_course_without_submissions( - db_pool: &Pool, - org: Uuid, course_id: Uuid, course_name: &str, course_slug: &str, - admin: Uuid, - jwt_key: Arc, + common_course_data: CommonCourseData, ) -> Result { + let CommonCourseData { + db_pool, + organization_id: org, + admin_user_id: admin, + student_user_id: _, + example_normal_user_ids: _, + jwt_key, + } = common_course_data; let spec_fetcher = models_requests::make_spec_fetcher(Uuid::new_v4(), Arc::clone(&jwt_key)); info!("inserting sample course {}", course_name); let mut conn = db_pool.acquire().await?; @@ -4176,15 +4257,17 @@ pub async fn seed_peer_review_course_without_submissions( Uuid::new_v5(&course_id, b"b354830c-38c7-4b83-8370-0e7222272c56"); let (exercise_block_1, exercise_1, slide_1, task_1) = create_best_exercise( - exercise_1_id, - exercise_1_slide_1_id, - exercise_1_slide_1_task_1_id, - block_id_1, block_id_2, exercise_1_slide_1_task_1_spec_1_id, exercise_1_slide_1_task_1_spec_2_id, exercise_1_slide_1_task_1_spec_3_id, Some("ManualReviewEverything".to_string()), + CommonExerciseData { + exercise_id: exercise_1_id, + exercise_slide_id: exercise_1_slide_1_id, + exercise_task_id: exercise_1_slide_1_task_1_id, + block_id: block_id_1, + }, ); create_page( @@ -4228,15 +4311,17 @@ pub async fn seed_peer_review_course_without_submissions( Uuid::new_v5(&course_id, b"9f6e4ad4-b9f5-40cf-b071-642da7058fec"); let (exercise_block_2, exercise_2, slide_1, task_1) = create_best_exercise( - exercise_2_id, - exercise_2_slide_1_id, - exercise_2_slide_1_task_1_id, - block_id_3, block_id_4, exercise_2_slide_1_task_1_spec_1_id, exercise_2_slide_1_task_1_spec_2_id, exercise_2_slide_1_task_1_spec_3_id, Some("AutomaticallyAcceptOrManualReviewByAverage".to_string()), + CommonExerciseData { + exercise_id: exercise_2_id, + exercise_slide_id: exercise_2_slide_1_id, + exercise_task_id: exercise_2_slide_1_task_1_id, + block_id: block_id_3, + }, ); create_page( @@ -4280,15 +4365,17 @@ pub async fn seed_peer_review_course_without_submissions( Uuid::new_v5(&course_id, b"31443721-fc55-4ea6-9b2a-2da8a6a991df"); let (exercise_block_3, exercise_3, slide_1, task_1) = create_best_exercise( - exercise_3_id, - exercise_3_slide_1_id, - exercise_3_slide_1_task_1_id, - block_id_5, block_id_6, exercise_3_slide_1_task_1_spec_1_id, exercise_3_slide_1_task_1_spec_2_id, exercise_3_slide_1_task_1_spec_3_id, Some("AutomaticallyAcceptOrRejectByAverage".to_string()), + CommonExerciseData { + exercise_id: exercise_3_id, + exercise_slide_id: exercise_3_slide_1_id, + exercise_task_id: exercise_3_slide_1_task_1_id, + block_id: block_id_5, + }, ); create_page( @@ -4332,15 +4419,17 @@ pub async fn seed_peer_review_course_without_submissions( Uuid::new_v5(&course_id, b"c17f23ca-7daa-40dd-b390-1ac8531dd17d"); let (exercise_block_1, exercise_1, slide_1, task_1) = create_best_exercise( - exercise_4_id, - exercise_4_slide_1_id, - exercise_4_slide_1_task_1_id, - block_id_7, block_id_8, exercise_4_slide_1_task_1_spec_1_id, exercise_4_slide_1_task_1_spec_2_id, exercise_4_slide_1_task_1_spec_3_id, Some("ManualReviewEverything2".to_string()), + CommonExerciseData { + exercise_id: exercise_4_id, + exercise_slide_id: exercise_4_slide_1_id, + exercise_task_id: exercise_4_slide_1_task_1_id, + block_id: block_id_7, + }, ); create_page( diff --git a/services/headless-lms/server/src/programs/seed/seed_helpers.rs b/services/headless-lms/server/src/programs/seed/seed_helpers.rs index bad5b5b351fa..c55b07520b6d 100644 --- a/services/headless-lms/server/src/programs/seed/seed_helpers.rs +++ b/services/headless-lms/server/src/programs/seed/seed_helpers.rs @@ -24,8 +24,6 @@ use std::sync::Arc; use uuid::Uuid; use crate::domain::models_requests::{self, JwtKey}; -// fix this -#[allow(clippy::too_many_arguments)] pub async fn create_page( conn: &mut PgConnection, course_id: Uuid, @@ -105,23 +103,33 @@ pub fn heading(content: &str, client_id: Uuid, level: i32) -> GutenbergBlock { } } -#[allow(clippy::too_many_arguments)] +#[derive(Clone, Copy)] +pub struct CommonExerciseData { + pub exercise_id: Uuid, + pub exercise_slide_id: Uuid, + pub exercise_task_id: Uuid, + pub block_id: Uuid, +} + pub fn create_best_exercise( - exercise_id: Uuid, - exercise_slide_id: Uuid, - exercise_task_id: Uuid, - block_id: Uuid, paragraph_id: Uuid, spec_1: Uuid, spec_2: Uuid, spec_3: Uuid, exercise_name: Option, + exercise_data: CommonExerciseData, ) -> ( GutenbergBlock, CmsPageExercise, CmsPageExerciseSlide, CmsPageExerciseTask, ) { + let CommonExerciseData { + exercise_id, + exercise_slide_id, + exercise_task_id, + block_id, + } = exercise_data; let (exercise_block, exercise, mut slides, mut tasks) = example_exercise_flexible( exercise_id, exercise_name.unwrap_or_else(|| "Best exercise".to_string()), @@ -237,23 +245,25 @@ pub fn example_exercise_flexible( (block, exercise, slides, tasks) } -#[allow(clippy::too_many_arguments)] pub fn quizzes_exercise( name: String, - exercise_id: Uuid, - exercise_slide_id: Uuid, - exercise_task_id: Uuid, - block_id: Uuid, paragraph_id: Uuid, needs_peer_review: bool, private_spec: serde_json::Value, deadline: Option>, + exercise_data: CommonExerciseData, ) -> ( GutenbergBlock, CmsPageExercise, CmsPageExerciseSlide, CmsPageExerciseTask, ) { + let CommonExerciseData { + exercise_id, + exercise_slide_id, + exercise_task_id, + block_id, + } = exercise_data; let block = GutenbergBlock { client_id: block_id, name: "moocfi/exercise".to_string(), @@ -308,7 +318,7 @@ pub async fn submit_and_grade( out_of_100: f32, ) -> Result<()> { // combine the id with the user id to ensure it's unique - let id = [id, &user_id.as_bytes()[..]].concat(); + let id: Vec = [id, &user_id.as_bytes()[..]].concat(); let slide_submission = exercise_slide_submissions::insert_exercise_slide_submission_with_id( conn, Uuid::new_v4(), @@ -387,6 +397,7 @@ pub async fn submit_and_grade( Ok(()) } +#[allow(clippy::too_many_arguments)] pub async fn create_exam( conn: &mut PgConnection, name: String, @@ -417,28 +428,38 @@ pub async fn create_exam( let (exam_exercise_block_1, exam_exercise_1, exam_exercise_slide_1, exam_exercise_task_1) = quizzes_exercise( "Multiple choice with feedback".to_string(), - Uuid::new_v5(&course_id, b"b1b16970-60bc-426e-9537-b29bd2185db3"), - Uuid::new_v5(&course_id, b"ea461a21-e0b4-4e09-a811-231f583b3dcb"), - Uuid::new_v5(&course_id, b"9d8ccf47-3e83-4459-8f2f-8e546a75f372"), - Uuid::new_v5(&course_id, b"a4edb4e5-507d-43f1-8058-9d95941dbf09"), Uuid::new_v5(&course_id, b"eced4875-ece9-4c3d-ad0a-2443e61b3e78"), false, serde_json::from_str(include_str!( "../../assets/quizzes-multiple-choice-feedback.json" ))?, None, + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"b1b16970-60bc-426e-9537-b29bd2185db3"), + exercise_slide_id: Uuid::new_v5( + &course_id, + b"ea461a21-e0b4-4e09-a811-231f583b3dcb", + ), + exercise_task_id: Uuid::new_v5(&course_id, b"9d8ccf47-3e83-4459-8f2f-8e546a75f372"), + block_id: Uuid::new_v5(&course_id, b"a4edb4e5-507d-43f1-8058-9d95941dbf09"), + }, ); let (exam_exercise_block_2, exam_exercise_2, exam_exercise_slide_2, exam_exercise_task_2) = create_best_exercise( - Uuid::new_v5(&course_id, b"44f472e5-b726-4c50-89a1-93f4170673f5"), - Uuid::new_v5(&course_id, b"23182b3d-fbf4-4c0d-93fa-e9ddc199cc52"), - Uuid::new_v5(&course_id, b"ca105826-5007-439f-87be-c25f9c79506e"), - Uuid::new_v5(&course_id, b"96a9e586-cf88-4cb2-b7c9-efc2bc47e90b"), Uuid::new_v5(&course_id, b"fe5bb5a9-d0ab-4072-abe1-119c9c1e4f4a"), Uuid::new_v5(&course_id, b"22959aad-26fc-4212-8259-c128cdab8b08"), Uuid::new_v5(&course_id, b"d8ba9e92-4530-4a74-9b11-eb708fa54d40"), Uuid::new_v5(&course_id, b"846f4895-f573-41e2-9926-cd700723ac18"), Some("Best exercise".to_string()), + CommonExerciseData { + exercise_id: Uuid::new_v5(&course_id, b"44f472e5-b726-4c50-89a1-93f4170673f5"), + exercise_slide_id: Uuid::new_v5( + &course_id, + b"23182b3d-fbf4-4c0d-93fa-e9ddc199cc52", + ), + exercise_task_id: Uuid::new_v5(&course_id, b"ca105826-5007-439f-87be-c25f9c79506e"), + block_id: Uuid::new_v5(&course_id, b"96a9e586-cf88-4cb2-b7c9-efc2bc47e90b"), + }, ); pages::insert_page( conn, diff --git a/services/headless-lms/server/src/programs/seed/seed_organizations/uh_cs.rs b/services/headless-lms/server/src/programs/seed/seed_organizations/uh_cs.rs index c2e9ee1466f9..c90083695ba9 100644 --- a/services/headless-lms/server/src/programs/seed/seed_organizations/uh_cs.rs +++ b/services/headless-lms/server/src/programs/seed/seed_organizations/uh_cs.rs @@ -24,7 +24,7 @@ use crate::{ programs::seed::{ seed_courses::{ create_glossary_course, seed_cs_course_material, - seed_peer_review_course_without_submissions, seed_sample_course, + seed_peer_review_course_without_submissions, seed_sample_course, CommonCourseData, }, seed_helpers::create_exam, }, @@ -69,49 +69,148 @@ pub async fn seed_organization_uh_cs( info!("inserting uh-cs courses"); // Seed courses in groups to improve performance. We cannot create a new task for each course because it is causing stack overflows in headless-lms entrypoint in seemingly unrelated code. + let cs_data = CommonCourseData { + db_pool: db_pool.clone(), + organization_id: uh_cs_organization_id, + admin_user_id, + student_user_id, + example_normal_user_ids: Arc::new(example_normal_user_ids.clone()), + jwt_key: Arc::clone(&jwt_key), + }; let ( - (cs_intro, automatic_completions_id, introduction_to_localizing), - (manual_completions_id, automatic_course_with_exam_id), - (certificates_id,), + cs_intro, + automatic_completions_id, + introduction_to_localizing, + manual_completions_id, + automatic_course_with_exam_id, + certificates_id, .., ) = try_join!( - run_parallelly(courses_group_1( - db_pool.clone(), - uh_cs_organization_id, - admin_user_id, - student_user_id, - example_normal_user_ids.clone(), - Arc::clone(&jwt_key), + // using these ids + run_parallelly(seed_sample_course( + Uuid::parse_str("7f36cf71-c2d2-41fc-b2ae-bbbcafab0ea5")?, + "Introduction to everything", + "introduction-to-everything", + cs_data.clone(), )), - run_parallelly(courses_group_2( - db_pool.clone(), - uh_cs_organization_id, - admin_user_id, - student_user_id, - example_normal_user_ids.clone(), - Arc::clone(&jwt_key), + run_parallelly(seed_sample_course( + Uuid::parse_str("b39b64f3-7718-4556-ac2b-333f3ed4096f")?, + "Automatic Completions", + "automatic-completions", + cs_data.clone(), )), - run_parallelly(courses_group_3( - db_pool.clone(), - uh_cs_organization_id, - admin_user_id, - student_user_id, - example_normal_user_ids.clone(), - Arc::clone(&jwt_key), + run_parallelly(seed_sample_course( + Uuid::parse_str("639f4d25-9376-49b5-bcca-7cba18c38565")?, + "Introduction to localizing", + "introduction-to-localizing", + cs_data.clone(), )), - run_parallelly(courses_group_4( - db_pool.clone(), - uh_cs_organization_id, - admin_user_id, - student_user_id, - example_normal_user_ids.clone(), - Arc::clone(&jwt_key), + run_parallelly(seed_sample_course( + Uuid::parse_str("34f4e7b7-9f55-48a7-95d7-3fc3e89553b5")?, + "Manual Completions", + "manual-completions", + cs_data.clone(), )), - run_parallelly(courses_group_5( - db_pool.clone(), - uh_cs_organization_id, - admin_user_id, - Arc::clone(&jwt_key), + run_parallelly(seed_sample_course( + Uuid::parse_str("260b2157-94ad-4791-91c7-f236f203c338")?, + "Automatic Course with Exam", + "automatic-course-with-exam", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("51ce5ea4-2587-407e-bea9-421309f77f69")?, + "Certificates", + "certificates", + cs_data.clone(), + )), + // not using these ids + run_parallelly(seed_sample_course( + Uuid::parse_str("4dde368a-5e5d-4001-b8aa-13079390f818")?, + "Model solutions", + "model-solutions", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("edaa1c52-15cd-458d-8ce2-1e4010641244")?, + "Course Modules", + "course-modules", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("d18b3780-563d-4326-b311-8d0e132901cd")?, + "Introduction to feedback", + "introduction-to-feedback", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("0ab2c4c5-3aad-4daa-a8fe-c26e956fde35")?, + "Introduction to history", + "introduction-to-history", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("cae7da38-9486-47da-9106-bff9b6a280f2")?, + "Introduction to edit proposals", + "introduction-to-edit-proposals", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("b4cb334c-11d6-4e93-8f3d-849c4abfcd67")?, + "Point view for teachers", + "point-view-for-teachers", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("1e0c52c7-8cb9-4089-b1c3-c24fc0dd5ae4")?, + "Advanced course instance management", + "advanced-course-instance-management", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("0cf67777-0edb-480c-bdb6-13f90c136fc3")?, + "Advanced exercise states", + "advanced-exercise-states", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("c218ca00-dbde-4b0c-ab98-4f075c49425a")?, + "Glossary course", + "glossary-course", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("a2002fc3-2c87-4aae-a5e5-9d14617aad2b")?, + "Permission management", + "permission-management", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("f9579c00-d0bb-402b-affd-7db330dcb11f")?, + "Redirections", + "redirections", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("9da60c66-9517-46e4-b351-07d0f7aa6cd4")?, + "Limited tries", + "limited-tries", + cs_data.clone(), + )), + run_parallelly(seed_sample_course( + Uuid::parse_str("86cbc198-601c-42f4-8e0f-3e6cce49bbfc")?, + "Course Structure", + "course-structure", + cs_data.clone(), + )), + run_parallelly(create_glossary_course( + Uuid::parse_str("e5b89931-e3d6-4930-9692-61539748c12c")?, + cs_data.clone(), + )), + run_parallelly(seed_peer_review_course_without_submissions( + Uuid::parse_str("c47e1cfd-a2da-4fd1-aca8-f2b2d906c4c0")?, + "Peer review Course", + "peer-review-course", + cs_data.clone(), )) )?; @@ -357,308 +456,3 @@ pub async fn seed_organization_uh_cs( cs_intro_course_id: cs_intro, }) } - -async fn courses_group_1( - db_pool: Pool, - uh_cs_organization_id: Uuid, - admin_user_id: Uuid, - student_user_id: Uuid, - example_normal_user_ids: Vec, - jwt_key: Arc, -) -> anyhow::Result<(Uuid, Uuid, Uuid)> { - let cs_intro = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("7f36cf71-c2d2-41fc-b2ae-bbbcafab0ea5")?, - "Introduction to everything", - "introduction-to-everything", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let _model_course = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("4dde368a-5e5d-4001-b8aa-13079390f818")?, - "Model solutions", - "model-solutions", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let automatic_completions_id = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("b39b64f3-7718-4556-ac2b-333f3ed4096f")?, - "Automatic Completions", - "automatic-completions", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let introduction_to_localizing = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("639f4d25-9376-49b5-bcca-7cba18c38565")?, - "Introduction to localizing", - "introduction-to-localizing", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("edaa1c52-15cd-458d-8ce2-1e4010641244")?, - "Course Modules", - "course-modules", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - Ok(( - cs_intro, - automatic_completions_id, - introduction_to_localizing, - )) -} - -async fn courses_group_2( - db_pool: Pool, - uh_cs_organization_id: Uuid, - admin_user_id: Uuid, - student_user_id: Uuid, - example_normal_user_ids: Vec, - jwt_key: Arc, -) -> anyhow::Result<(Uuid, Uuid)> { - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("d18b3780-563d-4326-b311-8d0e132901cd")?, - "Introduction to feedback", - "introduction-to-feedback", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("0ab2c4c5-3aad-4daa-a8fe-c26e956fde35")?, - "Introduction to history", - "introduction-to-history", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("cae7da38-9486-47da-9106-bff9b6a280f2")?, - "Introduction to edit proposals", - "introduction-to-edit-proposals", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let manual_completions = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("34f4e7b7-9f55-48a7-95d7-3fc3e89553b5")?, - "Manual Completions", - "manual-completions", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let automatic_exam_course_completions = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("260b2157-94ad-4791-91c7-f236f203c338")?, - "Automatic Course with Exam", - "automatic-course-with-exam", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - Ok((manual_completions, automatic_exam_course_completions)) -} - -async fn courses_group_3( - db_pool: Pool, - uh_cs_organization_id: Uuid, - admin_user_id: Uuid, - student_user_id: Uuid, - example_normal_user_ids: Vec, - jwt_key: Arc, -) -> anyhow::Result<(Uuid,)> { - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("b4cb334c-11d6-4e93-8f3d-849c4abfcd67")?, - "Point view for teachers", - "point-view-for-teachers", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("1e0c52c7-8cb9-4089-b1c3-c24fc0dd5ae4")?, - "Advanced course instance management", - "advanced-course-instance-management", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("0cf67777-0edb-480c-bdb6-13f90c136fc3")?, - "Advanced exercise states", - "advanced-exercise-states", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("c218ca00-dbde-4b0c-ab98-4f075c49425a")?, - "Glossary course", - "glossary-course", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - let certificates_id = seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("51ce5ea4-2587-407e-bea9-421309f77f69")?, - "Certificates", - "certificates", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - Ok((certificates_id,)) -} - -async fn courses_group_4( - db_pool: Pool, - uh_cs_organization_id: Uuid, - admin_user_id: Uuid, - student_user_id: Uuid, - example_normal_user_ids: Vec, - jwt_key: Arc, -) -> anyhow::Result<()> { - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("a2002fc3-2c87-4aae-a5e5-9d14617aad2b")?, - "Permission management", - "permission-management", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("f9579c00-d0bb-402b-affd-7db330dcb11f")?, - "Redirections", - "redirections", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("9da60c66-9517-46e4-b351-07d0f7aa6cd4")?, - "Limited tries", - "limited-tries", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - seed_sample_course( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("86cbc198-601c-42f4-8e0f-3e6cce49bbfc")?, - "Course Structure", - "course-structure", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), - ) - .await?; - create_glossary_course( - &db_pool, - uh_cs_organization_id, - admin_user_id, - Uuid::parse_str("e5b89931-e3d6-4930-9692-61539748c12c")?, - Arc::clone(&jwt_key), - ) - .await?; - - Ok(()) -} - -async fn courses_group_5( - db_pool: Pool, - uh_cs_organization_id: Uuid, - admin_user_id: Uuid, - jwt_key: Arc, -) -> anyhow::Result<()> { - seed_peer_review_course_without_submissions( - &db_pool, - uh_cs_organization_id, - Uuid::parse_str("c47e1cfd-a2da-4fd1-aca8-f2b2d906c4c0")?, - "Peer review Course", - "peer-review-course", - admin_user_id, - Arc::clone(&jwt_key), - ) - .await?; - - Ok(()) -} diff --git a/services/headless-lms/server/src/programs/seed/seed_organizations/uh_mathstat.rs b/services/headless-lms/server/src/programs/seed/seed_organizations/uh_mathstat.rs index 5421a46920f9..f906b2d11fda 100644 --- a/services/headless-lms/server/src/programs/seed/seed_organizations/uh_mathstat.rs +++ b/services/headless-lms/server/src/programs/seed/seed_organizations/uh_mathstat.rs @@ -16,7 +16,7 @@ use sqlx::{Pool, Postgres}; use crate::{ domain::models_requests::{self, JwtKey}, - programs::seed::seed_courses::seed_sample_course, + programs::seed::seed_courses::{seed_sample_course, CommonCourseData}, }; use super::super::seed_users::SeedUsersResult; @@ -119,16 +119,19 @@ pub async fn seed_organization_uh_mathstat( ) .await?; + let uh_data = CommonCourseData { + db_pool: db_pool.clone(), + organization_id: uh_mathstat_id, + admin_user_id, + student_user_id, + example_normal_user_ids: Arc::new(example_normal_user_ids.clone()), + jwt_key: Arc::clone(&jwt_key), + }; let introduction_to_citations = seed_sample_course( - &db_pool, - uh_mathstat_id, Uuid::parse_str("049061ba-ac30-49f1-aa9d-b7566dc22b78")?, "Introduction to citations", "introduction-to-citations", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), + uh_data.clone(), ) .await?; @@ -153,15 +156,10 @@ pub async fn seed_organization_uh_mathstat( .await?; let preview_unopened_chapters = seed_sample_course( - &db_pool, - uh_mathstat_id, Uuid::parse_str("dc276e05-6152-4a45-b31d-97a0c2700a68")?, "Preview unopened chapters", "preview-unopened-chapters", - admin_user_id, - student_user_id, - &example_normal_user_ids, - Arc::clone(&jwt_key), + uh_data.clone(), ) .await?; diff --git a/services/headless-lms/utils/src/futures.rs b/services/headless-lms/utils/src/futures.rs index 7d315071249e..b87c4d245ffb 100644 --- a/services/headless-lms/utils/src/futures.rs +++ b/services/headless-lms/utils/src/futures.rs @@ -7,7 +7,8 @@ pub async fn run_parallelly( where T: std::marker::Send + 'static, { - let handle = tokio::spawn(future); + // boxing our futures helps avoid stack overflow + let handle = tokio::spawn(Box::pin(future)); match handle.await { Ok(Ok(result)) => Ok(result), Ok(Err(err)) => Err(err), From dc83a2c5a7c7fd4d3394bfabf188b6faad22556d Mon Sep 17 00:00:00 2001 From: Heliozoa Date: Wed, 12 Jul 2023 10:32:16 +0300 Subject: [PATCH 2/4] Use futures-utils --- services/headless-lms/Cargo.lock | 1 + services/headless-lms/entrypoint/Cargo.toml | 2 ++ services/headless-lms/entrypoint/src/main.rs | 36 ++++++++++++------- .../server/src/programs/seed/mod.rs | 14 ++++---- services/headless-lms/utils/src/futures.rs | 4 +-- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/services/headless-lms/Cargo.lock b/services/headless-lms/Cargo.lock index ab33abb7034f..878a9f488786 100644 --- a/services/headless-lms/Cargo.lock +++ b/services/headless-lms/Cargo.lock @@ -1479,6 +1479,7 @@ version = "0.1.0" dependencies = [ "actix-web", "anyhow", + "futures-util", "headless-lms-server", "tokio", ] diff --git a/services/headless-lms/entrypoint/Cargo.toml b/services/headless-lms/entrypoint/Cargo.toml index 69284ba877a1..904ee8ed0240 100644 --- a/services/headless-lms/entrypoint/Cargo.toml +++ b/services/headless-lms/entrypoint/Cargo.toml @@ -16,5 +16,7 @@ headless-lms-server = { path = "../server" } actix-web = "4.3.1" # Flexible concrete Error type built on std::error::Error anyhow = "1.0.71" +# Combinators and utilities for working with Futures, Streams, Sinks, and the AsyncRead and AsyncWrite traits. +futures-util = "0.3.28" # A runtime for writing reliable network applications without compromising speed. tokio = "1.29.1" diff --git a/services/headless-lms/entrypoint/src/main.rs b/services/headless-lms/entrypoint/src/main.rs index 2578ea4fb43f..6be4b05e0d27 100644 --- a/services/headless-lms/entrypoint/src/main.rs +++ b/services/headless-lms/entrypoint/src/main.rs @@ -1,5 +1,6 @@ use std::future::Future; +use futures_util::FutureExt; use headless_lms_server::programs; /// The entrypoint to all the binaries provided by the project. @@ -8,23 +9,32 @@ fn main() -> anyhow::Result<()> { let program_name = std::env::args() .nth(1) .expect("No program name provided as the first argument."); - match program_name.as_str() { - "doc-file-generator" => tokio_run(programs::doc_file_generator::main())?, - "email-deliver" => tokio_run(programs::email_deliver::main())?, - "ended-exams-processor" => tokio_run(programs::ended_exams_processor::main())?, + let future = match program_name.as_str() { + "doc-file-generator" => programs::doc_file_generator::main().boxed_local(), + "email-deliver" => programs::email_deliver::main().boxed_local(), + "ended-exams-processor" => programs::ended_exams_processor::main().boxed_local(), "open-university-registration-link-fetcher" => { - tokio_run(programs::open_university_registration_link_fetcher::main())? + programs::open_university_registration_link_fetcher::main().boxed_local() } - "regrader" => tokio_run(programs::regrader::main())?, - "seed" => tokio_run(programs::seed::main())?, - "service-info-fetcher" => tokio_run(programs::service_info_fetcher::main())?, - "peer-review-updater" => tokio_run(programs::peer_review_updater::main())?, - "start-server" => actix_run(programs::start_server::main())?, - "sorter" => programs::sorter::sort()?, - "sync-tmc-users" => tokio_run(programs::sync_tmc_users::main())?, - "calculate-page-visit-stats" => tokio_run(programs::calculate_page_visit_stats::main())?, + "regrader" => programs::regrader::main().boxed_local(), + "seed" => programs::seed::main().boxed_local(), + "service-info-fetcher" => programs::service_info_fetcher::main().boxed_local(), + "peer-review-updater" => programs::peer_review_updater::main().boxed_local(), + "start-server" => { + // we'll run the server on the actix runtime without boxing it + actix_run(programs::start_server::main())?; + return Ok(()); + } + "sorter" => { + // not async so no need to involve a runtime + programs::sorter::sort()?; + return Ok(()); + } + "sync-tmc-users" => programs::sync_tmc_users::main().boxed_local(), + "calculate-page-visit-stats" => programs::calculate_page_visit_stats::main().boxed_local(), _ => panic!("Unknown program name: {}", program_name), }; + tokio_run(future)?; Ok(()) } diff --git a/services/headless-lms/server/src/programs/seed/mod.rs b/services/headless-lms/server/src/programs/seed/mod.rs index 3eec2ecffd14..5108f5384046 100644 --- a/services/headless-lms/server/src/programs/seed/mod.rs +++ b/services/headless-lms/server/src/programs/seed/mod.rs @@ -34,20 +34,18 @@ pub async fn main() -> anyhow::Result<()> { )?; let (uh_cs_organization_result, _uh_mathstat_organization_id) = try_join!( - Box::pin(run_parallelly( - seed_organizations::uh_cs::seed_organization_uh_cs( - db_pool.clone(), - seed_users_result.clone(), - Arc::clone(&jwt_key), - ) + run_parallelly(seed_organizations::uh_cs::seed_organization_uh_cs( + db_pool.clone(), + seed_users_result.clone(), + Arc::clone(&jwt_key), )), - Box::pin(run_parallelly( + run_parallelly( seed_organizations::uh_mathstat::seed_organization_uh_mathstat( db_pool.clone(), seed_users_result.clone(), Arc::clone(&jwt_key), ) - )) + ) )?; seed_roles::seed_roles(&db_pool, &seed_users_result, &uh_cs_organization_result).await?; diff --git a/services/headless-lms/utils/src/futures.rs b/services/headless-lms/utils/src/futures.rs index b87c4d245ffb..49b4ccd311ae 100644 --- a/services/headless-lms/utils/src/futures.rs +++ b/services/headless-lms/utils/src/futures.rs @@ -1,4 +1,4 @@ -use futures::Future; +use futures::{Future, FutureExt}; /// For use with join! or try_join! Makes the future to run parallelly with other tasks instead of concurrently. See: . pub async fn run_parallelly( @@ -8,7 +8,7 @@ where T: std::marker::Send + 'static, { // boxing our futures helps avoid stack overflow - let handle = tokio::spawn(Box::pin(future)); + let handle = tokio::spawn(future.boxed()); match handle.await { Ok(Ok(result)) => Ok(result), Ok(Err(err)) => Err(err), From 8d8f82786afb895f6622cedc1e18325e4926750c Mon Sep 17 00:00:00 2001 From: Heliozoa Date: Wed, 12 Jul 2023 11:22:56 +0300 Subject: [PATCH 3/4] Increase timeout for seed pool --- services/headless-lms/server/src/programs/seed/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/headless-lms/server/src/programs/seed/mod.rs b/services/headless-lms/server/src/programs/seed/mod.rs index 5108f5384046..e845a685201f 100644 --- a/services/headless-lms/server/src/programs/seed/mod.rs +++ b/services/headless-lms/server/src/programs/seed/mod.rs @@ -8,7 +8,7 @@ pub mod seed_playground_examples; pub mod seed_roles; pub mod seed_users; -use std::{env, process::Command, sync::Arc}; +use std::{env, process::Command, sync::Arc, time::Duration}; use crate::{domain::models_requests::JwtKey, setup_tracing}; @@ -69,6 +69,8 @@ async fn setup_seed_environment() -> anyhow::Result> { let db_pool = PgPoolOptions::new() .max_connections(10) .min_connections(5) + // the seed process can take a while, default is 30 + .acquire_timeout(Duration::from_secs(90)) .connect(&db_url) .await?; From a2acfef67c315174a7834d0f47afc4e053efae1b Mon Sep 17 00:00:00 2001 From: Heliozoa Date: Wed, 12 Jul 2023 11:24:28 +0300 Subject: [PATCH 4/4] Error on non-zero exit code from system test db setup script --- system-tests/src/setup/globalSetup.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/system-tests/src/setup/globalSetup.ts b/system-tests/src/setup/globalSetup.ts index 510bc96ec2c5..9395060aabfd 100644 --- a/system-tests/src/setup/globalSetup.ts +++ b/system-tests/src/setup/globalSetup.ts @@ -44,9 +44,13 @@ async function setupSystemTestDb() { // spawnSync is the easiest way to wait for the script to finish while inheriting stdio. // Using a sync method hare shoud not be a problem since this is a setup script const res = spawnSync(setupSystemTestDbScriptPath, { stdio: "inherit" }) - if (res.error) { + if (res.status != 0) { console.error("Error: Could not setup system test db.") - throw res.error + if (res.error) { + throw res.error + } else { + throw new Error(`System test db setup script returned non-zero status code ${res.status}`) + } } console.log("System test db setup complete.") } finally {