From f1b7589b2936335957a6a1da1eea3d66233ad0ce Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Sat, 26 Aug 2023 08:53:24 +0300 Subject: refactor: reorganizing packages Former-commit-id: 99410223654c2a5ffc15fdab6ec3e921b5410cba --- backend/handlers/map.go | 314 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 backend/handlers/map.go (limited to 'backend/handlers/map.go') diff --git a/backend/handlers/map.go b/backend/handlers/map.go new file mode 100644 index 0000000..b47e793 --- /dev/null +++ b/backend/handlers/map.go @@ -0,0 +1,314 @@ +package handlers + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/pektezol/leastportalshub/backend/database" + "github.com/pektezol/leastportalshub/backend/models" +) + +type MapSummaryResponse struct { + Map models.Map `json:"map"` + Summary models.MapSummary `json:"summary"` +} + +type ChaptersResponse struct { + Game models.Game `json:"game"` + Chapters []models.Chapter `json:"chapters"` +} + +type ChapterMapsResponse struct { + Chapter models.Chapter `json:"chapter"` + Maps []models.MapShort `json:"maps"` +} + +// GET Map Summary +// +// @Description Get map summary with specified id. +// @Tags maps +// @Produce json +// @Param id path int true "Map ID" +// @Success 200 {object} models.Response{data=MapSummaryResponse} +// @Failure 400 {object} models.Response +// @Router /maps/{id}/summary [get] +func FetchMapSummary(c *gin.Context) { + id := c.Param("id") + response := MapSummaryResponse{Map: models.Map{}, Summary: models.MapSummary{Routes: []models.MapRoute{}}} + intID, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + // Get map data + response.Map.ID = intID + sql := `SELECT m.id, g.name, c.name, m.name, m.image, g.is_coop + 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` + err = database.DB.QueryRow(sql, id).Scan(&response.Map.ID, &response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &response.Map.Image, &response.Map.IsCoop) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + // Get map routes and histories + sql = `SELECT r.id, c.id, c.name, h.user_name, h.score_count, h.record_date, r.description, r.showcase, COALESCE(avg(rating), 0.0) FROM map_routes r + INNER JOIN categories c ON r.category_id = c.id + INNER JOIN map_history h ON r.map_id = h.map_id AND r.category_id = h.category_id + LEFT JOIN map_ratings rt ON r.map_id = rt.map_id AND r.category_id = rt.category_id + WHERE r.map_id = $1 AND h.score_count = r.score_count GROUP BY r.id, c.id, h.user_name, h.score_count, h.record_date, r.description, r.showcase + ORDER BY h.record_date ASC;` + rows, err := database.DB.Query(sql, id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + for rows.Next() { + route := models.MapRoute{Category: models.Category{}, History: models.MapHistory{}} + err = rows.Scan(&route.RouteID, &route.Category.ID, &route.Category.Name, &route.History.RunnerName, &route.History.ScoreCount, &route.History.Date, &route.Description, &route.Showcase, &route.Rating) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + response.Summary.Routes = append(response.Summary.Routes, route) + } + // Return response + c.JSON(http.StatusOK, models.Response{ + Success: true, + Message: "Successfully retrieved map summary.", + Data: response, + }) +} + +// GET Map Leaderboards +// +// @Description Get map leaderboards with specified id. +// @Tags maps +// @Produce json +// @Param id path int true "Map ID" +// @Success 200 {object} models.Response{data=models.Map{data=models.MapRecords}} +// @Failure 400 {object} models.Response +// @Router /maps/{id}/leaderboards [get] +func FetchMapLeaderboards(c *gin.Context) { + // TODO: make new response type + id := c.Param("id") + // Get map data + var mapData models.Map + var mapRecordsData models.MapRecords + var isDisabled bool + intID, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + mapData.ID = intID + sql := `SELECT g.name, c.name, m.name, is_disabled, m.image + 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` + err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled, &mapData.Image) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + if isDisabled { + c.JSON(http.StatusBadRequest, models.ErrorResponse("Map is not available for competitive boards.")) + return + } + // TODO: avatar and names for host & partner + // Get records from the map + if mapData.GameName == "Portal 2 - Cooperative" { + var records []models.RecordMP + sql = `SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date + FROM ( + SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date, + ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn + FROM records_mp + WHERE map_id = $1 + ) sub + WHERE rn = 1` + rows, err := database.DB.Query(sql, id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + placement := 1 + ties := 0 + for rows.Next() { + var record models.RecordMP + err := rows.Scan(&record.RecordID, &record.HostID, &record.PartnerID, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + if len(records) != 0 && records[len(records)-1].ScoreTime == record.ScoreTime { + ties++ + record.Placement = placement - ties + } else { + record.Placement = placement + } + records = append(records, record) + placement++ + } + mapRecordsData.Records = records + } else { + var records []models.RecordSP + sql = `SELECT id, user_id, users.user_name, users.avatar_link, score_count, score_time, demo_id, record_date + FROM ( + SELECT id, user_id, score_count, score_time, demo_id, record_date, + ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn + FROM records_sp + WHERE map_id = $1 + ) sub + INNER JOIN users ON user_id = users.steam_id + WHERE rn = 1` + rows, err := database.DB.Query(sql, id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + placement := 1 + ties := 0 + for rows.Next() { + var record models.RecordSP + err := rows.Scan(&record.RecordID, &record.UserID, &record.UserName, &record.UserAvatar, &record.ScoreCount, &record.ScoreTime, &record.DemoID, &record.RecordDate) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + if len(records) != 0 && records[len(records)-1].ScoreTime == record.ScoreTime { + ties++ + record.Placement = placement - ties + } else { + record.Placement = placement + } + records = append(records, record) + placement++ + } + mapRecordsData.Records = records + } + // mapData.Data = mapRecordsData + // Return response + c.JSON(http.StatusOK, models.Response{ + Success: true, + Message: "Successfully retrieved map leaderboards.", + Data: mapData, + }) +} + +// GET Games +// +// @Description Get games from the leaderboards. +// @Tags games & chapters +// @Produce json +// @Success 200 {object} models.Response{data=[]models.Game} +// @Failure 400 {object} models.Response +// @Router /games [get] +func FetchGames(c *gin.Context) { + rows, err := database.DB.Query(`SELECT id, name, is_coop FROM games`) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + var games []models.Game + for rows.Next() { + var game models.Game + if err := rows.Scan(&game.ID, &game.Name, &game.IsCoop); err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + games = append(games, game) + } + c.JSON(http.StatusOK, models.Response{ + Success: true, + Message: "Successfully retrieved games.", + Data: games, + }) +} + +// GET Chapters of a Game +// +// @Description Get chapters from the specified game id. +// @Tags games & chapters +// @Produce json +// @Param id path int true "Game ID" +// @Success 200 {object} models.Response{data=ChaptersResponse} +// @Failure 400 {object} models.Response +// @Router /games/{id} [get] +func FetchChapters(c *gin.Context) { + gameID := c.Param("id") + intID, err := strconv.Atoi(gameID) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + var response ChaptersResponse + 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) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + var chapters []models.Chapter + var gameName string + for rows.Next() { + var chapter models.Chapter + if err := rows.Scan(&chapter.ID, &chapter.Name, &gameName); err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + chapters = append(chapters, chapter) + } + response.Game.ID = intID + response.Game.Name = gameName + response.Chapters = chapters + c.JSON(http.StatusOK, models.Response{ + Success: true, + Message: "Successfully retrieved chapters.", + Data: response, + }) +} + +// GET Maps of a Chapter +// +// @Description Get maps from the specified chapter id. +// @Tags games & chapters +// @Produce json +// @Param id path int true "Chapter ID" +// @Success 200 {object} models.Response{data=ChapterMapsResponse} +// @Failure 400 {object} models.Response +// @Router /chapters/{id} [get] +func FetchChapterMaps(c *gin.Context) { + chapterID := c.Param("id") + intID, err := strconv.Atoi(chapterID) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + var response ChapterMapsResponse + 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) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + var maps []models.MapShort + var chapterName string + for rows.Next() { + var mapShort models.MapShort + if err := rows.Scan(&mapShort.ID, &mapShort.Name, &chapterName); err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + maps = append(maps, mapShort) + } + response.Chapter.ID = intID + response.Chapter.Name = chapterName + response.Maps = maps + c.JSON(http.StatusOK, models.Response{ + Success: true, + Message: "Successfully retrieved maps.", + Data: response, + }) +} -- cgit v1.2.3 From ee533d9405e3ffe1fd1a073e29f839568c465ba7 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:31:29 +0300 Subject: feat: better leaderboards response, coop additions (#45) Former-commit-id: 3a4a8af14d054512204b5ca4c25a6603ec94773e --- backend/handlers/map.go | 104 +++++++++++++++++++++++++++++++++++------------ backend/models/models.go | 28 ------------- 2 files changed, 79 insertions(+), 53 deletions(-) (limited to 'backend/handlers/map.go') diff --git a/backend/handlers/map.go b/backend/handlers/map.go index b47e793..9b0caef 100644 --- a/backend/handlers/map.go +++ b/backend/handlers/map.go @@ -3,6 +3,7 @@ package handlers import ( "net/http" "strconv" + "time" "github.com/gin-gonic/gin" "github.com/pektezol/leastportalshub/backend/database" @@ -14,6 +15,11 @@ type MapSummaryResponse struct { Summary models.MapSummary `json:"summary"` } +type MapLeaderboardsResponse struct { + Map models.Map `json:"map"` + Records any `json:"records"` +} + type ChaptersResponse struct { Game models.Game `json:"game"` Chapters []models.Chapter `json:"chapters"` @@ -24,6 +30,34 @@ type ChapterMapsResponse struct { Maps []models.MapShort `json:"maps"` } +type RecordSingleplayer struct { + Placement int `json:"placement"` + RecordID int `json:"record_id"` + ScoreCount int `json:"score_count"` + ScoreTime int `json:"score_time"` + UserID string `json:"user_id"` + UserName string `json:"user_name"` + UserAvatar string `json:"user_avatar"` + DemoID string `json:"demo_id"` + RecordDate time.Time `json:"record_date"` +} + +type RecordMultiplayer struct { + Placement int `json:"placement"` + RecordID int `json:"record_id"` + ScoreCount int `json:"score_count"` + ScoreTime int `json:"score_time"` + HostID string `json:"host_id"` + HostName string `json:"host_name"` + HostAvatar string `json:"host_avatar"` + PartnerID string `json:"partner_id"` + PartnerName string `json:"partner_name"` + PartnerAvatar string `json:"partner_avatar"` + HostDemoID string `json:"host_demo_id"` + PartnerDemoID string `json:"partner_demo_id"` + RecordDate time.Time `json:"record_date"` +} + // GET Map Summary // // @Description Get map summary with specified id. @@ -88,28 +122,29 @@ func FetchMapSummary(c *gin.Context) { // @Tags maps // @Produce json // @Param id path int true "Map ID" -// @Success 200 {object} models.Response{data=models.Map{data=models.MapRecords}} +// @Success 200 {object} models.Response{data=MapLeaderboardsResponse} // @Failure 400 {object} models.Response // @Router /maps/{id}/leaderboards [get] func FetchMapLeaderboards(c *gin.Context) { // TODO: make new response type id := c.Param("id") // Get map data - var mapData models.Map - var mapRecordsData models.MapRecords + response := MapLeaderboardsResponse{Map: models.Map{}, Records: nil} + // var mapData models.Map + // var mapRecordsData models.MapRecords var isDisabled bool intID, err := strconv.Atoi(id) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } - mapData.ID = intID + response.Map.ID = intID sql := `SELECT g.name, c.name, m.name, is_disabled, m.image 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` - err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled, &mapData.Image) + err = database.DB.QueryRow(sql, id).Scan(&response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &isDisabled, &response.Map.Image) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -119,17 +154,38 @@ func FetchMapLeaderboards(c *gin.Context) { return } // TODO: avatar and names for host & partner - // Get records from the map - if mapData.GameName == "Portal 2 - Cooperative" { - var records []models.RecordMP - sql = `SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date - FROM ( - SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date, - ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn - FROM records_mp - WHERE map_id = $1 - ) sub - WHERE rn = 1` + if response.Map.GameName == "Portal 2 - Cooperative" { + records := []RecordMultiplayer{} + sql = `SELECT + sub.id, + sub.host_id, + host.user_name AS host_user_name, + host.avatar_link AS host_avatar_link, + sub.partner_id, + partner.user_name AS partner_user_name, + partner.avatar_link AS partner_avatar_link, + sub.score_count, + sub.score_time, + sub.host_demo_id, + sub.partner_demo_id, + sub.record_date + FROM ( + SELECT + id, + host_id, + partner_id, + score_count, + score_time, + host_demo_id, + partner_demo_id, + record_date, + ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn + FROM records_mp + WHERE map_id = $1 + ) sub + JOIN users AS host ON sub.host_id = host.steam_id + JOIN users AS partner ON sub.partner_id = partner.steam_id + WHERE sub.rn = 1;` rows, err := database.DB.Query(sql, id) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -138,8 +194,8 @@ func FetchMapLeaderboards(c *gin.Context) { placement := 1 ties := 0 for rows.Next() { - var record models.RecordMP - err := rows.Scan(&record.RecordID, &record.HostID, &record.PartnerID, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate) + var record RecordMultiplayer + err := rows.Scan(&record.RecordID, &record.HostID, &record.HostName, &record.HostAvatar, &record.PartnerID, &record.PartnerName, &record.PartnerAvatar, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -153,9 +209,9 @@ func FetchMapLeaderboards(c *gin.Context) { records = append(records, record) placement++ } - mapRecordsData.Records = records + response.Records = records } else { - var records []models.RecordSP + records := []RecordSingleplayer{} sql = `SELECT id, user_id, users.user_name, users.avatar_link, score_count, score_time, demo_id, record_date FROM ( SELECT id, user_id, score_count, score_time, demo_id, record_date, @@ -173,7 +229,7 @@ func FetchMapLeaderboards(c *gin.Context) { placement := 1 ties := 0 for rows.Next() { - var record models.RecordSP + var record RecordSingleplayer err := rows.Scan(&record.RecordID, &record.UserID, &record.UserName, &record.UserAvatar, &record.ScoreCount, &record.ScoreTime, &record.DemoID, &record.RecordDate) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) @@ -188,14 +244,12 @@ func FetchMapLeaderboards(c *gin.Context) { records = append(records, record) placement++ } - mapRecordsData.Records = records + response.Records = records } - // mapData.Data = mapRecordsData - // Return response c.JSON(http.StatusOK, models.Response{ Success: true, Message: "Successfully retrieved map leaderboards.", - Data: mapData, + Data: response, }) } diff --git a/backend/models/models.go b/backend/models/models.go index f124db5..b706d25 100644 --- a/backend/models/models.go +++ b/backend/models/models.go @@ -104,34 +104,6 @@ type Links struct { Twitch string `json:"twitch"` } -type RecordSP struct { - RecordID int `json:"record_id"` - Placement int `json:"placement"` - UserID string `json:"user_id"` - UserName string `json:"user_name"` - UserAvatar string `json:"user_avatar"` - ScoreCount int `json:"score_count"` - ScoreTime int `json:"score_time"` - DemoID string `json:"demo_id"` - RecordDate time.Time `json:"record_date"` -} - -type RecordMP struct { - RecordID int `json:"record_id"` - Placement int `json:"placement"` - HostID string `json:"host_id"` - HostName string `json:"host_name"` - HostAvatar string `json:"host_avatar"` - PartnerID string `json:"partner_id"` - PartnerName string `json:"partner_name"` - PartnerAvatar string `json:"partner_avatar"` - ScoreCount int `json:"score_count"` - ScoreTime int `json:"score_time"` - HostDemoID string `json:"host_demo_id"` - PartnerDemoID string `json:"partner_demo_id"` - RecordDate time.Time `json:"record_date"` -} - type PlayerSummaries struct { SteamId string `json:"steamid"` CommunityVisibilityState int `json:"communityvisibilitystate"` -- cgit v1.2.3 From 5a285a5d811a955a8eb380a598595e159e9935e5 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:40:27 +0300 Subject: fix: actually get is_coop data for the given map (#45) Former-commit-id: f29b6ca5d0e23ae622451b011e7d64758a8f598c --- backend/handlers/map.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backend/handlers/map.go') diff --git a/backend/handlers/map.go b/backend/handlers/map.go index 9b0caef..0a0206e 100644 --- a/backend/handlers/map.go +++ b/backend/handlers/map.go @@ -139,12 +139,12 @@ func FetchMapLeaderboards(c *gin.Context) { return } response.Map.ID = intID - sql := `SELECT g.name, c.name, m.name, is_disabled, m.image + sql := `SELECT g.name, c.name, m.name, is_disabled, m.image, g.is_coop 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` - err = database.DB.QueryRow(sql, id).Scan(&response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &isDisabled, &response.Map.Image) + err = database.DB.QueryRow(sql, id).Scan(&response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &isDisabled, &response.Map.Image, &response.Map.IsCoop) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return -- cgit v1.2.3 From dd9a047dc6512b3b6419ac4bd05a77bc22be95b0 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:26:48 +0300 Subject: fix: imrpoved user models on responses Former-commit-id: 3aeb7e76928081664f33a4012bd1d84c81eef77c --- backend/handlers/home.go | 9 ++++----- backend/handlers/map.go | 42 ++++++++++++++++++------------------------ backend/models/models.go | 11 ++++++++--- 3 files changed, 30 insertions(+), 32 deletions(-) (limited to 'backend/handlers/map.go') diff --git a/backend/handlers/home.go b/backend/handlers/home.go index 53be1de..eb3912c 100644 --- a/backend/handlers/home.go +++ b/backend/handlers/home.go @@ -68,7 +68,7 @@ func Rankings(c *gin.Context) { ranking := models.UserRanking{} var currentCount int var totalCount int - err = rows.Scan(&ranking.UserID, &ranking.UserName, ¤tCount, &totalCount, &ranking.TotalScore) + err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -100,7 +100,7 @@ func Rankings(c *gin.Context) { ranking := models.UserRanking{} var currentCount int var totalCount int - err = rows.Scan(&ranking.UserID, &ranking.UserName, ¤tCount, &totalCount, &ranking.TotalScore) + err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -113,11 +113,10 @@ func Rankings(c *gin.Context) { // Has both so they are qualified for overall ranking for _, spRanking := range response.Singleplayer { for _, mpRanking := range response.Multiplayer { - if spRanking.UserID == mpRanking.UserID { + if spRanking.User.SteamID == mpRanking.User.SteamID { totalScore := spRanking.TotalScore + mpRanking.TotalScore overallRanking := models.UserRanking{ - UserID: spRanking.UserID, - UserName: spRanking.UserName, + User: spRanking.User, TotalScore: totalScore, } response.Overall = append(response.Overall, overallRanking) diff --git a/backend/handlers/map.go b/backend/handlers/map.go index 0a0206e..1d9cee8 100644 --- a/backend/handlers/map.go +++ b/backend/handlers/map.go @@ -31,31 +31,25 @@ type ChapterMapsResponse struct { } type RecordSingleplayer struct { - Placement int `json:"placement"` - RecordID int `json:"record_id"` - ScoreCount int `json:"score_count"` - ScoreTime int `json:"score_time"` - UserID string `json:"user_id"` - UserName string `json:"user_name"` - UserAvatar string `json:"user_avatar"` - DemoID string `json:"demo_id"` - RecordDate time.Time `json:"record_date"` + Placement int `json:"placement"` + RecordID int `json:"record_id"` + ScoreCount int `json:"score_count"` + ScoreTime int `json:"score_time"` + User models.UserShortWithAvatar `json:"user"` + DemoID string `json:"demo_id"` + RecordDate time.Time `json:"record_date"` } type RecordMultiplayer struct { - Placement int `json:"placement"` - RecordID int `json:"record_id"` - ScoreCount int `json:"score_count"` - ScoreTime int `json:"score_time"` - HostID string `json:"host_id"` - HostName string `json:"host_name"` - HostAvatar string `json:"host_avatar"` - PartnerID string `json:"partner_id"` - PartnerName string `json:"partner_name"` - PartnerAvatar string `json:"partner_avatar"` - HostDemoID string `json:"host_demo_id"` - PartnerDemoID string `json:"partner_demo_id"` - RecordDate time.Time `json:"record_date"` + Placement int `json:"placement"` + RecordID int `json:"record_id"` + ScoreCount int `json:"score_count"` + ScoreTime int `json:"score_time"` + Host models.UserShortWithAvatar `json:"host"` + Partner models.UserShortWithAvatar `json:"partner"` + HostDemoID string `json:"host_demo_id"` + PartnerDemoID string `json:"partner_demo_id"` + RecordDate time.Time `json:"record_date"` } // GET Map Summary @@ -195,7 +189,7 @@ func FetchMapLeaderboards(c *gin.Context) { ties := 0 for rows.Next() { var record RecordMultiplayer - err := rows.Scan(&record.RecordID, &record.HostID, &record.HostName, &record.HostAvatar, &record.PartnerID, &record.PartnerName, &record.PartnerAvatar, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate) + err := rows.Scan(&record.RecordID, &record.Host.SteamID, &record.Host.UserName, &record.Host.AvatarLink, &record.Partner.SteamID, &record.Partner.UserName, &record.Partner.AvatarLink, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return @@ -230,7 +224,7 @@ func FetchMapLeaderboards(c *gin.Context) { ties := 0 for rows.Next() { var record RecordSingleplayer - err := rows.Scan(&record.RecordID, &record.UserID, &record.UserName, &record.UserAvatar, &record.ScoreCount, &record.ScoreTime, &record.DemoID, &record.RecordDate) + err := rows.Scan(&record.RecordID, &record.User.SteamID, &record.User.UserName, &record.User.AvatarLink, &record.ScoreCount, &record.ScoreTime, &record.DemoID, &record.RecordDate) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return diff --git a/backend/models/models.go b/backend/models/models.go index b706d25..2d54295 100644 --- a/backend/models/models.go +++ b/backend/models/models.go @@ -33,6 +33,12 @@ type UserShort struct { UserName string `json:"user_name"` } +type UserShortWithAvatar struct { + SteamID string `json:"steam_id"` + UserName string `json:"user_name"` + AvatarLink string `json:"avatar_link"` +} + type Map struct { ID int `json:"id"` GameName string `json:"game_name"` @@ -71,9 +77,8 @@ type MapRecords struct { } type UserRanking struct { - UserID string `json:"user_id"` - UserName string `json:"user_name"` - TotalScore int `json:"total_score"` + User UserShort `json:"user"` + TotalScore int `json:"total_score"` } type Game struct { -- cgit v1.2.3