diff options
| author | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-08-20 12:51:26 +0300 |
|---|---|---|
| committer | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-08-20 12:51:26 +0300 |
| commit | ca7acc2fdc6e6c8371ca5bbeeaabb02d11bb1bee (patch) | |
| tree | 1196cbb2b253ecaddd80934cc849cfd52f68b3e4 /backend | |
| parent | fix: change map history from timestamp to date (diff) | |
| download | lphub-ca7acc2fdc6e6c8371ca5bbeeaabb02d11bb1bee.tar.gz lphub-ca7acc2fdc6e6c8371ca5bbeeaabb02d11bb1bee.tar.bz2 lphub-ca7acc2fdc6e6c8371ca5bbeeaabb02d11bb1bee.zip | |
refactor: move structs around for better understanding
Former-commit-id: 0030a6b0c7b228772d8e27f5722ee6de1718786b
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/controllers/homeController.go | 18 | ||||
| -rw-r--r-- | backend/controllers/loginController.go | 16 | ||||
| -rw-r--r-- | backend/controllers/mapController.go | 27 | ||||
| -rw-r--r-- | backend/controllers/modController.go | 67 | ||||
| -rw-r--r-- | backend/controllers/recordController.go | 20 | ||||
| -rw-r--r-- | backend/controllers/userController.go | 43 | ||||
| -rw-r--r-- | backend/models/models.go | 14 | ||||
| -rw-r--r-- | backend/models/requests.go | 39 | ||||
| -rw-r--r-- | backend/models/responses.go | 64 |
9 files changed, 152 insertions, 156 deletions
diff --git a/backend/controllers/homeController.go b/backend/controllers/homeController.go index c94590a..d1b99cb 100644 --- a/backend/controllers/homeController.go +++ b/backend/controllers/homeController.go | |||
| @@ -10,6 +10,16 @@ import ( | |||
| 10 | "github.com/pektezol/leastportalshub/backend/models" | 10 | "github.com/pektezol/leastportalshub/backend/models" |
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | type SearchResponse struct { | ||
| 14 | Players []models.UserShort `json:"players"` | ||
| 15 | Maps []models.MapShort `json:"maps"` | ||
| 16 | } | ||
| 17 | |||
| 18 | type RankingsResponse struct { | ||
| 19 | RankingsSP []models.UserRanking `json:"rankings_sp"` | ||
| 20 | RankingsMP []models.UserRanking `json:"rankings_mp"` | ||
| 21 | } | ||
| 22 | |||
| 13 | func Home(c *gin.Context) { | 23 | func Home(c *gin.Context) { |
| 14 | user, exists := c.Get("user") | 24 | user, exists := c.Get("user") |
| 15 | if !exists { | 25 | if !exists { |
| @@ -26,7 +36,7 @@ func Home(c *gin.Context) { | |||
| 26 | // @Description Get rankings of every player. | 36 | // @Description Get rankings of every player. |
| 27 | // @Tags rankings | 37 | // @Tags rankings |
| 28 | // @Produce json | 38 | // @Produce json |
| 29 | // @Success 200 {object} models.Response{data=models.RankingsResponse} | 39 | // @Success 200 {object} models.Response{data=RankingsResponse} |
| 30 | // @Failure 400 {object} models.Response | 40 | // @Failure 400 {object} models.Response |
| 31 | // @Router /rankings [get] | 41 | // @Router /rankings [get] |
| 32 | func Rankings(c *gin.Context) { | 42 | func Rankings(c *gin.Context) { |
| @@ -116,7 +126,7 @@ func Rankings(c *gin.Context) { | |||
| 116 | c.JSON(http.StatusOK, models.Response{ | 126 | c.JSON(http.StatusOK, models.Response{ |
| 117 | Success: true, | 127 | Success: true, |
| 118 | Message: "Successfully retrieved rankings.", | 128 | Message: "Successfully retrieved rankings.", |
| 119 | Data: models.RankingsResponse{ | 129 | Data: RankingsResponse{ |
| 120 | RankingsSP: spRankings, | 130 | RankingsSP: spRankings, |
| 121 | RankingsMP: mpRankings, | 131 | RankingsMP: mpRankings, |
| 122 | }, | 132 | }, |
| @@ -129,14 +139,14 @@ func Rankings(c *gin.Context) { | |||
| 129 | // @Tags search | 139 | // @Tags search |
| 130 | // @Produce json | 140 | // @Produce json |
| 131 | // @Param q query string false "Search user or map name." | 141 | // @Param q query string false "Search user or map name." |
| 132 | // @Success 200 {object} models.Response{data=models.SearchResponse} | 142 | // @Success 200 {object} models.Response{data=SearchResponse} |
| 133 | // @Failure 400 {object} models.Response | 143 | // @Failure 400 {object} models.Response |
| 134 | // @Router /search [get] | 144 | // @Router /search [get] |
| 135 | func SearchWithQuery(c *gin.Context) { | 145 | func SearchWithQuery(c *gin.Context) { |
| 136 | query := c.Query("q") | 146 | query := c.Query("q") |
| 137 | query = strings.ToLower(query) | 147 | query = strings.ToLower(query) |
| 138 | log.Println(query) | 148 | log.Println(query) |
| 139 | var response models.SearchResponse | 149 | var response SearchResponse |
| 140 | // Cache all maps for faster response | 150 | // Cache all maps for faster response |
| 141 | var maps = []models.MapShort{ | 151 | var maps = []models.MapShort{ |
| 142 | {ID: 1, Name: "Container Ride"}, | 152 | {ID: 1, Name: "Container Ride"}, |
diff --git a/backend/controllers/loginController.go b/backend/controllers/loginController.go index e907b22..76bf51f 100644 --- a/backend/controllers/loginController.go +++ b/backend/controllers/loginController.go | |||
| @@ -15,13 +15,17 @@ import ( | |||
| 15 | "github.com/solovev/steam_go" | 15 | "github.com/solovev/steam_go" |
| 16 | ) | 16 | ) |
| 17 | 17 | ||
| 18 | type LoginResponse struct { | ||
| 19 | Token string `json:"token"` | ||
| 20 | } | ||
| 21 | |||
| 18 | // Login | 22 | // Login |
| 19 | // | 23 | // |
| 20 | // @Description Get (redirect) login page for Steam auth. | 24 | // @Description Get (redirect) login page for Steam auth. |
| 21 | // @Tags login | 25 | // @Tags login |
| 22 | // @Accept json | 26 | // @Accept json |
| 23 | // @Produce json | 27 | // @Produce json |
| 24 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 28 | // @Success 200 {object} models.Response{data=LoginResponse} |
| 25 | // @Failure 400 {object} models.Response | 29 | // @Failure 400 {object} models.Response |
| 26 | // @Router /login [get] | 30 | // @Router /login [get] |
| 27 | func Login(c *gin.Context) { | 31 | func Login(c *gin.Context) { |
| @@ -85,7 +89,7 @@ func Login(c *gin.Context) { | |||
| 85 | // c.JSON(http.StatusOK, models.Response{ | 89 | // c.JSON(http.StatusOK, models.Response{ |
| 86 | // Success: true, | 90 | // Success: true, |
| 87 | // Message: "Successfully generated token.", | 91 | // Message: "Successfully generated token.", |
| 88 | // Data: models.LoginResponse{ | 92 | // Data: LoginResponse{ |
| 89 | // Token: tokenString, | 93 | // Token: tokenString, |
| 90 | // }, | 94 | // }, |
| 91 | // }) | 95 | // }) |
| @@ -99,7 +103,7 @@ func Login(c *gin.Context) { | |||
| 99 | // @Tags auth | 103 | // @Tags auth |
| 100 | // @Produce json | 104 | // @Produce json |
| 101 | // | 105 | // |
| 102 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 106 | // @Success 200 {object} models.Response{data=LoginResponse} |
| 103 | // @Failure 404 {object} models.Response | 107 | // @Failure 404 {object} models.Response |
| 104 | // @Router /token [get] | 108 | // @Router /token [get] |
| 105 | func GetCookie(c *gin.Context) { | 109 | func GetCookie(c *gin.Context) { |
| @@ -111,7 +115,7 @@ func GetCookie(c *gin.Context) { | |||
| 111 | c.JSON(http.StatusOK, models.Response{ | 115 | c.JSON(http.StatusOK, models.Response{ |
| 112 | Success: true, | 116 | Success: true, |
| 113 | Message: "Token cookie successfully retrieved.", | 117 | Message: "Token cookie successfully retrieved.", |
| 114 | Data: models.LoginResponse{ | 118 | Data: LoginResponse{ |
| 115 | Token: cookie, | 119 | Token: cookie, |
| 116 | }, | 120 | }, |
| 117 | }) | 121 | }) |
| @@ -123,7 +127,7 @@ func GetCookie(c *gin.Context) { | |||
| 123 | // @Tags auth | 127 | // @Tags auth |
| 124 | // @Produce json | 128 | // @Produce json |
| 125 | // | 129 | // |
| 126 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 130 | // @Success 200 {object} models.Response{data=LoginResponse} |
| 127 | // @Failure 404 {object} models.Response | 131 | // @Failure 404 {object} models.Response |
| 128 | // @Router /token [delete] | 132 | // @Router /token [delete] |
| 129 | func DeleteCookie(c *gin.Context) { | 133 | func DeleteCookie(c *gin.Context) { |
| @@ -136,7 +140,7 @@ func DeleteCookie(c *gin.Context) { | |||
| 136 | c.JSON(http.StatusOK, models.Response{ | 140 | c.JSON(http.StatusOK, models.Response{ |
| 137 | Success: true, | 141 | Success: true, |
| 138 | Message: "Token cookie successfully deleted.", | 142 | Message: "Token cookie successfully deleted.", |
| 139 | Data: models.LoginResponse{ | 143 | Data: LoginResponse{ |
| 140 | Token: cookie, | 144 | Token: cookie, |
| 141 | }, | 145 | }, |
| 142 | }) | 146 | }) |
diff --git a/backend/controllers/mapController.go b/backend/controllers/mapController.go index ebd65dd..0a324d6 100644 --- a/backend/controllers/mapController.go +++ b/backend/controllers/mapController.go | |||
| @@ -9,18 +9,33 @@ import ( | |||
| 9 | "github.com/pektezol/leastportalshub/backend/models" | 9 | "github.com/pektezol/leastportalshub/backend/models" |
| 10 | ) | 10 | ) |
| 11 | 11 | ||
| 12 | type MapSummaryResponse struct { | ||
| 13 | Map models.Map `json:"map"` | ||
| 14 | Summary models.MapSummary `json:"summary"` | ||
| 15 | } | ||
| 16 | |||
| 17 | type ChaptersResponse struct { | ||
| 18 | Game models.Game `json:"game"` | ||
| 19 | Chapters []models.Chapter `json:"chapters"` | ||
| 20 | } | ||
| 21 | |||
| 22 | type ChapterMapsResponse struct { | ||
| 23 | Chapter models.Chapter `json:"chapter"` | ||
| 24 | Maps []models.MapShort `json:"maps"` | ||
| 25 | } | ||
| 26 | |||
| 12 | // GET Map Summary | 27 | // GET Map Summary |
| 13 | // | 28 | // |
| 14 | // @Description Get map summary with specified id. | 29 | // @Description Get map summary with specified id. |
| 15 | // @Tags maps | 30 | // @Tags maps |
| 16 | // @Produce json | 31 | // @Produce json |
| 17 | // @Param id path int true "Map ID" | 32 | // @Param id path int true "Map ID" |
| 18 | // @Success 200 {object} models.Response{data=models.MapSummaryResponse} | 33 | // @Success 200 {object} models.Response{data=MapSummaryResponse} |
| 19 | // @Failure 400 {object} models.Response | 34 | // @Failure 400 {object} models.Response |
| 20 | // @Router /maps/{id}/summary [get] | 35 | // @Router /maps/{id}/summary [get] |
| 21 | func FetchMapSummary(c *gin.Context) { | 36 | func FetchMapSummary(c *gin.Context) { |
| 22 | id := c.Param("id") | 37 | id := c.Param("id") |
| 23 | response := models.MapSummaryResponse{Map: models.Map{}, Summary: models.MapSummary{Routes: []models.MapRoute{}}} | 38 | response := MapSummaryResponse{Map: models.Map{}, Summary: models.MapSummary{Routes: []models.MapRoute{}}} |
| 24 | intID, err := strconv.Atoi(id) | 39 | intID, err := strconv.Atoi(id) |
| 25 | if err != nil { | 40 | if err != nil { |
| 26 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 41 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| @@ -220,7 +235,7 @@ func FetchGames(c *gin.Context) { | |||
| 220 | // @Tags games & chapters | 235 | // @Tags games & chapters |
| 221 | // @Produce json | 236 | // @Produce json |
| 222 | // @Param id path int true "Game ID" | 237 | // @Param id path int true "Game ID" |
| 223 | // @Success 200 {object} models.Response{data=models.ChaptersResponse} | 238 | // @Success 200 {object} models.Response{data=ChaptersResponse} |
| 224 | // @Failure 400 {object} models.Response | 239 | // @Failure 400 {object} models.Response |
| 225 | // @Router /games/{id} [get] | 240 | // @Router /games/{id} [get] |
| 226 | func FetchChapters(c *gin.Context) { | 241 | func FetchChapters(c *gin.Context) { |
| @@ -230,7 +245,7 @@ func FetchChapters(c *gin.Context) { | |||
| 230 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 245 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 231 | return | 246 | return |
| 232 | } | 247 | } |
| 233 | var response models.ChaptersResponse | 248 | var response ChaptersResponse |
| 234 | rows, err := database.DB.Query(`SELECT c.id, c.name, g.name FROM chapters c INNER JOIN games g ON c.game_id = g.id WHERE game_id = $1`, gameID) | 249 | rows, err := database.DB.Query(`SELECT c.id, c.name, g.name FROM chapters c INNER JOIN games g ON c.game_id = g.id WHERE game_id = $1`, gameID) |
| 235 | if err != nil { | 250 | if err != nil { |
| 236 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 251 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| @@ -262,7 +277,7 @@ func FetchChapters(c *gin.Context) { | |||
| 262 | // @Tags games & chapters | 277 | // @Tags games & chapters |
| 263 | // @Produce json | 278 | // @Produce json |
| 264 | // @Param id path int true "Chapter ID" | 279 | // @Param id path int true "Chapter ID" |
| 265 | // @Success 200 {object} models.Response{data=models.ChapterMapsResponse} | 280 | // @Success 200 {object} models.Response{data=ChapterMapsResponse} |
| 266 | // @Failure 400 {object} models.Response | 281 | // @Failure 400 {object} models.Response |
| 267 | // @Router /chapters/{id} [get] | 282 | // @Router /chapters/{id} [get] |
| 268 | func FetchChapterMaps(c *gin.Context) { | 283 | func FetchChapterMaps(c *gin.Context) { |
| @@ -272,7 +287,7 @@ func FetchChapterMaps(c *gin.Context) { | |||
| 272 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 287 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 273 | return | 288 | return |
| 274 | } | 289 | } |
| 275 | var response models.ChapterMapsResponse | 290 | var response ChapterMapsResponse |
| 276 | rows, err := database.DB.Query(`SELECT m.id, m.name, c.name FROM maps m INNER JOIN chapters c ON m.chapter_id = c.id WHERE chapter_id = $1`, chapterID) | 291 | rows, err := database.DB.Query(`SELECT m.id, m.name, c.name FROM maps m INNER JOIN chapters c ON m.chapter_id = c.id WHERE chapter_id = $1`, chapterID) |
| 277 | if err != nil { | 292 | if err != nil { |
| 278 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 293 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
diff --git a/backend/controllers/modController.go b/backend/controllers/modController.go index e2add1f..7ce5cb4 100644 --- a/backend/controllers/modController.go +++ b/backend/controllers/modController.go | |||
| @@ -3,21 +3,48 @@ package controllers | |||
| 3 | import ( | 3 | import ( |
| 4 | "net/http" | 4 | "net/http" |
| 5 | "strconv" | 5 | "strconv" |
| 6 | "time" | ||
| 6 | 7 | ||
| 7 | "github.com/gin-gonic/gin" | 8 | "github.com/gin-gonic/gin" |
| 8 | "github.com/pektezol/leastportalshub/backend/database" | 9 | "github.com/pektezol/leastportalshub/backend/database" |
| 9 | "github.com/pektezol/leastportalshub/backend/models" | 10 | "github.com/pektezol/leastportalshub/backend/models" |
| 10 | ) | 11 | ) |
| 11 | 12 | ||
| 13 | type CreateMapSummaryRequest struct { | ||
| 14 | CategoryID int `json:"category_id" binding:"required"` | ||
| 15 | Description string `json:"description" binding:"required"` | ||
| 16 | Showcase string `json:"showcase"` | ||
| 17 | UserName string `json:"user_name" binding:"required"` | ||
| 18 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 19 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 20 | } | ||
| 21 | |||
| 22 | type EditMapSummaryRequest struct { | ||
| 23 | RouteID int `json:"route_id" binding:"required"` | ||
| 24 | Description string `json:"description" binding:"required"` | ||
| 25 | Showcase string `json:"showcase"` | ||
| 26 | UserName string `json:"user_name" binding:"required"` | ||
| 27 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 28 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 29 | } | ||
| 30 | |||
| 31 | type DeleteMapSummaryRequest struct { | ||
| 32 | RouteID int `json:"route_id" binding:"required"` | ||
| 33 | } | ||
| 34 | |||
| 35 | type EditMapImageRequest struct { | ||
| 36 | Image string `json:"image" binding:"required"` | ||
| 37 | } | ||
| 38 | |||
| 12 | // POST Map Summary | 39 | // POST Map Summary |
| 13 | // | 40 | // |
| 14 | // @Description Create map summary with specified map id. | 41 | // @Description Create map summary with specified map id. |
| 15 | // @Tags maps | 42 | // @Tags maps |
| 16 | // @Produce json | 43 | // @Produce json |
| 17 | // @Param Authorization header string true "JWT Token" | 44 | // @Param Authorization header string true "JWT Token" |
| 18 | // @Param id path int true "Map ID" | 45 | // @Param id path int true "Map ID" |
| 19 | // @Param request body models.CreateMapSummaryRequest true "Body" | 46 | // @Param request body CreateMapSummaryRequest true "Body" |
| 20 | // @Success 200 {object} models.Response{data=models.CreateMapSummaryRequest} | 47 | // @Success 200 {object} models.Response{data=CreateMapSummaryRequest} |
| 21 | // @Failure 400 {object} models.Response | 48 | // @Failure 400 {object} models.Response |
| 22 | // @Router /maps/{id}/summary [post] | 49 | // @Router /maps/{id}/summary [post] |
| 23 | func CreateMapSummary(c *gin.Context) { | 50 | func CreateMapSummary(c *gin.Context) { |
| @@ -44,7 +71,7 @@ func CreateMapSummary(c *gin.Context) { | |||
| 44 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 71 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 45 | return | 72 | return |
| 46 | } | 73 | } |
| 47 | var request models.CreateMapSummaryRequest | 74 | var request CreateMapSummaryRequest |
| 48 | if err := c.BindJSON(&request); err != nil { | 75 | if err := c.BindJSON(&request); err != nil { |
| 49 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 76 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 50 | return | 77 | return |
| @@ -100,10 +127,10 @@ func CreateMapSummary(c *gin.Context) { | |||
| 100 | // @Description Edit map summary with specified map id. | 127 | // @Description Edit map summary with specified map id. |
| 101 | // @Tags maps | 128 | // @Tags maps |
| 102 | // @Produce json | 129 | // @Produce json |
| 103 | // @Param Authorization header string true "JWT Token" | 130 | // @Param Authorization header string true "JWT Token" |
| 104 | // @Param id path int true "Map ID" | 131 | // @Param id path int true "Map ID" |
| 105 | // @Param request body models.EditMapSummaryRequest true "Body" | 132 | // @Param request body EditMapSummaryRequest true "Body" |
| 106 | // @Success 200 {object} models.Response{data=models.EditMapSummaryRequest} | 133 | // @Success 200 {object} models.Response{data=EditMapSummaryRequest} |
| 107 | // @Failure 400 {object} models.Response | 134 | // @Failure 400 {object} models.Response |
| 108 | // @Router /maps/{id}/summary [put] | 135 | // @Router /maps/{id}/summary [put] |
| 109 | func EditMapSummary(c *gin.Context) { | 136 | func EditMapSummary(c *gin.Context) { |
| @@ -130,7 +157,7 @@ func EditMapSummary(c *gin.Context) { | |||
| 130 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 157 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 131 | return | 158 | return |
| 132 | } | 159 | } |
| 133 | var request models.EditMapSummaryRequest | 160 | var request EditMapSummaryRequest |
| 134 | if err := c.BindJSON(&request); err != nil { | 161 | if err := c.BindJSON(&request); err != nil { |
| 135 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 162 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 136 | return | 163 | return |
| @@ -186,10 +213,10 @@ func EditMapSummary(c *gin.Context) { | |||
| 186 | // @Description Delete map summary with specified map id. | 213 | // @Description Delete map summary with specified map id. |
| 187 | // @Tags maps | 214 | // @Tags maps |
| 188 | // @Produce json | 215 | // @Produce json |
| 189 | // @Param Authorization header string true "JWT Token" | 216 | // @Param Authorization header string true "JWT Token" |
| 190 | // @Param id path int true "Map ID" | 217 | // @Param id path int true "Map ID" |
| 191 | // @Param request body models.DeleteMapSummaryRequest true "Body" | 218 | // @Param request body DeleteMapSummaryRequest true "Body" |
| 192 | // @Success 200 {object} models.Response{data=models.DeleteMapSummaryRequest} | 219 | // @Success 200 {object} models.Response{data=DeleteMapSummaryRequest} |
| 193 | // @Failure 400 {object} models.Response | 220 | // @Failure 400 {object} models.Response |
| 194 | // @Router /maps/{id}/summary [delete] | 221 | // @Router /maps/{id}/summary [delete] |
| 195 | func DeleteMapSummary(c *gin.Context) { | 222 | func DeleteMapSummary(c *gin.Context) { |
| @@ -216,7 +243,7 @@ func DeleteMapSummary(c *gin.Context) { | |||
| 216 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 243 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 217 | return | 244 | return |
| 218 | } | 245 | } |
| 219 | var request models.DeleteMapSummaryRequest | 246 | var request DeleteMapSummaryRequest |
| 220 | if err := c.BindJSON(&request); err != nil { | 247 | if err := c.BindJSON(&request); err != nil { |
| 221 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 248 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 222 | return | 249 | return |
| @@ -276,10 +303,10 @@ func DeleteMapSummary(c *gin.Context) { | |||
| 276 | // @Description Edit map image with specified map id. | 303 | // @Description Edit map image with specified map id. |
| 277 | // @Tags maps | 304 | // @Tags maps |
| 278 | // @Produce json | 305 | // @Produce json |
| 279 | // @Param Authorization header string true "JWT Token" | 306 | // @Param Authorization header string true "JWT Token" |
| 280 | // @Param id path int true "Map ID" | 307 | // @Param id path int true "Map ID" |
| 281 | // @Param request body models.EditMapImageRequest true "Body" | 308 | // @Param request body EditMapImageRequest true "Body" |
| 282 | // @Success 200 {object} models.Response{data=models.EditMapImageRequest} | 309 | // @Success 200 {object} models.Response{data=EditMapImageRequest} |
| 283 | // @Failure 400 {object} models.Response | 310 | // @Failure 400 {object} models.Response |
| 284 | // @Router /maps/{id}/image [put] | 311 | // @Router /maps/{id}/image [put] |
| 285 | func EditMapImage(c *gin.Context) { | 312 | func EditMapImage(c *gin.Context) { |
| @@ -306,7 +333,7 @@ func EditMapImage(c *gin.Context) { | |||
| 306 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 333 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 307 | return | 334 | return |
| 308 | } | 335 | } |
| 309 | var request models.EditMapImageRequest | 336 | var request EditMapImageRequest |
| 310 | if err := c.BindJSON(&request); err != nil { | 337 | if err := c.BindJSON(&request); err != nil { |
| 311 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 338 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 312 | return | 339 | return |
diff --git a/backend/controllers/recordController.go b/backend/controllers/recordController.go index 951be41..d141fc3 100644 --- a/backend/controllers/recordController.go +++ b/backend/controllers/recordController.go | |||
| @@ -19,6 +19,18 @@ import ( | |||
| 19 | "google.golang.org/api/drive/v3" | 19 | "google.golang.org/api/drive/v3" |
| 20 | ) | 20 | ) |
| 21 | 21 | ||
| 22 | type RecordRequest struct { | ||
| 23 | HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` | ||
| 24 | PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` | ||
| 25 | IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange"` | ||
| 26 | PartnerID string `json:"partner_id" form:"partner_id"` | ||
| 27 | } | ||
| 28 | |||
| 29 | type RecordResponse struct { | ||
| 30 | ScoreCount int `json:"score_count"` | ||
| 31 | ScoreTime int `json:"score_time"` | ||
| 32 | } | ||
| 33 | |||
| 22 | // POST Record | 34 | // POST Record |
| 23 | // | 35 | // |
| 24 | // @Description Post record with demo of a specific map. | 36 | // @Description Post record with demo of a specific map. |
| @@ -31,7 +43,7 @@ import ( | |||
| 31 | // @Param partner_demo formData file false "Partner Demo" | 43 | // @Param partner_demo formData file false "Partner Demo" |
| 32 | // @Param is_partner_orange formData boolean false "Is Partner Orange" | 44 | // @Param is_partner_orange formData boolean false "Is Partner Orange" |
| 33 | // @Param partner_id formData string false "Partner ID" | 45 | // @Param partner_id formData string false "Partner ID" |
| 34 | // @Success 200 {object} models.Response{data=models.RecordResponse} | 46 | // @Success 200 {object} models.Response{data=RecordResponse} |
| 35 | // @Failure 400 {object} models.Response | 47 | // @Failure 400 {object} models.Response |
| 36 | // @Failure 401 {object} models.Response | 48 | // @Failure 401 {object} models.Response |
| 37 | // @Router /maps/{id}/record [post] | 49 | // @Router /maps/{id}/record [post] |
| @@ -61,7 +73,7 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 61 | isCoop = true | 73 | isCoop = true |
| 62 | } | 74 | } |
| 63 | // Get record request | 75 | // Get record request |
| 64 | var record models.RecordRequest | 76 | var record RecordRequest |
| 65 | if err := c.ShouldBind(&record); err != nil { | 77 | if err := c.ShouldBind(&record); err != nil { |
| 66 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 78 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 67 | return | 79 | return |
| @@ -183,7 +195,7 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 183 | c.JSON(http.StatusOK, models.Response{ | 195 | c.JSON(http.StatusOK, models.Response{ |
| 184 | Success: true, | 196 | Success: true, |
| 185 | Message: "Successfully created record.", | 197 | Message: "Successfully created record.", |
| 186 | Data: models.RecordResponse{ScoreCount: hostDemoScoreCount, ScoreTime: hostDemoScoreTime}, | 198 | Data: RecordResponse{ScoreCount: hostDemoScoreCount, ScoreTime: hostDemoScoreTime}, |
| 187 | }) | 199 | }) |
| 188 | } | 200 | } |
| 189 | 201 | ||
| @@ -253,6 +265,7 @@ func serviceAccount() *http.Client { | |||
| 253 | return client | 265 | return client |
| 254 | } | 266 | } |
| 255 | 267 | ||
| 268 | // Create Gdrive file | ||
| 256 | func createFile(service *drive.Service, name string, mimeType string, content io.Reader, parentId string) (*drive.File, error) { | 269 | func createFile(service *drive.Service, name string, mimeType string, content io.Reader, parentId string) (*drive.File, error) { |
| 257 | f := &drive.File{ | 270 | f := &drive.File{ |
| 258 | MimeType: mimeType, | 271 | MimeType: mimeType, |
| @@ -269,6 +282,7 @@ func createFile(service *drive.Service, name string, mimeType string, content io | |||
| 269 | return file, nil | 282 | return file, nil |
| 270 | } | 283 | } |
| 271 | 284 | ||
| 285 | // Delete Gdrive file | ||
| 272 | func deleteFile(service *drive.Service, fileId string) { | 286 | func deleteFile(service *drive.Service, fileId string) { |
| 273 | service.Files.Delete(fileId) | 287 | service.Files.Delete(fileId) |
| 274 | } | 288 | } |
diff --git a/backend/controllers/userController.go b/backend/controllers/userController.go index 6aa77fc..0dae155 100644 --- a/backend/controllers/userController.go +++ b/backend/controllers/userController.go | |||
| @@ -11,6 +11,21 @@ import ( | |||
| 11 | "github.com/pektezol/leastportalshub/backend/models" | 11 | "github.com/pektezol/leastportalshub/backend/models" |
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | type ProfileResponse struct { | ||
| 15 | Profile bool `json:"profile"` | ||
| 16 | SteamID string `json:"steam_id"` | ||
| 17 | UserName string `json:"user_name"` | ||
| 18 | AvatarLink string `json:"avatar_link"` | ||
| 19 | CountryCode string `json:"country_code"` | ||
| 20 | ScoresSP []ScoreResponse `json:"scores_sp"` | ||
| 21 | ScoresMP []ScoreResponse `json:"scores_mp"` | ||
| 22 | } | ||
| 23 | |||
| 24 | type ScoreResponse struct { | ||
| 25 | MapID int `json:"map_id"` | ||
| 26 | Records any `json:"records"` | ||
| 27 | } | ||
| 28 | |||
| 14 | // GET Profile | 29 | // GET Profile |
| 15 | // | 30 | // |
| 16 | // @Description Get profile page of session user. | 31 | // @Description Get profile page of session user. |
| @@ -18,7 +33,7 @@ import ( | |||
| 18 | // @Accept json | 33 | // @Accept json |
| 19 | // @Produce json | 34 | // @Produce json |
| 20 | // @Param Authorization header string true "JWT Token" | 35 | // @Param Authorization header string true "JWT Token" |
| 21 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 36 | // @Success 200 {object} models.Response{data=ProfileResponse} |
| 22 | // @Failure 400 {object} models.Response | 37 | // @Failure 400 {object} models.Response |
| 23 | // @Failure 401 {object} models.Response | 38 | // @Failure 401 {object} models.Response |
| 24 | // @Router /profile [get] | 39 | // @Router /profile [get] |
| @@ -30,7 +45,7 @@ func Profile(c *gin.Context) { | |||
| 30 | return | 45 | return |
| 31 | } | 46 | } |
| 32 | // Retrieve singleplayer records | 47 | // Retrieve singleplayer records |
| 33 | var scoresSP []models.ScoreResponse | 48 | var scoresSP []ScoreResponse |
| 34 | sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` | 49 | sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` |
| 35 | rows, err := database.DB.Query(sql, user.(models.User).SteamID) | 50 | rows, err := database.DB.Query(sql, user.(models.User).SteamID) |
| 36 | if err != nil { | 51 | if err != nil { |
| @@ -50,13 +65,13 @@ func Profile(c *gin.Context) { | |||
| 50 | // New map | 65 | // New map |
| 51 | recordsSP = []models.RecordSP{} | 66 | recordsSP = []models.RecordSP{} |
| 52 | recordsSP = append(recordsSP, record) | 67 | recordsSP = append(recordsSP, record) |
| 53 | scoresSP = append(scoresSP, models.ScoreResponse{ | 68 | scoresSP = append(scoresSP, ScoreResponse{ |
| 54 | MapID: mapID, | 69 | MapID: mapID, |
| 55 | Records: recordsSP, | 70 | Records: recordsSP, |
| 56 | }) | 71 | }) |
| 57 | } | 72 | } |
| 58 | // Retrieve multiplayer records | 73 | // Retrieve multiplayer records |
| 59 | var scoresMP []models.ScoreResponse | 74 | var scoresMP []ScoreResponse |
| 60 | sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp | 75 | sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp |
| 61 | WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` | 76 | WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` |
| 62 | rows, err = database.DB.Query(sql, user.(models.User).SteamID, user.(models.User).SteamID) | 77 | rows, err = database.DB.Query(sql, user.(models.User).SteamID, user.(models.User).SteamID) |
| @@ -77,7 +92,7 @@ func Profile(c *gin.Context) { | |||
| 77 | // New map | 92 | // New map |
| 78 | recordsMP = []models.RecordMP{} | 93 | recordsMP = []models.RecordMP{} |
| 79 | recordsMP = append(recordsMP, record) | 94 | recordsMP = append(recordsMP, record) |
| 80 | scoresMP = append(scoresMP, models.ScoreResponse{ | 95 | scoresMP = append(scoresMP, ScoreResponse{ |
| 81 | MapID: mapID, | 96 | MapID: mapID, |
| 82 | Records: recordsMP, | 97 | Records: recordsMP, |
| 83 | }) | 98 | }) |
| @@ -85,7 +100,7 @@ func Profile(c *gin.Context) { | |||
| 85 | c.JSON(http.StatusOK, models.Response{ | 100 | c.JSON(http.StatusOK, models.Response{ |
| 86 | Success: true, | 101 | Success: true, |
| 87 | Message: "Successfully retrieved user scores.", | 102 | Message: "Successfully retrieved user scores.", |
| 88 | Data: models.ProfileResponse{ | 103 | Data: ProfileResponse{ |
| 89 | Profile: true, | 104 | Profile: true, |
| 90 | SteamID: user.(models.User).SteamID, | 105 | SteamID: user.(models.User).SteamID, |
| 91 | UserName: user.(models.User).UserName, | 106 | UserName: user.(models.User).UserName, |
| @@ -105,7 +120,7 @@ func Profile(c *gin.Context) { | |||
| 105 | // @Accept json | 120 | // @Accept json |
| 106 | // @Produce json | 121 | // @Produce json |
| 107 | // @Param id path int true "User ID" | 122 | // @Param id path int true "User ID" |
| 108 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 123 | // @Success 200 {object} models.Response{data=ProfileResponse} |
| 109 | // @Failure 400 {object} models.Response | 124 | // @Failure 400 {object} models.Response |
| 110 | // @Failure 404 {object} models.Response | 125 | // @Failure 404 {object} models.Response |
| 111 | // @Router /users/{id} [get] | 126 | // @Router /users/{id} [get] |
| @@ -132,7 +147,7 @@ func FetchUser(c *gin.Context) { | |||
| 132 | return | 147 | return |
| 133 | } | 148 | } |
| 134 | // Retrieve singleplayer records | 149 | // Retrieve singleplayer records |
| 135 | var scoresSP []models.ScoreResponse | 150 | var scoresSP []ScoreResponse |
| 136 | sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` | 151 | sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` |
| 137 | rows, err := database.DB.Query(sql, user.SteamID) | 152 | rows, err := database.DB.Query(sql, user.SteamID) |
| 138 | if err != nil { | 153 | if err != nil { |
| @@ -152,13 +167,13 @@ func FetchUser(c *gin.Context) { | |||
| 152 | // New map | 167 | // New map |
| 153 | recordsSP = []models.RecordSP{} | 168 | recordsSP = []models.RecordSP{} |
| 154 | recordsSP = append(recordsSP, record) | 169 | recordsSP = append(recordsSP, record) |
| 155 | scoresSP = append(scoresSP, models.ScoreResponse{ | 170 | scoresSP = append(scoresSP, ScoreResponse{ |
| 156 | MapID: mapID, | 171 | MapID: mapID, |
| 157 | Records: recordsSP, | 172 | Records: recordsSP, |
| 158 | }) | 173 | }) |
| 159 | } | 174 | } |
| 160 | // Retrieve multiplayer records | 175 | // Retrieve multiplayer records |
| 161 | var scoresMP []models.ScoreResponse | 176 | var scoresMP []ScoreResponse |
| 162 | sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp | 177 | sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp |
| 163 | WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` | 178 | WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` |
| 164 | rows, err = database.DB.Query(sql, user.SteamID, user.SteamID) | 179 | rows, err = database.DB.Query(sql, user.SteamID, user.SteamID) |
| @@ -179,7 +194,7 @@ func FetchUser(c *gin.Context) { | |||
| 179 | // New map | 194 | // New map |
| 180 | recordsMP = []models.RecordMP{} | 195 | recordsMP = []models.RecordMP{} |
| 181 | recordsMP = append(recordsMP, record) | 196 | recordsMP = append(recordsMP, record) |
| 182 | scoresMP = append(scoresMP, models.ScoreResponse{ | 197 | scoresMP = append(scoresMP, ScoreResponse{ |
| 183 | MapID: mapID, | 198 | MapID: mapID, |
| 184 | Records: recordsMP, | 199 | Records: recordsMP, |
| 185 | }) | 200 | }) |
| @@ -187,7 +202,7 @@ func FetchUser(c *gin.Context) { | |||
| 187 | c.JSON(http.StatusOK, models.Response{ | 202 | c.JSON(http.StatusOK, models.Response{ |
| 188 | Success: true, | 203 | Success: true, |
| 189 | Message: "Successfully retrieved user scores.", | 204 | Message: "Successfully retrieved user scores.", |
| 190 | Data: models.ProfileResponse{ | 205 | Data: ProfileResponse{ |
| 191 | Profile: true, | 206 | Profile: true, |
| 192 | SteamID: user.SteamID, | 207 | SteamID: user.SteamID, |
| 193 | UserName: user.UserName, | 208 | UserName: user.UserName, |
| @@ -207,7 +222,7 @@ func FetchUser(c *gin.Context) { | |||
| 207 | // @Accept json | 222 | // @Accept json |
| 208 | // @Produce json | 223 | // @Produce json |
| 209 | // @Param Authorization header string true "JWT Token" | 224 | // @Param Authorization header string true "JWT Token" |
| 210 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 225 | // @Success 200 {object} models.Response{data=ProfileResponse} |
| 211 | // @Failure 400 {object} models.Response | 226 | // @Failure 400 {object} models.Response |
| 212 | // @Failure 401 {object} models.Response | 227 | // @Failure 401 {object} models.Response |
| 213 | // @Router /profile [post] | 228 | // @Router /profile [post] |
| @@ -233,7 +248,7 @@ func UpdateUser(c *gin.Context) { | |||
| 233 | c.JSON(http.StatusOK, models.Response{ | 248 | c.JSON(http.StatusOK, models.Response{ |
| 234 | Success: true, | 249 | Success: true, |
| 235 | Message: "Successfully updated user.", | 250 | Message: "Successfully updated user.", |
| 236 | Data: models.ProfileResponse{ | 251 | Data: ProfileResponse{ |
| 237 | Profile: true, | 252 | Profile: true, |
| 238 | SteamID: user.(models.User).SteamID, | 253 | SteamID: user.(models.User).SteamID, |
| 239 | UserName: profile.PersonaName, | 254 | UserName: profile.PersonaName, |
diff --git a/backend/models/models.go b/backend/models/models.go index 1231cb1..e21ba6a 100644 --- a/backend/models/models.go +++ b/backend/models/models.go | |||
| @@ -4,6 +4,20 @@ import ( | |||
| 4 | "time" | 4 | "time" |
| 5 | ) | 5 | ) |
| 6 | 6 | ||
| 7 | type Response struct { | ||
| 8 | Success bool `json:"success"` | ||
| 9 | Message string `json:"message"` | ||
| 10 | Data any `json:"data"` | ||
| 11 | } | ||
| 12 | |||
| 13 | func ErrorResponse(message string) Response { | ||
| 14 | return Response{ | ||
| 15 | Success: false, | ||
| 16 | Message: message, | ||
| 17 | Data: nil, | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 7 | type User struct { | 21 | type User struct { |
| 8 | SteamID string `json:"steam_id"` | 22 | SteamID string `json:"steam_id"` |
| 9 | UserName string `json:"user_name"` | 23 | UserName string `json:"user_name"` |
diff --git a/backend/models/requests.go b/backend/models/requests.go deleted file mode 100644 index 0113597..0000000 --- a/backend/models/requests.go +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | package models | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "mime/multipart" | ||
| 5 | "time" | ||
| 6 | ) | ||
| 7 | |||
| 8 | type CreateMapSummaryRequest struct { | ||
| 9 | CategoryID int `json:"category_id" binding:"required"` | ||
| 10 | Description string `json:"description" binding:"required"` | ||
| 11 | Showcase string `json:"showcase"` | ||
| 12 | UserName string `json:"user_name" binding:"required"` | ||
| 13 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 14 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 15 | } | ||
| 16 | |||
| 17 | type EditMapSummaryRequest struct { | ||
| 18 | RouteID int `json:"route_id" binding:"required"` | ||
| 19 | Description string `json:"description" binding:"required"` | ||
| 20 | Showcase string `json:"showcase"` | ||
| 21 | UserName string `json:"user_name" binding:"required"` | ||
| 22 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 23 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 24 | } | ||
| 25 | |||
| 26 | type DeleteMapSummaryRequest struct { | ||
| 27 | RouteID int `json:"route_id" binding:"required"` | ||
| 28 | } | ||
| 29 | |||
| 30 | type EditMapImageRequest struct { | ||
| 31 | Image string `json:"image" binding:"required"` | ||
| 32 | } | ||
| 33 | |||
| 34 | type RecordRequest struct { | ||
| 35 | HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` | ||
| 36 | PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` | ||
| 37 | IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange"` | ||
| 38 | PartnerID string `json:"partner_id" form:"partner_id"` | ||
| 39 | } | ||
diff --git a/backend/models/responses.go b/backend/models/responses.go deleted file mode 100644 index 459911c..0000000 --- a/backend/models/responses.go +++ /dev/null | |||
| @@ -1,64 +0,0 @@ | |||
| 1 | package models | ||
| 2 | |||
| 3 | type Response struct { | ||
| 4 | Success bool `json:"success"` | ||
| 5 | Message string `json:"message"` | ||
| 6 | Data any `json:"data"` | ||
| 7 | } | ||
| 8 | |||
| 9 | type LoginResponse struct { | ||
| 10 | Token string `json:"token"` | ||
| 11 | } | ||
| 12 | |||
| 13 | type RankingsResponse struct { | ||
| 14 | RankingsSP []UserRanking `json:"rankings_sp"` | ||
| 15 | RankingsMP []UserRanking `json:"rankings_mp"` | ||
| 16 | } | ||
| 17 | |||
| 18 | type ProfileResponse struct { | ||
| 19 | Profile bool `json:"profile"` | ||
| 20 | SteamID string `json:"steam_id"` | ||
| 21 | UserName string `json:"user_name"` | ||
| 22 | AvatarLink string `json:"avatar_link"` | ||
| 23 | CountryCode string `json:"country_code"` | ||
| 24 | ScoresSP []ScoreResponse `json:"scores_sp"` | ||
| 25 | ScoresMP []ScoreResponse `json:"scores_mp"` | ||
| 26 | } | ||
| 27 | |||
| 28 | type ScoreResponse struct { | ||
| 29 | MapID int `json:"map_id"` | ||
| 30 | Records any `json:"records"` | ||
| 31 | } | ||
| 32 | |||
| 33 | type MapSummaryResponse struct { | ||
| 34 | Map Map `json:"map"` | ||
| 35 | Summary MapSummary `json:"summary"` | ||
| 36 | } | ||
| 37 | |||
| 38 | type SearchResponse struct { | ||
| 39 | Players []UserShort `json:"players"` | ||
| 40 | Maps []MapShort `json:"maps"` | ||
| 41 | } | ||
| 42 | |||
| 43 | type ChaptersResponse struct { | ||
| 44 | Game Game `json:"game"` | ||
| 45 | Chapters []Chapter `json:"chapters"` | ||
| 46 | } | ||
| 47 | |||
| 48 | type ChapterMapsResponse struct { | ||
| 49 | Chapter Chapter `json:"chapter"` | ||
| 50 | Maps []MapShort `json:"maps"` | ||
| 51 | } | ||
| 52 | |||
| 53 | type RecordResponse struct { | ||
| 54 | ScoreCount int `json:"score_count"` | ||
| 55 | ScoreTime int `json:"score_time"` | ||
| 56 | } | ||
| 57 | |||
| 58 | func ErrorResponse(message string) Response { | ||
| 59 | return Response{ | ||
| 60 | Success: false, | ||
| 61 | Message: message, | ||
| 62 | Data: nil, | ||
| 63 | } | ||
| 64 | } | ||