headless_lms_server/domain/csv_export/
user_exercise_states_export.rs

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