Skip to content

Commit

Permalink
Add langs endpoint to fetch enrolled course instances with TMC exercises
Browse files Browse the repository at this point in the history
  • Loading branch information
Heliozoa committed Apr 11, 2024
1 parent a07715e commit 5adbc53
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 14 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 95 additions & 1 deletion services/headless-lms/models/src/course_instances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,45 @@ WHERE cie.user_id = $1
Ok(course_instances)
}

pub async fn get_enrolled_course_instances_for_user_with_exercise_type(
conn: &mut PgConnection,
user_id: Uuid,
exercise_type: &str,
) -> ModelResult<Vec<CourseInstanceWithCourseInfo>> {
let course_instances = sqlx::query_as!(
CourseInstanceWithCourseInfo,
r#"
SELECT DISTINCT ON (ci.id)
c.id AS course_id,
c.slug AS course_slug,
c.name AS course_name,
c.description AS course_description,
ci.id AS course_instance_id,
ci.name AS course_instance_name,
ci.description AS course_instance_description
FROM course_instances AS ci
JOIN course_instance_enrollments AS cie ON ci.id = cie.course_instance_id
LEFT JOIN courses AS c ON ci.course_id = c.id
LEFT JOIN exercises AS e ON e.course_id = c.id
LEFT JOIN exercise_slides AS es ON es.exercise_id = e.id
LEFT JOIN exercise_tasks AS et ON et.exercise_slide_id = es.id
WHERE cie.user_id = $1
AND et.exercise_type = $2
AND ci.deleted_at IS NULL
AND cie.deleted_at IS NULL
AND c.deleted_at IS NULL
AND e.deleted_at IS NULL
AND es.deleted_at IS NULL
AND et.deleted_at IS NULL
"#,
user_id,
exercise_type,
)
.fetch_all(conn)
.await?;
Ok(course_instances)
}

