headless_lms_server/controllers/main_frontend/
course_modules.rs

1use headless_lms_models::course_module_completions::CourseModuleCompletion;
2use models::{
3    course_modules::{self, CourseModule},
4    library::progressing::{CompletionRegistrationLink, UserCompletionInformation},
5};
6
7use crate::prelude::*;
8
9/**
10GET `/api/v0/main-frontend/course-modules/{course_module_id}`
11
12Returns information about the course module.
13*/
14#[instrument(skip(pool))]
15async fn get_course_module(
16    course_module_id: web::Path<Uuid>,
17    pool: web::Data<PgPool>,
18    user: AuthUser,
19) -> ControllerResult<web::Json<CourseModule>> {
20    let mut conn = pool.acquire().await?;
21    let course_module = course_modules::get_by_id(&mut conn, *course_module_id).await?;
22    let token = authorize(
23        &mut conn,
24        Act::View,
25        Some(user.id),
26        Res::Course(course_module.course_id),
27    )
28    .await?;
29    token.authorized_ok(web::Json(course_module))
30}
31
32/**
33GET `/api/v0/main-frontend/course-modules/{course_module_id}/user-completion`
34
35Gets active users's completion for the course, if it exists.
36*/
37#[instrument(skip(pool))]
38async fn get_course_module_completion_information_for_user(
39    course_module_id: web::Path<Uuid>,
40    pool: web::Data<PgPool>,
41    user: AuthUser,
42) -> ControllerResult<web::Json<UserCompletionInformation>> {
43    let mut conn = pool.acquire().await?;
44    let course_module = course_modules::get_by_id(&mut conn, *course_module_id).await?;
45    // Proper request validation is based on whether a completion exists for the user or not.
46    let token = authorize(
47        &mut conn,
48        Act::View,
49        Some(user.id),
50        Res::Course(course_module.course_id),
51    )
52    .await?;
53    let information = models::library::progressing::get_user_completion_information(
54        &mut conn,
55        user.id,
56        &course_module,
57    )
58    .await?;
59    token.authorized_ok(web::Json(information))
60}
61
62/**
63GET `/api/v0/main-frontend/course-modules/{course_slug}/completion-registration-link`
64*/
65#[instrument(skip(pool))]
66async fn get_course_module_completion_registration_link(
67    course_module_id: web::Path<Uuid>,
68    pool: web::Data<PgPool>,
69    user: AuthUser,
70) -> ControllerResult<web::Json<CompletionRegistrationLink>> {
71    let mut conn = pool.acquire().await?;
72    let course_module = course_modules::get_by_id(&mut conn, *course_module_id).await?;
73    // Proper request validation is based on whether a completion exists for the user or not.
74    let token = authorize(
75        &mut conn,
76        Act::View,
77        Some(user.id),
78        Res::Course(course_module.course_id),
79    )
80    .await?;
81    let completion_registration_link =
82        models::library::progressing::get_completion_registration_link_and_save_attempt(
83            &mut conn,
84            user.id,
85            &course_module,
86        )
87        .await?;
88    token.authorized_ok(web::Json(completion_registration_link))
89}
90
91async fn enable_or_disable_certificate_generation(
92    params: web::Path<(Uuid, bool)>,
93    pool: web::Data<PgPool>,
94    user: AuthUser,
95) -> ControllerResult<web::Json<bool>> {
96    let mut conn = pool.acquire().await?;
97    let (course_module_id, enabled) = params.into_inner();
98
99    let course_module = course_modules::get_by_id(&mut conn, course_module_id).await?;
100    // Proper request validation is based on whether a completion exists for the user or not.
101    let token = authorize(
102        &mut conn,
103        Act::Edit,
104        Some(user.id),
105        Res::Course(course_module.course_id),
106    )
107    .await?;
108    models::course_modules::update_certification_enabled(&mut conn, course_module_id, enabled)
109        .await?;
110
111    token.authorized_ok(web::Json(true))
112}
113
114/**
115GET `/api/v0/main-frontend/course-modules/{course_module_id}/course-module-completion`
116
117Gets users's best completion for the course.
118*/
119#[instrument(skip(pool))]
120async fn get_best_course_module_completion_for_user(
121    course_module_id: web::Path<Uuid>,
122    pool: web::Data<PgPool>,
123    user: AuthUser,
124) -> ControllerResult<web::Json<Option<CourseModuleCompletion>>> {
125    let mut conn = pool.acquire().await?;
126    let course_module = course_modules::get_by_id(&mut conn, *course_module_id).await?;
127
128    let token = authorize(
129        &mut conn,
130        Act::View,
131        Some(user.id),
132        Res::Course(course_module.course_id),
133    )
134    .await?;
135
136    let information =
137        models::course_module_completions::get_best_completion_by_user_and_course_module_id(
138            &mut conn,
139            user.id,
140            *course_module_id,
141        )
142        .await?;
143    token.authorized_ok(web::Json(information))
144}
145
146/**
147Add a route for each controller in this module.
148
149The name starts with an underline in order to appear before other functions in the module documentation.
150
151We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
152*/
153pub fn _add_routes(cfg: &mut ServiceConfig) {
154    cfg.route("/{course_module_id}", web::get().to(get_course_module))
155        .route(
156            "/{course_module_id}/user-completion",
157            web::get().to(get_course_module_completion_information_for_user),
158        )
159        .route(
160            "/{course_module_id}/completion-registration-link",
161            web::get().to(get_course_module_completion_registration_link),
162        )
163        .route(
164            "/{course_module_id}/set-certificate-generation/{enabled}",
165            web::post().to(enable_or_disable_certificate_generation),
166        )
167        .route(
168            "/{course_module_id}/course-module-completion",
169            web::get().to(get_best_course_module_completion_for_user),
170        );
171}