Skip to main content

headless_lms_server/domain/csv_export/
code_giveaway_codes.rs

1use anyhow::Result;
2use bytes::Bytes;
3
4use futures::TryStreamExt;
5use headless_lms_models::code_giveaway_codes;
6use secrecy::ExposeSecret;
7
8use async_trait::async_trait;
9
10use crate::domain::csv_export::CsvWriter;
11
12use sqlx::PgConnection;
13use std::io::Write;
14use tokio::sync::mpsc::UnboundedSender;
15
16use uuid::Uuid;
17
18use crate::prelude::*;
19
20use super::{
21    super::authorization::{AuthorizationToken, AuthorizedResponse},
22    CSVExportAdapter, CsvExportDataLoader,
23};
24
25pub struct CodeGiveawayCodesExportOperation {
26    pub code_giveaway_id: Uuid,
27}
28
29#[async_trait]
30impl CsvExportDataLoader for CodeGiveawayCodesExportOperation {
31    async fn load_data(
32        &self,
33        sender: UnboundedSender<Result<AuthorizedResponse<Bytes>, ControllerError>>,
34        conn: &mut PgConnection,
35        token: AuthorizationToken,
36    ) -> anyhow::Result<CSVExportAdapter> {
37        export_code_giveaway_codes(
38            &mut *conn,
39            self.code_giveaway_id,
40            CSVExportAdapter {
41                sender,
42                authorization_token: token,
43            },
44        )
45        .await
46    }
47}
48
49/// Writes giveaway codes as csv into the writer
50pub async fn export_code_giveaway_codes<W>(
51    conn: &mut PgConnection,
52    code_giveaway_id: Uuid,
53    writer: W,
54) -> Result<W>
55where
56    W: Write + Send + 'static,
57{
58    let headers = IntoIterator::into_iter([
59        "id".to_string(),
60        "created_at".to_string(),
61        "updated_at".to_string(),
62        "code_giveaway_id".to_string(),
63        "code_given_to_user_id".to_string(),
64        "added_by_user_id".to_string(),
65        "code".to_string(),
66    ]);
67
68    let mut stream =
69        code_giveaway_codes::stream_given_code_giveaway_codes(conn, code_giveaway_id).await;
70
71    let writer = CsvWriter::new_with_initialized_headers(writer, headers).await?;
72    while let Some(next) = stream.try_next().await? {
73        let csv_row = vec![
74            next.id.to_string(),
75            next.created_at.to_rfc3339(),
76            next.updated_at.to_rfc3339(),
77            next.code_giveaway_id.to_string(),
78            next.code_given_to_user_id
79                .map(|o| o.to_string())
80                .unwrap_or("".to_string()),
81            next.added_by_user_id.to_string(),
82            // CSV export is an intended exposure (admin download of the codes).
83            next.code.expose_secret().to_string(),
84        ];
85        writer.write_record(csv_row);
86    }
87    let writer = writer.finish().await?;
88    Ok(writer)
89}