diff options
| author | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-08-26 08:53:24 +0300 |
|---|---|---|
| committer | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-08-26 08:53:24 +0300 |
| commit | f1b7589b2936335957a6a1da1eea3d66233ad0ce (patch) | |
| tree | 1975af217c190f5dbdb23b96015cef45206302d4 /backend/handlers/home.go | |
| parent | docs: profile improvement swagger (#51) (diff) | |
| download | lphub-f1b7589b2936335957a6a1da1eea3d66233ad0ce.tar.gz lphub-f1b7589b2936335957a6a1da1eea3d66233ad0ce.tar.bz2 lphub-f1b7589b2936335957a6a1da1eea3d66233ad0ce.zip | |
refactor: reorganizing packages
Former-commit-id: 99410223654c2a5ffc15fdab6ec3e921b5410cba
Diffstat (limited to 'backend/handlers/home.go')
| -rw-r--r-- | backend/handlers/home.go | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/backend/handlers/home.go b/backend/handlers/home.go new file mode 100644 index 0000000..6e9a0df --- /dev/null +++ b/backend/handlers/home.go | |||
| @@ -0,0 +1,294 @@ | |||
| 1 | package handlers | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "log" | ||
| 5 | "net/http" | ||
| 6 | "strings" | ||
| 7 | |||
| 8 | "github.com/gin-gonic/gin" | ||
| 9 | "github.com/pektezol/leastportalshub/backend/database" | ||
| 10 | "github.com/pektezol/leastportalshub/backend/models" | ||
| 11 | ) | ||
| 12 | |||
| 13 | type SearchResponse struct { | ||
| 14 | Players []models.UserShort `json:"players"` | ||
| 15 | Maps []models.MapShort `json:"maps"` | ||
| 16 | } | ||
| 17 | |||
| 18 | type RankingsResponse struct { | ||
| 19 | RankingsSP []models.UserRanking `json:"rankings_sp"` | ||
| 20 | RankingsMP []models.UserRanking `json:"rankings_mp"` | ||
| 21 | } | ||
| 22 | |||
| 23 | func Home(c *gin.Context) { | ||
| 24 | user, exists := c.Get("user") | ||
| 25 | if !exists { | ||
| 26 | c.JSON(200, "no id, not auth") | ||
| 27 | } else { | ||
| 28 | c.JSON(200, gin.H{ | ||
| 29 | "output": user, | ||
| 30 | }) | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | // GET Rankings | ||
| 35 | // | ||
| 36 | // @Description Get rankings of every player. | ||
| 37 | // @Tags rankings | ||
| 38 | // @Produce json | ||
| 39 | // @Success 200 {object} models.Response{data=RankingsResponse} | ||
| 40 | // @Failure 400 {object} models.Response | ||
| 41 | // @Router /rankings [get] | ||
| 42 | func Rankings(c *gin.Context) { | ||
| 43 | rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) | ||
| 44 | if err != nil { | ||
| 45 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 46 | return | ||
| 47 | } | ||
| 48 | var spRankings []models.UserRanking | ||
| 49 | var mpRankings []models.UserRanking | ||
| 50 | for rows.Next() { | ||
| 51 | var userID, username string | ||
| 52 | err := rows.Scan(&userID, &username) | ||
| 53 | if err != nil { | ||
| 54 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 55 | return | ||
| 56 | } | ||
| 57 | // Getting all sp records for each user | ||
| 58 | var uniqueSingleUserRecords, totalSingleMaps int | ||
| 59 | sql := `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps | ||
| 60 | WHERE is_coop = FALSE AND is_disabled = false) FROM records_sp WHERE user_id = $1` | ||
| 61 | err = database.DB.QueryRow(sql, userID).Scan(&uniqueSingleUserRecords, &totalSingleMaps) | ||
| 62 | if err != nil { | ||
| 63 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 64 | return | ||
| 65 | } | ||
| 66 | // Has all singleplayer records | ||
| 67 | if uniqueSingleUserRecords == totalSingleMaps { | ||
| 68 | var ranking models.UserRanking | ||
| 69 | ranking.UserID = userID | ||
| 70 | ranking.UserName = username | ||
| 71 | sql := `SELECT DISTINCT map_id, score_count FROM records_sp WHERE user_id = $1 ORDER BY map_id, score_count` | ||
| 72 | rows, err := database.DB.Query(sql, userID) | ||
| 73 | if err != nil { | ||
| 74 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 75 | return | ||
| 76 | } | ||
| 77 | totalScore := 0 | ||
| 78 | var maps []int | ||
| 79 | for rows.Next() { | ||
| 80 | var mapID, scoreCount int | ||
| 81 | rows.Scan(&mapID, &scoreCount) | ||
| 82 | if len(maps) != 0 && maps[len(maps)-1] == mapID { | ||
| 83 | continue | ||
| 84 | } | ||
| 85 | totalScore += scoreCount | ||
| 86 | maps = append(maps, mapID) | ||
| 87 | } | ||
| 88 | ranking.TotalScore = totalScore | ||
| 89 | spRankings = append(spRankings, ranking) | ||
| 90 | } | ||
| 91 | // Getting all mp records for each user | ||
| 92 | var uniqueMultiUserRecords, totalMultiMaps int | ||
| 93 | sql = `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps | ||
| 94 | WHERE is_coop = TRUE AND is_disabled = false) FROM records_mp WHERE host_id = $1 OR partner_id = $2` | ||
| 95 | err = database.DB.QueryRow(sql, userID, userID).Scan(&uniqueMultiUserRecords, &totalMultiMaps) | ||
| 96 | if err != nil { | ||
| 97 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 98 | return | ||
| 99 | } | ||
| 100 | // Has all singleplayer records | ||
| 101 | if uniqueMultiUserRecords == totalMultiMaps { | ||
| 102 | var ranking models.UserRanking | ||
| 103 | ranking.UserID = userID | ||
| 104 | ranking.UserName = username | ||
| 105 | sql := `SELECT DISTINCT map_id, score_count FROM records_mp WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id, score_count` | ||
| 106 | rows, err := database.DB.Query(sql, userID, userID) | ||
| 107 | if err != nil { | ||
| 108 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 109 | return | ||
| 110 | } | ||
| 111 | totalScore := 0 | ||
| 112 | var maps []int | ||
| 113 | for rows.Next() { | ||
| 114 | var mapID, scoreCount int | ||
| 115 | rows.Scan(&mapID, &scoreCount) | ||
| 116 | if len(maps) != 0 && maps[len(maps)-1] == mapID { | ||
| 117 | continue | ||
| 118 | } | ||
| 119 | totalScore += scoreCount | ||
| 120 | maps = append(maps, mapID) | ||
| 121 | } | ||
| 122 | ranking.TotalScore = totalScore | ||
| 123 | mpRankings = append(mpRankings, ranking) | ||
| 124 | } | ||
| 125 | } | ||
| 126 | c.JSON(http.StatusOK, models.Response{ | ||
| 127 | Success: true, | ||
| 128 | Message: "Successfully retrieved rankings.", | ||
| 129 | Data: RankingsResponse{ | ||
| 130 | RankingsSP: spRankings, | ||
| 131 | RankingsMP: mpRankings, | ||
| 132 | }, | ||
| 133 | }) | ||
| 134 | } | ||
| 135 | |||
| 136 | // GET Search With Query | ||
| 137 | // | ||
| 138 | // @Description Get all user and map data matching to the query. | ||
| 139 | // @Tags search | ||
| 140 | // @Produce json | ||
| 141 | // @Param q query string false "Search user or map name." | ||
| 142 | // @Success 200 {object} models.Response{data=SearchResponse} | ||
| 143 | // @Failure 400 {object} models.Response | ||
| 144 | // @Router /search [get] | ||
| 145 | func SearchWithQuery(c *gin.Context) { | ||
| 146 | query := c.Query("q") | ||
| 147 | query = strings.ToLower(query) | ||
| 148 | log.Println(query) | ||
| 149 | var response SearchResponse | ||
| 150 | // Cache all maps for faster response | ||
| 151 | var maps = []models.MapShort{ | ||
| 152 | {ID: 1, Name: "Container Ride"}, | ||
| 153 | {ID: 2, Name: "Portal Carousel"}, | ||
| 154 | {ID: 3, Name: "Portal Gun"}, | ||
| 155 | {ID: 4, Name: "Smooth Jazz"}, | ||
| 156 | {ID: 5, Name: "Cube Momentum"}, | ||
| 157 | {ID: 6, Name: "Future Starter"}, | ||
| 158 | {ID: 7, Name: "Secret Panel"}, | ||
| 159 | {ID: 8, Name: "Wakeup"}, | ||
| 160 | {ID: 9, Name: "Incinerator"}, | ||
| 161 | {ID: 10, Name: "Laser Intro"}, | ||
| 162 | {ID: 11, Name: "Laser Stairs"}, | ||
| 163 | {ID: 12, Name: "Dual Lasers"}, | ||
| 164 | {ID: 13, Name: "Laser Over Goo"}, | ||
| 165 | {ID: 14, Name: "Catapult Intro"}, | ||
| 166 | {ID: 15, Name: "Trust Fling"}, | ||
| 167 | {ID: 16, Name: "Pit Flings"}, | ||
| 168 | {ID: 17, Name: "Fizzler Intro"}, | ||
| 169 | {ID: 18, Name: "Ceiling Catapult"}, | ||
| 170 | {ID: 19, Name: "Ricochet"}, | ||
| 171 | {ID: 20, Name: "Bridge Intro"}, | ||
| 172 | {ID: 21, Name: "Bridge The Gap"}, | ||
| 173 | {ID: 22, Name: "Turret Intro"}, | ||
| 174 | {ID: 23, Name: "Laser Relays"}, | ||
| 175 | {ID: 24, Name: "Turret Blocker"}, | ||
| 176 | {ID: 25, Name: "Laser vs Turret"}, | ||
| 177 | {ID: 26, Name: "Pull The Rug"}, | ||
| 178 | {ID: 27, Name: "Column Blocker"}, | ||
| 179 | {ID: 28, Name: "Laser Chaining"}, | ||
| 180 | {ID: 29, Name: "Triple Laser"}, | ||
| 181 | {ID: 30, Name: "Jail Break"}, | ||
| 182 | {ID: 31, Name: "Escape"}, | ||
| 183 | {ID: 32, Name: "Turret Factory"}, | ||
| 184 | {ID: 33, Name: "Turret Sabotage"}, | ||
| 185 | {ID: 34, Name: "Neurotoxin Sabotage"}, | ||
| 186 | {ID: 35, Name: "Core"}, | ||
| 187 | {ID: 36, Name: "Underground"}, | ||
| 188 | {ID: 37, Name: "Cave Johnson"}, | ||
| 189 | {ID: 38, Name: "Repulsion Intro"}, | ||
| 190 | {ID: 39, Name: "Bomb Flings"}, | ||
| 191 | {ID: 40, Name: "Crazy Box"}, | ||
| 192 | {ID: 41, Name: "PotatOS"}, | ||
| 193 | {ID: 42, Name: "Propulsion Intro"}, | ||
| 194 | {ID: 43, Name: "Propulsion Flings"}, | ||
| 195 | {ID: 44, Name: "Conversion Intro"}, | ||
| 196 | {ID: 45, Name: "Three Gels"}, | ||
| 197 | {ID: 46, Name: "Test"}, | ||
| 198 | {ID: 47, Name: "Funnel Intro"}, | ||
| 199 | {ID: 48, Name: "Ceiling Button"}, | ||
| 200 | {ID: 49, Name: "Wall Button"}, | ||
| 201 | {ID: 50, Name: "Polarity"}, | ||
| 202 | {ID: 51, Name: "Funnel Catch"}, | ||
| 203 | {ID: 52, Name: "Stop The Box"}, | ||
| 204 | {ID: 53, Name: "Laser Catapult"}, | ||
| 205 | {ID: 54, Name: "Laser Platform"}, | ||
| 206 | {ID: 55, Name: "Propulsion Catch"}, | ||
| 207 | {ID: 56, Name: "Repulsion Polarity"}, | ||
| 208 | {ID: 57, Name: "Finale 1"}, | ||
| 209 | {ID: 58, Name: "Finale 2"}, | ||
| 210 | {ID: 59, Name: "Finale 3"}, | ||
| 211 | {ID: 60, Name: "Finale 4"}, | ||
| 212 | {ID: 61, Name: "Calibration"}, | ||
| 213 | {ID: 62, Name: "Hub"}, | ||
| 214 | {ID: 63, Name: "Doors"}, | ||
| 215 | {ID: 64, Name: "Buttons"}, | ||
| 216 | {ID: 65, Name: "Lasers"}, | ||
| 217 | {ID: 66, Name: "Rat Maze"}, | ||
| 218 | {ID: 67, Name: "Laser Crusher"}, | ||
| 219 | {ID: 68, Name: "Behind The Scenes"}, | ||
| 220 | {ID: 69, Name: "Flings"}, | ||
| 221 | {ID: 70, Name: "Infinifling"}, | ||
| 222 | {ID: 71, Name: "Team Retrieval"}, | ||
| 223 | {ID: 72, Name: "Vertical Flings"}, | ||
| 224 | {ID: 73, Name: "Catapults"}, | ||
| 225 | {ID: 74, Name: "Multifling"}, | ||
| 226 | {ID: 75, Name: "Fling Crushers"}, | ||
| 227 | {ID: 76, Name: "Industrial Fan"}, | ||
| 228 | {ID: 77, Name: "Cooperative Bridges"}, | ||
| 229 | {ID: 78, Name: "Bridge Swap"}, | ||
| 230 | {ID: 79, Name: "Fling Block"}, | ||
| 231 | {ID: 80, Name: "Catapult Block"}, | ||
| 232 | {ID: 81, Name: "Bridge Fling"}, | ||
| 233 | {ID: 82, Name: "Turret Walls"}, | ||
| 234 | {ID: 83, Name: "Turret Assasin"}, | ||
| 235 | {ID: 84, Name: "Bridge Testing"}, | ||
| 236 | {ID: 85, Name: "Cooperative Funnels"}, | ||
| 237 | {ID: 86, Name: "Funnel Drill"}, | ||
| 238 | {ID: 87, Name: "Funnel Catch"}, | ||
| 239 | {ID: 88, Name: "Funnel Laser"}, | ||
| 240 | {ID: 89, Name: "Cooperative Polarity"}, | ||
| 241 | {ID: 90, Name: "Funnel Hop"}, | ||
| 242 | {ID: 91, Name: "Advanced Polarity"}, | ||
| 243 | {ID: 92, Name: "Funnel Maze"}, | ||
| 244 | {ID: 93, Name: "Turret Warehouse"}, | ||
| 245 | {ID: 94, Name: "Repulsion Jumps"}, | ||
| 246 | {ID: 95, Name: "Double Bounce"}, | ||
| 247 | {ID: 96, Name: "Bridge Repulsion"}, | ||
| 248 | {ID: 97, Name: "Wall Repulsion"}, | ||
| 249 | {ID: 98, Name: "Propulsion Crushers"}, | ||
| 250 | {ID: 99, Name: "Turret Ninja"}, | ||
| 251 | {ID: 100, Name: "Propulsion Retrieval"}, | ||
| 252 | {ID: 101, Name: "Vault Entrance"}, | ||
| 253 | {ID: 102, Name: "Seperation"}, | ||
| 254 | {ID: 103, Name: "Triple Axis"}, | ||
| 255 | {ID: 104, Name: "Catapult Catch"}, | ||
| 256 | {ID: 105, Name: "Bridge Gels"}, | ||
| 257 | {ID: 106, Name: "Maintenance"}, | ||
| 258 | {ID: 107, Name: "Bridge Catch"}, | ||
| 259 | {ID: 108, Name: "Double Lift"}, | ||
| 260 | {ID: 109, Name: "Gel Maze"}, | ||
| 261 | {ID: 110, Name: "Crazier Box"}, | ||
| 262 | } | ||
| 263 | var filteredMaps []models.MapShort | ||
| 264 | for _, m := range maps { | ||
| 265 | if strings.Contains(strings.ToLower(m.Name), strings.ToLower(query)) { | ||
| 266 | filteredMaps = append(filteredMaps, m) | ||
| 267 | } | ||
| 268 | } | ||
| 269 | response.Maps = filteredMaps | ||
| 270 | if len(response.Maps) == 0 { | ||
| 271 | response.Maps = []models.MapShort{} | ||
| 272 | } | ||
| 273 | rows, err := database.DB.Query("SELECT steam_id, user_name FROM users WHERE lower(user_name) LIKE $1", "%"+query+"%") | ||
| 274 | if err != nil { | ||
| 275 | log.Fatal(err) | ||
| 276 | } | ||
| 277 | defer rows.Close() | ||
| 278 | for rows.Next() { | ||
| 279 | var user models.UserShort | ||
| 280 | if err := rows.Scan(&user.SteamID, &user.UserName); err != nil { | ||
| 281 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 282 | return | ||
| 283 | } | ||
| 284 | response.Players = append(response.Players, user) | ||
| 285 | } | ||
| 286 | if len(response.Players) == 0 { | ||
| 287 | response.Players = []models.UserShort{} | ||
| 288 | } | ||
| 289 | c.JSON(http.StatusOK, models.Response{ | ||
| 290 | Success: true, | ||
| 291 | Message: "Search successfully retrieved.", | ||
| 292 | Data: response, | ||
| 293 | }) | ||
| 294 | } | ||