11use crate :: {
22 config:: Config ,
3- database:: entities:: players:: PlayerRole ,
3+ database:: entities:: {
4+ game_report:: { self , GameReportModel } ,
5+ players:: PlayerRole ,
6+ } ,
47 middleware:: auth:: MaybeAuth ,
58 services:: game:: { snapshot:: GameSnapshot , store:: Games } ,
69 utils:: types:: GameID ,
@@ -11,6 +14,7 @@ use axum::{
1114 response:: { IntoResponse , Response } ,
1215 Extension , Json ,
1316} ;
17+ use sea_orm:: { DatabaseConnection , DbErr , EntityTrait , PaginatorTrait , QueryOrder } ;
1418use serde:: { Deserialize , Serialize } ;
1519use std:: sync:: Arc ;
1620use thiserror:: Error ;
@@ -21,8 +25,14 @@ pub enum GamesError {
2125 /// The requested game could not be found (For specific game lookup)
2226 #[ error( "Game not found" ) ]
2327 NotFound ,
28+
29+ /// Permission not allowed
2430 #[ error( "Missing required access" ) ]
2531 NoPermission ,
32+
33+ /// Database error occurred
34+ #[ error( "Internal server error" ) ]
35+ Database ( #[ from] DbErr ) ,
2636}
2737
2838/// The query structure for a players query
@@ -37,18 +47,30 @@ pub struct GamesRequest {
3747 count : Option < u8 > ,
3848}
3949
40- /// Response from the players endpoint which contains a list of
41- /// players and whether there is more players after
50+ /// Response from the games endpoint which contains a list of
51+ /// games and whether there is more games after
4252#[ derive( Serialize ) ]
4353pub struct GamesResponse {
44- /// The list of players retrieved
54+ /// The list of games retrieved
4555 games : Vec < GameSnapshot > ,
4656 /// Whether there is more players left in the database
4757 more : bool ,
4858 /// Total number of items available
4959 total_items : usize ,
5060}
5161
62+ #[ derive( Serialize ) ]
63+ pub struct GameReportsResponse {
64+ /// The list of game reports retrieved
65+ games : Vec < GameReportModel > ,
66+ /// Whether there is more reports left in the database
67+ more : bool ,
68+ /// Total number of pages available
69+ total_pages : u64 ,
70+ /// Total number of items available
71+ total_items : u64 ,
72+ }
73+
5274/// GET /api/games
5375///
5476/// Handles requests for a paginated list of games that
@@ -115,12 +137,69 @@ pub async fn get_game(
115137 Ok ( Json ( snapshot) )
116138}
117139
140+ /// GET /api/game-reports
141+ ///
142+ /// Handles requests for a paginated list of games reports of games
143+ /// that have already ended. Query provides the start offset
144+ /// and the number of games to respond with.
145+ pub async fn get_game_reports (
146+ MaybeAuth ( auth) : MaybeAuth ,
147+ Query ( GamesRequest { offset, count } ) : Query < GamesRequest > ,
148+ Extension ( db) : Extension < DatabaseConnection > ,
149+ Extension ( config) : Extension < Arc < Config > > ,
150+ ) -> Result < Json < GameReportsResponse > , GamesError > {
151+ if let ( None , false ) = ( & auth, config. api . public_games ) {
152+ return Err ( GamesError :: NoPermission ) ;
153+ }
154+
155+ const DEFAULT_COUNT : u8 = 20 ;
156+
157+ let count = count. unwrap_or ( DEFAULT_COUNT ) ;
158+
159+ let paginator = game_report:: Entity :: find ( )
160+ . order_by_asc ( game_report:: Column :: CreatedAt )
161+ . paginate ( & db, count as u64 ) ;
162+ let page = offset as u64 ;
163+ let totals = paginator. num_items_and_pages ( ) . await ?;
164+ let more = page < totals. number_of_pages ;
165+ let games = paginator. fetch_page ( page) . await ?;
166+
167+ Ok ( Json ( GameReportsResponse {
168+ games,
169+ more,
170+ total_pages : totals. number_of_pages ,
171+ total_items : totals. number_of_items ,
172+ } ) )
173+ }
174+
175+ /// GET /api/game-reports/{id}
176+ ///
177+ /// Get a specific game report
178+ pub async fn get_game_report (
179+ MaybeAuth ( auth) : MaybeAuth ,
180+ Path ( game_id) : Path < GameID > ,
181+ Extension ( db) : Extension < DatabaseConnection > ,
182+ Extension ( config) : Extension < Arc < Config > > ,
183+ ) -> Result < Json < GameReportModel > , GamesError > {
184+ if let ( None , false ) = ( & auth, config. api . public_games ) {
185+ return Err ( GamesError :: NoPermission ) ;
186+ }
187+
188+ let game = game_report:: Entity :: find_by_id ( game_id)
189+ . one ( & db)
190+ . await ?
191+ . ok_or ( GamesError :: NotFound ) ?;
192+
193+ Ok ( Json ( game) )
194+ }
195+
118196/// Response implementation for games errors
119197impl IntoResponse for GamesError {
120198 fn into_response ( self ) -> Response {
121199 let status_code = match & self {
122200 Self :: NotFound => StatusCode :: NOT_FOUND ,
123201 Self :: NoPermission => StatusCode :: FORBIDDEN ,
202+ Self :: Database ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
124203 } ;
125204
126205 ( status_code, self . to_string ( ) ) . into_response ( )
0 commit comments