Make handlers asynchronous

This commit is contained in:
Savanni D'Gerinel 2024-12-31 16:34:59 -05:00
parent 82e41d711b
commit b2a7577c9d
4 changed files with 77 additions and 5 deletions

View File

@ -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<Vec<Game>, AppError, FatalError> { pub async fn list_games(&self) -> ResultExt<Vec<Game>, AppError, FatalError> {
let games = self.0.write().await.db.games().await; let games = self.0.write().await.db.games().await;
match games { match games {

View File

@ -74,16 +74,38 @@ pub async fn check_password(
} }
} }
pub async fn authenticated<F, A>( pub async fn auth_required<F, A, Fut>(
core: Core, core: Core,
headers: HeaderMap, headers: HeaderMap,
f: F, f: F,
) -> (StatusCode, Json<Option<A>>) ) -> (StatusCode, Json<Option<A>>)
where where
F: FnOnce(User) -> (StatusCode, Json<Option<A>>), F: FnOnce(User) -> Fut,
Fut: Future<Output = (StatusCode, Json<Option<A>>)>,
{ {
match check_session(&core, headers).await { 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<F, A, Fut>(
core: Core,
headers: HeaderMap,
f: F,
) -> (StatusCode, Json<Option<A>>)
where
F: FnOnce(User) -> Fut,
Fut: Future<Output = (StatusCode, Json<Option<A>>)>,
{
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::Ok(None) => (StatusCode::UNAUTHORIZED, Json(None)),
ResultExt::Err(_err) => (StatusCode::BAD_REQUEST, Json(None)), ResultExt::Err(_err) => (StatusCode::BAD_REQUEST, Json(None)),
ResultExt::Fatal(err) => panic!("{}", err), ResultExt::Fatal(err) => panic!("{}", err),
@ -95,21 +117,39 @@ where
pub struct UserProfile { pub struct UserProfile {
pub userid: UserId, pub userid: UserId,
pub username: String, pub username: String,
pub is_admin: bool,
} }
pub async fn get_user(core: Core, headers: HeaderMap) -> (StatusCode, Json<Option<UserProfile>>) { pub async fn get_user(core: Core, headers: HeaderMap) -> (StatusCode, Json<Option<UserProfile>>) {
authenticated(core.clone(), headers, |user| { auth_required(core.clone(), headers, |user| async move {
( (
StatusCode::OK, StatusCode::OK,
Json(Some(UserProfile { Json(Some(UserProfile {
userid: UserId::from(user.id), userid: UserId::from(user.id),
username: user.name, username: user.name,
is_admin: user.admin,
})), })),
) )
}) })
.await .await
} }
#[derive(Deserialize, Serialize)]
#[typeshare]
pub struct CreateUserRequest {
username: String,
}
pub async fn create_user(core: Core, headers: HeaderMap, req: CreateUserRequest) -> (StatusCode, Json<Option<()>>) {
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( pub async fn handle_auth(
auth_ctx: &AuthDB, auth_ctx: &AuthDB,

View File

@ -8,7 +8,9 @@ use axum::{
use crate::{ use crate::{
core::Core, 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 { pub fn routes(core: Core) -> Router {
@ -34,6 +36,13 @@ pub fn routes(core: Core) -> Router {
let core = core.clone(); let core = core.clone();
move |headers: HeaderMap| get_user(core, headers) move |headers: HeaderMap| get_user(core, headers)
}) })
.put({
let core = core.clone();
move |headers: HeaderMap, req: Json<CreateUserRequest>| {
let Json(req) = req;
create_user(core, headers, req)
}
}),
) )
} }
@ -163,4 +172,16 @@ mod test {
async fn an_admin_can_create_a_user() { async fn an_admin_can_create_a_user() {
unimplemented!(); 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!();
}
} }

View File

@ -50,6 +50,9 @@ pub enum AppError {
#[error("wat {0}")] #[error("wat {0}")]
UnexpectedError(String), UnexpectedError(String),
#[error("this username is not available")]
UsernameUnavailable,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]