/// Deletes submissions, peer reviews, points and etc. for a course and user. Main purpose is for teachers who are testing their course with their own accounts.
pub async fn reset_progress_on_course_instance_for_user(
conn: &mut PgConnection,
Expand Down Expand Up @@ -749,7 +788,10 @@ WHERE user_id = $1
#[cfg(test)]
mod test {
use super::*;
use crate::test_helper::*;
use crate::{
course_instance_enrollments::NewCourseInstanceEnrollment, exercise_tasks::NewExerciseTask,
test_helper::*,
};

#[tokio::test]
async fn allows_only_one_instance_per_course_without_name() {
Expand Down Expand Up @@ -779,4 +821,56 @@ mod test {
.await
.unwrap();
}

#[tokio::test]
async fn gets_enrolled_course_instances_for_user_with_exercise_type() {
insert_data!(:tx, user:user_id, :org, course:course_id, :instance, course_module:_course_module_id, chapter:chapter_id, page:page_id, :exercise, slide:exercise_slide_id);

// enroll user on course
crate::course_instance_enrollments::insert_enrollment_and_set_as_current(
tx.as_mut(),
NewCourseInstanceEnrollment {
course_id,
user_id,
course_instance_id: instance.id,
},
)
.await
.unwrap();
let course_instances =
get_enrolled_course_instances_for_user_with_exercise_type(tx.as_mut(), user_id, "TMC")
.await
.unwrap();
assert!(
course_instances.is_empty(),
"user should not be enrolled on any course with TMC exercises"
);

// insert tmc exercise task
crate::exercise_tasks::insert(
tx.as_mut(),
PKeyPolicy::Generate,
NewExerciseTask {
assignment: Vec::new(),
exercise_slide_id,
exercise_type: "TMC".to_string(),
model_solution_spec: None,
private_spec: None,
public_spec: None,
order_number: 1,
},
)
.await
.unwrap();
let course_instances =
get_enrolled_course_instances_for_user_with_exercise_type(tx.as_mut(), user_id, "TMC")
.await
.unwrap();
assert_eq!(
course_instances.len(),
1,
"user should be enrolled on one course with TMC exercises"
);
tx.rollback().await;
}
}
9 changes: 5 additions & 4 deletions services/headless-lms/models/src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub const TEST_HELPER_EXERCISE_SERVICE_NAME: &str = "exercise_type";
/// Helper macro that can be used to conveniently insert data that has some prerequisites.
/// The macro accepts variable arguments in the following order:
///
/// tx, user, org, course, instance, course_module, page, chapter, exercise, slide, task
/// tx, user, org, course, instance, course_module, chapter, page, exercise, slide, task
///
/// Arguments can be given in either of two forms:
///
Expand All @@ -103,7 +103,7 @@ pub const TEST_HELPER_EXERCISE_SERVICE_NAME: &str = "exercise_type";
/// would use existing variables tx and u to insert and declare variables for an organization and course named org and course.
macro_rules! insert_data {
// these rules transform individual arguments like "user" into "user: user"
// arg before ; has no name
// arg before potential ; has no name
($($name:ident: $var:ident, )* :$ident:ident, $($tt:tt)*) => {
insert_data!($($name: $var, )* $ident: $ident, $($tt)*);
};
Expand Down Expand Up @@ -291,7 +291,8 @@ macro_rules! insert_data {
pub use crate::insert_data;

// checks that correct usage of the macro compiles
#[allow(unused)]
async fn _test() {
insert_data!(:tx, user:u, org:o, course: c, instance: _instance, course_module: m, chapter: c, :page, exercise: e, :slide, task: task);
println!("{task}")
insert_data!(tx:t, user:u, org:o, course:c, instance:i, course_module:m, chapter:c, page:p, exercise:e, slide:s, task:tsk);
insert_data!(:tx, :user, :org, :course, :instance, :course_module, :chapter, :page, :exercise, :slide, :task);
}
10 changes: 6 additions & 4 deletions services/headless-lms/server/src/controllers/langs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::collections::HashSet;
/**
* GET /api/v0/langs/course-instances
*
* Returns the course instances that the user is currently enrolled on.
* Returns the course instances that the user is currently enrolled on that contain TMC exercises.
*/
#[instrument(skip(pool))]
async fn get_course_instances(
Expand All @@ -25,9 +25,11 @@ async fn get_course_instances(
let mut conn = pool.acquire().await?;

let course_instances =
models::course_instances::get_enrolled_course_instances_for_user(&mut conn, user.id)
.await?
.convert();
models::course_instances::get_enrolled_course_instances_for_user_with_exercise_type(
&mut conn, user.id, "TMC",
)
.await?
.convert();

// if the user is enrolled on the course, they should be able to view it regardless of permissions
let token = skip_authorize();
Expand Down
27 changes: 26 additions & 1 deletion services/headless-lms/server/src/programs/seed/seed_courses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub struct CommonCourseData {
pub organization_id: Uuid,
pub admin_user_id: Uuid,
pub student_user_id: Uuid,
pub langs_user_id: Uuid,
pub example_normal_user_ids: Arc<Vec<Uuid>>,
pub jwt_key: Arc<JwtKey>,
pub base_url: String,
Expand All @@ -65,6 +66,7 @@ pub async fn seed_sample_course(
organization_id: org,
admin_user_id: admin,
student_user_id: student,
langs_user_id,
example_normal_user_ids: users,
jwt_key,
base_url,
Expand Down Expand Up @@ -1783,6 +1785,15 @@ pub async fn seed_sample_course(
)
.await?;
}
course_instance_enrollments::insert_enrollment_and_set_as_current(
&mut conn,
NewCourseInstanceEnrollment {
course_id,
course_instance_id: default_instance.id,
user_id: langs_user_id,
},
)
.await?;

// feedback
info!("sample feedback");
Expand Down Expand Up @@ -1978,6 +1989,7 @@ pub async fn create_glossary_course(
organization_id: org_id,
admin_user_id: admin,
student_user_id: _,
langs_user_id: _,
example_normal_user_ids: _,
jwt_key,
base_url,
Expand Down Expand Up @@ -2100,6 +2112,7 @@ pub async fn seed_cs_course_material(
db_pool: &Pool<Postgres>,
org: Uuid,
admin: Uuid,
langs_user_id: Uuid,
base_url: String,
jwt_key: Arc<JwtKey>,
) -> Result<Uuid> {
Expand All @@ -2119,7 +2132,7 @@ pub async fn seed_cs_course_material(
is_test_mode: false,
copy_user_permissions: false,
};
let (course, front_page, _default_instance, default_module) =
let (course, front_page, default_instance, default_module) =
library::content_management::create_new_course(
&mut conn,
PKeyPolicy::Fixed(CreateNewCourseFixedIds {
Expand Down Expand Up @@ -2953,6 +2966,17 @@ pub async fn seed_cs_course_material(
)
.await?;

// enrollments
course_instance_enrollments::insert_enrollment_and_set_as_current(
&mut conn,
NewCourseInstanceEnrollment {
course_id: course.id,
course_instance_id: default_instance.id,
user_id: langs_user_id,
},
)
.await?;

Ok(course.id)
}

Expand Down Expand Up @@ -4367,6 +4391,7 @@ pub async fn seed_peer_review_course_without_submissions(
organization_id: org,
admin_user_id: admin,
student_user_id: _,
langs_user_id: _,
example_normal_user_ids: _,
jwt_key,
base_url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use headless_lms_models::{
course_instances::{self, NewCourseInstance},
course_modules::{self, AutomaticCompletionRequirements, CompletionPolicy},
courses::NewCourse,
library::content_management::CreateNewCourseFixedIds,
library::{
self,
content_management::CreateNewCourseFixedIds,
progressing::{TeacherManualCompletion, TeacherManualCompletionRequest},
},
open_university_registration_links, organizations,
Expand Down Expand Up @@ -64,7 +64,7 @@ pub async fn seed_organization_uh_cs(
student_3_user_id,
student_4_user_id: _,
student_5_user_id: _,
langs_user_id: _,
langs_user_id,
} = seed_users_result;
let _ = seed_file_storage_result;

Expand Down Expand Up @@ -95,6 +95,7 @@ pub async fn seed_organization_uh_cs(
organization_id: uh_cs_organization_id,
admin_user_id,
student_user_id: student_3_user_id,
langs_user_id,
example_normal_user_ids: Arc::new(example_normal_user_ids.clone()),
jwt_key: Arc::clone(&jwt_key),
base_url: base_url.clone(),
Expand Down Expand Up @@ -434,6 +435,7 @@ pub async fn seed_organization_uh_cs(
&db_pool,
uh_cs_organization_id,
admin_user_id,
langs_user_id,
base_url.clone(),
Arc::clone(&jwt_key),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub async fn seed_organization_uh_mathstat(
student_3_user_id,
student_4_user_id: _,
student_5_user_id: _,
langs_user_id: _,
langs_user_id,
} = seed_users_result;
let _ = seed_file_storage_result;

Expand Down Expand Up @@ -148,6 +148,7 @@ pub async fn seed_organization_uh_mathstat(
organization_id: uh_mathstat_id,
admin_user_id,
student_user_id: student_3_user_id,
langs_user_id,
example_normal_user_ids: Arc::new(example_normal_user_ids.clone()),
jwt_key: Arc::clone(&jwt_key),
base_url,
Expand Down
2 changes: 1 addition & 1 deletion services/tmc/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The TestMyCode exercise service is used for programming exercises.
The TestMyCode exercise service is used for programming exercises. Handles exercises of the `"TMC"` exercise type.

## Setup

Expand Down

0 comments on commit 5adbc53

Please sign in to comment.