hermod_api/handlers/
form.rs

1use actix_web::{web, HttpRequest, HttpResponse};
2use serde::{Deserialize, Serialize};
3use sqlx::PgPool;
4use tracing::field::Empty;
5use uuid::Uuid;
6
7use super::ApplicationResponse;
8use crate::{db::NewForm, handlers::ApplicationError, services::jwt::JwtClient};
9
10#[tracing::instrument(name = "handlers::form::list", skip(pool, jwt), fields(username=Empty, user_id=Empty))]
11/// get(form/list) runs an SQL query to retrieve all the forms belonging to the user who sent the request
12pub async fn list_forms(
13    pool: web::Data<PgPool>,
14    request: HttpRequest,
15    jwt: web::Data<JwtClient>,
16) -> ApplicationResponse {
17    let current_user = jwt.user_or_403(request).await?;
18    let forms = sqlx::query!(
19        r#"
20            SELECT * FROM form
21            WHERE account_id=$1"#,
22        current_user.id,
23    )
24    .fetch_all(pool.as_ref())
25    .await?;
26    Ok(HttpResponse::Ok().body(format!("{:?},", forms)))
27}
28
29/*
30#[derive(serde::Serialize, serde::Deserialize)]
31pub enum FieldType {
32    Checkbox,
33    Image,
34    Radio,
35    Text,
36    Email,
37    Phone,
38    NumField,
39    NumSlider,
40    DateTime,
41}
42 */
43
44#[derive(Deserialize)]
45pub struct FormGetRequest {
46    pub form_id: Uuid,
47}
48
49#[derive(Serialize)]
50pub struct FormGetResponse {
51    pub fields: Vec<String>,
52}
53
54#[tracing::instrument(name = "handlers::form::get", skip(query, pool))]
55/// get(form) runs an SQL query on a provided form id and returns a JSON object of the fields
56pub async fn get_form(
57    query: web::Query<FormGetRequest>,
58    pool: web::Data<PgPool>,
59) -> ApplicationResponse {
60    // Validate that such a requested form exists
61    if let Some(form) = sqlx::query!("SELECT * FROM form WHERE id=$1", &query.form_id)
62        .fetch_optional(pool.as_ref())
63        .await?
64    {
65        // Retrieve fields associated with form
66        let fields = sqlx::query!("SELECT * FROM form_input WHERE form_id=$1", form.id)
67            .fetch_all(pool.as_ref())
68            .await?;
69
70        // Gather field types into a struct
71        let form_response_data = FormGetResponse {
72            fields: fields.iter().map(|f| String::from(&f.r#type)).collect(),
73        };
74
75        Ok(HttpResponse::Ok().body(serde_json::to_string(&form_response_data).unwrap()))
76    } else {
77        Err(ApplicationError::NotFoundError(format!(
78            "No form found with id {}.",
79            &query.form_id
80        )))
81    }
82}
83
84#[derive(Deserialize)]
85pub struct FormCreationRequest {
86    pub qr_code_id: Uuid,
87    pub fields: Vec<String>,
88}
89
90#[tracing::instrument(name = "handlers::form::store", skip(json, pool, request, jwt), fields(username=Empty, user_id=Empty))]
91/// post(form/store) runs an SQL query to store a new form and all its associated fields
92pub async fn store_form(
93    json: web::Json<FormCreationRequest>,
94    pool: web::Data<PgPool>,
95    request: HttpRequest,
96    jwt: web::Data<JwtClient>,
97) -> ApplicationResponse {
98    let current_user = jwt.user_or_403(request).await?;
99
100    // Store form first to avoid foreign key constrain
101    let mut new_form = NewForm::default();
102    new_form.qr_code_id = json.qr_code_id;
103    new_form.account_id = current_user.id;
104    new_form.store(pool.as_ref()).await?;
105
106    // Create a transaction to store each form input
107    let mut tx = pool.begin().await?;
108
109    // Queue a SQL query for each form input
110    for field in json.fields.iter() {
111        sqlx::query!(
112            r#"INSERT INTO form_input (id, form_id, type) 
113                VALUES ($1, $2, $3)"#,
114            Uuid::new_v4(),
115            new_form.id,
116            field
117        )
118        .execute(&mut tx)
119        .await?;
120    }
121
122    // Commit the transaction
123    tx.commit().await?;
124
125    Ok(HttpResponse::Ok().body(format!("Stored new form with id {}.", new_form.id)))
126}