/* * Copyright (C) 2022 Aravinth Manivannan * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use std::collections::HashMap; use actix_web::{web, HttpRequest, HttpResponse, Responder}; use serde::{Deserialize, Serialize}; use crate::errors::*; use crate::AppCtx; use crate::*; pub mod routes { use super::*; #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct Forms { pub submit: &'static str, } impl Forms { pub const fn new() -> Self { Self { submit: "/api/v1/forms/submit", } } } } pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(upload); } #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] enum FormDType { Num(f64), Str(String), } impl FormDType { fn apply_types(&mut self) { if let Self::Str(data) = self { if let Ok(num) = data.parse::() { *self = Self::Num(num); } } } } pub type FormValue = HashMap; #[actix_web_codegen_const_routes::post(path = "API_V1_ROUTES.forms.submit")] async fn upload( req: HttpRequest, ctx: AppCtx, payload: web::Either, web::Form>, ) -> ServiceResult { let host = { let c = req.connection_info(); c.host().to_owned() }; let path = req.uri(); //ctx.db.add_site(host).await.unwrap(); let data = match payload { web::Either::Left(json) => json.into_inner(), web::Either::Right(form) => { let mut form = form.into_inner(); for (_, v) in form.iter_mut() { v.apply_types(); } serde_json::to_value(&form).unwrap() } }; ctx.db .add_form_submission(&data, &host, path.path()) .await .unwrap(); println!("{:?}", data); //ctx.gitea.report(&payload).await; Ok(HttpResponse::Ok().json(data)) } #[cfg(test)] pub mod tests { use actix_web::{ http::{header, StatusCode}, test, App, }; use super::*; #[derive(Serialize, Clone, Deserialize, PartialEq)] struct Foo { foo: String, num: f64, } #[actix_rt::test] async fn submit_works() { // const USERNAME: &str = "index_works"; // const PASSWORD: &str = "23k4j;123k4j1;l23kj4"; let settings = Settings::new().unwrap(); // let settings = Settings::new().unwrap(); let ctx = AppCtx::new(crate::ctx::Ctx::new(&settings).await); let app = test::init_service( App::new() .app_data(ctx.clone()) .configure(crate::routes::services), ) .await; let foo = Foo { foo: "Foo".into(), num: 2.33, }; // upload json let upload_json = test::call_service( &app, test::TestRequest::post() .uri(API_V1_ROUTES.forms.submit) .set_json(&foo) .to_request(), ) .await; if upload_json.status() != StatusCode::OK { let resp_err: crate::errors::ErrorToResponse = test::read_body_json(upload_json).await; panic!("{:?}", resp_err.error); } assert_eq!(upload_json.status(), StatusCode::OK); let json: serde_json::Value = test::read_body_json(upload_json).await; // upload url encoded let upload_form = test::call_service( &app, test::TestRequest::post() .uri(API_V1_ROUTES.forms.submit) .uri(API_V1_ROUTES.forms.submit) .set_form(&foo) .to_request(), ) .await; if upload_form.status() != StatusCode::OK { let resp_err: crate::errors::ErrorToResponse = test::read_body_json(upload_form).await; panic!("{:?}", resp_err.error); } assert_eq!(upload_form.status(), StatusCode::OK); let form: serde_json::Value = test::read_body_json(upload_form).await; assert_eq!(form, json); } }