feat: list survey responses per campaign

This commit is contained in:
Aravinth Manivannan 2023-01-26 18:25:52 +05:30
parent f6030577a0
commit aa63783794
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
2 changed files with 170 additions and 118 deletions

View file

@ -23,6 +23,7 @@ use sqlx::types::time::OffsetDateTime;
use uuid::Uuid; use uuid::Uuid;
use super::{get_admin_check_login, get_uuid}; use super::{get_admin_check_login, get_uuid};
use crate::api::v1::bench::Bench;
use crate::errors::*; use crate::errors::*;
use crate::AppData; use crate::AppData;
@ -35,6 +36,7 @@ pub mod routes {
pub delete: &'static str, pub delete: &'static str,
// pub get_feedback: &'static str, // pub get_feedback: &'static str,
pub list: &'static str, pub list: &'static str,
pub results: &'static str,
} }
impl Campaign { impl Campaign {
@ -43,8 +45,14 @@ pub mod routes {
let delete = "/admin/api/v1/campaign/{uuid}/delete"; let delete = "/admin/api/v1/campaign/{uuid}/delete";
// let get_feedback = "/api/v1/campaign/{uuid}/feedback"; // let get_feedback = "/api/v1/campaign/{uuid}/feedback";
let list = "/admin/api/v1/campaign/list"; let list = "/admin/api/v1/campaign/list";
let results = "/admin/api/v1/campaign/{uuid}/results";
Campaign { add, delete, list } Campaign {
add,
delete,
list,
results,
}
} }
// pub fn get_benches_route(&self, campaign_id: &str) -> String { // pub fn get_benches_route(&self, campaign_id: &str) -> String {
// self.get_feedback.replace("{uuid}", &campaign_id) // self.get_feedback.replace("{uuid}", &campaign_id)
@ -53,10 +61,18 @@ pub mod routes {
pub fn get_delete_route(&self, campaign_id: &str) -> String { pub fn get_delete_route(&self, campaign_id: &str) -> String {
self.delete.replace("{uuid}", campaign_id) self.delete.replace("{uuid}", campaign_id)
} }
pub fn get_results_route(&self, campaign_id: &str) -> String {
self.results.replace("{uuid}", campaign_id)
}
} }
} }
pub mod runners { pub mod runners {
use futures::try_join;
use crate::api::v1::bench::Bench;
use super::*; use super::*;
pub async fn add_runner( pub async fn add_runner(
@ -144,86 +160,111 @@ pub mod runners {
Ok(list_resp) Ok(list_resp)
} }
// pub async fn get_benches( #[derive(Debug)]
// username: &str, struct InternalSurveyResp {
// uuid: &str, id: i32,
// data: &AppData, user_id: Uuid,
// ) -> ServiceResult<GetFeedbackResp> { threads: Option<i32>,
// let uuid = Uuid::parse_str(uuid).map_err(|_| ServiceError::NotAnId)?; device_user_provided: String,
// device_software_recognised: String,
// struct FeedbackInternal { }
// time: OffsetDateTime,
// description: String, #[derive(Debug)]
// helpful: bool, struct InnerU {
// } created_at: OffsetDateTime,
// id: Uuid,
// struct Name { }
// name: String,
// } impl From<InnerU> for SurveyUser {
// fn from(u: InnerU) -> Self {
// let name_fut = sqlx::query_as!( Self {
// Name, id: u.id,
// "SELECT name created_at: u.created_at.unix_timestamp(),
// FROM survey_campaigns }
// WHERE uuid = $1 }
// AND }
// user_id = (
// SELECT pub async fn get_results(
// ID username: &str,
// FROM uuid: &Uuid,
// kaizen_users data: &AppData,
// WHERE page: usize,
// name = $2 limit: usize,
// ) ) -> ServiceResult<Vec<SurveyResponse>> {
// ", // let uuid = Uuid::parse_str(uuid).map_err(|_| ServiceError::NotAnId)?;
// uuid,
// username let mut db_responses = sqlx::query_as!(
// ) InternalSurveyResp,
// .fetch_one(&data.db); //.await?; "SELECT
// ID,
// let feedback_fut = sqlx::query_as!( device_software_recognised,
// FeedbackInternal, threads,
// "SELECT user_id,
// time, description, helpful device_user_provided
// FROM FROM
// kaizen_feedbacks survey_responses
// WHERE campaign_id = ( WHERE
// SELECT uuid campaign_id = (
// FROM SELECT ID FROM survey_campaigns
// survey_campaigns WHERE
// WHERE ID = $1
// uuid = $1 AND
// AND user_id = (SELECT ID FROM survey_admins WHERE name = $2)
// user_id = ( )
// SELECT LIMIT $3 OFFSET $4
// ID ",
// FROM uuid,
// kaizen_users username,
// WHERE limit as i32,
// name = $2 page as i32,
// ) )
// )", .fetch_all(&data.db)
// uuid, .await?;
// username
// ) let mut responses = Vec::with_capacity(db_responses.len());
// .fetch_all(&data.db); println!("responses {:?}", db_responses);
// let (name, mut feedbacks) = try_join!(name_fut, feedback_fut)?; for r in db_responses.drain(0..) {
// //.await?; let benches_fut = sqlx::query_as!(
// Bench,
// let mut feedback_resp = Vec::with_capacity(feedbacks.len()); "SELECT
// feedbacks.drain(0..).for_each(|f| { duration,
// feedback_resp.push(Feedback { difficulty
// time: f.time.unix_timestamp() as u64, FROM
// description: f.description, survey_benches
// helpful: f.helpful, WHERE
// }); resp_id = $1
// }); ",
// r.id,
// Ok(GetFeedbackResp { )
// feedbacks: feedback_resp, .fetch_all(&data.db);
// name: name.name,
// }) let user_fut = sqlx::query_as!(
// } InnerU,
"SELECT
created_at,
ID
FROM
survey_users
WHERE
ID = $1
",
r.user_id,
)
.fetch_one(&data.db);
let (benches, user) = try_join!(benches_fut, user_fut)?;
let user = user.into();
responses.push(SurveyResponse {
benches,
user,
device_user_provided: r.device_user_provided,
device_software_recognised: r.device_software_recognised,
id: r.id as usize,
threads: r.threads.map(|t| t as usize),
})
}
Ok(responses)
}
pub async fn delete( pub async fn delete(
uuid: &Uuid, uuid: &Uuid,
@ -236,11 +277,11 @@ pub mod runners {
WHERE WHERE
user_id = ( user_id = (
SELECT SELECT
ID ID
FROM FROM
survey_admins survey_admins
WHERE WHERE
name = $1 name = $1
) )
AND AND
id = ($2)", id = ($2)",
@ -269,35 +310,23 @@ pub async fn delete(
Ok(HttpResponse::Ok()) Ok(HttpResponse::Ok())
} }
//#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//pub struct Feedback { pub struct SurveyResponse {
// pub time: u64, pub user: SurveyUser,
// pub description: String, pub device_user_provided: String,
// pub helpful: bool, pub device_software_recognised: String,
//} pub id: usize,
// pub threads: Option<usize>,
//#[derive(Serialize, Deserialize)] pub benches: Vec<Bench>,
//pub struct GetFeedbackResp { }
// pub name: String,
// pub feedbacks: Vec<Feedback>,
//}
//
//#[actix_web_codegen_const_routes::post(
// path = "crate::V1_API_ROUTES.campaign.get_feedback",
// wrap = "crate::CheckLogin"
//)]
//pub async fn get_feedback(
// id: Identity,
// data: AppData,
// path: web::Path<String>,
//) -> ServiceResult<impl Responder> {
// let username = id.identity().unwrap();
// let path = path.into_inner();
// let feedback_resp = runners::get_feedback(&username, &path, &data).await?;
// Ok(HttpResponse::Ok().json(feedback_resp))
//}
#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SurveyUser {
pub created_at: i64, // OffsetDateTime,
pub id: Uuid,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ListCampaignResp { pub struct ListCampaignResp {
pub name: String, pub name: String,
pub uuid: String, pub uuid: String,
@ -317,13 +346,13 @@ pub async fn list_campaign(
Ok(HttpResponse::Ok().json(list_resp)) Ok(HttpResponse::Ok().json(list_resp))
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AddCapmaign { pub struct AddCapmaign {
pub name: String, pub name: String,
pub difficulties: Vec<i32>, pub difficulties: Vec<i32>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AddCapmaignResp { pub struct AddCapmaignResp {
pub campaign_id: String, pub campaign_id: String,
} }
@ -431,6 +460,29 @@ mod tests {
let list = list_campaings(data.clone(), cookies.clone()).await; let list = list_campaings(data.clone(), cookies.clone()).await;
assert!(list.iter().any(|c| c.name == NAME)); assert!(list.iter().any(|c| c.name == NAME));
let responses = super::runners::get_results(
NAME,
&uuid::Uuid::parse_str(&campaign.campaign_id).unwrap(),
&AppData::new(data.clone()),
0,
50,
)
.await
.unwrap();
assert_eq!(responses.len(), 1);
assert_eq!(responses[0].threads, Some(THREADS as usize));
let mut l = responses[0].benches.clone();
l.sort_by(|a, b| a.difficulty.cmp(&b.difficulty));
let mut r = BENCHES.clone();
r.sort_by(|a, b| a.difficulty.cmp(&b.difficulty));
assert_eq!(l, r);
assert_eq!(
responses[0].device_software_recognised,
DEVICE_SOFTWARE_RECOGNISED
);
assert_eq!(responses[0].device_user_provided, DEVICE_USER_PROVIDED);
bad_post_req_test_witout_payload( bad_post_req_test_witout_payload(
NAME, NAME,
PASSWORD, PASSWORD,

View file

@ -157,13 +157,13 @@ async fn register(
} }
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Bench { pub struct Bench {
pub duration: f32, pub duration: f32,
pub difficulty: i32, pub difficulty: i32,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Submission { pub struct Submission {
pub device_user_provided: String, pub device_user_provided: String,
pub device_software_recognised: String, pub device_software_recognised: String,
@ -171,7 +171,7 @@ pub struct Submission {
pub benches: Vec<Bench>, pub benches: Vec<Bench>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SubmissionProof { pub struct SubmissionProof {
pub token: String, pub token: String,
pub proof: String, pub proof: String,
@ -304,7 +304,7 @@ async fn submit(
Ok(HttpResponse::Ok().json(resp)) Ok(HttpResponse::Ok().json(resp))
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BenchConfig { pub struct BenchConfig {
pub difficulties: Vec<i32>, pub difficulties: Vec<i32>,
} }