mcaptcha/pages/panel/
utils.rs

1// Copyright (C) 2024  Aravinth Manivannan <realaravinth@batsense.net>
2// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6use actix_identity::Identity;
7use actix_web::{web, HttpResponse, Responder};
8use sailfish::TemplateOnce;
9
10use crate::api::v1::stats::{percentile_bench_runner, PercentileReq, PercentileResp};
11use crate::errors::PageResult;
12use crate::pages::auth::sudo::SudoPage;
13use crate::AppData;
14
15pub mod routes {
16    pub struct Utils {
17        pub percentile: &'static str,
18    }
19
20    impl Utils {
21        pub const fn new() -> Self {
22            Utils {
23                percentile: "/utils/percentile",
24            }
25        }
26
27        pub const fn get_sitemap() -> [&'static str; 1] {
28            const S: Utils = Utils::new();
29            [S.percentile]
30        }
31    }
32}
33
34pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
35    cfg.service(get_percentile);
36    cfg.service(post_percentile);
37}
38
39const PAGE: &str = "Difficulty factor statistics";
40
41#[derive(TemplateOnce, Clone)]
42#[template(path = "panel/utils/percentile/index.html")]
43pub struct PercentilePage {
44    time: Option<u32>,
45    percentile: Option<f64>,
46    difficulty_factor: Option<u32>,
47}
48
49#[my_codegen::get(
50    path = "crate::PAGES.panel.utils.percentile",
51    wrap = "crate::pages::get_middleware()"
52)]
53async fn get_percentile(id: Identity) -> PageResult<impl Responder> {
54    let data = PercentilePage {
55        time: None,
56        percentile: None,
57        difficulty_factor: None,
58    };
59
60    let body = data.render_once().unwrap();
61    Ok(HttpResponse::Ok()
62        .content_type("text/html; charset=utf-8")
63        .body(body))
64}
65
66#[my_codegen::post(
67    path = "crate::PAGES.panel.utils.percentile",
68    wrap = "crate::pages::get_middleware()"
69)]
70async fn post_percentile(
71    data: AppData,
72    id: Identity,
73    payload: web::Form<PercentileReq>,
74) -> PageResult<impl Responder> {
75    let resp = percentile_bench_runner(&data, &payload).await?;
76    let page = PercentilePage {
77        time: Some(payload.time),
78        percentile: Some(payload.percentile),
79        difficulty_factor: resp.difficulty_factor,
80    };
81
82    let body = page.render_once().unwrap();
83    Ok(HttpResponse::Ok()
84        .content_type("text/html; charset=utf-8")
85        .body(body))
86}
87
88#[cfg(test)]
89mod tests {
90    use actix_web::{http::StatusCode, test, web::Bytes, App};
91
92    use super::*;
93    use crate::api::v1::services;
94    use crate::*;
95
96    #[actix_rt::test]
97    async fn page_stats_bench_work_pg() {
98        let data = crate::tests::pg::get_data().await;
99        page_stats_bench_work(data).await;
100    }
101
102    #[actix_rt::test]
103    async fn page_stats_bench_work_maria() {
104        let data = crate::tests::maria::get_data().await;
105        page_stats_bench_work(data).await;
106    }
107
108    async fn page_stats_bench_work(data: ArcData) {
109        use crate::tests::*;
110
111        const NAME: &str = "pagebenchstatsuesr";
112        const EMAIL: &str = "pagebenchstatsuesr@testadminuser.com";
113        const PASSWORD: &str = "longpassword2";
114
115        const DEVICE_USER_PROVIDED: &str = "foo";
116        const DEVICE_SOFTWARE_RECOGNISED: &str = "Foobar.v2";
117        const THREADS: i32 = 4;
118
119        let data = &data;
120        {
121            delete_user(&data, NAME).await;
122        }
123
124        register_and_signin(data, NAME, EMAIL, PASSWORD).await;
125        // create captcha
126        let (_, signin_resp, key) = add_levels_util(data, NAME, PASSWORD).await;
127        let app = get_app!(data).await;
128        let cookies = get_cookie!(signin_resp);
129
130        let page = 1;
131        let tmp_id = uuid::Uuid::new_v4();
132        let download_rotue = V1_API_ROUTES
133            .survey
134            .get_download_route(&tmp_id.to_string(), page);
135
136        let download_req = test::call_service(
137            &app,
138            test::TestRequest::get().uri(&download_rotue).to_request(),
139        )
140        .await;
141        assert_eq!(download_req.status(), StatusCode::NOT_FOUND);
142
143        data.db
144            .analytics_create_psuedo_id_if_not_exists(&key.key)
145            .await
146            .unwrap();
147
148        let psuedo_id = data
149            .db
150            .analytics_get_psuedo_id_from_capmaign_id(&key.key)
151            .await
152            .unwrap();
153
154        for i in 1..6 {
155            println!("[{i}] Saving analytics");
156            let analytics = db_core::CreatePerformanceAnalytics {
157                time: i,
158                difficulty_factor: i,
159                worker_type: "wasm".into(),
160            };
161            data.db.analysis_save(&key.key, &analytics).await.unwrap();
162        }
163
164        let msg = PercentileReq {
165            time: 1,
166            percentile: 99.00,
167        };
168        let resp = test::call_service(
169            &app,
170            post_request!(&msg, V1_API_ROUTES.stats.percentile_benches).to_request(),
171        )
172        .await;
173        assert_eq!(resp.status(), StatusCode::OK);
174        let resp: PercentileResp = test::read_body_json(resp).await;
175
176        assert!(resp.difficulty_factor.is_none());
177
178        let msg = PercentileReq {
179            time: 1,
180            percentile: 100.00,
181        };
182
183        let resp = test::call_service(
184            &app,
185            post_request!(&msg, V1_API_ROUTES.stats.percentile_benches).to_request(),
186        )
187        .await;
188        assert_eq!(resp.status(), StatusCode::OK);
189        let resp: PercentileResp = test::read_body_json(resp).await;
190
191        // start
192        let percentile_resp = test::call_service(
193            &app,
194            test::TestRequest::get()
195                .uri(&crate::PAGES.panel.utils.percentile)
196                .cookie(cookies.clone())
197                .to_request(),
198        )
199        .await;
200
201        assert_eq!(percentile_resp.status(), StatusCode::OK);
202
203        let body: Bytes = test::read_body(percentile_resp).await;
204        let body = String::from_utf8(body.to_vec()).unwrap();
205
206        assert!(body.contains("Maximum time taken"));
207
208        let percentile_resp = test::call_service(
209            &app,
210            test::TestRequest::get()
211                .uri(&crate::PAGES.panel.utils.percentile)
212                .cookie(cookies.clone())
213                .to_request(),
214        )
215        .await;
216
217        assert_eq!(percentile_resp.status(), StatusCode::OK);
218
219        let body: Bytes = test::read_body(percentile_resp).await;
220        let body = String::from_utf8(body.to_vec()).unwrap();
221
222        assert!(body.contains("Maximum time taken"));
223
224        // end
225        // start post
226
227        let msg = PercentileReq {
228            time: 1,
229            percentile: 99.00,
230        };
231
232        let percentile_resp = test::call_service(
233            &app,
234            test::TestRequest::post()
235                .uri(&crate::PAGES.panel.utils.percentile)
236                .set_form(&msg)
237                .cookie(cookies.clone())
238                .to_request(),
239        )
240        .await;
241
242        assert_eq!(percentile_resp.status(), StatusCode::OK);
243
244        let body: Bytes = test::read_body(percentile_resp).await;
245        let body = String::from_utf8(body.to_vec()).unwrap();
246
247        assert!(body.contains(
248            "Not enough inputs to compute statistics. Please try again later"
249        ));
250        assert!(body.contains(&1.to_string()));
251        assert!(body.contains(&99.00.to_string()));
252        // end post
253
254        // start post
255
256        let msg = PercentileReq {
257            time: 2,
258            percentile: 100.00,
259        };
260
261        let percentile_resp = test::call_service(
262            &app,
263            test::TestRequest::post()
264                .uri(&crate::PAGES.panel.utils.percentile)
265                .set_form(&msg)
266                .cookie(cookies.clone())
267                .to_request(),
268        )
269        .await;
270
271        assert_eq!(percentile_resp.status(), StatusCode::OK);
272
273        let body: Bytes = test::read_body(percentile_resp).await;
274        let body = String::from_utf8(body.to_vec()).unwrap();
275
276        assert!(body.contains("Difficulty factor: 2"));
277        assert!(body.contains(&2.to_string()));
278        assert!(body.contains(&100.00.to_string()));
279    }
280}