tenebrous-sheets/src/routes/characters/new.rs

128 lines
3.7 KiB
Rust
Raw Normal View History

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<CharacterDataType, &'v RawStr> {
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<BytesMut, Error> {
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<NewCharacterForm>,
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<Template, Error> {
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 = "<form>")]
pub(super) fn new_character_submit(
form: Result<Form<NewCharacterForm>, FormError>,
logged_in_user: &User,
conn: TenebrousDbConn,
) -> Result<Redirect, Template> {
//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::<String, String>::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()
}