From 8638c1d598b4b47affa74b1e4bc15bdd45d7022d Mon Sep 17 00:00:00 2001 From: projectmoon Date: Sat, 5 Dec 2020 20:15:14 +0000 Subject: [PATCH] Clean up 'TemplateContext', handle character visibility. --- src/models/characters.rs | 27 +++++++++++++++++++++++++-- src/routes/characters.rs | 22 +++++++--------------- src/routes/root.rs | 13 ++++++++++--- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/models/characters.rs b/src/models/characters.rs index c531a35..ad7b3cf 100644 --- a/src/models/characters.rs +++ b/src/models/characters.rs @@ -1,17 +1,40 @@ +use crate::models::users::User; use crate::schema::characters; -use rocket::http::RawStr; -use rocket::request::{self, FromParam, FromRequest, Request}; 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>, } +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 { + 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)] #[table_name = "characters"] pub struct NewCharacter<'a> { diff --git a/src/routes/characters.rs b/src/routes/characters.rs index 457cec0..527bdd9 100644 --- a/src/routes/characters.rs +++ b/src/routes/characters.rs @@ -1,12 +1,8 @@ use crate::db::{Dao, TenebrousDbConn}; use crate::errors::Error; -use crate::models::{ - characters::{CharacterEntry, NewCharacter}, - users::User, -}; +use crate::models::users::User; use rocket::response::Redirect; use rocket_contrib::templates::Template; -use serde_derive::Serialize; use std::collections::HashMap; pub(crate) fn routes() -> Vec { @@ -18,23 +14,19 @@ pub(crate) fn routes() -> Vec { ] } -//TODO make private -- currently is referenced in homepage route. -//or move to common place. -#[derive(Serialize)] -pub struct TemplateContext<'a> { - pub characters: Vec, - pub user: &'a User, -} - -//TODO should return result based on whether or not character is publicly viewable. #[get("//")] fn view_character( character_id: i32, username: String, conn: TenebrousDbConn, + logged_in_user: Option<&User>, ) -> Result { 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(); context.insert("name", character.name); diff --git a/src/routes/root.rs b/src/routes/root.rs index 3c6f2b9..2afb8a2 100644 --- a/src/routes/root.rs +++ b/src/routes/root.rs @@ -3,18 +3,25 @@ use crate::errors::Error; use crate::models::{characters::CharacterEntry, users::User}; use rocket::response::Redirect; use rocket_contrib::templates::Template; +use serde_derive::Serialize; pub fn routes() -> Vec { 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("/")] fn user_index(user: &User, conn: TenebrousDbConn) -> Result { - use crate::routes::characters::TemplateContext; let characters = conn.load_character_list(user.id)?; - let context = TemplateContext { - characters: characters, + let context = UserHomeContext { + characters: &characters, user: user, };