use crate::db::{Dao, TenebrousDbConn}; use crate::errors::Error; use crate::models::{ characters::{CharacterDataType, NewCharacter}, proto::cofd::*, users::User, }; use prost::{bytes::BytesMut, Message}; use rocket::http::RawStr; use rocket::request::{Form, FormError, FromFormValue}; use rocket::response::Redirect; use rocket_contrib::templates::Template; use std::collections::HashMap; #[derive(FromForm, Serialize)] pub(super) struct NewCharacterForm { name: String, system: CharacterDataType, } #[derive(Serialize)] pub(super) struct RawNewCharacterForm { name: String, system: String, } impl<'v> FromFormValue<'v> for CharacterDataType { type Error = &'v RawStr; fn from_form_value(form_value: &'v RawStr) -> Result { let system = form_value.url_decode().or(Err("bad input"))?; match system.as_ref() { "cofd" => Ok(CharacterDataType::ChroniclesOfDarknessV1), "changeling" => Ok(CharacterDataType::ChangelingV1), _ => Err(form_value), } } } fn create_new_sheet(system: &CharacterDataType) -> Result { use CharacterDataType::*; let sheet: BytesMut = match system { ChroniclesOfDarknessV1 => { let sheet = CofdSheet::default(); let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&sheet)); sheet.encode(&mut buf)?; buf } ChangelingV1 => { let mut sheet = ChangelingSheet::default(); sheet.base = Some(CofdSheet::default()); let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&sheet)); sheet.encode(&mut buf)?; buf } }; Ok(sheet) } fn create_new_character( form: Form, user_id: i32, conn: TenebrousDbConn, ) -> Result<(), Error> { let sheet = create_new_sheet(&form.system)?; let insert = NewCharacter { user_id: user_id, viewable: true, character_name: &form.name, data_type: form.system, data_version: 1, data: &sheet, }; conn.insert_character(insert)?; Ok(()) } #[get("/new")] pub(super) fn new_character_page( logged_in_user: &User, conn: TenebrousDbConn, ) -> Result { let mut context = HashMap::new(); let form = NewCharacterForm { name: "".to_string(), system: CharacterDataType::ChroniclesOfDarknessV1, }; context.insert("form", form); Ok(Template::render("characters/new_character", context)) } #[post("/new", data = "
")] pub(super) fn new_character_submit( form: Result, FormError>, logged_in_user: &User, conn: TenebrousDbConn, ) -> Result { //TODO redirect to character edit page //TODO redirect back to new character page with an error and filled-out form if validation errors. if let Err(e) = form { //Not sure how to repopulate the form. let mut context = HashMap::new(); let form = NewCharacterForm { name: "".to_string(), system: CharacterDataType::ChroniclesOfDarknessV1, }; context.insert("form", form); return Err(Template::render("characters/new_character", context)); } match create_new_character(form.unwrap(), logged_in_user.id, conn) { Ok(_) => Ok(crate::routes::common::redirect_to_index()), Err(e) => { let context = HashMap::::new(); return Err(Template::render("characters/new_character", context)); } } } #[get("/new", rank = 2)] pub(super) fn new_character_not_logged_in() -> Redirect { crate::routes::common::redirect_to_login() }