diff options
| -rw-r--r-- | backend/handlers/home.go | 48 | ||||
| -rw-r--r-- | backend/handlers/map.go | 2 | ||||
| -rw-r--r-- | backend/handlers/user.go | 304 | ||||
| -rw-r--r-- | backend/models/models.go | 7 | ||||
| -rw-r--r-- | docs/docs.go | 7 | ||||
| -rw-r--r-- | docs/swagger.json | 7 | ||||
| -rw-r--r-- | docs/swagger.yaml | 6 |
7 files changed, 249 insertions, 132 deletions
diff --git a/backend/handlers/home.go b/backend/handlers/home.go index 5863218..16ac993 100644 --- a/backend/handlers/home.go +++ b/backend/handlers/home.go | |||
| @@ -43,8 +43,8 @@ func Rankings(c *gin.Context) { | |||
| 43 | Multiplayer: []models.UserRanking{}, | 43 | Multiplayer: []models.UserRanking{}, |
| 44 | } | 44 | } |
| 45 | // Singleplayer rankings | 45 | // Singleplayer rankings |
| 46 | sql := `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id), | 46 | sql := `SELECT u.steam_id, u.user_name, u.avatar_link, COUNT(DISTINCT map_id), |
| 47 | (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), | 47 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Singleplayer' AND is_disabled = false), |
| 48 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 48 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 49 | SELECT | 49 | SELECT |
| 50 | user_id, | 50 | user_id, |
| @@ -63,7 +63,7 @@ func Rankings(c *gin.Context) { | |||
| 63 | ranking := models.UserRanking{} | 63 | ranking := models.UserRanking{} |
| 64 | var currentCount int | 64 | var currentCount int |
| 65 | var totalCount int | 65 | var totalCount int |
| 66 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) | 66 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, &ranking.User.AvatarLink, ¤tCount, &totalCount, &ranking.TotalScore) |
| 67 | if err != nil { | 67 | if err != nil { |
| 68 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 68 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 69 | return | 69 | return |
| @@ -74,8 +74,8 @@ func Rankings(c *gin.Context) { | |||
| 74 | response.Singleplayer = append(response.Singleplayer, ranking) | 74 | response.Singleplayer = append(response.Singleplayer, ranking) |
| 75 | } | 75 | } |
| 76 | // Multiplayer rankings | 76 | // Multiplayer rankings |
| 77 | sql = `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id), | 77 | sql = `SELECT u.steam_id, u.user_name, u.avatar_link, COUNT(DISTINCT map_id), |
| 78 | (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), | 78 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Cooperative' AND is_disabled = false), |
| 79 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 79 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 80 | SELECT | 80 | SELECT |
| 81 | host_id, | 81 | host_id, |
| @@ -95,7 +95,7 @@ func Rankings(c *gin.Context) { | |||
| 95 | ranking := models.UserRanking{} | 95 | ranking := models.UserRanking{} |
| 96 | var currentCount int | 96 | var currentCount int |
| 97 | var totalCount int | 97 | var totalCount int |
| 98 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, ¤tCount, &totalCount, &ranking.TotalScore) | 98 | err = rows.Scan(&ranking.User.SteamID, &ranking.User.UserName, &ranking.User.AvatarLink, ¤tCount, &totalCount, &ranking.TotalScore) |
| 99 | if err != nil { | 99 | if err != nil { |
| 100 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 100 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 101 | return | 101 | return |
| @@ -121,12 +121,48 @@ func Rankings(c *gin.Context) { | |||
| 121 | sort.Slice(response.Singleplayer, func(i, j int) bool { | 121 | sort.Slice(response.Singleplayer, func(i, j int) bool { |
| 122 | return response.Singleplayer[i].TotalScore < response.Singleplayer[j].TotalScore | 122 | return response.Singleplayer[i].TotalScore < response.Singleplayer[j].TotalScore |
| 123 | }) | 123 | }) |
| 124 | placement := 1 | ||
| 125 | ties := 0 | ||
| 126 | for index := 0; index < len(response.Singleplayer); index++ { | ||
| 127 | if index != 0 && response.Singleplayer[index-1].TotalScore == response.Singleplayer[index].TotalScore { | ||
| 128 | ties++ | ||
| 129 | response.Singleplayer[index].Placement = placement - ties | ||
| 130 | } else { | ||
| 131 | ties = 0 | ||
| 132 | response.Singleplayer[index].Placement = placement | ||
| 133 | } | ||
| 134 | placement++ | ||
| 135 | } | ||
| 124 | sort.Slice(response.Multiplayer, func(i, j int) bool { | 136 | sort.Slice(response.Multiplayer, func(i, j int) bool { |
| 125 | return response.Multiplayer[i].TotalScore < response.Multiplayer[j].TotalScore | 137 | return response.Multiplayer[i].TotalScore < response.Multiplayer[j].TotalScore |
| 126 | }) | 138 | }) |
| 139 | placement = 1 | ||
| 140 | ties = 0 | ||
| 141 | for index := 0; index < len(response.Multiplayer); index++ { | ||
| 142 | if index != 0 && response.Multiplayer[index-1].TotalScore == response.Multiplayer[index].TotalScore { | ||
| 143 | ties++ | ||
| 144 | response.Multiplayer[index].Placement = placement - ties | ||
| 145 | } else { | ||
| 146 | ties = 0 | ||
| 147 | response.Multiplayer[index].Placement = placement | ||
| 148 | } | ||
| 149 | placement++ | ||
| 150 | } | ||
| 127 | sort.Slice(response.Overall, func(i, j int) bool { | 151 | sort.Slice(response.Overall, func(i, j int) bool { |
| 128 | return response.Overall[i].TotalScore < response.Overall[j].TotalScore | 152 | return response.Overall[i].TotalScore < response.Overall[j].TotalScore |
| 129 | }) | 153 | }) |
| 154 | placement = 1 | ||
| 155 | ties = 0 | ||
| 156 | for index := 0; index < len(response.Overall); index++ { | ||
| 157 | if index != 0 && response.Overall[index-1].TotalScore == response.Overall[index].TotalScore { | ||
| 158 | ties++ | ||
| 159 | response.Overall[index].Placement = placement - ties | ||
| 160 | } else { | ||
| 161 | ties = 0 | ||
| 162 | response.Overall[index].Placement = placement | ||
| 163 | } | ||
| 164 | placement++ | ||
| 165 | } | ||
| 130 | c.JSON(http.StatusOK, models.Response{ | 166 | c.JSON(http.StatusOK, models.Response{ |
| 131 | Success: true, | 167 | Success: true, |
| 132 | Message: "Successfully retrieved rankings.", | 168 | Message: "Successfully retrieved rankings.", |
diff --git a/backend/handlers/map.go b/backend/handlers/map.go index faccee4..c0776d1 100644 --- a/backend/handlers/map.go +++ b/backend/handlers/map.go | |||
| @@ -228,6 +228,7 @@ func FetchMapLeaderboards(c *gin.Context) { | |||
| 228 | ties++ | 228 | ties++ |
| 229 | record.Placement = placement - ties | 229 | record.Placement = placement - ties |
| 230 | } else { | 230 | } else { |
| 231 | ties = 0 | ||
| 231 | record.Placement = placement | 232 | record.Placement = placement |
| 232 | } | 233 | } |
| 233 | records = append(records, record) | 234 | records = append(records, record) |
| @@ -278,6 +279,7 @@ func FetchMapLeaderboards(c *gin.Context) { | |||
| 278 | ties++ | 279 | ties++ |
| 279 | record.Placement = placement - ties | 280 | record.Placement = placement - ties |
| 280 | } else { | 281 | } else { |
| 282 | ties = 0 | ||
| 281 | record.Placement = placement | 283 | record.Placement = placement |
| 282 | } | 284 | } |
| 283 | records = append(records, record) | 285 | records = append(records, record) |
diff --git a/backend/handlers/user.go b/backend/handlers/user.go index f04145e..777d60c 100644 --- a/backend/handlers/user.go +++ b/backend/handlers/user.go | |||
| @@ -132,7 +132,7 @@ func Profile(c *gin.Context) { | |||
| 132 | rankings.Overall.CompletionCount = rankings.Singleplayer.CompletionCount + rankings.Cooperative.CompletionCount | 132 | rankings.Overall.CompletionCount = rankings.Singleplayer.CompletionCount + rankings.Cooperative.CompletionCount |
| 133 | // Get user ranking placement for singleplayer | 133 | // Get user ranking placement for singleplayer |
| 134 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), | 134 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), |
| 135 | (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), | 135 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Singleplayer' AND maps.is_disabled = false), |
| 136 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 136 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 137 | SELECT user_id, MIN(score_count) AS min_score_count FROM records_sp GROUP BY user_id, map_id) AS subquery WHERE user_id = u.steam_id) | 137 | SELECT user_id, MIN(score_count) AS min_score_count FROM records_sp GROUP BY user_id, map_id) AS subquery WHERE user_id = u.steam_id) |
| 138 | FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name | 138 | FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name |
| @@ -166,11 +166,11 @@ func Profile(c *gin.Context) { | |||
| 166 | } | 166 | } |
| 167 | // Get user ranking placement for multiplayer | 167 | // Get user ranking placement for multiplayer |
| 168 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), | 168 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), |
| 169 | (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), | 169 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Cooperative' AND is_disabled = false), |
| 170 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 170 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 171 | SELECT host_id, partner_id, MIN(score_count) AS min_score_count FROM records_mp GROUP BY host_id, partner_id, map_id) AS subquery WHERE host_id = u.steam_id OR partner_id = u.steam_id) | 171 | SELECT host_id, partner_id, MIN(score_count) AS min_score_count FROM records_mp GROUP BY host_id, partner_id, map_id) AS subquery WHERE host_id = u.steam_id OR partner_id = u.steam_id) |
| 172 | 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 | 172 | 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 |
| 173 | HAVING COUNT(DISTINCT map_id) = (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) | 173 | HAVING COUNT(DISTINCT map_id) = (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = true AND is_disabled = false) |
| 174 | ORDER BY total_min_score_count ASC;` | 174 | ORDER BY total_min_score_count ASC;` |
| 175 | rows, err = database.DB.Query(sql) | 175 | rows, err = database.DB.Query(sql) |
| 176 | if err != nil { | 176 | if err != nil { |
| @@ -198,61 +198,96 @@ func Profile(c *gin.Context) { | |||
| 198 | } | 198 | } |
| 199 | rankings.Cooperative.Rank = placement | 199 | rankings.Cooperative.Rank = placement |
| 200 | } | 200 | } |
| 201 | // TODO: Get user ranking placement for overall if they qualify | 201 | // Get user ranking placement for overall if they qualify |
| 202 | // if (rankings.Singleplayer.Rank != 0) && (rankings.Cooperative.Rank != 0) { | 202 | if rankings.Singleplayer.Rank != 0 && rankings.Cooperative.Rank != 0 { |
| 203 | // sql = `SELECT steam_id, SUM(total_min_score_count) AS total_score | 203 | sql = `WITH user_sp AS ( |
| 204 | // FROM ( | 204 | SELECT u.steam_id, |
| 205 | // SELECT u.steam_id, | 205 | SUM(subquery.min_score_count) AS total_min_score_count |
| 206 | // (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 206 | FROM users u |
| 207 | // SELECT | 207 | LEFT JOIN ( |
| 208 | // user_id, | 208 | SELECT user_id, map_id, MIN(score_count) AS min_score_count |
| 209 | // MIN(score_count) AS min_score_count | 209 | FROM records_sp |
| 210 | // FROM records_sp | 210 | GROUP BY user_id, map_id |
| 211 | // GROUP BY user_id, map_id | 211 | ) AS subquery ON subquery.user_id = u.steam_id |
| 212 | // ) AS subquery | 212 | WHERE u.steam_id IN ( |
| 213 | // WHERE user_id = u.steam_id) AS total_min_score_count | 213 | SELECT user_id |
| 214 | // FROM records_sp sp | 214 | FROM records_sp sp |
| 215 | // JOIN users u ON u.steam_id = sp.user_id | 215 | JOIN maps m ON sp.map_id = m.id |
| 216 | // UNION ALL | 216 | JOIN games g ON m.game_id = g.id |
| 217 | // SELECT u.steam_id, | 217 | WHERE g.is_coop = FALSE AND m.is_disabled = FALSE |
| 218 | // (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 218 | GROUP BY user_id |
| 219 | // SELECT | 219 | HAVING COUNT(DISTINCT sp.map_id) = ( |
| 220 | // host_id, | 220 | SELECT COUNT(maps.name) |
| 221 | // partner_id, | 221 | FROM maps |
| 222 | // MIN(score_count) AS min_score_count | 222 | INNER JOIN games g ON maps.game_id = g.id |
| 223 | // FROM records_mp | 223 | WHERE g.is_coop = FALSE AND maps.is_disabled = FALSE |
| 224 | // GROUP BY host_id, partner_id, map_id | 224 | ) |
| 225 | // ) AS subquery | 225 | ) |
| 226 | // WHERE host_id = u.steam_id OR partner_id = u.steam_id) AS total_min_score_count | 226 | GROUP BY u.steam_id |
| 227 | // FROM records_mp mp | 227 | ), user_mp AS ( |
| 228 | // JOIN users u ON u.steam_id = mp.host_id OR u.steam_id = mp.partner_id | 228 | SELECT u.steam_id, |
| 229 | // ) AS combined_scores | 229 | SUM(subquery.min_score_count) AS total_min_score_count |
| 230 | // GROUP BY steam_id ORDER BY total_score ASC;` | 230 | FROM users u |
| 231 | // rows, err = database.DB.Query(sql) | 231 | LEFT JOIN ( |
| 232 | // if err != nil { | 232 | SELECT host_id, partner_id, map_id, MIN(score_count) AS min_score_count |
| 233 | // c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 233 | FROM records_mp |
| 234 | // return | 234 | GROUP BY host_id, partner_id, map_id |
| 235 | // } | 235 | ) AS subquery ON subquery.host_id = u.steam_id OR subquery.partner_id = u.steam_id |
| 236 | // placement = 1 | 236 | WHERE u.steam_id IN ( |
| 237 | // for rows.Next() { | 237 | SELECT host_id |
| 238 | // var steamID string | 238 | FROM records_mp mp |
| 239 | // var userPortalCount int | 239 | JOIN maps m ON mp.map_id = m.id |
| 240 | // err = rows.Scan(&steamID, &userPortalCount) | 240 | JOIN games g ON m.game_id = g.id |
| 241 | // if err != nil { | 241 | WHERE g.is_coop = TRUE AND m.is_disabled = FALSE |
| 242 | // c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 242 | GROUP BY host_id |
| 243 | // return | 243 | HAVING COUNT(DISTINCT mp.map_id) = ( |
| 244 | // } | 244 | SELECT COUNT(maps.name) |
| 245 | // if completionCount != totalCount { | 245 | FROM maps |
| 246 | // placement++ | 246 | INNER JOIN games g ON maps.game_id = g.id |
| 247 | // continue | 247 | WHERE g.is_coop = TRUE AND maps.is_disabled = FALSE |
| 248 | // } | 248 | ) |
| 249 | // if steamID != user.(models.User).SteamID { | 249 | UNION |
| 250 | // placement++ | 250 | SELECT partner_id |
| 251 | // continue | 251 | FROM records_mp mp |
| 252 | // } | 252 | JOIN maps m ON mp.map_id = m.id |
| 253 | // rankings.Cooperative.Rank = placement | 253 | JOIN games g ON m.game_id = g.id |
| 254 | // } | 254 | WHERE g.is_coop = TRUE AND m.is_disabled = FALSE |
| 255 | // } | 255 | GROUP BY partner_id |
| 256 | HAVING COUNT(DISTINCT mp.map_id) = ( | ||
| 257 | SELECT COUNT(maps.name) | ||
| 258 | FROM maps | ||
| 259 | INNER JOIN games g ON maps.game_id = g.id | ||
| 260 | WHERE g.is_coop = TRUE AND maps.is_disabled = FALSE | ||
| 261 | ) | ||
| 262 | ) | ||
| 263 | GROUP BY u.steam_id | ||
| 264 | ) | ||
| 265 | SELECT COALESCE(sp.steam_id, mp.steam_id) AS steam_id, | ||
| 266 | COALESCE(sp.total_min_score_count, 0) + COALESCE(mp.total_min_score_count, 0) AS overall_total_min_score_count | ||
| 267 | FROM user_sp sp | ||
| 268 | INNER JOIN user_mp mp ON sp.steam_id = mp.steam_id | ||
| 269 | ORDER BY overall_total_min_score_count ASC;` | ||
| 270 | rows, err = database.DB.Query(sql) | ||
| 271 | if err != nil { | ||
| 272 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 273 | return | ||
| 274 | } | ||
| 275 | placement = 1 | ||
| 276 | for rows.Next() { | ||
| 277 | var steamID string | ||
| 278 | var userPortalCount int | ||
| 279 | err = rows.Scan(&steamID, &userPortalCount) | ||
| 280 | if err != nil { | ||
| 281 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 282 | return | ||
| 283 | } | ||
| 284 | if steamID != user.(models.User).SteamID { | ||
| 285 | placement++ | ||
| 286 | continue | ||
| 287 | } | ||
| 288 | rankings.Overall.Rank = placement | ||
| 289 | } | ||
| 290 | } | ||
| 256 | records := []ProfileRecords{} | 291 | records := []ProfileRecords{} |
| 257 | // Get singleplayer records | 292 | // Get singleplayer records |
| 258 | sql = `SELECT m.game_id, m.chapter_id, sp.map_id, m."name", (SELECT mr.score_count FROM map_routes mr WHERE mr.map_id = sp.map_id ORDER BY mr.score_count ASC LIMIT 1) AS wr_count, sp.score_count, sp.score_time, sp.demo_id, sp.record_date | 293 | sql = `SELECT m.game_id, m.chapter_id, sp.map_id, m."name", (SELECT mr.score_count FROM map_routes mr WHERE mr.map_id = sp.map_id ORDER BY mr.score_count ASC LIMIT 1) AS wr_count, sp.score_count, sp.score_time, sp.demo_id, sp.record_date |
| @@ -419,7 +454,7 @@ func FetchUser(c *gin.Context) { | |||
| 419 | rankings.Overall.CompletionCount = rankings.Singleplayer.CompletionCount + rankings.Cooperative.CompletionCount | 454 | rankings.Overall.CompletionCount = rankings.Singleplayer.CompletionCount + rankings.Cooperative.CompletionCount |
| 420 | // Get user ranking placement for singleplayer | 455 | // Get user ranking placement for singleplayer |
| 421 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), | 456 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), |
| 422 | (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), | 457 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Singleplayer' AND maps.is_disabled = false), |
| 423 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 458 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 424 | SELECT user_id, MIN(score_count) AS min_score_count FROM records_sp GROUP BY user_id, map_id) AS subquery WHERE user_id = u.steam_id) | 459 | SELECT user_id, MIN(score_count) AS min_score_count FROM records_sp GROUP BY user_id, map_id) AS subquery WHERE user_id = u.steam_id) |
| 425 | FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name | 460 | FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name |
| @@ -453,11 +488,11 @@ func FetchUser(c *gin.Context) { | |||
| 453 | } | 488 | } |
| 454 | // Get user ranking placement for multiplayer | 489 | // Get user ranking placement for multiplayer |
| 455 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), | 490 | sql = `SELECT u.steam_id, COUNT(DISTINCT map_id), |
| 456 | (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), | 491 | (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g."name" = 'Portal 2 - Cooperative' AND is_disabled = false), |
| 457 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 492 | (SELECT SUM(min_score_count) AS total_min_score_count FROM ( |
| 458 | SELECT host_id, partner_id, MIN(score_count) AS min_score_count FROM records_mp GROUP BY host_id, partner_id, map_id) AS subquery WHERE host_id = u.steam_id OR partner_id = u.steam_id) | 493 | SELECT host_id, partner_id, MIN(score_count) AS min_score_count FROM records_mp GROUP BY host_id, partner_id, map_id) AS subquery WHERE host_id = u.steam_id OR partner_id = u.steam_id) |
| 459 | 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 | 494 | 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 |
| 460 | HAVING COUNT(DISTINCT map_id) = (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) | 495 | HAVING COUNT(DISTINCT map_id) = (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = true AND is_disabled = false) |
| 461 | ORDER BY total_min_score_count ASC;` | 496 | ORDER BY total_min_score_count ASC;` |
| 462 | rows, err = database.DB.Query(sql) | 497 | rows, err = database.DB.Query(sql) |
| 463 | if err != nil { | 498 | if err != nil { |
| @@ -485,61 +520,96 @@ func FetchUser(c *gin.Context) { | |||
| 485 | } | 520 | } |
| 486 | rankings.Cooperative.Rank = placement | 521 | rankings.Cooperative.Rank = placement |
| 487 | } | 522 | } |
| 488 | // TODO: Get user ranking placement for overall if they qualify | 523 | // Get user ranking placement for overall if they qualify |
| 489 | // if (rankings.Singleplayer.Rank != 0) && (rankings.Cooperative.Rank != 0) { | 524 | if rankings.Singleplayer.Rank != 0 && rankings.Cooperative.Rank != 0 { |
| 490 | // sql = `SELECT steam_id, SUM(total_min_score_count) AS total_score | 525 | sql = `WITH user_sp AS ( |
| 491 | // FROM ( | 526 | SELECT u.steam_id, |
| 492 | // SELECT u.steam_id, | 527 | SUM(subquery.min_score_count) AS total_min_score_count |
| 493 | // (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 528 | FROM users u |
| 494 | // SELECT | 529 | LEFT JOIN ( |
| 495 | // user_id, | 530 | SELECT user_id, map_id, MIN(score_count) AS min_score_count |
| 496 | // MIN(score_count) AS min_score_count | 531 | FROM records_sp |
| 497 | // FROM records_sp | 532 | GROUP BY user_id, map_id |
| 498 | // GROUP BY user_id, map_id | 533 | ) AS subquery ON subquery.user_id = u.steam_id |
| 499 | // ) AS subquery | 534 | WHERE u.steam_id IN ( |
| 500 | // WHERE user_id = u.steam_id) AS total_min_score_count | 535 | SELECT user_id |
| 501 | // FROM records_sp sp | 536 | FROM records_sp sp |
| 502 | // JOIN users u ON u.steam_id = sp.user_id | 537 | JOIN maps m ON sp.map_id = m.id |
| 503 | // UNION ALL | 538 | JOIN games g ON m.game_id = g.id |
| 504 | // SELECT u.steam_id, | 539 | WHERE g.is_coop = FALSE AND m.is_disabled = FALSE |
| 505 | // (SELECT SUM(min_score_count) AS total_min_score_count FROM ( | 540 | GROUP BY user_id |
| 506 | // SELECT | 541 | HAVING COUNT(DISTINCT sp.map_id) = ( |
| 507 | // host_id, | 542 | SELECT COUNT(maps.name) |
| 508 | // partner_id, | 543 | FROM maps |
| 509 | // MIN(score_count) AS min_score_count | 544 | INNER JOIN games g ON maps.game_id = g.id |
| 510 | // FROM records_mp | 545 | WHERE g.is_coop = FALSE AND maps.is_disabled = FALSE |
| 511 | // GROUP BY host_id, partner_id, map_id | 546 | ) |
| 512 | // ) AS subquery | 547 | ) |
| 513 | // WHERE host_id = u.steam_id OR partner_id = u.steam_id) AS total_min_score_count | 548 | GROUP BY u.steam_id |
| 514 | // FROM records_mp mp | 549 | ), user_mp AS ( |
| 515 | // JOIN users u ON u.steam_id = mp.host_id OR u.steam_id = mp.partner_id | 550 | SELECT u.steam_id, |
| 516 | // ) AS combined_scores | 551 | SUM(subquery.min_score_count) AS total_min_score_count |
| 517 | // GROUP BY steam_id ORDER BY total_score ASC;` | 552 | FROM users u |
| 518 | // rows, err = database.DB.Query(sql) | 553 | LEFT JOIN ( |
| 519 | // if err != nil { | 554 | SELECT host_id, partner_id, map_id, MIN(score_count) AS min_score_count |
| 520 | // c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 555 | FROM records_mp |
| 521 | // return | 556 | GROUP BY host_id, partner_id, map_id |
| 522 | // } | 557 | ) AS subquery ON subquery.host_id = u.steam_id OR subquery.partner_id = u.steam_id |
| 523 | // placement = 1 | 558 | WHERE u.steam_id IN ( |
| 524 | // for rows.Next() { | 559 | SELECT host_id |
| 525 | // var steamID string | 560 | FROM records_mp mp |
| 526 | // var userPortalCount int | 561 | JOIN maps m ON mp.map_id = m.id |
| 527 | // err = rows.Scan(&steamID, &userPortalCount) | 562 | JOIN games g ON m.game_id = g.id |
| 528 | // if err != nil { | 563 | WHERE g.is_coop = TRUE AND m.is_disabled = FALSE |
| 529 | // c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 564 | GROUP BY host_id |
| 530 | // return | 565 | HAVING COUNT(DISTINCT mp.map_id) = ( |
| 531 | // } | 566 | SELECT COUNT(maps.name) |
| 532 | // if completionCount != totalCount { | 567 | FROM maps |
| 533 | // placement++ | 568 | INNER JOIN games g ON maps.game_id = g.id |
| 534 | // continue | 569 | WHERE g.is_coop = TRUE AND maps.is_disabled = FALSE |
| 535 | // } | 570 | ) |
| 536 | // if steamID != user.SteamID { | 571 | UNION |
| 537 | // placement++ | 572 | SELECT partner_id |
| 538 | // continue | 573 | FROM records_mp mp |
| 539 | // } | 574 | JOIN maps m ON mp.map_id = m.id |
| 540 | // rankings.Cooperative.Rank = placement | 575 | JOIN games g ON m.game_id = g.id |
| 541 | // } | 576 | WHERE g.is_coop = TRUE AND m.is_disabled = FALSE |
| 542 | // } | 577 | GROUP BY partner_id |
| 578 | HAVING COUNT(DISTINCT mp.map_id) = ( | ||
| 579 | SELECT COUNT(maps.name) | ||
| 580 | FROM maps | ||
| 581 | INNER JOIN games g ON maps.game_id = g.id | ||
| 582 | WHERE g.is_coop = TRUE AND maps.is_disabled = FALSE | ||
| 583 | ) | ||
| 584 | ) | ||
| 585 | GROUP BY u.steam_id | ||
| 586 | ) | ||
| 587 | SELECT COALESCE(sp.steam_id, mp.steam_id) AS steam_id, | ||
| 588 | COALESCE(sp.total_min_score_count, 0) + COALESCE(mp.total_min_score_count, 0) AS overall_total_min_score_count | ||
| 589 | FROM user_sp sp | ||
| 590 | INNER JOIN user_mp mp ON sp.steam_id = mp.steam_id | ||
| 591 | ORDER BY overall_total_min_score_count ASC;` | ||
| 592 | rows, err = database.DB.Query(sql) | ||
| 593 | if err != nil { | ||
| 594 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 595 | return | ||
| 596 | } | ||
| 597 | placement = 1 | ||
| 598 | for rows.Next() { | ||
| 599 | var steamID string | ||
| 600 | var userPortalCount int | ||
| 601 | err = rows.Scan(&steamID, &userPortalCount) | ||
| 602 | if err != nil { | ||
| 603 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 604 | return | ||
| 605 | } | ||
| 606 | if steamID != user.SteamID { | ||
| 607 | placement++ | ||
| 608 | continue | ||
| 609 | } | ||
| 610 | rankings.Overall.Rank = placement | ||
| 611 | } | ||
| 612 | } | ||
| 543 | records := []ProfileRecords{} | 613 | records := []ProfileRecords{} |
| 544 | // Get singleplayer records | 614 | // Get singleplayer records |
| 545 | sql = `SELECT m.game_id, m.chapter_id, sp.map_id, m."name", (SELECT mr.score_count FROM map_routes mr WHERE mr.map_id = sp.map_id ORDER BY mr.score_count ASC LIMIT 1) AS wr_count, sp.score_count, sp.score_time, sp.demo_id, sp.record_date | 615 | sql = `SELECT m.game_id, m.chapter_id, sp.map_id, m."name", (SELECT mr.score_count FROM map_routes mr WHERE mr.map_id = sp.map_id ORDER BY mr.score_count ASC LIMIT 1) AS wr_count, sp.score_count, sp.score_time, sp.demo_id, sp.record_date |
| @@ -609,7 +679,7 @@ func FetchUser(c *gin.Context) { | |||
| 609 | Success: true, | 679 | Success: true, |
| 610 | Message: "Successfully retrieved user scores.", | 680 | Message: "Successfully retrieved user scores.", |
| 611 | Data: ProfileResponse{ | 681 | Data: ProfileResponse{ |
| 612 | Profile: true, | 682 | Profile: false, |
| 613 | SteamID: user.SteamID, | 683 | SteamID: user.SteamID, |
| 614 | UserName: user.UserName, | 684 | UserName: user.UserName, |
| 615 | AvatarLink: user.AvatarLink, | 685 | AvatarLink: user.AvatarLink, |
diff --git a/backend/models/models.go b/backend/models/models.go index e5d92fb..8e16c1c 100644 --- a/backend/models/models.go +++ b/backend/models/models.go | |||
| @@ -78,8 +78,9 @@ type MapRecords struct { | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | type UserRanking struct { | 80 | type UserRanking struct { |
| 81 | User UserShort `json:"user"` | 81 | Placement int `json:"placement"` |
| 82 | TotalScore int `json:"total_score"` | 82 | User UserShortWithAvatar `json:"user"` |
| 83 | TotalScore int `json:"total_score"` | ||
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | type Game struct { | 86 | type Game struct { |
| @@ -105,7 +106,7 @@ type Title struct { | |||
| 105 | 106 | ||
| 106 | type Links struct { | 107 | type Links struct { |
| 107 | P2SR string `json:"p2sr"` | 108 | P2SR string `json:"p2sr"` |
| 108 | Steam string `json:"stream"` | 109 | Steam string `json:"steam"` |
| 109 | YouTube string `json:"youtube"` | 110 | YouTube string `json:"youtube"` |
| 110 | Twitch string `json:"twitch"` | 111 | Twitch string `json:"twitch"` |
| 111 | } | 112 | } |
diff --git a/docs/docs.go b/docs/docs.go index 5a107c1..bb2738c 100644 --- a/docs/docs.go +++ b/docs/docs.go | |||
| @@ -1794,7 +1794,7 @@ const docTemplate = `{ | |||
| 1794 | "p2sr": { | 1794 | "p2sr": { |
| 1795 | "type": "string" | 1795 | "type": "string" |
| 1796 | }, | 1796 | }, |
| 1797 | "stream": { | 1797 | "steam": { |
| 1798 | "type": "string" | 1798 | "type": "string" |
| 1799 | }, | 1799 | }, |
| 1800 | "twitch": { | 1800 | "twitch": { |
| @@ -1933,11 +1933,14 @@ const docTemplate = `{ | |||
| 1933 | "models.UserRanking": { | 1933 | "models.UserRanking": { |
| 1934 | "type": "object", | 1934 | "type": "object", |
| 1935 | "properties": { | 1935 | "properties": { |
| 1936 | "placement": { | ||
| 1937 | "type": "integer" | ||
| 1938 | }, | ||
| 1936 | "total_score": { | 1939 | "total_score": { |
| 1937 | "type": "integer" | 1940 | "type": "integer" |
| 1938 | }, | 1941 | }, |
| 1939 | "user": { | 1942 | "user": { |
| 1940 | "$ref": "#/definitions/models.UserShort" | 1943 | "$ref": "#/definitions/models.UserShortWithAvatar" |
| 1941 | } | 1944 | } |
| 1942 | } | 1945 | } |
| 1943 | }, | 1946 | }, |
diff --git a/docs/swagger.json b/docs/swagger.json index d118ce7..ffc30a9 100644 --- a/docs/swagger.json +++ b/docs/swagger.json | |||
| @@ -1787,7 +1787,7 @@ | |||
| 1787 | "p2sr": { | 1787 | "p2sr": { |
| 1788 | "type": "string" | 1788 | "type": "string" |
| 1789 | }, | 1789 | }, |
| 1790 | "stream": { | 1790 | "steam": { |
| 1791 | "type": "string" | 1791 | "type": "string" |
| 1792 | }, | 1792 | }, |
| 1793 | "twitch": { | 1793 | "twitch": { |
| @@ -1926,11 +1926,14 @@ | |||
| 1926 | "models.UserRanking": { | 1926 | "models.UserRanking": { |
| 1927 | "type": "object", | 1927 | "type": "object", |
| 1928 | "properties": { | 1928 | "properties": { |
| 1929 | "placement": { | ||
| 1930 | "type": "integer" | ||
| 1931 | }, | ||
| 1929 | "total_score": { | 1932 | "total_score": { |
| 1930 | "type": "integer" | 1933 | "type": "integer" |
| 1931 | }, | 1934 | }, |
| 1932 | "user": { | 1935 | "user": { |
| 1933 | "$ref": "#/definitions/models.UserShort" | 1936 | "$ref": "#/definitions/models.UserShortWithAvatar" |
| 1934 | } | 1937 | } |
| 1935 | } | 1938 | } |
| 1936 | }, | 1939 | }, |
diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 3e83fe8..6cd460f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml | |||
| @@ -351,7 +351,7 @@ definitions: | |||
| 351 | properties: | 351 | properties: |
| 352 | p2sr: | 352 | p2sr: |
| 353 | type: string | 353 | type: string |
| 354 | stream: | 354 | steam: |
| 355 | type: string | 355 | type: string |
| 356 | twitch: | 356 | twitch: |
| 357 | type: string | 357 | type: string |
| @@ -441,10 +441,12 @@ definitions: | |||
| 441 | type: object | 441 | type: object |
| 442 | models.UserRanking: | 442 | models.UserRanking: |
| 443 | properties: | 443 | properties: |
| 444 | placement: | ||
| 445 | type: integer | ||
| 444 | total_score: | 446 | total_score: |
| 445 | type: integer | 447 | type: integer |
| 446 | user: | 448 | user: |
| 447 | $ref: '#/definitions/models.UserShort' | 449 | $ref: '#/definitions/models.UserShortWithAvatar' |
| 448 | type: object | 450 | type: object |
| 449 | models.UserShort: | 451 | models.UserShort: |
| 450 | properties: | 452 | properties: |