Clean up 'TemplateContext', handle character visibility.

This commit is contained in:
jeff 2020-12-05 20:15:14 +00:00
parent 0530011138
commit ec5be56858
3 changed files with 42 additions and 20 deletions

View File

@ -1,17 +1,40 @@
use crate::models::users::User;
use crate::schema::characters; use crate::schema::characters;
use rocket::http::RawStr;
use rocket::request::{self, FromParam, FromRequest, Request};
use serde_derive::Serialize; 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)] #[derive(Serialize, Debug, Queryable)]
pub struct CharacterEntry { pub struct CharacterEntry {
pub id: i32, pub id: i32,
pub user_id: i32, pub user_id: i32,
pub viewable: bool, pub viewable: bool,
pub name: String, pub name: String,
//TODO don't need to carry around character data for this.
pub data: Option<Vec<u8>>, pub data: Option<Vec<u8>>,
} }
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)
} else {
None
}
};
Some(self).and_then(character_is_visible)
}
}
/// Represents insert of a new character into the database. Property
/// names correspond to columns.
#[derive(Insertable)] #[derive(Insertable)]
#[table_name = "characters"] #[table_name = "characters"]
pub struct NewCharacter<'a> { pub struct NewCharacter<'a> {

View File

@ -1,12 +1,8 @@
use crate::db::{Dao, TenebrousDbConn}; use crate::db::{Dao, TenebrousDbConn};
use crate::errors::Error; use crate::errors::Error;
use crate::models::{ use crate::models::users::User;
characters::{CharacterEntry, NewCharacter},
users::User,
};
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use serde_derive::Serialize;
use std::collections::HashMap; use std::collections::HashMap;
pub(crate) fn routes() -> Vec<rocket::Route> { pub(crate) fn routes() -> Vec<rocket::Route> {
@ -18,23 +14,19 @@ pub(crate) fn routes() -> Vec<rocket::Route> {
] ]
} }
//TODO make private -- currently is referenced in homepage route.
//or move to common place.
#[derive(Serialize)]
pub struct TemplateContext<'a> {
pub characters: Vec<CharacterEntry>,
pub user: &'a User,
}
//TODO should return result based on whether or not character is publicly viewable.
#[get("/<username>/<character_id>")] #[get("/<username>/<character_id>")]
fn view_character( fn view_character(
character_id: i32, character_id: i32,
username: String, username: String,
conn: TenebrousDbConn, conn: TenebrousDbConn,
logged_in_user: Option<&User>,
) -> Result<Template, Error> { ) -> 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)?.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 mut context = HashMap::new(); let mut context = HashMap::new();
context.insert("name", character.name); context.insert("name", character.name);

View File

@ -3,18 +3,25 @@ use crate::errors::Error;
use crate::models::{characters::CharacterEntry, users::User}; use crate::models::{characters::CharacterEntry, users::User};
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use serde_derive::Serialize;
pub fn routes() -> Vec<rocket::Route> { pub fn routes() -> Vec<rocket::Route> {
routes![index, user_index] routes![index, user_index]
} }
/// Information to display to the user on their home page.
#[derive(Serialize)]
pub struct UserHomeContext<'a> {
pub characters: &'a [CharacterEntry],
pub user: &'a User,
}
#[get("/")] #[get("/")]
fn user_index(user: &User, conn: TenebrousDbConn) -> Result<Template, Error> { fn user_index(user: &User, conn: TenebrousDbConn) -> Result<Template, Error> {
use crate::routes::characters::TemplateContext;
let characters = conn.load_character_list(user.id)?; let characters = conn.load_character_list(user.id)?;
let context = TemplateContext { let context = UserHomeContext {
characters: characters, characters: &characters,
user: user, user: user,
}; };