WIP - at a crossroads where we need some kind of auth mechanism
This commit is contained in:
parent
81c1ace175
commit
a867fdd831
|
@ -4,6 +4,7 @@ use rocket::response::status;
|
||||||
use rocket::response::{self, Responder};
|
use rocket::response::{self, Responder};
|
||||||
use rocket_contrib::templates::Template;
|
use rocket_contrib::templates::Template;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::Into;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -48,6 +49,28 @@ impl Error {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn message(&self) -> String {
|
||||||
|
if self.is_sensitive() {
|
||||||
|
"internal error".to_string()
|
||||||
|
} else {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for tonic::Status {
|
||||||
|
fn from(err: Error) -> tonic::Status {
|
||||||
|
use tonic::{Code, Status};
|
||||||
|
use Error::*;
|
||||||
|
match err {
|
||||||
|
NotFound => Status::new(Code::NotFound, err.message()),
|
||||||
|
NotLoggedIn => Status::new(Code::Unauthenticated, err.message()),
|
||||||
|
NoPermission => Status::new(Code::PermissionDenied, err.message()),
|
||||||
|
InvalidInput => Status::new(Code::InvalidArgument, err.message()),
|
||||||
|
_ => Status::new(Code::Internal, err.message()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
|
|
89
src/grpc.rs
89
src/grpc.rs
|
@ -1,7 +1,66 @@
|
||||||
use crate::models::proto::cofd::api::cofd_api_server::{CofdApi, CofdApiServer};
|
use crate::db::Dao;
|
||||||
|
use crate::errors::Error;
|
||||||
|
use crate::models::characters::Character;
|
||||||
|
use crate::models::proto::cofd::api::cofd_api_server::CofdApi;
|
||||||
use crate::models::proto::cofd::api::UpdateSkillValueRequest;
|
use crate::models::proto::cofd::api::UpdateSkillValueRequest;
|
||||||
use crate::models::proto::cofd::cofd_sheet::Skill;
|
use crate::models::proto::cofd::cofd_sheet::Skill;
|
||||||
use tonic::{transport::Server, Request, Response, Status};
|
use crate::models::proto::cofd::*;
|
||||||
|
use crate::models::users::User;
|
||||||
|
use std::collections::btree_map::{Entry, OccupiedEntry};
|
||||||
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
|
/// 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: &sqlx::SqlitePool,
|
||||||
|
logged_in_user: Option<&User>,
|
||||||
|
owner: &str,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_skill_entry<'a>(
|
||||||
|
sheet: &'a mut CofdSheet,
|
||||||
|
skill_name: &'a str,
|
||||||
|
) -> Option<OccupiedEntry<'a, String, Skill>> {
|
||||||
|
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<OccupiedEntry<_, _>> = '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())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CofdApiService {
|
pub struct CofdApiService {
|
||||||
|
@ -14,8 +73,30 @@ impl CofdApi for CofdApiService {
|
||||||
&self,
|
&self,
|
||||||
request: Request<UpdateSkillValueRequest>, // Accept request of type HelloRequest
|
request: Request<UpdateSkillValueRequest>, // Accept request of type HelloRequest
|
||||||
) -> Result<Response<Skill>, Status> {
|
) -> Result<Response<Skill>, Status> {
|
||||||
// Return an instance of type HelloReply
|
//Can use metadata map to add user id inside interceptor for auth.
|
||||||
println!("Got a request: {:?}", request);
|
let request = request.into_inner();
|
||||||
|
let mut character = load_character(
|
||||||
|
&self.db,
|
||||||
|
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)?;
|
||||||
|
self.db
|
||||||
|
.update_character_sheet(&character)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.into())?; //TODO maybe use crate Error for db
|
||||||
|
|
||||||
let reply = Skill::default();
|
let reply = Skill::default();
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use crate::db::{Dao, TenebrousDbConn};
|
use crate::db::{Dao, TenebrousDbConn};
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
use crate::models::characters::{Character, CharacterDataType, DynCharacterData, Visibility};
|
use crate::models::characters::Character;
|
||||||
use crate::models::proto::cofd::*;
|
use crate::models::proto::cofd::*;
|
||||||
use crate::models::users::User;
|
use crate::models::users::User;
|
||||||
use rocket_contrib::templates::Template;
|
|
||||||
use serde::Serialize;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::btree_map::{Entry, OccupiedEntry};
|
use std::collections::btree_map::{Entry, OccupiedEntry};
|
||||||
|
|
||||||
pub(crate) fn routes() -> Vec<rocket::Route> {
|
pub(crate) fn routes() -> Vec<rocket::Route> {
|
||||||
|
|
Loading…
Reference in New Issue