2020-12-08 22:26:47 +00:00
|
|
|
use crate::db::{Dao, TenebrousDbConn};
|
|
|
|
use crate::errors::Error;
|
|
|
|
use crate::models::{
|
|
|
|
characters::{CharacterDataType, NewCharacter},
|
2020-12-09 21:25:31 +00:00
|
|
|
convert::ValidationError,
|
2020-12-08 22:26:47 +00:00
|
|
|
users::User,
|
|
|
|
};
|
2020-12-09 21:25:31 +00:00
|
|
|
use rocket::{request::Form, response::Redirect};
|
2020-12-08 22:26:47 +00:00
|
|
|
use rocket_contrib::templates::Template;
|
2020-12-09 21:25:31 +00:00
|
|
|
use strum::IntoEnumIterator;
|
2020-12-08 22:26:47 +00:00
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
/// Form submission for creating a new character.
|
2020-12-08 22:26:47 +00:00
|
|
|
#[derive(FromForm, Serialize)]
|
|
|
|
pub(super) struct NewCharacterForm {
|
|
|
|
name: String,
|
2020-12-09 21:25:31 +00:00
|
|
|
system: Result<CharacterDataType, ValidationError>,
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
/// Template context for the new character page. Serves as both a
|
|
|
|
/// means of populating form fields and reindering error messages.
|
2020-12-08 22:26:47 +00:00
|
|
|
#[derive(Serialize)]
|
2020-12-09 21:25:31 +00:00
|
|
|
pub(super) struct NewCharacterContext {
|
2020-12-08 22:26:47 +00:00
|
|
|
name: String,
|
2020-12-09 21:25:31 +00:00
|
|
|
error_message: String,
|
|
|
|
selected_system: CharacterDataType,
|
|
|
|
systems: Vec<CharacterDataType>,
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
impl NewCharacterContext {
|
|
|
|
/// Default empty context, used when page first loads.
|
|
|
|
pub fn default() -> NewCharacterContext {
|
|
|
|
NewCharacterContext {
|
|
|
|
name: "".to_string(),
|
|
|
|
error_message: "".to_string(),
|
|
|
|
selected_system: CharacterDataType::ChroniclesOfDarknessV1,
|
|
|
|
systems: CharacterDataType::iter().collect(),
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
/// Create a context from a form submission. Used to repopulate
|
|
|
|
/// fields in the form when an error is sent back.
|
|
|
|
pub fn from_form(form: &Form<NewCharacterForm>) -> NewCharacterContext {
|
|
|
|
let system: CharacterDataType = *form
|
|
|
|
.system
|
|
|
|
.as_ref()
|
|
|
|
.unwrap_or(&CharacterDataType::ChroniclesOfDarknessV1);
|
2020-12-08 22:26:47 +00:00
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
NewCharacterContext {
|
|
|
|
name: form.name.clone(),
|
|
|
|
error_message: "".to_string(),
|
|
|
|
selected_system: system,
|
|
|
|
systems: CharacterDataType::iter().collect(),
|
|
|
|
}
|
|
|
|
}
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
/// Create and insert a new character into the database. The form is
|
|
|
|
/// assumed to be successfully validated.
|
2020-12-13 13:57:50 +00:00
|
|
|
async fn create_new_character(
|
2020-12-09 21:25:31 +00:00
|
|
|
form: &Form<NewCharacterForm>,
|
2020-12-08 22:26:47 +00:00
|
|
|
user_id: i32,
|
2020-12-29 23:06:41 +00:00
|
|
|
conn: TenebrousDbConn<'_>,
|
2020-12-08 22:26:47 +00:00
|
|
|
) -> Result<(), Error> {
|
2020-12-09 21:25:31 +00:00
|
|
|
let system: CharacterDataType = *form.system.as_ref().unwrap();
|
2020-12-13 13:57:50 +00:00
|
|
|
let sheet: Vec<u8> = system.create_data()?.to_vec();
|
2020-12-08 22:26:47 +00:00
|
|
|
|
|
|
|
let insert = NewCharacter {
|
|
|
|
user_id: user_id,
|
|
|
|
viewable: true,
|
2020-12-29 23:06:41 +00:00
|
|
|
character_name: &form.name,
|
2020-12-09 21:25:31 +00:00
|
|
|
data_type: system,
|
2020-12-08 22:26:47 +00:00
|
|
|
data_version: 1,
|
2020-12-29 23:06:41 +00:00
|
|
|
data: &sheet,
|
2020-12-08 22:26:47 +00:00
|
|
|
};
|
|
|
|
|
2020-12-13 13:57:50 +00:00
|
|
|
conn.insert_character(insert).await?;
|
2020-12-08 22:26:47 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
/// Render an error message on the new character page, repopulating
|
|
|
|
/// the form based on information from the passed-in form.
|
|
|
|
fn render_error(form: &Form<NewCharacterForm>, error: String) -> Template {
|
|
|
|
let mut context = NewCharacterContext::from_form(form);
|
|
|
|
context.error_message = error;
|
|
|
|
Template::render("characters/new_character", context)
|
|
|
|
}
|
2020-12-09 08:58:49 +00:00
|
|
|
|
2020-12-09 21:25:31 +00:00
|
|
|
#[get("/new")]
|
|
|
|
pub(super) fn new_character_page(_logged_in_user: &User) -> Result<Template, Error> {
|
|
|
|
Ok(Template::render(
|
|
|
|
"characters/new_character",
|
|
|
|
NewCharacterContext::default(),
|
|
|
|
))
|
2020-12-09 08:58:49 +00:00
|
|
|
}
|
|
|
|
|
2020-12-08 22:26:47 +00:00
|
|
|
#[post("/new", data = "<form>")]
|
2020-12-13 13:57:50 +00:00
|
|
|
pub(super) async fn new_character_submit(
|
2020-12-09 21:25:31 +00:00
|
|
|
form: Form<NewCharacterForm>,
|
2020-12-08 22:26:47 +00:00
|
|
|
logged_in_user: &User,
|
2020-12-29 23:06:41 +00:00
|
|
|
conn: TenebrousDbConn<'_>,
|
2020-12-08 22:26:47 +00:00
|
|
|
) -> Result<Redirect, Template> {
|
2020-12-09 21:25:31 +00:00
|
|
|
if let Err(e) = &form.system {
|
|
|
|
return Err(render_error(&form, e.to_string().clone()));
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 13:57:50 +00:00
|
|
|
match create_new_character(&form, logged_in_user.id, conn).await {
|
2020-12-08 22:26:47 +00:00
|
|
|
Ok(_) => Ok(crate::routes::common::redirect_to_index()),
|
2020-12-09 21:25:31 +00:00
|
|
|
Err(e) => Err(render_error(&form, e.to_string().clone())),
|
2020-12-08 22:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/new", rank = 2)]
|
|
|
|
pub(super) fn new_character_not_logged_in() -> Redirect {
|
|
|
|
crate::routes::common::redirect_to_login()
|
|
|
|
}
|