From b698884b49892a633108c917c28acd0ad773d28e Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sun, 27 Feb 2022 20:41:45 +0530 Subject: [PATCH] feat: gist creation form --- src/pages/gists/new.rs | 116 ++++++++++++++++++++++++++++++++++++++- src/pages/gists/tests.rs | 44 ++++++++++++++- 2 files changed, 156 insertions(+), 4 deletions(-) diff --git a/src/pages/gists/new.rs b/src/pages/gists/new.rs index 9a8557c..a759581 100644 --- a/src/pages/gists/new.rs +++ b/src/pages/gists/new.rs @@ -41,6 +41,7 @@ pub fn register_templates(t: &mut tera::Tera) { pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(new); + cfg.service(new_submit); } pub struct NewGist { @@ -84,7 +85,6 @@ impl NewGist { ctx.insert(PAYLOAD_KEY, &[FieldNames::<&'static str>::default()]); } - println!("{:?}", ctx.get(PAYLOAD_KEY)); let ctx = RefCell::new(ctx); Self { ctx } } @@ -200,6 +200,117 @@ fn get_description(payload: &serde_json::Value) -> Option<&str> { None } +fn is_add_file(payload: &serde_json::Value) -> bool { + payload.get("add_file").is_some() +} + +struct FormExtractedData<'a> { + description: Option<&'a str>, + visibility: GistVisibility, + files: Vec>, + username: String, +} + +fn extract_form<'a>( + id: &Identity, + data: &AppData, + payload: &'a serde_json::Value, +) -> PageResult, NewGist> { + let username = id.identity().unwrap(); + let description = get_description(payload); + let gist = FieldNames::<&str>::from_serde_json(payload).map_err(|(resp, e)| { + PageError::new( + NewGist::new(&username, &data.settings, description, Some(&resp)), + e, + ) + })?; + let visibility = get_visibility(payload) + .map_err(|e| map_err(&username, data, description, Some(&gist), e))?; + let resp = FormExtractedData { + description, + visibility, + files: gist, + username, + }; + + Ok(resp) +} + +fn map_err( + username: &str, + data: &AppData, + description: Option<&str>, + gist: Option<&[FieldNames<&str>]>, + e: ServiceError, +) -> PageError { + PageError::new(NewGist::new(username, &data.settings, description, gist), e) +} + +#[my_codegen::post(path = "PAGES.gist.new", wrap = "super::get_auth_middleware()")] +async fn new_submit( + data: AppData, + db: crate::DB, + payload: web::Form, + id: Identity, +) -> PageResult { + let mut form_data = extract_form(&id, &data, &payload)?; + let html = ContentType::html(); + + if is_add_file(&payload) { + form_data.files.push(FieldNames::<&str>::default()); + let page = NewGist::new( + &form_data.username, + &data.settings, + form_data.description, + Some(&form_data.files), + ) + .render(); + return Ok(HttpResponse::Ok().content_type(html).body(page)); + }; + + let mut files: Vec = Vec::with_capacity(form_data.files.len()); + form_data + .files + .clone() + .drain(..) + .for_each(|f| files.push(f.into())); + + let map_err = |e: ServiceError| -> PageError { + map_err( + &form_data.username, + &data, + form_data.description, + Some(&form_data.files), + e, + ) + }; + let msg = CreateGist { + owner: &form_data.username, + description: form_data.description, + visibility: &form_data.visibility, + }; + + let mut db_gist = data.new_gist(db.as_ref(), &msg).await.map_err(&map_err)?; + + data.write_file( + db.as_ref(), + GistID::Repository(&mut db_gist.repository), + &files, + ) + .await + .map_err(&map_err)?; + + Ok(HttpResponse::Found() + .insert_header(( + http::header::LOCATION, + PAGES.gist.get_gist_route(&PostCommentPath { + username: form_data.username, + gist: db_gist.id, + }), + )) + .finish()) +} + #[cfg(test)] mod tests { use serde_json::json; @@ -324,5 +435,8 @@ mod tests { f.content, FileType::File(GistContentType::Text(fields1.content.to_owned())) ); + + assert!(!is_add_file(&json!({ "foo": "bar"}))); + assert!(is_add_file(&json!({ "add_file": "bar"}))); } } diff --git a/src/pages/gists/tests.rs b/src/pages/gists/tests.rs index f1240f0..568867c 100644 --- a/src/pages/gists/tests.rs +++ b/src/pages/gists/tests.rs @@ -17,20 +17,22 @@ use actix_web::http::StatusCode; use actix_web::test; -use super::*; +use db_core::prelude::*; + +use super::new::*; use crate::data::Data; use crate::tests::*; use crate::*; #[actix_rt::test] -async fn postgres_gists_work() { +async fn postgres_pages_gists_work() { let (db, data) = sqlx_postgres::get_data().await; gists_new_route_works(data.clone(), db.clone()).await; } #[actix_rt::test] -async fn sqlite_gists_work() { +async fn sqlite_pages_gists_work() { let (db, data) = sqlx_sqlite::get_data().await; gists_new_route_works(data.clone(), db.clone()).await; } @@ -48,4 +50,40 @@ async fn gists_new_route_works(data: Arc, db: BoxDB) { let app = get_app!(data, db).await; let new_gist = get_request!(&app, PAGES.gist.new, cookies.clone()); assert_eq!(new_gist.status(), StatusCode::OK); + let files = FieldNames::::new(1); + + // create gist + let payload = serde_json::json!({ + "description": "", + "visibility": GistVisibility::Private.to_str(), + files.filename.clone() : "foo.md", + files.content.clone() : "foo.md", + }); + + let resp = test::call_service( + &app, + post_request!(&payload, PAGES.gist.new, FORM) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::FOUND); + + // add new file during gist creation + let payload = serde_json::json!({ + "description": "", + "visibility": GistVisibility::Private.to_str(), + files.filename.clone() : "foo.md", + files.content.clone() : "foo.md", + "add_file": "", + }); + + let resp = test::call_service( + &app, + post_request!(&payload, PAGES.gist.new, FORM) + .cookie(cookies) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::OK); }