From 937160bfda2c8edc5ff5dd73899b517bb0ceb515 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Wed, 3 May 2023 16:05:30 +0300 Subject: fix: sql typos, routing change --- backend/controllers/homeController.go | 10 ++--- backend/controllers/mapController.go | 22 +++++------ backend/controllers/recordController.go | 12 +++--- backend/controllers/userController.go | 14 +++---- backend/middleware/auth.go | 2 +- backend/routes/routes.go | 4 +- docs/docs.go | 67 +++++++++++++++++++-------------- docs/swagger.json | 67 +++++++++++++++++++-------------- docs/swagger.yaml | 53 +++++++++++++++----------- 9 files changed, 140 insertions(+), 111 deletions(-) diff --git a/backend/controllers/homeController.go b/backend/controllers/homeController.go index 206e3ae..edb770f 100644 --- a/backend/controllers/homeController.go +++ b/backend/controllers/homeController.go @@ -29,7 +29,7 @@ func Home(c *gin.Context) { // @Failure 400 {object} models.Response // @Router /demo [get] func Rankings(c *gin.Context) { - rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users;`) + rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -46,7 +46,7 @@ func Rankings(c *gin.Context) { // Getting all sp records for each user var uniqueSingleUserRecords, totalSingleMaps int sql := `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps - WHERE is_coop = FALSE AND is_disabled = false) FROM records_sp WHERE user_id = $1;` + WHERE is_coop = FALSE AND is_disabled = false) FROM records_sp WHERE user_id = $1` err = database.DB.QueryRow(sql, userID).Scan(&uniqueSingleUserRecords, &totalSingleMaps) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -57,7 +57,7 @@ func Rankings(c *gin.Context) { var ranking models.UserRanking ranking.UserID = userID ranking.UserName = username - sql := `SELECT DISTINCT map_id, score_count FROM records_sp WHERE user_id = $1 ORDER BY map_id, score_count;` + sql := `SELECT DISTINCT map_id, score_count FROM records_sp WHERE user_id = $1 ORDER BY map_id, score_count` rows, err := database.DB.Query(sql, userID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -80,7 +80,7 @@ func Rankings(c *gin.Context) { // Getting all mp records for each user var uniqueMultiUserRecords, totalMultiMaps int sql = `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps - WHERE is_coop = TRUE AND is_disabled = false) FROM records_mp WHERE host_id = $1 OR partner_id = $2;` + WHERE is_coop = TRUE AND is_disabled = false) FROM records_mp WHERE host_id = $1 OR partner_id = $2` err = database.DB.QueryRow(sql, userID, userID).Scan(&uniqueMultiUserRecords, &totalMultiMaps) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -91,7 +91,7 @@ func Rankings(c *gin.Context) { var ranking models.UserRanking ranking.UserID = userID ranking.UserName = username - sql := `SELECT DISTINCT map_id, score_count FROM records_mp WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id, score_count;` + sql := `SELECT DISTINCT map_id, score_count FROM records_mp WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id, score_count` rows, err := database.DB.Query(sql, userID, userID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) diff --git a/backend/controllers/mapController.go b/backend/controllers/mapController.go index 506daa2..d8783b7 100644 --- a/backend/controllers/mapController.go +++ b/backend/controllers/mapController.go @@ -56,7 +56,7 @@ func FetchMapSummary(c *gin.Context) { FROM maps m INNER JOIN games g ON m.game_id = g.id INNER JOIN chapters c ON m.chapter_id = c.id - WHERE m.id = $1;` + WHERE m.id = $1` // TODO: CategoryScores err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &mapSummaryData.Description, &mapSummaryData.Showcase, &routers, &mapSummaryData.Rating) if err != nil { @@ -68,7 +68,7 @@ func FetchMapSummary(c *gin.Context) { var historyDates pq.StringArray sql = `SELECT array_agg(user_name), array_agg(score_count), array_agg(record_date) FROM map_history - WHERE map_id = $1;` + WHERE map_id = $1` err = database.DB.QueryRow(sql, id).Scan(&historyNames, &historyScores, &historyDates) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -123,7 +123,7 @@ func FetchMapLeaderboards(c *gin.Context) { FROM maps m INNER JOIN games g ON m.game_id = g.id INNER JOIN chapters c ON m.chapter_id = c.id - WHERE m.id = $1;` + WHERE m.id = $1` err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -144,7 +144,7 @@ func FetchMapLeaderboards(c *gin.Context) { FROM records_mp WHERE map_id = $1 ) sub - WHERE rn = 1;` + WHERE rn = 1` rows, err := database.DB.Query(sql, id) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -179,7 +179,7 @@ func FetchMapLeaderboards(c *gin.Context) { WHERE map_id = $1 ) sub INNER JOIN users ON user_id = users.steam_id - WHERE rn = 1;` + WHERE rn = 1` rows, err := database.DB.Query(sql, id) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -217,7 +217,7 @@ func FetchMapLeaderboards(c *gin.Context) { // GET Games // // @Summary Get games from the leaderboards. -// @Tags games +// @Tags games & chapters // @Produce json // @Success 200 {object} models.Response{data=[]models.Game} // @Failure 400 {object} models.Response @@ -247,12 +247,12 @@ func FetchGames(c *gin.Context) { // GET Chapters of a Game // // @Summary Get chapters from the specified game id. -// @Tags chapters +// @Tags games & chapters // @Produce json // @Param id path int true "Game ID" // @Success 200 {object} models.Response{data=models.ChaptersResponse} // @Failure 400 {object} models.Response -// @Router /chapters/{id} [get] +// @Router /games/{id} [get] func FetchChapters(c *gin.Context) { gameID := c.Param("id") intID, err := strconv.Atoi(gameID) @@ -289,12 +289,12 @@ func FetchChapters(c *gin.Context) { // GET Maps of a Chapter // // @Summary Get maps from the specified chapter id. -// @Tags maps +// @Tags games & chapters // @Produce json // @Param id path int true "Chapter ID" -// @Success 200 {object} models.Response{data=[]models.MapShort} +// @Success 200 {object} models.Response{data=models.ChapterMapsResponse} // @Failure 400 {object} models.Response -// @Router /maps/{id} [get] +// @Router /chapters/{id} [get] func FetchChapterMaps(c *gin.Context) { chapterID := c.Param("id") intID, err := strconv.Atoi(chapterID) diff --git a/backend/controllers/recordController.go b/backend/controllers/recordController.go index bafa844..627be57 100644 --- a/backend/controllers/recordController.go +++ b/backend/controllers/recordController.go @@ -46,7 +46,7 @@ func CreateRecordWithDemo(c *gin.Context) { var gameID int var isCoop bool var isDisabled bool - sql := `SELECT game_id, is_disabled FROM maps WHERE id = $1;` + sql := `SELECT game_id, is_disabled FROM maps WHERE id = $1` err := database.DB.QueryRow(sql, mapId).Scan(&gameID, &isDisabled) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -153,7 +153,7 @@ func CreateRecordWithDemo(c *gin.Context) { // Insert into records if isCoop { sql := `INSERT INTO records_mp(map_id,score_count,score_time,host_id,partner_id,host_demo_id,partner_demo_id) - VALUES($1, $2, $3, $4, $5, $6, $7);` + VALUES($1, $2, $3, $4, $5, $6, $7)` var hostID string var partnerID string if record.IsPartnerOrange { @@ -171,7 +171,7 @@ func CreateRecordWithDemo(c *gin.Context) { } // If a new world record based on portal count // if record.ScoreCount < wrScore { - // _, err := tx.Exec(`UPDATE maps SET wr_score = $1, wr_time = $2 WHERE id = $3;`, record.ScoreCount, record.ScoreTime, mapId) + // _, err := tx.Exec(`UPDATE maps SET wr_score = $1, wr_time = $2 WHERE id = $3`, record.ScoreCount, record.ScoreTime, mapId) // if err != nil { // c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) // return @@ -179,7 +179,7 @@ func CreateRecordWithDemo(c *gin.Context) { // } } else { sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) - VALUES($1, $2, $3, $4, $5);` + VALUES($1, $2, $3, $4, $5)` _, err := tx.Exec(sql, mapId, record.ScoreCount, record.ScoreTime, user.(models.User).SteamID, hostDemoUUID) if err != nil { deleteFile(srv, fileID) @@ -188,7 +188,7 @@ func CreateRecordWithDemo(c *gin.Context) { } // If a new world record based on portal count // if record.ScoreCount < wrScore { - // _, err := tx.Exec(`UPDATE maps SET wr_score = $1, wr_time = $2 WHERE id = $3;`, record.ScoreCount, record.ScoreTime, mapId) + // _, err := tx.Exec(`UPDATE maps SET wr_score = $1, wr_time = $2 WHERE id = $3`, record.ScoreCount, record.ScoreTime, mapId) // if err != nil { // c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) // return @@ -224,7 +224,7 @@ func DownloadDemoWithID(c *gin.Context) { c.JSON(http.StatusBadRequest, models.ErrorResponse("Invalid id given.")) return } - err := database.DB.QueryRow(`SELECT location_id FROM demos WHERE id = $1;`, uuid).Scan(&locationID) + err := database.DB.QueryRow(`SELECT location_id FROM demos WHERE id = $1`, uuid).Scan(&locationID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return diff --git a/backend/controllers/userController.go b/backend/controllers/userController.go index 5ad800d..adf936b 100644 --- a/backend/controllers/userController.go +++ b/backend/controllers/userController.go @@ -31,7 +31,7 @@ func Profile(c *gin.Context) { } // Retrieve singleplayer records var scoresSP []models.ScoreResponse - sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id;` + sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` rows, err := database.DB.Query(sql, user.(models.User).SteamID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -58,7 +58,7 @@ func Profile(c *gin.Context) { // Retrieve multiplayer records var scoresMP []models.ScoreResponse sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp - WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id;` + WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` rows, err = database.DB.Query(sql, user.(models.User).SteamID, user.(models.User).SteamID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -119,7 +119,7 @@ func FetchUser(c *gin.Context) { } // Check if user exists var user models.User - err := database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, id).Scan( + err := database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1`, id).Scan( &user.SteamID, &user.UserName, &user.AvatarLink, &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) if user.SteamID == "" { @@ -133,7 +133,7 @@ func FetchUser(c *gin.Context) { } // Retrieve singleplayer records var scoresSP []models.ScoreResponse - sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id;` + sql := `SELECT id, map_id, score_count, score_time, demo_id, record_date FROM records_sp WHERE user_id = $1 ORDER BY map_id` rows, err := database.DB.Query(sql, user.SteamID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -160,7 +160,7 @@ func FetchUser(c *gin.Context) { // Retrieve multiplayer records var scoresMP []models.ScoreResponse sql = `SELECT id, map_id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date FROM records_mp - WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id;` + WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id` rows, err = database.DB.Query(sql, user.SteamID, user.SteamID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -225,7 +225,7 @@ func UpdateUser(c *gin.Context) { } // Update profile _, err = database.DB.Exec(`UPDATE users SET username = $1, avatar_link = $2, country_code = $3, updated_at = $4 - WHERE steam_id = $5;`, profile.PersonaName, profile.AvatarFull, profile.LocCountryCode, time.Now().UTC(), user.(models.User).SteamID) + WHERE steam_id = $5`, profile.PersonaName, profile.AvatarFull, profile.LocCountryCode, time.Now().UTC(), user.(models.User).SteamID) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -268,7 +268,7 @@ func UpdateCountryCode(c *gin.Context) { return } var validCode string - err := database.DB.QueryRow(`SELECT country_code FROM countries WHERE country_code = $1;`, code).Scan(&validCode) + err := database.DB.QueryRow(`SELECT country_code FROM countries WHERE country_code = $1`, code).Scan(&validCode) if err != nil { c.JSON(http.StatusNotFound, models.ErrorResponse(err.Error())) return diff --git a/backend/middleware/auth.go b/backend/middleware/auth.go index cd00a30..14a0b78 100644 --- a/backend/middleware/auth.go +++ b/backend/middleware/auth.go @@ -36,7 +36,7 @@ func CheckAuth(c *gin.Context) { } // Get user from DB var user models.User - database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, claims["sub"]).Scan( + database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1`, claims["sub"]).Scan( &user.SteamID, &user.UserName, &user.AvatarLink, &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) if user.SteamID == "" { diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 2741208..2554fa4 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go @@ -26,10 +26,10 @@ func InitRoutes(router *gin.Engine) { v1.GET("/maps/:id/summary", middleware.CheckAuth, controllers.FetchMapSummary) v1.GET("/maps/:id/leaderboards", middleware.CheckAuth, controllers.FetchMapLeaderboards) v1.POST("/maps/:id/record", middleware.CheckAuth, controllers.CreateRecordWithDemo) - v1.GET("/maps/:id", controllers.FetchChapterMaps) v1.GET("/rankings", middleware.CheckAuth, controllers.Rankings) v1.GET("/search", controllers.Search) v1.GET("/games", controllers.FetchGames) - v1.GET("/chapters/:id", controllers.FetchChapters) + v1.GET("/games/:id", controllers.FetchChapters) + v1.GET("/chapters/:id", controllers.FetchChapterMaps) } } diff --git a/docs/docs.go b/docs/docs.go index 164db20..cd129f0 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -26,13 +26,13 @@ const docTemplate = `{ "application/json" ], "tags": [ - "chapters" + "games \u0026 chapters" ], - "summary": "Get chapters from the specified game id.", + "summary": "Get maps from the specified chapter id.", "parameters": [ { "type": "integer", - "description": "Game ID", + "description": "Chapter ID", "name": "id", "in": "path", "required": true @@ -50,7 +50,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "$ref": "#/definitions/models.ChaptersResponse" + "$ref": "#/definitions/models.ChapterMapsResponse" } } } @@ -146,7 +146,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "games" + "games \u0026 chapters" ], "summary": "Get games from the leaderboards.", "responses": { @@ -180,18 +180,24 @@ const docTemplate = `{ } } }, - "/login": { + "/games/{id}": { "get": { - "consumes": [ - "application/json" - ], "produces": [ "application/json" ], "tags": [ - "login" + "games \u0026 chapters" + ], + "summary": "Get chapters from the specified game id.", + "parameters": [ + { + "type": "integer", + "description": "Game ID", + "name": "id", + "in": "path", + "required": true + } ], - "summary": "Get (redirect) login page for Steam auth.", "responses": { "200": { "description": "OK", @@ -204,7 +210,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "$ref": "#/definitions/models.LoginResponse" + "$ref": "#/definitions/models.ChaptersResponse" } } } @@ -220,24 +226,18 @@ const docTemplate = `{ } } }, - "/maps/{id}": { + "/login": { "get": { + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ - "maps" - ], - "summary": "Get maps from the specified chapter id.", - "parameters": [ - { - "type": "integer", - "description": "Chapter ID", - "name": "id", - "in": "path", - "required": true - } + "login" ], + "summary": "Get (redirect) login page for Steam auth.", "responses": { "200": { "description": "OK", @@ -250,10 +250,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.MapShort" - } + "$ref": "#/definitions/models.LoginResponse" } } } @@ -751,6 +748,20 @@ const docTemplate = `{ } } }, + "models.ChapterMapsResponse": { + "type": "object", + "properties": { + "chapter": { + "$ref": "#/definitions/models.Chapter" + }, + "maps": { + "type": "array", + "items": { + "$ref": "#/definitions/models.MapShort" + } + } + } + }, "models.ChaptersResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 653d52f..442745f 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -19,13 +19,13 @@ "application/json" ], "tags": [ - "chapters" + "games \u0026 chapters" ], - "summary": "Get chapters from the specified game id.", + "summary": "Get maps from the specified chapter id.", "parameters": [ { "type": "integer", - "description": "Game ID", + "description": "Chapter ID", "name": "id", "in": "path", "required": true @@ -43,7 +43,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/models.ChaptersResponse" + "$ref": "#/definitions/models.ChapterMapsResponse" } } } @@ -139,7 +139,7 @@ "application/json" ], "tags": [ - "games" + "games \u0026 chapters" ], "summary": "Get games from the leaderboards.", "responses": { @@ -173,18 +173,24 @@ } } }, - "/login": { + "/games/{id}": { "get": { - "consumes": [ - "application/json" - ], "produces": [ "application/json" ], "tags": [ - "login" + "games \u0026 chapters" + ], + "summary": "Get chapters from the specified game id.", + "parameters": [ + { + "type": "integer", + "description": "Game ID", + "name": "id", + "in": "path", + "required": true + } ], - "summary": "Get (redirect) login page for Steam auth.", "responses": { "200": { "description": "OK", @@ -197,7 +203,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/models.LoginResponse" + "$ref": "#/definitions/models.ChaptersResponse" } } } @@ -213,24 +219,18 @@ } } }, - "/maps/{id}": { + "/login": { "get": { + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ - "maps" - ], - "summary": "Get maps from the specified chapter id.", - "parameters": [ - { - "type": "integer", - "description": "Chapter ID", - "name": "id", - "in": "path", - "required": true - } + "login" ], + "summary": "Get (redirect) login page for Steam auth.", "responses": { "200": { "description": "OK", @@ -243,10 +243,7 @@ "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.MapShort" - } + "$ref": "#/definitions/models.LoginResponse" } } } @@ -744,6 +741,20 @@ } } }, + "models.ChapterMapsResponse": { + "type": "object", + "properties": { + "chapter": { + "$ref": "#/definitions/models.Chapter" + }, + "maps": { + "type": "array", + "items": { + "$ref": "#/definitions/models.MapShort" + } + } + } + }, "models.ChaptersResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 88f2d7f..fa1a26d 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -7,6 +7,15 @@ definitions: name: type: string type: object + models.ChapterMapsResponse: + properties: + chapter: + $ref: '#/definitions/models.Chapter' + maps: + items: + $ref: '#/definitions/models.MapShort' + type: array + type: object models.ChaptersResponse: properties: chapters: @@ -195,7 +204,7 @@ paths: /chapters/{id}: get: parameters: - - description: Game ID + - description: Chapter ID in: path name: id required: true @@ -210,15 +219,15 @@ paths: - $ref: '#/definitions/models.Response' - properties: data: - $ref: '#/definitions/models.ChaptersResponse' + $ref: '#/definitions/models.ChapterMapsResponse' type: object "400": description: Bad Request schema: $ref: '#/definitions/models.Response' - summary: Get chapters from the specified game id. + summary: Get maps from the specified chapter id. tags: - - chapters + - games & chapters /demo: get: produces: @@ -286,11 +295,15 @@ paths: $ref: '#/definitions/models.Response' summary: Get games from the leaderboards. tags: - - games - /login: + - games & chapters + /games/{id}: get: - consumes: - - application/json + parameters: + - description: Game ID + in: path + name: id + required: true + type: integer produces: - application/json responses: @@ -301,23 +314,19 @@ paths: - $ref: '#/definitions/models.Response' - properties: data: - $ref: '#/definitions/models.LoginResponse' + $ref: '#/definitions/models.ChaptersResponse' type: object "400": description: Bad Request schema: $ref: '#/definitions/models.Response' - summary: Get (redirect) login page for Steam auth. + summary: Get chapters from the specified game id. tags: - - login - /maps/{id}: + - games & chapters + /login: get: - parameters: - - description: Chapter ID - in: path - name: id - required: true - type: integer + consumes: + - application/json produces: - application/json responses: @@ -328,17 +337,15 @@ paths: - $ref: '#/definitions/models.Response' - properties: data: - items: - $ref: '#/definitions/models.MapShort' - type: array + $ref: '#/definitions/models.LoginResponse' type: object "400": description: Bad Request schema: $ref: '#/definitions/models.Response' - summary: Get maps from the specified chapter id. + summary: Get (redirect) login page for Steam auth. tags: - - maps + - login /maps/{id}/leaderboards: get: parameters: -- cgit v1.2.3