add end game endpoint
This commit is contained in:
@@ -41,12 +41,17 @@ const turnSchema = Joi.object({
|
||||
end_points: Joi.number().integer().min(0).required()
|
||||
});
|
||||
|
||||
const endGameSchema = Joi.object({
|
||||
winner: Joi.number().integer().positive()
|
||||
});
|
||||
|
||||
const schemasByPath = {
|
||||
"/api/users": userSchema,
|
||||
"/api/games": createGameSchema,
|
||||
"/api/games/:id/players": addPlayerSchema,
|
||||
"/api/games/:id/lock": lockGameSchema,
|
||||
"/api/games/:id/turns": turnSchema
|
||||
"/api/games/:id/turns": turnSchema,
|
||||
"/api/games/:id/end": endGameSchema,
|
||||
};
|
||||
|
||||
export function generateRequestBodies() {
|
||||
@@ -402,6 +407,66 @@ router.patch("/games/:id/lock", asyncHandler(async (req, res) => {
|
||||
}
|
||||
}));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/games/{id}/end:
|
||||
* patch:
|
||||
* summary: End a game
|
||||
* parameters:
|
||||
* - name: id
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Game marked as finished
|
||||
* content:
|
||||
* application/json:
|
||||
* example:
|
||||
* message: "Game finished"
|
||||
* gameId: 1
|
||||
*/
|
||||
router.patch("/games/:id/end", asyncHandler(async (req,res) => {
|
||||
const gameId = parseInt(req.params.id, 10);
|
||||
if (isNaN(gameId)) throw new ApiError(400, "Invalid game ID");
|
||||
|
||||
const { error, value } = endGameSchema.validate(req.body);
|
||||
if (error) throw new ApiError(400, error.details[0].message);
|
||||
|
||||
const { winner } = value;
|
||||
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
await conn.beginTransaction();
|
||||
|
||||
const [gameRows] = await conn.query("SELECT * FROM games WHERE id = ?", [gameId]);
|
||||
if (!gameRows.length) throw new ApiError(404, "Game not found");
|
||||
if (gameRows[0].is_finished) throw new ApiError(400, "Game is already finished");
|
||||
|
||||
if (winner) {
|
||||
const [playerRows] = await conn.query(
|
||||
"SELECT 1 FROM game_players WHERE game = ? AND user = ?",
|
||||
[gameId, winner]
|
||||
);
|
||||
if (!playerRows.length) throw new ApiError(400, "Winner must be a player in the game");
|
||||
}
|
||||
|
||||
await conn.query(
|
||||
"UPDATE games SET is_finished = TRUE, winner = ? WHERE id = ?",
|
||||
[winner || null, gameId]
|
||||
);
|
||||
|
||||
await conn.commit();
|
||||
res.json({ message: "Game finished", gameId });
|
||||
} catch (err) {
|
||||
await conn.rollback();
|
||||
throw new ApiError(500, "Failed to finish game", err);
|
||||
} finally {
|
||||
conn.release();
|
||||
}
|
||||
}));
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/games/{id}/players:
|
||||
|
||||
@@ -94,6 +94,40 @@ const migrations = [
|
||||
ADD CONSTRAINT uniq_game_user UNIQUE (game, user);
|
||||
`);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "merge_current_games_into_games",
|
||||
up: async (conn) => {
|
||||
await conn.query(`
|
||||
ALTER TABLE game_players
|
||||
DROP FOREIGN KEY game_players_ibfk_1;
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
ALTER TABLE turns
|
||||
DROP FOREIGN KEY turns_ibfk_1;
|
||||
`);
|
||||
|
||||
await conn.query(`DROP TABLE IF EXISTS games;`);
|
||||
await conn.query(`ALTER TABLE current_games RENAME TO games;`);
|
||||
|
||||
await conn.query(`
|
||||
ALTER TABLE games
|
||||
ADD COLUMN is_finished BOOL DEFAULT FALSE AFTER is_local,
|
||||
ADD COLUMN winner INT DEFAULT NULL AFTER is_finished,
|
||||
ADD CONSTRAINT fk_games_winner FOREIGN KEY (winner) REFERENCES users(id);
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
ALTER TABLE game_players
|
||||
ADD CONSTRAINT fk_game_players_game FOREIGN KEY (game) REFERENCES games(id);
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
ALTER TABLE turns
|
||||
ADD CONSTRAINT fk_turns_game FOREIGN KEY (game) REFERENCES games(id);
|
||||
`);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user