diff options
Diffstat (limited to '')
| -rw-r--r-- | backend/handlers/home.go (renamed from backend/controllers/homeController.go) | 169 |
1 files changed, 87 insertions, 82 deletions
diff --git a/backend/controllers/homeController.go b/backend/handlers/home.go index c94590a..2095a74 100644 --- a/backend/controllers/homeController.go +++ b/backend/handlers/home.go | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | package controllers | 1 | package handlers |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "log" | 4 | "log" |
| 5 | "net/http" | 5 | "net/http" |
| 6 | "sort" | ||
| 6 | "strings" | 7 | "strings" |
| 7 | 8 | ||
| 8 | "github.com/gin-gonic/gin" | 9 | "github.com/gin-gonic/gin" |
| @@ -10,15 +11,15 @@ import ( | |||
| 10 | "github.com/pektezol/leastportalshub/backend/models" | 11 | "github.com/pektezol/leastportalshub/backend/models" |
| 11 | ) | 12 | ) |
| 12 | 13 | ||
| 13 | func Home(c *gin.Context) { | 14 | type SearchResponse struct { |
| 14 | user, exists := c.Get("user") | 15 | Players []models.UserShort `json:"players"` |
| 15 | if !exists { | 16 | Maps []models.MapShort `json:"maps"` |
| 16 | c.JSON(200, "no id, not auth") | 17 | } |
| 17 | } else { | 18 | |
| 18 | c.JSON(200, gin.H{ | 19 | type RankingsResponse struct { |
| 19 | "output": user, | 20 | Overall []models.UserRanking `json:"rankings_overall"` |
| 20 | }) | 21 | Singleplayer []models.UserRanking `json:"rankings_singleplayer"` |
| 21 | } | 22 | Multiplayer []models.UserRanking `json:"rankings_multiplayer"` |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | // GET Rankings | 25 | // GET Rankings |
| @@ -26,100 +27,104 @@ func Home(c *gin.Context) { | |||
| 26 | // @Description Get rankings of every player. | 27 | // @Description Get rankings of every player. |
| 27 | // @Tags rankings | 28 | // @Tags rankings |
| 28 | // @Produce json | 29 | // @Produce json |
| 29 | // @Success 200 {object} models.Response{data=models.RankingsResponse} | 30 | // @Success 200 {object} models.Response{data=RankingsResponse} |
| 30 | // @Failure 400 {object} models.Response | 31 | // @Failure 400 {object} models.Response |
| 31 | // @Router /rankings [get] | 32 | // @Router /rankings [get] |
| 32 | func Rankings(c *gin.Context) { | 33 | func Rankings(c *gin.Context) { |
| 33 | rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) | 34 | response := RankingsResponse{ |
| 35 | Overall: []models.UserRanking{}, | ||
| 36 | Singleplayer: []models.UserRanking{}, | ||
| 37 | Multiplayer: []models.UserRanking{}, | ||
| 38 | } | ||
| 39 | // Singleplayer rankings | ||
| 40 | sql := `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id), | ||
| 41 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = FALSE AND is_disabled = false), | ||
| 42 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | ||
| 43 | SELECT | ||
| 44 | user_id, | ||
| 45 | MIN(score_count) AS min_score_count | ||
| 46 | FROM records_sp | ||
| 47 | GROUP BY user_id, map_id | ||
| 48 | ) AS subquery | ||
| 49 | WHERE user_id = u.steam_id) | ||
| 50 | FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name` | ||
| 51 | rows, err := database.DB.Query(sql) | ||
| 34 | if err != nil { | 52 | if err != nil { |
| 35 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 53 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 36 | return | 54 | return |
| 37 | } | 55 | } |
| 38 | var spRankings []models.UserRanking | ||
| 39 | var mpRankings []models.UserRanking | ||
| 40 | for rows.Next() { | 56 | for rows.Next() { |
| 41 | var userID, username string | 57 | ranking := models.UserRanking{} |
| 42 | err := rows.Scan(&userID, &username) | 58 | var currentCount int |
| 43 | if err != nil { | 59 | var totalCount int |
| 44 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 60 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) |
| 45 | return | ||
| 46 | } | ||
| 47 | // Getting all sp records for each user | ||
| 48 | var uniqueSingleUserRecords, totalSingleMaps int | ||
| 49 | sql := `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps | ||
| 50 | WHERE is_coop = FALSE AND is_disabled = false) FROM records_sp WHERE user_id = $1` | ||
| 51 | err = database.DB.QueryRow(sql, userID).Scan(&uniqueSingleUserRecords, &totalSingleMaps) | ||
| 52 | if err != nil { | 61 | if err != nil { |
| 53 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 62 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 54 | return | 63 | return |
| 55 | } | 64 | } |
| 56 | // Has all singleplayer records | 65 | if currentCount != totalCount { |
| 57 | if uniqueSingleUserRecords == totalSingleMaps { | 66 | continue |
| 58 | var ranking models.UserRanking | ||
| 59 | ranking.UserID = userID | ||
| 60 | ranking.UserName = username | ||
| 61 | sql := `SELECT DISTINCT map_id, score_count FROM records_sp WHERE user_id = $1 ORDER BY map_id, score_count` | ||
| 62 | rows, err := database.DB.Query(sql, userID) | ||
| 63 | if err != nil { | ||
| 64 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 65 | return | ||
| 66 | } | ||
| 67 | totalScore := 0 | ||
| 68 | var maps []int | ||
| 69 | for rows.Next() { | ||
| 70 | var mapID, scoreCount int | ||
| 71 | rows.Scan(&mapID, &scoreCount) | ||
| 72 | if len(maps) != 0 && maps[len(maps)-1] == mapID { | ||
| 73 | continue | ||
| 74 | } | ||
| 75 | totalScore += scoreCount | ||
| 76 | maps = append(maps, mapID) | ||
| 77 | } | ||
| 78 | ranking.TotalScore = totalScore | ||
| 79 | spRankings = append(spRankings, ranking) | ||
| 80 | } | 67 | } |
| 81 | // Getting all mp records for each user | 68 | response.Singleplayer = append(response.Singleplayer, ranking) |
| 82 | var uniqueMultiUserRecords, totalMultiMaps int | 69 | } |
| 83 | sql = `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps | 70 | // Multiplayer rankings |
| 84 | WHERE is_coop = TRUE AND is_disabled = false) FROM records_mp WHERE host_id = $1 OR partner_id = $2` | 71 | sql = `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id), |
| 85 | err = database.DB.QueryRow(sql, userID, userID).Scan(&uniqueMultiUserRecords, &totalMultiMaps) | 72 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = FALSE AND is_disabled = false), |
| 73 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | ||
| 74 | SELECT | ||
| 75 | host_id, | ||
| 76 | partner_id, | ||
| 77 | MIN(score_count) AS min_score_count | ||
| 78 | FROM records_mp | ||
| 79 | GROUP BY host_id, partner_id, map_id | ||
| 80 | ) AS subquery | ||
| 81 | WHERE host_id = u.steam_id OR partner_id = u.steam_id) | ||
| 82 | FROM records_mp mp JOIN users u ON u.steam_id = mp.host_id OR u.steam_id = mp.partner_id GROUP BY u.steam_id, u.user_name` | ||
| 83 | rows, err = database.DB.Query(sql) | ||
| 84 | if err != nil { | ||
| 85 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 86 | return | ||
| 87 | } | ||
| 88 | for rows.Next() { | ||
| 89 | ranking := models.UserRanking{} | ||
| 90 | var currentCount int | ||
| 91 | var totalCount int | ||
| 92 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) | ||
| 86 | if err != nil { | 93 | if err != nil { |
| 87 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 94 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 88 | return | 95 | return |
| 89 | } | 96 | } |
| 90 | // Has all singleplayer records | 97 | if currentCount != totalCount { |
| 91 | if uniqueMultiUserRecords == totalMultiMaps { | 98 | continue |
| 92 | var ranking models.UserRanking | 99 | } |
| 93 | ranking.UserID = userID | 100 | response.Multiplayer = append(response.Multiplayer, ranking) |
| 94 | ranking.UserName = username | 101 | } |
| 95 | sql := `SELECT DISTINCT map_id, score_count FROM records_mp WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id, score_count` | 102 | // Has both so they are qualified for overall ranking |
| 96 | rows, err := database.DB.Query(sql, userID, userID) | 103 | for _, spRanking := range response.Singleplayer { |
| 97 | if err != nil { | 104 | for _, mpRanking := range response.Multiplayer { |
| 98 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 105 | if spRanking.User.SteamID == mpRanking.User.SteamID { |
| 99 | return | 106 | totalScore := spRanking.TotalScore + mpRanking.TotalScore |
| 100 | } | 107 | overallRanking := models.UserRanking{ |
| 101 | totalScore := 0 | 108 | User: spRanking.User, |
| 102 | var maps []int | 109 | TotalScore: totalScore, |
| 103 | for rows.Next() { | ||
| 104 | var mapID, scoreCount int | ||
| 105 | rows.Scan(&mapID, &scoreCount) | ||
| 106 | if len(maps) != 0 && maps[len(maps)-1] == mapID { | ||
| 107 | continue | ||
| 108 | } | 110 | } |
| 109 | totalScore += scoreCount | 111 | response.Overall = append(response.Overall, overallRanking) |
| 110 | maps = append(maps, mapID) | ||
| 111 | } | 112 | } |
| 112 | ranking.TotalScore = totalScore | ||
| 113 | mpRankings = append(mpRankings, ranking) | ||
| 114 | } | 113 | } |
| 115 | } | 114 | } |
| 115 | sort.Slice(response.Singleplayer, func(i, j int) bool { | ||
| 116 | return response.Singleplayer[i].TotalScore < response.Singleplayer[j].TotalScore | ||
| 117 | }) | ||
| 118 | sort.Slice(response.Multiplayer, func(i, j int) bool { | ||
| 119 | return response.Multiplayer[i].TotalScore < response.Multiplayer[j].TotalScore | ||
| 120 | }) | ||
| 121 | sort.Slice(response.Overall, func(i, j int) bool { | ||
| 122 | return response.Overall[i].TotalScore < response.Overall[j].TotalScore | ||
| 123 | }) | ||
| 116 | c.JSON(http.StatusOK, models.Response{ | 124 | c.JSON(http.StatusOK, models.Response{ |
| 117 | Success: true, | 125 | Success: true, |
| 118 | Message: "Successfully retrieved rankings.", | 126 | Message: "Successfully retrieved rankings.", |
| 119 | Data: models.RankingsResponse{ | 127 | Data: response, |
| 120 | RankingsSP: spRankings, | ||
| 121 | RankingsMP: mpRankings, | ||
| 122 | }, | ||
| 123 | }) | 128 | }) |
| 124 | } | 129 | } |
| 125 | 130 | ||
| @@ -129,14 +134,14 @@ func Rankings(c *gin.Context) { | |||
| 129 | // @Tags search | 134 | // @Tags search |
| 130 | // @Produce json | 135 | // @Produce json |
| 131 | // @Param q query string false "Search user or map name." | 136 | // @Param q query string false "Search user or map name." |
| 132 | // @Success 200 {object} models.Response{data=models.SearchResponse} | 137 | // @Success 200 {object} models.Response{data=SearchResponse} |
| 133 | // @Failure 400 {object} models.Response | 138 | // @Failure 400 {object} models.Response |
| 134 | // @Router /search [get] | 139 | // @Router /search [get] |
| 135 | func SearchWithQuery(c *gin.Context) { | 140 | func SearchWithQuery(c *gin.Context) { |
| 136 | query := c.Query("q") | 141 | query := c.Query("q") |
| 137 | query = strings.ToLower(query) | 142 | query = strings.ToLower(query) |
| 138 | log.Println(query) | 143 | log.Println(query) |
| 139 | var response models.SearchResponse | 144 | var response SearchResponse |
| 140 | // Cache all maps for faster response | 145 | // Cache all maps for faster response |
| 141 | var maps = []models.MapShort{ | 146 | var maps = []models.MapShort{ |
| 142 | {ID: 1, Name: "Container Ride"}, | 147 | {ID: 1, Name: "Container Ride"}, |