diff --git a/visions/server/src/core.rs b/visions/server/src/core.rs index 8cecb45..ad90579 100644 --- a/visions/server/src/core.rs +++ b/visions/server/src/core.rs @@ -126,6 +126,14 @@ impl Core { } } + pub async fn create_user(&self, username: &str) -> ResultExt<(), AppError, FatalError> { + let state = self.0.read().await; + match return_error!(self.user_by_username(username).await) { + Some(_) => error(AppError::UsernameUnavailable), + None => unimplemented!(), + } + } + pub async fn list_games(&self) -> ResultExt, AppError, FatalError> { let games = self.0.write().await.db.games().await; match games { diff --git a/visions/server/src/handlers/mod.rs b/visions/server/src/handlers/mod.rs index 740f5ad..37d35bf 100644 --- a/visions/server/src/handlers/mod.rs +++ b/visions/server/src/handlers/mod.rs @@ -74,16 +74,38 @@ pub async fn check_password( } } -pub async fn authenticated( +pub async fn auth_required( core: Core, headers: HeaderMap, f: F, ) -> (StatusCode, Json>) where - F: FnOnce(User) -> (StatusCode, Json>), + F: FnOnce(User) -> Fut, + Fut: Future>)>, { match check_session(&core, headers).await { - ResultExt::Ok(Some(user)) => f(user), + ResultExt::Ok(Some(user)) => f(user).await, + ResultExt::Ok(None) => (StatusCode::UNAUTHORIZED, Json(None)), + ResultExt::Err(_err) => (StatusCode::BAD_REQUEST, Json(None)), + ResultExt::Fatal(err) => panic!("{}", err), + } +} + +pub async fn admin_required( + core: Core, + headers: HeaderMap, + f: F, + ) -> (StatusCode, Json>) +where + F: FnOnce(User) -> Fut, + Fut: Future>)>, +{ + match check_session(&core, headers).await { + ResultExt::Ok(Some(user)) => if user.admin { + f(user).await + } else { + (StatusCode::FORBIDDEN, Json(None)) + }, ResultExt::Ok(None) => (StatusCode::UNAUTHORIZED, Json(None)), ResultExt::Err(_err) => (StatusCode::BAD_REQUEST, Json(None)), ResultExt::Fatal(err) => panic!("{}", err), @@ -95,21 +117,39 @@ where pub struct UserProfile { pub userid: UserId, pub username: String, + pub is_admin: bool, } pub async fn get_user(core: Core, headers: HeaderMap) -> (StatusCode, Json>) { - authenticated(core.clone(), headers, |user| { + auth_required(core.clone(), headers, |user| async move { ( StatusCode::OK, Json(Some(UserProfile { userid: UserId::from(user.id), username: user.name, + is_admin: user.admin, })), ) }) .await } +#[derive(Deserialize, Serialize)] +#[typeshare] +pub struct CreateUserRequest { + username: String, +} + +pub async fn create_user(core: Core, headers: HeaderMap, req: CreateUserRequest) -> (StatusCode, Json>) { + auth_required(core.clone(), headers, |_admin| async { + match core.create_user(&req.username).await { + ResultExt::Ok(_) => (StatusCode::OK, Json(None)), + ResultExt::Err(err) => (StatusCode::BAD_REQUEST, Json(None)), + ResultExt::Fatal(fatal) => panic!("{}", fatal), + } + }).await +} + /* pub async fn handle_auth( auth_ctx: &AuthDB, diff --git a/visions/server/src/routes.rs b/visions/server/src/routes.rs index 2337e19..3e71dda 100644 --- a/visions/server/src/routes.rs +++ b/visions/server/src/routes.rs @@ -8,7 +8,9 @@ use axum::{ use crate::{ core::Core, - handlers::{check_password, get_user, healthcheck, AuthRequest}, + handlers::{ + check_password, create_user, get_user, healthcheck, AuthRequest, CreateUserRequest, + }, }; pub fn routes(core: Core) -> Router { @@ -34,6 +36,13 @@ pub fn routes(core: Core) -> Router { let core = core.clone(); move |headers: HeaderMap| get_user(core, headers) }) + .put({ + let core = core.clone(); + move |headers: HeaderMap, req: Json| { + let Json(req) = req; + create_user(core, headers, req) + } + }), ) } @@ -163,4 +172,16 @@ mod test { async fn an_admin_can_create_a_user() { unimplemented!(); } + + #[ignore] + #[tokio::test] + async fn a_user_can_create_a_game() { + unimplemented!(); + } + + #[ignore] + #[tokio::test] + async fn gms_can_invite_others_into_a_game() { + unimplemented!(); + } } diff --git a/visions/server/src/types.rs b/visions/server/src/types.rs index 6e8fc4c..3fbc70e 100644 --- a/visions/server/src/types.rs +++ b/visions/server/src/types.rs @@ -50,6 +50,9 @@ pub enum AppError { #[error("wat {0}")] UnexpectedError(String), + + #[error("this username is not available")] + UsernameUnavailable, } #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]