Skip to main content

headless_lms_server/controllers/main_frontend/
email_templates.rs

1//! Controllers for requests starting with `/api/v0/main-frontend/email-templates/`.
2
3use models::email_templates::{EmailTemplate, EmailTemplateNew};
4use utoipa::OpenApi;
5
6use crate::domain::error::missing_controller_error;
7use crate::prelude::*;
8
9#[derive(OpenApi)]
10#[openapi(paths(get_all_email_templates, create_email_template, delete_email_template))]
11pub(crate) struct MainFrontendEmailTemplatesApiDoc;
12
13/**
14GET `/api/v0/main-frontend/email-templates`
15*/
16#[instrument(skip(pool))]
17#[utoipa::path(
18    get,
19    path = "",
20    operation_id = "getEmailTemplates",
21    tag = "email_templates",
22    responses(
23        (status = 200, description = "Email templates", body = Vec<EmailTemplate>)
24    )
25)]
26async fn get_all_email_templates(
27    pool: web::Data<PgPool>,
28    user: AuthUser,
29) -> ControllerResult<web::Json<Vec<EmailTemplate>>> {
30    let mut conn = pool.acquire().await?;
31    let token = authorize(
32        &mut conn,
33        Act::Administrate,
34        Some(user.id),
35        Res::GlobalPermissions,
36    )
37    .await?;
38    let email_templates = models::email_templates::get_all_email_templates(&mut conn).await?;
39    token.authorized_ok(web::Json(email_templates))
40}
41
42/**
43POST `/api/v0/main-frontend/email-templates`
44
45Creates a global template; rejects a second live one for the same type and language.
46*/
47#[instrument(skip(pool))]
48#[utoipa::path(
49    post,
50    path = "",
51    operation_id = "createEmailTemplate",
52    tag = "email_templates",
53    request_body = EmailTemplateNew,
54    responses(
55        (status = 200, description = "Created email template", body = EmailTemplate)
56    )
57)]
58async fn create_email_template(
59    payload: web::Json<EmailTemplateNew>,
60    pool: web::Data<PgPool>,
61    user: AuthUser,
62) -> ControllerResult<web::Json<EmailTemplate>> {
63    let mut conn = pool.acquire().await?;
64    let token = authorize(
65        &mut conn,
66        Act::Administrate,
67        Some(user.id),
68        Res::GlobalPermissions,
69    )
70    .await?;
71    let mut new_template = payload.into_inner();
72    new_template
73        .content
74        .get_or_insert_with(|| serde_json::json!([]));
75    let created =
76        models::email_templates::insert_global_email_template_if_absent(&mut conn, new_template)
77            .await?
78            .ok_or_else(missing_controller_error(
79                ControllerErrorType::BadRequest,
80                "A template of this type and language already exists.",
81            ))?;
82    token.authorized_ok(web::Json(created))
83}
84
85/**
86DELETE `/api/v0/main-frontend/email-templates/:id`
87*/
88#[instrument(skip(pool))]
89#[utoipa::path(
90    delete,
91    path = "/{email_template_id}",
92    operation_id = "deleteEmailTemplate",
93    tag = "email_templates",
94    params(
95        ("email_template_id" = Uuid, Path, description = "Email template id")
96    ),
97    responses(
98        (status = 200, description = "Deleted email template", body = EmailTemplate)
99    )
100)]
101async fn delete_email_template(
102    email_template_id: web::Path<Uuid>,
103    pool: web::Data<PgPool>,
104    user: AuthUser,
105) -> ControllerResult<web::Json<EmailTemplate>> {
106    let mut conn = pool.acquire().await?;
107    let email_template =
108        models::email_templates::get_email_template(&mut conn, *email_template_id).await?;
109    let token = if let Some(course_id) = email_template.course_id {
110        authorize(&mut conn, Act::Teach, Some(user.id), Res::Course(course_id)).await?
111    } else {
112        authorize(
113            &mut conn,
114            Act::Administrate,
115            Some(user.id),
116            Res::GlobalPermissions,
117        )
118        .await?
119    };
120    let deleted =
121        models::email_templates::delete_email_template(&mut conn, *email_template_id).await?;
122
123    token.authorized_ok(web::Json(deleted))
124}
125
126/**
127Add a route for each controller in this module.
128
129The name starts with an underline in order to appear before other functions in the module documentation.
130
131We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
132*/
133pub fn _add_routes(cfg: &mut ServiceConfig) {
134    cfg.route("", web::get().to(get_all_email_templates))
135        .route("", web::post().to(create_email_template))
136        .route(
137            "/{email_template_id}",
138            web::delete().to(delete_email_template),
139        );
140}