headless_lms_server/controllers/main_frontend/
code_giveaways.rs

1//! Controllers for requests starting with `/api/v0/main-frontend/code-giveaways`.
2use chrono::Utc;
3use domain::csv_export::{code_giveaway_codes::CodeGiveawayCodesExportOperation, general_export};
4use headless_lms_models::{
5    code_giveaway_codes::CodeGiveawayCode,
6    code_giveaways::{CodeGiveaway, NewCodeGiveaway},
7};
8
9use crate::prelude::*;
10
11/**
12GET `/api/v0/main-frontend/code-giveaways/by-course/:course_id` - Returns code giveaways for a course.
13 */
14#[instrument(skip(pool))]
15async fn get_code_giveaways_by_course(
16    pool: web::Data<PgPool>,
17    course_id: web::Path<Uuid>,
18    user: AuthUser,
19) -> ControllerResult<web::Json<Vec<CodeGiveaway>>> {
20    let mut conn = pool.acquire().await?;
21
22    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
23
24    let code_giveaways = models::code_giveaways::get_all_for_course(&mut conn, *course_id).await?;
25
26    token.authorized_ok(web::Json(code_giveaways))
27}
28
29/**
30 * POST `/api/v0/main-frontend/code-giveaways - Creates a new code giveaway.
31 */
32#[instrument(skip(pool))]
33async fn create_code_giveaway(
34    pool: web::Data<PgPool>,
35    code_giveaway: web::Json<NewCodeGiveaway>,
36    user: AuthUser,
37) -> ControllerResult<web::Json<CodeGiveaway>> {
38    let mut conn = pool.acquire().await?;
39
40    let token = authorize(
41        &mut conn,
42        Act::Edit,
43        Some(user.id),
44        Res::Course(code_giveaway.course_id),
45    )
46    .await?;
47
48    let code_giveaway = models::code_giveaways::insert(&mut conn, &code_giveaway).await?;
49
50    token.authorized_ok(web::Json(code_giveaway))
51}
52
53/**
54 * GET `/api/v0/main-frontend/code-giveaways/:id - Gets a code giveaway by ID.
55 */
56#[instrument(skip(pool))]
57async fn get_code_giveaway_by_id(
58    pool: web::Data<PgPool>,
59    id: web::Path<Uuid>,
60    user: AuthUser,
61) -> ControllerResult<web::Json<CodeGiveaway>> {
62    let mut conn = pool.acquire().await?;
63
64    let code_giveaway = models::code_giveaways::get_by_id(&mut conn, *id).await?;
65
66    let token = authorize(
67        &mut conn,
68        Act::Edit,
69        Some(user.id),
70        Res::Course(code_giveaway.course_id),
71    )
72    .await?;
73
74    token.authorized_ok(web::Json(code_giveaway))
75}
76
77/**
78 * POST `/api/v0/main-frontend/code-giveaways/:id/codes - Adds new codes to a code giveaway.
79 */
80#[instrument(skip(pool))]
81async fn add_codes_to_code_giveaway(
82    pool: web::Data<PgPool>,
83    id: web::Path<Uuid>,
84    codes: web::Json<Vec<String>>,
85    user: AuthUser,
86) -> ControllerResult<web::Json<Vec<CodeGiveawayCode>>> {
87    let mut conn = pool.acquire().await?;
88
89    let code_giveaway = models::code_giveaways::get_by_id(&mut conn, *id).await?;
90
91    let token = authorize(
92        &mut conn,
93        Act::Edit,
94        Some(user.id),
95        Res::Course(code_giveaway.course_id),
96    )
97    .await?;
98
99    let codes = models::code_giveaway_codes::insert_many(&mut conn, *id, &codes, user.id).await?;
100
101    token.authorized_ok(web::Json(codes))
102}
103
104/**
105 * GET `/api/v0/main-frontend/code-giveaways/:id/codes - Gets codes for a code giveaway by ID.
106 */
107#[instrument(skip(pool))]
108async fn get_codes_by_code_giveaway_id(
109    pool: web::Data<PgPool>,
110    id: web::Path<Uuid>,
111    user: AuthUser,
112) -> ControllerResult<web::Json<Vec<CodeGiveawayCode>>> {
113    let mut conn = pool.acquire().await?;
114
115    let code_giveaway = models::code_giveaways::get_by_id(&mut conn, *id).await?;
116
117    let token = authorize(
118        &mut conn,
119        Act::Edit,
120        Some(user.id),
121        Res::Course(code_giveaway.course_id),
122    )
123    .await?;
124
125    let codes = models::code_giveaway_codes::get_all_by_code_giveaway_id(&mut conn, *id).await?;
126
127    token.authorized_ok(web::Json(codes))
128}
129
130/**
131 * DELETE `/api/v0/main-frontend/code-giveaways/:id/codes/:code_id - Deletes a code giveaway code.
132 */
133#[instrument(skip(pool))]
134async fn delete_code_giveaway_code(
135    pool: web::Data<PgPool>,
136    path: web::Path<(Uuid, Uuid)>,
137    user: AuthUser,
138) -> ControllerResult<web::Json<()>> {
139    let (id, code_id) = path.into_inner();
140    let mut conn = pool.acquire().await?;
141
142    let giveaway = models::code_giveaways::get_by_id(&mut conn, id).await?;
143    let code = models::code_giveaway_codes::get_by_id(&mut conn, code_id).await?;
144
145    if id != code.code_giveaway_id {
146        return Err(ControllerError::new(
147            ControllerErrorType::BadRequest,
148            "Code giveaway and code course mismatch",
149            None,
150        ));
151    }
152
153    let token = authorize(
154        &mut conn,
155        Act::Edit,
156        Some(user.id),
157        Res::Course(giveaway.course_id),
158    )
159    .await?;
160
161    models::code_giveaway_codes::delete_by_id(&mut conn, code_id).await?;
162
163    token.authorized_ok(web::Json(()))
164}
165
166/**
167 * GET `/api/v0/main-frontend/code-giveaways/:id/codes/csv - Gets codes for a code giveaway by ID as CSV.
168 */
169#[instrument(skip(pool))]
170async fn get_codes_by_code_giveaway_id_csv(
171    pool: web::Data<PgPool>,
172    id: web::Path<Uuid>,
173    user: AuthUser,
174) -> ControllerResult<HttpResponse> {
175    let mut conn = pool.acquire().await?;
176
177    let code_giveaway = models::code_giveaways::get_by_id(&mut conn, *id).await?;
178    let course = models::courses::get_course(&mut conn, code_giveaway.course_id).await?;
179
180    let token = authorize(
181        &mut conn,
182        Act::Edit,
183        Some(user.id),
184        Res::Course(code_giveaway.course_id),
185    )
186    .await?;
187
188    general_export(
189        pool,
190        &format!(
191            "attachment; filename=\"Giveaway codes {} / {} - {}.csv\"",
192            code_giveaway.name,
193            course.name,
194            Utc::now().format("%Y-%m-%d")
195        ),
196        CodeGiveawayCodesExportOperation {
197            code_giveaway_id: *id,
198        },
199        token,
200    )
201    .await
202}
203
204/**
205Add a route for each controller in this module.
206
207The name starts with an underline in order to appear before other functions in the module documentation.
208
209We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
210*/
211pub fn _add_routes(cfg: &mut ServiceConfig) {
212    cfg.route(
213        "by-course/{course_id}",
214        web::get().to(get_code_giveaways_by_course),
215    )
216    .route("", web::post().to(create_code_giveaway))
217    .route("{id}", web::get().to(get_code_giveaway_by_id))
218    .route("{id}/codes", web::get().to(get_codes_by_code_giveaway_id))
219    .route(
220        "{id}/codes/csv",
221        web::get().to(get_codes_by_code_giveaway_id_csv),
222    )
223    .route("{id}/codes", web::post().to(add_codes_to_code_giveaway))
224    .route(
225        "{id}/codes/{code_id}",
226        web::delete().to(delete_code_giveaway_code),
227    );
228}