use crate::db::{Dao, TenebrousDbConn}; use crate::errors::Error; use crate::models::characters::Character; use crate::models::proto::cofd::*; use crate::models::users::User; use std::collections::btree_map::{Entry, OccupiedEntry}; pub(crate) fn routes() -> Vec { routes![ cofd::update_basic_info, cofd::update_attributes, cofd::update_attribute_value, cofd::update_skills, cofd::update_skill_value, cofd::add_condition, cofd::remove_condition ] } /// Load the character belonging to the given user, as long as they're /// the owner of that character. Returns an error if user is not /// logged in, the owner of the character is not found, or the logged /// in user does not have the permission to access this character. async fn load_character( conn: &TenebrousDbConn<'_>, logged_in_user: Option<&User>, owner: &str, character_id: i32, ) -> Result { let logged_in_user = logged_in_user.ok_or(Error::NotLoggedIn)?; let character: Character = conn .load_character(character_id) .await? .ok_or(Error::NotFound)?; if &logged_in_user.username != owner { return Err(Error::NoPermission); } Ok(character) } /// Protobuf-based REST endpoints for editing a character. mod cofd { use super::*; use crate::models::proto::cofd::cofd_sheet::Skill; use crate::models::proto::{cofd::api::*, cofd::*, Proto}; fn find_skill_entry<'a>( sheet: &'a mut CofdSheet, skill_name: &'a str, ) -> Option> { let all_skills = vec![ &mut sheet.mental_skills, &mut sheet.physical_skills, &mut sheet.social_skills, ]; // Search all skill lists for this value using "workaround" to // break value from for loops. let skill: Option> = 'l: loop { for skill_map in all_skills { if let Entry::Occupied(entry) = skill_map.entry(skill_name.to_owned()) { break 'l Some(entry); } } break None; }; skill } fn find_skill<'a>(sheet: &'a mut CofdSheet, skill_name: &'a str) -> Option<&'a mut Skill> { find_skill_entry(sheet, skill_name).map(|entry| entry.into_mut()) } #[post("/cofd///basic-info", data = "")] pub(super) fn update_basic_info<'a>( owner: String, character_id: i32, info: Proto, ) -> &'a str { "lol" } #[post("/cofd///attributes", data = "")] pub(super) fn update_attributes<'a>( owner: String, character_id: i32, info: Proto, ) -> &'a str { "lol" } #[post("/rpc/cofd/update_attribute_value", data = "")] pub(super) async fn update_attribute_value<'a>( req: Proto, conn: TenebrousDbConn<'_>, logged_in_user: Option<&User>, ) -> Result<&'a str, Error> { let mut character = load_character( &conn, logged_in_user, &req.character_username, req.character_id, ) .await?; let mut sheet: CofdSheet = character.try_deserialize()?; let value = req.attribute_value; match req.attribute_name.to_lowercase().as_ref() { "strength" => Ok(sheet.strength = value), "dexterity" => Ok(sheet.dexterity = value), "stamina" => Ok(sheet.stamina = value), "intelligence" => Ok(sheet.intelligence = value), "wits" => Ok(sheet.wits = value), "resolve" => Ok(sheet.resolve = value), "presence" => Ok(sheet.presence = value), "manipulation" => Ok(sheet.manipulation = value), "composure" => Ok(sheet.composure = value), _ => Err(Error::InvalidInput), }?; character.update_data(sheet)?; conn.update_character_sheet(&character).await?; Ok("lol") } #[patch( "/cofd///skills", data = "", rank = 1 )] pub(super) async fn update_skills<'a>( owner: String, character_id: i32, skill_update: Proto, conn: TenebrousDbConn<'_>, logged_in_user: Option<&User>, ) -> Result<&'a str, Error> { let mut character = load_character(&conn, logged_in_user, &owner, character_id).await?; let mut sheet: CofdSheet = character.try_deserialize()?; let updated_skill: &Skill = skill_update.skill.as_ref().ok_or(Error::InvalidInput)?; let skill_entry = find_skill_entry(&mut sheet, &skill_update.name); skill_entry .map(|mut entry| entry.insert(updated_skill.clone())) .ok_or(Error::InvalidInput)?; println!( "updated skill {} with {:?}", skill_update.name, skill_update.skill ); character.update_data(sheet)?; conn.update_character_sheet(&character).await?; Ok("lol") } #[post("/rpc/cofd/update_skill_value", data = "")] pub(super) async fn update_skill_value<'a>( request: Proto, conn: TenebrousDbConn<'_>, logged_in_user: Option<&User>, ) -> Result<&'a str, Error> { println!("{:#?}", request); let mut character = load_character( &conn, logged_in_user, &request.character_username, request.character_id, ) .await?; let mut sheet: CofdSheet = character.try_deserialize()?; let skill: Option<&mut Skill> = find_skill(&mut sheet, &request.skill_name); skill .map(|s| s.dots = request.skill_value) .ok_or(Error::InvalidInput)?; println!("updated skill value",); character.update_data(sheet)?; conn.update_character_sheet(&character).await?; Ok("lol") } #[put("/cofd///conditions", data = "")] pub(super) fn add_condition<'a>( owner: String, character_id: i32, info: Proto, ) -> &'a str { "lol" } #[delete("/cofd///conditions", data = "")] pub(super) fn remove_condition<'a>( owner: String, character_id: i32, info: Proto, ) -> &'a str { "lol" } }