tenebrous-sheets/src/routes/api.rs

166 lines
5.4 KiB
Rust
Raw Normal View History

use crate::db::{Dao, TenebrousDbConn};
use crate::errors::Error;
use crate::models::characters::{Character, CharacterDataType, DynCharacterData, Visibility};
use crate::models::proto::cofd::*;
use crate::models::users::User;
use rocket_contrib::templates::Template;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::btree_map::{Entry, OccupiedEntry};
pub(crate) fn routes() -> Vec<rocket::Route> {
routes![
cofd::update_basic_info,
cofd::update_attributes,
cofd::update_attribute,
cofd::update_skills,
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: String,
character_id: i32,
) -> Result<Character, Error> {
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};
#[post("/cofd/<owner>/<character_id>/basic-info", data = "<info>")]
pub(super) fn update_basic_info<'a>(
owner: String,
character_id: i32,
info: Proto<BasicInfo>,
) -> &'a str {
"lol"
}
#[post("/cofd/<owner>/<character_id>/attributes", data = "<info>")]
pub(super) fn update_attributes<'a>(
owner: String,
character_id: i32,
info: Proto<Attributes>,
) -> &'a str {
"lol"
}
2020-12-27 21:49:08 +00:00
#[patch("/cofd/<owner>/<character_id>/attributes", data = "<attr_update>")]
pub(super) async fn update_attribute<'a>(
owner: String,
character_id: i32,
2020-12-27 21:49:08 +00:00
attr_update: Proto<Attribute>,
conn: TenebrousDbConn<'_>,
2020-12-27 21:49:08 +00:00
logged_in_user: Option<&User>,
) -> Result<&'a str, Error> {
let mut character = load_character(&conn, logged_in_user, owner, character_id).await?;
2020-12-27 21:49:08 +00:00
let mut sheet: CofdSheet = character.try_deserialize()?;
match attr_update.name.to_lowercase().as_ref() {
"strength" => Ok(sheet.strength = attr_update.value),
"dexterity" => Ok(sheet.dexterity = attr_update.value),
"stamina" => Ok(sheet.stamina = attr_update.value),
"intelligence" => Ok(sheet.intelligence = attr_update.value),
"wits" => Ok(sheet.wits = attr_update.value),
"resolve" => Ok(sheet.resolve = attr_update.value),
"presence" => Ok(sheet.presence = attr_update.value),
"manipulation" => Ok(sheet.manipulation = attr_update.value),
"composure" => Ok(sheet.composure = attr_update.value),
2020-12-27 21:49:08 +00:00
_ => Err(Error::InvalidInput),
}?;
println!(
"updated {} attribute {} to {}",
character.character_name, attr_update.name, attr_update.value
);
character.update_data(sheet)?;
conn.update_character_sheet(&character).await?;
2020-12-27 21:49:08 +00:00
Ok("lol")
}
#[patch("/cofd/<owner>/<character_id>/skills", data = "<skill_update>")]
pub(super) async fn update_skills<'a>(
owner: String,
character_id: i32,
skill_update: Proto<SkillUpdate>,
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 skill: &Skill = skill_update.skill.as_ref().ok_or(Error::InvalidInput)?;
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_entry: Option<OccupiedEntry<_, _>> = 'l: loop {
for skill_map in all_skills {
if let Entry::Occupied(entry) = skill_map.entry(skill_update.name.clone()) {
break 'l Some(entry);
}
}
break None;
};
skill_entry
.map(|mut entry| entry.insert(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")
}
#[put("/cofd/<owner>/<character_id>/conditions", data = "<info>")]
pub(super) fn add_condition<'a>(
owner: String,
character_id: i32,
info: Proto<Condition>,
) -> &'a str {
"lol"
}
#[delete("/cofd/<owner>/<character_id>/conditions", data = "<info>")]
pub(super) fn remove_condition<'a>(
owner: String,
character_id: i32,
info: Proto<Condition>,
) -> &'a str {
"lol"
}
}