From 5074fe277eb50f14b20a7c7fc0e32c68e665bd19 Mon Sep 17 00:00:00 2001 From: Martin Indra Date: Tue, 13 Dec 2022 19:59:14 +0100 Subject: [PATCH] de_server: Add join game endpoint Relates to #255. --- crates/server/src/db.rs | 1 + crates/server/src/games/db.rs | 13 ++++++++++++- crates/server/src/games/endpoints.rs | 26 ++++++++++++++++++++++++++ docs/content/lobby/openapi.yaml | 22 ++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/crates/server/src/db.rs b/crates/server/src/db.rs index dd33fa1bc..630d36a23 100644 --- a/crates/server/src/db.rs +++ b/crates/server/src/db.rs @@ -1,5 +1,6 @@ pub const SQLITE_CONSTRAINT_PRIMARYKEY: &str = "1555"; pub const SQLITE_CONSTRAINT_UNIQUE: &str = "2067"; +pub const SQLITE_CONSTRAINT_FOREIGNKEY: &str = "787"; #[macro_export] macro_rules! db_error { diff --git a/crates/server/src/games/db.rs b/crates/server/src/games/db.rs index dd5761023..cd4e2b8ae 100644 --- a/crates/server/src/games/db.rs +++ b/crates/server/src/games/db.rs @@ -7,7 +7,7 @@ use thiserror::Error; use super::model::{Game, GameConfig}; use crate::{ auth::model::MAX_USERNAME_LEN, - db::{SQLITE_CONSTRAINT_PRIMARYKEY, SQLITE_CONSTRAINT_UNIQUE}, + db::{SQLITE_CONSTRAINT_FOREIGNKEY, SQLITE_CONSTRAINT_PRIMARYKEY, SQLITE_CONSTRAINT_UNIQUE}, db_error, games::model::{MAX_GAME_NAME_LEN, MAX_MAP_NAME_LEN}, }; @@ -88,6 +88,10 @@ impl Games { Ok(()) } + pub(super) async fn add_player(&self, username: &str, game: &str) -> Result<(), AdditionError> { + Self::add_player_inner(self.pool, false, username, game).await + } + async fn add_player_inner<'c, E>( executor: E, author: bool, @@ -104,6 +108,11 @@ impl Games { .execute(executor) .await; + db_error!( + result, + AdditionError::UserOrGameDoesNotExist, + SQLITE_CONSTRAINT_FOREIGNKEY + ); db_error!( result, AdditionError::AlreadyInAGame, @@ -206,6 +215,8 @@ pub(super) enum CreationError { pub(super) enum AdditionError { #[error("User is already in another game")] AlreadyInAGame, + #[error("The user or the game does not exist")] + UserOrGameDoesNotExist, #[error("A database error encountered")] Database(#[source] sqlx::Error), #[error(transparent)] diff --git a/crates/server/src/games/endpoints.rs b/crates/server/src/games/endpoints.rs index 89f6278b7..7eb5a82b2 100644 --- a/crates/server/src/games/endpoints.rs +++ b/crates/server/src/games/endpoints.rs @@ -13,6 +13,7 @@ pub(super) fn configure(cfg: &mut web::ServiceConfig) { web::scope("/games") .service(create) .service(list) + .service(join) .service(leave), ); } @@ -58,6 +59,31 @@ async fn list(games: web::Data) -> impl Responder { } } +#[put("/{name}/join")] +async fn join( + claims: web::ReqData, + games: web::Data, + path: web::Path, +) -> impl Responder { + let name = path.into_inner(); + + match games.add_player(claims.username(), name.as_str()).await { + Ok(_) => HttpResponse::Ok().finish(), + Err(AdditionError::AlreadyInAGame) => { + warn!("Game joining error: a user is already in a different game."); + HttpResponse::Forbidden().json("User is already in a different game.") + } + Err(AdditionError::UserOrGameDoesNotExist) => { + warn!("Game joining error: the game or the user does not exist"); + HttpResponse::NotFound().json("Game not found.") + } + Err(error) => { + error!("Error while adding a player to a game: {:?}", error); + HttpResponse::InternalServerError().finish() + } + } +} + #[put("/{name}/leave")] async fn leave( claims: web::ReqData, diff --git a/docs/content/lobby/openapi.yaml b/docs/content/lobby/openapi.yaml index 84b9aa48e..e63943385 100644 --- a/docs/content/lobby/openapi.yaml +++ b/docs/content/lobby/openapi.yaml @@ -100,6 +100,28 @@ paths: "409": description: A different game with the same name already exists. + /a/games/{name}/join: + put: + summary: Join the game. + description: >- + Join the game. The client must not be part of another game (including + this one). + security: + - bearerAuth: [] + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + "200": + description: The user successfully joined the game. + "403": + description: The user is already part of a game. + "404": + description: The game does not exist. + /a/games/{name}/leave: put: summary: Leave or abandon a game.