diff --git a/src/api/v1/admin/campaigns.rs b/src/api/v1/admin/campaigns.rs index 2211832..eb3265f 100644 --- a/src/api/v1/admin/campaigns.rs +++ b/src/api/v1/admin/campaigns.rs @@ -31,6 +31,8 @@ use crate::AppData; pub mod routes { use serde::{Deserialize, Serialize}; + use super::ResultsPage; + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct Campaign { pub add: &'static str, @@ -63,8 +65,26 @@ pub mod routes { self.delete.replace("{uuid}", campaign_id) } - pub fn get_results_route(&self, campaign_id: &str) -> String { - self.results.replace("{uuid}", campaign_id) + pub fn get_results_route( + &self, + campaign_id: &str, + modifier: Option, + ) -> String { + let mut res = self.results.replace("{uuid}", campaign_id); + if let Some(modifier) = modifier { + if let Some(page) = modifier.page { + res = format!("{res}?page={page}"); + } + + if let Some(bench_type) = modifier.bench_type { + if modifier.page.is_some() { + res = format!("{res}&bench_type={}", bench_type.to_string()); + } else { + res = format!("{res}?bench_type={}", bench_type.to_string()); + } + } + } + res } } } @@ -165,13 +185,13 @@ pub mod runners { #[derive(Debug)] struct InternalSurveyResp { - id: Option, - submitted_at: Option, - user_id: Option, + id: i32, + submitted_at: OffsetDateTime, + user_id: Uuid, threads: Option, - device_user_provided: Option, - device_software_recognised: Option, - name: Option, + device_user_provided: String, + device_software_recognised: String, + name: String, } #[derive(Debug)] @@ -195,10 +215,56 @@ pub mod runners { data: &AppData, page: usize, limit: usize, + filter: Option, ) -> ServiceResult> { - let mut db_responses = sqlx::query_as!( - InternalSurveyResp, - "SELECT + let mut db_responses = if let Some(filter) = filter { + sqlx::query_as!( + InternalSurveyResp, + "SELECT + survey_responses.ID, + survey_responses.device_software_recognised, + survey_responses.threads, + survey_responses.user_id, + survey_responses.submitted_at, + survey_responses.device_user_provided, + survey_bench_type.name + FROM + survey_responses + INNER JOIN survey_bench_type ON + survey_responses.submission_bench_type_id = survey_bench_type.ID + WHERE + survey_bench_type.name = $3 + AND + survey_responses.campaign_id = ( + SELECT ID FROM survey_campaigns + WHERE + ID = $1 + AND + user_id = (SELECT ID FROM survey_admins WHERE name = $2) + ) + LIMIT $4 OFFSET $5", + uuid, + username, + filter.to_string(), + limit as i32, + page as i32, + ) + .fetch_all(&data.db) + .await? + } else { + #[derive(Debug)] + struct I { + id: Option, + submitted_at: Option, + user_id: Option, + threads: Option, + device_user_provided: Option, + device_software_recognised: Option, + name: Option, + } + let mut i = sqlx::query_as!( + I, + "SELECT survey_responses.ID, survey_responses.device_software_recognised, survey_responses.threads, @@ -218,15 +284,29 @@ pub mod runners { AND user_id = (SELECT ID FROM survey_admins WHERE name = $2) ) - LIMIT $3 OFFSET $4 - ", - uuid, - username, - limit as i32, - page as i32, - ) - .fetch_all(&data.db) - .await?; + LIMIT $3 OFFSET $4", + uuid, + username, + limit as i32, + page as i32, + ) + .fetch_all(&data.db) + .await?; + + let mut res = Vec::with_capacity(i.len()); + i.drain(0..).for_each(|x| { + res.push(InternalSurveyResp { + id: x.id.unwrap(), + submitted_at: x.submitted_at.unwrap(), + user_id: x.user_id.unwrap(), + threads: x.threads, + device_user_provided: x.device_user_provided.unwrap(), + device_software_recognised: x.device_software_recognised.unwrap(), + name: x.name.unwrap(), + }) + }); + res + }; let mut responses = Vec::with_capacity(db_responses.len()); for r in db_responses.drain(0..) { @@ -263,13 +343,12 @@ pub mod runners { responses.push(SurveyResponse { benches, user, - device_user_provided: r.device_user_provided.unwrap(), - device_software_recognised: r.device_software_recognised.unwrap(), - submitted_at: r.submitted_at.unwrap().unix_timestamp(), - id: r.id.unwrap() as usize, - submission_type: SubmissionType::from_str(r.name.as_ref().unwrap()) - .unwrap(), - threads: Some(r.threads.unwrap() as usize), + device_user_provided: r.device_user_provided, + device_software_recognised: r.device_software_recognised, + submitted_at: r.submitted_at.unix_timestamp(), + id: r.id as usize, + submission_type: SubmissionType::from_str(&r.name).unwrap(), + threads: r.threads.map(|t| t as usize), }) } Ok(responses) @@ -378,12 +457,17 @@ pub fn services(cfg: &mut web::ServiceConfig) { #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct ResultsPage { page: Option, + pub bench_type: Option, } impl ResultsPage { pub fn page(&self) -> usize { self.page.unwrap_or(0) } + + pub fn new(page: Option, bench_type: Option) -> Self { + Self { page, bench_type } + } } #[actix_web_codegen_const_routes::get( @@ -397,9 +481,12 @@ pub async fn get_campaign_resutls( data: AppData, ) -> ServiceResult { let username = id.identity().unwrap(); + let query = query.into_inner(); let page = query.page(); - let results = runners::get_results(&username, &path, &data, page, 50).await?; + let results = + runners::get_results(&username, &path, &data, page, 50, query.bench_type) + .await?; Ok(HttpResponse::Ok().json(results)) } @@ -422,6 +509,7 @@ async fn add( #[cfg(test)] mod tests { use crate::api::v1::bench::Submission; + use crate::api::v1::bench::SubmissionType; use crate::errors::*; use crate::tests::*; use crate::*; @@ -493,7 +581,7 @@ mod tests { device_software_recognised: DEVICE_SOFTWARE_RECOGNISED.into(), threads: THREADS, benches: BENCHES.clone(), - submission_type: api::v1::bench::SubmissionType::Wasm, + submission_type: SubmissionType::Wasm, }; let _proof = @@ -508,6 +596,7 @@ mod tests { &AppData::new(data.clone()), 0, 50, + None, ) .await .unwrap(); @@ -518,6 +607,34 @@ mod tests { let mut r = BENCHES.clone(); r.sort_by(|a, b| a.difficulty.cmp(&b.difficulty)); + assert_eq!( + super::runners::get_results( + NAME, + &uuid::Uuid::parse_str(&campaign.campaign_id).unwrap(), + &AppData::new(data.clone()), + 0, + 50, + Some(SubmissionType::Wasm), + ) + .await + .unwrap(), + responses + ); + + assert_eq!( + super::runners::get_results( + NAME, + &uuid::Uuid::parse_str(&campaign.campaign_id).unwrap(), + &AppData::new(data.clone()), + 0, + 50, + Some(SubmissionType::Js), + ) + .await + .unwrap(), + Vec::default() + ); + assert_eq!(l, r); assert_eq!( responses[0].device_software_recognised, @@ -530,7 +647,7 @@ mod tests { &V1_API_ROUTES .admin .campaign - .get_results_route(&campaign.campaign_id), + .get_results_route(&campaign.campaign_id, None), cookies.clone() ); assert_eq!(results_resp.status(), StatusCode::OK);