Serialize characters as protobufs. Skeletal character creation.
Implements the absolute basics of the character creation flow, AKA most things are missing. Integrates a method of storing character data, support for that in the database, and a working character creation page. The only thing the page does at the moment is create a hardcoded basic CofD character sheet and save it to the database. There is no ability to change game system, fill in extra details, etc. There's also no ability to edit anything. Also added basic links to the registration and create new character pages.
This commit is contained in:
parent
8638c1d598
commit
8b3e8c70ae
|
@ -79,6 +79,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
|
@ -203,6 +209,12 @@ version = "1.3.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
|
@ -350,6 +362,12 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
|
@ -378,6 +396,12 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
|
@ -466,6 +490,15 @@ version = "0.9.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.17"
|
||||
|
@ -585,6 +618,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
|
@ -742,6 +784,12 @@ dependencies = [
|
|||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333"
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.36"
|
||||
|
@ -915,6 +963,16 @@ dependencies = [
|
|||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
|
@ -955,6 +1013,57 @@ dependencies = [
|
|||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck",
|
||||
"itertools",
|
||||
"log 0.4.11",
|
||||
"multimap",
|
||||
"petgraph",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tempfile",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
|
@ -1049,6 +1158,15 @@ version = "0.6.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.4.6"
|
||||
|
@ -1299,12 +1417,28 @@ dependencies = [
|
|||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tenebrous-sheets"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"log 0.4.11",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"rand",
|
||||
"rocket",
|
||||
"rocket_contrib",
|
||||
|
@ -1501,6 +1635,12 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
|
@ -1575,6 +1715,15 @@ version = "0.10.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
|
|
|
@ -3,10 +3,13 @@ name = "tenebrous-sheets"
|
|||
version = "0.1.0"
|
||||
authors = ["jeff <jeff@agnos.is>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[build-dependencies]
|
||||
prost-build = "0.6"
|
||||
|
||||
[dependencies]
|
||||
prost = "0.6"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
prost_build::compile_protos(&["proto/cofd.proto"], &["proto/"]).unwrap();
|
||||
}
|
|
@ -3,5 +3,7 @@ CREATE TABLE characters(
|
|||
user_id INTEGER NOT NULL,
|
||||
viewable BOOLEAN NOT NULL,
|
||||
character_name TEXT NOT NULL,
|
||||
character_data BLOB NUT NULL
|
||||
data_type TEXT NOT NULL,
|
||||
data_version INTEGER NOT NULL,
|
||||
data BLOB NOT NULL
|
||||
);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package models.proto.cofd;
|
||||
|
||||
//Base sheet for Chronicles of Darkness systems.
|
||||
message CofdSheet {
|
||||
message Merit {
|
||||
int32 dots = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message Condition {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
///Entry for a skill
|
||||
message Skill {
|
||||
int32 dots = 1;
|
||||
string name = 2;
|
||||
sint32 untrained_penalty = 3;
|
||||
repeated string specializations = 4;
|
||||
}
|
||||
|
||||
//A generic item with a name, physical description, and rules text.
|
||||
message Item {
|
||||
string name = 1;
|
||||
string description = 2;
|
||||
string rules = 3;
|
||||
}
|
||||
|
||||
//An entry for an attack. Usually a weapon.
|
||||
message Attack {
|
||||
string name = 1;
|
||||
int32 dice_pool = 2;
|
||||
int32 damage = 3;
|
||||
int32 range = 4;
|
||||
sint32 initiative_modifier = 5;
|
||||
int32 size = 6;
|
||||
}
|
||||
|
||||
string name = 1;
|
||||
string player = 2;
|
||||
string campaign = 3;
|
||||
string description = 4;
|
||||
|
||||
int32 strength = 6;
|
||||
int32 dexterity = 7;
|
||||
int32 stamina = 8;
|
||||
|
||||
int32 intelligence = 9;
|
||||
int32 wits = 10;
|
||||
int32 resolve = 11;
|
||||
|
||||
int32 presence = 12;
|
||||
int32 manipulation = 13;
|
||||
int32 composure = 14;
|
||||
|
||||
map<string, Skill> physical_skills = 16;
|
||||
map<string, Skill> mental_skills = 17;
|
||||
map<string, Skill> social_skills = 18;
|
||||
|
||||
repeated Merit merits = 15;
|
||||
repeated Condition conditions = 19;
|
||||
|
||||
int32 size = 20;
|
||||
int32 health = 21;
|
||||
int32 willpower = 22;
|
||||
int32 experience_points = 23;
|
||||
int32 beats = 24;
|
||||
|
||||
repeated Item items = 25;
|
||||
repeated Attack attacks = 26;
|
||||
|
||||
map<string, string> other_data = 27;
|
||||
}
|
||||
|
||||
message ChangelingSheet {
|
||||
CofdSheet base = 1;
|
||||
}
|
42
src/db.rs
42
src/db.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::models::characters::{CharacterEntry, NewCharacter};
|
||||
use crate::models::characters::{Character, NewCharacter, StrippedCharacter};
|
||||
use crate::models::users::{NewUser, User};
|
||||
use crate::schema::characters;
|
||||
use diesel::prelude::*;
|
||||
use diesel::SqliteConnection;
|
||||
|
||||
|
@ -8,21 +9,39 @@ pub(crate) struct TenebrousDbConn(SqliteConnection);
|
|||
|
||||
pub(crate) trait Dao {
|
||||
fn load_user_by_id(&self, id: i32) -> QueryResult<Option<User>>;
|
||||
|
||||
fn load_user(&self, for_username: &str) -> QueryResult<Option<User>>;
|
||||
|
||||
fn insert_user(&self, new_user: &NewUser) -> QueryResult<User>;
|
||||
|
||||
fn load_character_list(&self, for_user_id: i32) -> QueryResult<Vec<CharacterEntry>>;
|
||||
fn load_character_list(&self, for_user_id: i32) -> QueryResult<Vec<StrippedCharacter>>;
|
||||
|
||||
fn load_character(&self, character_id: i32) -> QueryResult<Option<CharacterEntry>>;
|
||||
fn load_character(&self, character_id: i32) -> QueryResult<Option<Character>>;
|
||||
|
||||
fn insert_character(&self, new_character: &NewCharacter) -> QueryResult<()>;
|
||||
fn insert_character(&self, new_character: NewCharacter) -> QueryResult<()>;
|
||||
}
|
||||
|
||||
type StrippedCharacterColumns = (
|
||||
characters::id,
|
||||
characters::user_id,
|
||||
characters::viewable,
|
||||
characters::character_name,
|
||||
characters::data_type,
|
||||
characters::data_version,
|
||||
);
|
||||
|
||||
const STRIPPED_CHARACTER_COLUMNS: StrippedCharacterColumns = (
|
||||
characters::id,
|
||||
characters::user_id,
|
||||
characters::viewable,
|
||||
characters::character_name,
|
||||
characters::data_type,
|
||||
characters::data_version,
|
||||
);
|
||||
|
||||
impl Dao for TenebrousDbConn {
|
||||
fn load_user_by_id(&self, user_id: i32) -> QueryResult<Option<User>> {
|
||||
use crate::schema::users::dsl::*;
|
||||
|
||||
users.filter(id.eq(user_id)).first(&self.0).optional()
|
||||
}
|
||||
|
||||
|
@ -48,12 +67,15 @@ impl Dao for TenebrousDbConn {
|
|||
.first(&self.0)?)
|
||||
}
|
||||
|
||||
fn load_character_list(&self, for_user_id: i32) -> QueryResult<Vec<CharacterEntry>> {
|
||||
fn load_character_list(&self, for_user_id: i32) -> QueryResult<Vec<StrippedCharacter>> {
|
||||
use crate::schema::characters::dsl::*;
|
||||
characters.filter(user_id.eq(for_user_id)).load(&self.0)
|
||||
characters
|
||||
.filter(user_id.eq(for_user_id))
|
||||
.select(STRIPPED_CHARACTER_COLUMNS)
|
||||
.load(&self.0)
|
||||
}
|
||||
|
||||
fn load_character(&self, character_id: i32) -> QueryResult<Option<CharacterEntry>> {
|
||||
fn load_character(&self, character_id: i32) -> QueryResult<Option<Character>> {
|
||||
use crate::schema::characters::dsl::*;
|
||||
|
||||
characters
|
||||
|
@ -62,9 +84,7 @@ impl Dao for TenebrousDbConn {
|
|||
.optional()
|
||||
}
|
||||
|
||||
fn insert_character(&self, new_character: &NewCharacter) -> QueryResult<()> {
|
||||
use crate::schema::characters;
|
||||
|
||||
fn insert_character(&self, new_character: NewCharacter) -> QueryResult<()> {
|
||||
diesel::insert_into(characters::table)
|
||||
.values(new_character)
|
||||
.execute(&self.0)?;
|
||||
|
|
|
@ -19,6 +19,9 @@ pub enum Error {
|
|||
|
||||
#[error("query error: {0}")]
|
||||
QueryError(#[from] diesel::result::Error),
|
||||
|
||||
#[error("serialization error: {0}")]
|
||||
SerializationError(#[from] prost::EncodeError),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod characters;
|
||||
pub mod proto;
|
||||
pub mod users;
|
||||
|
|
|
@ -2,34 +2,73 @@ use crate::models::users::User;
|
|||
use crate::schema::characters;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
/// An entry that appears in a user's character list. Properties are
|
||||
/// in order of table columns.
|
||||
#[derive(Serialize, Debug, Queryable)]
|
||||
pub struct CharacterEntry {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub viewable: bool,
|
||||
pub name: String,
|
||||
//TODO don't need to carry around character data for this.
|
||||
pub data: Option<Vec<u8>>,
|
||||
}
|
||||
/// Control system visibility of a character for a particular user.
|
||||
/// Implemented as a trait because there are multiple character
|
||||
/// structs that need this.
|
||||
pub(crate) trait Visibility {
|
||||
/// User ID that owns this character.
|
||||
fn user_id(&self) -> i32;
|
||||
|
||||
/// If the character is publicly visible.
|
||||
fn viewable(&self) -> bool;
|
||||
|
||||
impl CharacterEntry {
|
||||
/// Transform to an Option that holds the character, if the
|
||||
/// character is viewable to a potentially existing user. A
|
||||
/// character is "visible" if the public viewable property is set
|
||||
/// to true, or the user is the owner of the character. Consumes
|
||||
/// self.
|
||||
pub fn as_visible_for(self, user: Option<&User>) -> Option<CharacterEntry> {
|
||||
let character_is_visible = |c: CharacterEntry| {
|
||||
if c.viewable || user.map(|u| u.id) == Some(c.user_id) {
|
||||
Some(c)
|
||||
fn as_visible_for(self, user: Option<&User>) -> Option<Self>
|
||||
where
|
||||
Self: std::marker::Sized,
|
||||
{
|
||||
if self.viewable() || user.map(|u| u.id) == Some(self.user_id()) {
|
||||
Some(self)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Some(self).and_then(character_is_visible)
|
||||
/// An entry that appears in a user's character list. Properties are
|
||||
/// in order of table columns.
|
||||
#[derive(Serialize, Debug, Queryable)]
|
||||
pub struct Character {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub viewable: bool,
|
||||
pub character_name: String,
|
||||
pub data_type: String,
|
||||
pub data_version: i32,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Visibility for Character {
|
||||
fn user_id(&self) -> i32 {
|
||||
self.user_id
|
||||
}
|
||||
|
||||
fn viewable(&self) -> bool {
|
||||
self.viewable
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Queryable)]
|
||||
pub struct StrippedCharacter {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub viewable: bool,
|
||||
pub character_name: String,
|
||||
pub data_type: String,
|
||||
pub data_version: i32,
|
||||
}
|
||||
|
||||
impl Visibility for StrippedCharacter {
|
||||
fn user_id(&self) -> i32 {
|
||||
self.user_id
|
||||
}
|
||||
|
||||
fn viewable(&self) -> bool {
|
||||
self.viewable
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,5 +80,7 @@ pub struct NewCharacter<'a> {
|
|||
pub user_id: i32,
|
||||
pub viewable: bool,
|
||||
pub character_name: &'a str,
|
||||
pub character_data: &'a [u8],
|
||||
pub data_type: &'a str,
|
||||
pub data_version: i32,
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/// Contains the generated Chronicles of Darkness-related protocol
|
||||
/// buffer types.
|
||||
pub mod cofd {
|
||||
include!(concat!(env!("OUT_DIR"), "/models.proto.cofd.rs"));
|
||||
|
||||
pub(crate) trait DerivedStats {
|
||||
fn speed(&self) -> i32;
|
||||
}
|
||||
|
||||
impl DerivedStats for CofdSheet {
|
||||
fn speed(&self) -> i32 {
|
||||
self.size + self.stamina
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
use crate::db::{Dao, TenebrousDbConn};
|
||||
use crate::errors::Error;
|
||||
use crate::models::characters::Visibility;
|
||||
use crate::models::users::User;
|
||||
use rocket::request::Form;
|
||||
use rocket::response::Redirect;
|
||||
use rocket_contrib::templates::Template;
|
||||
use std::collections::HashMap;
|
||||
|
@ -9,11 +11,17 @@ pub(crate) fn routes() -> Vec<rocket::Route> {
|
|||
routes![
|
||||
view_character,
|
||||
new_character,
|
||||
create_new_character,
|
||||
new_character_not_logged_in,
|
||||
edit_character
|
||||
]
|
||||
}
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct NewCharacterForm {
|
||||
name: String, //TODO add game system
|
||||
}
|
||||
|
||||
#[get("/<username>/<character_id>")]
|
||||
fn view_character(
|
||||
character_id: i32,
|
||||
|
@ -29,7 +37,7 @@ fn view_character(
|
|||
.ok_or(Error::NotFound)?;
|
||||
|
||||
let mut context = HashMap::new();
|
||||
context.insert("name", character.name);
|
||||
context.insert("name", character.character_name);
|
||||
context.insert("username", user.username);
|
||||
Ok(Template::render("view_character", context))
|
||||
}
|
||||
|
@ -40,6 +48,37 @@ fn new_character(logged_in_user: &User, conn: TenebrousDbConn) -> Result<Templat
|
|||
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 new_character = CofdSheet::default();
|
||||
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: std::any::type_name::<CofdSheet>(),
|
||||
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()
|
||||
|
@ -61,7 +100,7 @@ fn edit_character(
|
|||
}
|
||||
|
||||
let mut context = HashMap::new();
|
||||
context.insert("name", character.name);
|
||||
context.insert("name", character.character_name);
|
||||
context.insert("username", owner.username);
|
||||
Ok(Template::render("view_character", context))
|
||||
}
|
||||
|
|
|
@ -4,3 +4,8 @@ use rocket::response::Redirect;
|
|||
pub(super) fn redirect_to_login() -> Redirect {
|
||||
Redirect::to(uri!(super::auth::login_page))
|
||||
}
|
||||
|
||||
/// Common redirect to the index page.
|
||||
pub(super) fn redirect_to_index() -> Redirect {
|
||||
Redirect::to(uri!(super::root::index))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::db::{Dao, TenebrousDbConn};
|
||||
use crate::errors::Error;
|
||||
use crate::models::{characters::CharacterEntry, users::User};
|
||||
use crate::models::characters::Visibility;
|
||||
use crate::models::{characters::StrippedCharacter, users::User};
|
||||
use rocket::response::Redirect;
|
||||
use rocket_contrib::templates::Template;
|
||||
use serde_derive::Serialize;
|
||||
|
@ -12,13 +13,18 @@ pub fn routes() -> Vec<rocket::Route> {
|
|||
/// Information to display to the user on their home page.
|
||||
#[derive(Serialize)]
|
||||
pub struct UserHomeContext<'a> {
|
||||
pub characters: &'a [CharacterEntry],
|
||||
pub characters: &'a [StrippedCharacter],
|
||||
pub user: &'a User,
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn user_index(user: &User, conn: TenebrousDbConn) -> Result<Template, Error> {
|
||||
let characters = conn.load_character_list(user.id)?;
|
||||
let characters: Vec<StrippedCharacter> = conn
|
||||
.load_character_list(user.id)?
|
||||
.into_iter()
|
||||
.map(|c| c.as_visible_for(Some(user)))
|
||||
.filter_map(|c| c)
|
||||
.collect();
|
||||
|
||||
let context = UserHomeContext {
|
||||
characters: &characters,
|
||||
|
|
|
@ -4,7 +4,9 @@ table! {
|
|||
user_id -> Integer,
|
||||
viewable -> Bool,
|
||||
character_name -> Text,
|
||||
character_data -> Nullable<Binary>,
|
||||
data_type -> Text,
|
||||
data_version -> Integer,
|
||||
data -> Binary,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,16 @@
|
|||
{% for char in characters %}
|
||||
<li>
|
||||
<a href="characters/{{ user.username }}/{{char.id}}">
|
||||
{{ char.name }}
|
||||
{{ char.character_name }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<a href="/characters/new">Create New</a>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<form action="/logout" method="post">
|
||||
<input type="submit" value="Logout" />
|
||||
|
|
|
@ -17,5 +17,9 @@
|
|||
<input type="password" name="password" id="password" value="" />
|
||||
<p><input type="submit" value="Login"></p>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<a href="/register">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
{% block content %}
|
||||
<div>
|
||||
New character page.
|
||||
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