Basic albeit mostly broken flow for creating new character.
This commit is contained in:
parent
1f07856e66
commit
7b4ffc3a02
|
@ -92,6 +92,17 @@ impl Character {
|
|||
|
||||
Ok(decoded)
|
||||
}
|
||||
|
||||
/// Upgrade the stored protobuf character data to its newest
|
||||
/// iteration, if new types have been created. Consumes self.
|
||||
pub fn uprade(self) -> Result<Character, Error> {
|
||||
// Currently, this just returns itself because there are no
|
||||
// iterations. But we could for example go from CofdSheet v1
|
||||
// to CofdSheet v2 by deserializing v1, applying a migration
|
||||
// to v2, then reserializing, and copying over all other
|
||||
// fields.
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Queryable)]
|
||||
|
|
|
@ -1,35 +1,49 @@
|
|||
use crate::db::{Dao, TenebrousDbConn};
|
||||
use crate::errors::Error;
|
||||
use crate::models::characters::{CharacterDataType, DynCharacterData, Visibility};
|
||||
use crate::models::characters::{Character, CharacterDataType, DynCharacterData, Visibility};
|
||||
use crate::models::users::User;
|
||||
use rocket::request::Form;
|
||||
use rocket::response::Redirect;
|
||||
use rocket_contrib::templates::Template;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
mod new;
|
||||
|
||||
pub(crate) fn routes() -> Vec<rocket::Route> {
|
||||
routes![
|
||||
view_character,
|
||||
new_character,
|
||||
create_new_character,
|
||||
new_character_not_logged_in,
|
||||
new::new_character,
|
||||
new::create_new_character,
|
||||
new::new_character_not_logged_in,
|
||||
edit_character
|
||||
]
|
||||
}
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct NewCharacterForm {
|
||||
name: String, //TODO add game system
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ViewCharacterTemplate<'a> {
|
||||
pub name: &'a str,
|
||||
pub username: &'a str,
|
||||
pub data_type: &'a CharacterDataType,
|
||||
pub sheet: Box<DynCharacterData>,
|
||||
}
|
||||
|
||||
fn view_character_template(user: &User, character: Character) -> Result<Template, Error> {
|
||||
let character = character.uprade()?;
|
||||
|
||||
let context = ViewCharacterTemplate {
|
||||
name: &character.character_name,
|
||||
username: &user.username,
|
||||
data_type: &character.data_type,
|
||||
sheet: character.dyn_deserialize()?,
|
||||
};
|
||||
|
||||
use CharacterDataType::*;
|
||||
let template = match character.data_type {
|
||||
ChroniclesOfDarknessV1 => Template::render("characters/view_character", context),
|
||||
ChangelingV1 => Template::render("characters/view_character", context),
|
||||
};
|
||||
|
||||
Ok(template)
|
||||
}
|
||||
|
||||
#[get("/<username>/<character_id>")]
|
||||
fn view_character(
|
||||
character_id: i32,
|
||||
|
@ -37,63 +51,15 @@ fn view_character(
|
|||
conn: TenebrousDbConn,
|
||||
logged_in_user: Option<&User>,
|
||||
) -> Result<Template, Error> {
|
||||
let user = conn.load_user(&username)?.ok_or(Error::NotFound)?;
|
||||
let user = &conn.load_user(&username)?.ok_or(Error::NotFound)?;
|
||||
|
||||
let character = conn
|
||||
.load_character(character_id)?
|
||||
.and_then(|c| c.as_visible_for(logged_in_user))
|
||||
.ok_or(Error::NotFound)?;
|
||||
|
||||
let context = ViewCharacterTemplate {
|
||||
name: &character.character_name,
|
||||
username: &user.username,
|
||||
sheet: character.dyn_deserialize()?,
|
||||
};
|
||||
|
||||
Ok(Template::render("view_character", context))
|
||||
}
|
||||
|
||||
#[get("/new")]
|
||||
fn new_character(logged_in_user: &User, conn: TenebrousDbConn) -> Result<Template, Error> {
|
||||
let context = HashMap::<String, String>::new();
|
||||
Ok(Template::render("new_character", context))
|
||||
}
|
||||
|
||||
#[post("/new", data = "<form>")]
|
||||
fn create_new_character(
|
||||
form: Form<NewCharacterForm>,
|
||||
logged_in_user: &User,
|
||||
conn: TenebrousDbConn,
|
||||
) -> Result<Redirect, Error> {
|
||||
//TODO redirect to character edit page
|
||||
//TODO redirect back to new character page with an error and filled-out form if validation errors.
|
||||
//TODO add game system.
|
||||
use crate::models::characters::NewCharacter;
|
||||
use crate::models::proto::cofd::CofdSheet;
|
||||
use prost::bytes::BytesMut;
|
||||
use prost::Message;
|
||||
|
||||
let mut new_character = CofdSheet::default();
|
||||
new_character.strength = 100;
|
||||
let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&new_character));
|
||||
new_character.encode(&mut buf)?;
|
||||
|
||||
let insert = NewCharacter {
|
||||
user_id: logged_in_user.id,
|
||||
viewable: true,
|
||||
character_name: &form.name,
|
||||
data_type: CharacterDataType::ChroniclesOfDarknessV1,
|
||||
data_version: 1,
|
||||
data: &buf,
|
||||
};
|
||||
|
||||
conn.insert_character(insert)?;
|
||||
Ok(super::common::redirect_to_index())
|
||||
}
|
||||
|
||||
#[get("/new", rank = 2)]
|
||||
fn new_character_not_logged_in() -> Redirect {
|
||||
super::common::redirect_to_login()
|
||||
let template = view_character_template(user, character)?;
|
||||
Ok(template)
|
||||
}
|
||||
|
||||
#[get("/<owner>/<character_id>/edit")]
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/new")]
|
||||
pub(super) fn new_character(
|
||||
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))
|
||||
}
|
||||
|
||||
fn new_sheet(system: &CharacterDataType) -> Result<BytesMut, Error> {
|
||||
let sheet = match system {
|
||||
CharacterDataType::ChroniclesOfDarknessV1 => {
|
||||
let mut new_character = CofdSheet::default();
|
||||
new_character.strength = 100;
|
||||
let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&new_character));
|
||||
new_character.encode(&mut buf)?;
|
||||
buf
|
||||
}
|
||||
CharacterDataType::ChangelingV1 => {
|
||||
let mut new_character = ChangelingSheet::default();
|
||||
new_character.base = Some(CofdSheet::default());
|
||||
new_character.base.as_mut().unwrap().strength = 100;
|
||||
let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&new_character));
|
||||
new_character.encode(&mut buf)?;
|
||||
buf
|
||||
}
|
||||
};
|
||||
|
||||
Ok(sheet)
|
||||
}
|
||||
|
||||
fn do_new_character(
|
||||
form: Form<NewCharacterForm>,
|
||||
user_id: i32,
|
||||
conn: TenebrousDbConn,
|
||||
) -> Result<(), Error> {
|
||||
let sheet = 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(())
|
||||
}
|
||||
|
||||
#[post("/new", data = "<form>")]
|
||||
pub(super) fn create_new_character(
|
||||
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 do_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()
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{% extends "base" %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
New character page.
|
||||
|
||||
<form action="/characters/new" method="post">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input id="name" name="name" type="text" value="{{ form.name }}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="system">System:</label>
|
||||
<select id="system" name="system">
|
||||
<option value="cofd">Chronicles of Darkness</option>
|
||||
<option value="changeling">Changeling</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="submit" value="Create Character" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
|
@ -4,6 +4,7 @@
|
|||
<div>
|
||||
<h1>Character {{name}}</h1>
|
||||
<h3>User: {{username}}</h3>
|
||||
<p>System: {{data_type}}</h3>
|
||||
<p>Strength: {{sheet.strength}}</p>
|
||||
</div>
|
||||
{% endblock content %}
|
|
@ -1,18 +0,0 @@
|
|||
{% extends "base" %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
New character page.
|
||||
|
||||
<form action="/characters/new" method="post">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input id="name" name="name" type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="submit" value="Create Character" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
Loading…
Reference in New Issue