aboutsummaryrefslogtreecommitdiff
path: root/backend/controllers/mapController.go
diff options
context:
space:
mode:
authorNidboj132 <lol2s@vp.plm>2023-09-05 18:23:11 +0200
committerNidboj132 <lol2s@vp.plm>2023-09-05 18:23:11 +0200
commit3869cb67351ccf3bc45b076f31afdc7133292c39 (patch)
treedc03341e147dde0964bf6be84b14e13424c647b7 /backend/controllers/mapController.go
parentadded graph and fixed some css (diff)
parentfix: create map summary, why the fuck does this have to be a pointer integer?? (diff)
downloadlphub-3869cb67351ccf3bc45b076f31afdc7133292c39.tar.gz
lphub-3869cb67351ccf3bc45b076f31afdc7133292c39.tar.bz2
lphub-3869cb67351ccf3bc45b076f31afdc7133292c39.zip
Merge branch 'main' of https://github.com/pektezol/LeastPortalsHub
Former-commit-id: 221385f463b7f5b0fc43a093b2c7c46e68d46d68
Diffstat (limited to 'backend/controllers/mapController.go')
-rw-r--r--backend/controllers/mapController.go299
1 files changed, 0 insertions, 299 deletions
diff --git a/backend/controllers/mapController.go b/backend/controllers/mapController.go
deleted file mode 100644
index ebd65dd..0000000
--- a/backend/controllers/mapController.go
+++ /dev/null
@@ -1,299 +0,0 @@
1package controllers
2
3import (
4 "net/http"
5 "strconv"
6
7 "github.com/gin-gonic/gin"
8 "github.com/pektezol/leastportalshub/backend/database"
9 "github.com/pektezol/leastportalshub/backend/models"
10)
11
12// GET Map Summary
13//
14// @Description Get map summary with specified id.
15// @Tags maps
16// @Produce json
17// @Param id path int true "Map ID"
18// @Success 200 {object} models.Response{data=models.MapSummaryResponse}
19// @Failure 400 {object} models.Response
20// @Router /maps/{id}/summary [get]
21func FetchMapSummary(c *gin.Context) {
22 id := c.Param("id")
23 response := models.MapSummaryResponse{Map: models.Map{}, Summary: models.MapSummary{Routes: []models.MapRoute{}}}
24 intID, err := strconv.Atoi(id)
25 if err != nil {
26 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
27 return
28 }
29 // Get map data
30 response.Map.ID = intID
31 sql := `SELECT m.id, g.name, c.name, m.name, m.image, g.is_coop
32 FROM maps m
33 INNER JOIN games g ON m.game_id = g.id
34 INNER JOIN chapters c ON m.chapter_id = c.id
35 WHERE m.id = $1`
36 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)
37 if err != nil {
38 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
39 return
40 }
41 // Get map routes and histories
42 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
43 INNER JOIN categories c ON r.category_id = c.id
44 INNER JOIN map_history h ON r.map_id = h.map_id AND r.category_id = h.category_id
45 LEFT JOIN map_ratings rt ON r.map_id = rt.map_id AND r.category_id = rt.category_id
46 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
47 ORDER BY h.record_date ASC;`
48 rows, err := database.DB.Query(sql, id)
49 if err != nil {
50 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
51 return
52 }
53 for rows.Next() {
54 route := models.MapRoute{Category: models.Category{}, History: models.MapHistory{}}
55 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)
56 if err != nil {
57 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
58 return
59 }
60 response.Summary.Routes = append(response.Summary.Routes, route)
61 }
62 // Return response
63 c.JSON(http.StatusOK, models.Response{
64 Success: true,
65 Message: "Successfully retrieved map summary.",
66 Data: response,
67 })
68}
69
70// GET Map Leaderboards
71//
72// @Description Get map leaderboards with specified id.
73// @Tags maps
74// @Produce json
75// @Param id path int true "Map ID"
76// @Success 200 {object} models.Response{data=models.Map{data=models.MapRecords}}
77// @Failure 400 {object} models.Response
78// @Router /maps/{id}/leaderboards [get]
79func FetchMapLeaderboards(c *gin.Context) {
80 // TODO: make new response type
81 id := c.Param("id")
82 // Get map data
83 var mapData models.Map
84 var mapRecordsData models.MapRecords
85 var isDisabled bool
86 intID, err := strconv.Atoi(id)
87 if err != nil {
88 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
89 return
90 }
91 mapData.ID = intID
92 sql := `SELECT g.name, c.name, m.name, is_disabled, m.image
93 FROM maps m
94 INNER JOIN games g ON m.game_id = g.id
95 INNER JOIN chapters c ON m.chapter_id = c.id
96 WHERE m.id = $1`
97 err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled, &mapData.Image)
98 if err != nil {
99 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
100 return
101 }
102 if isDisabled {
103 c.JSON(http.StatusBadRequest, models.ErrorResponse("Map is not available for competitive boards."))
104 return
105 }
106 // TODO: avatar and names for host & partner
107 // Get records from the map
108 if mapData.GameName == "Portal 2 - Cooperative" {
109 var records []models.RecordMP
110 sql = `SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date
111 FROM (
112 SELECT id, host_id, partner_id, score_count, score_time, host_demo_id, partner_demo_id, record_date,
113 ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn
114 FROM records_mp
115 WHERE map_id = $1
116 ) sub
117 WHERE rn = 1`
118 rows, err := database.DB.Query(sql, id)
119 if err != nil {
120 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
121 return
122 }
123 placement := 1
124 ties := 0
125 for rows.Next() {
126 var record models.RecordMP
127 err := rows.Scan(&record.RecordID, &record.HostID, &record.PartnerID, &record.ScoreCount, &record.ScoreTime, &record.HostDemoID, &record.PartnerDemoID, &record.RecordDate)
128 if err != nil {
129 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
130 return
131 }
132 if len(records) != 0 && records[len(records)-1].ScoreTime == record.ScoreTime {
133 ties++
134 record.Placement = placement - ties
135 } else {
136 record.Placement = placement
137 }
138 records = append(records, record)
139 placement++
140 }
141 mapRecordsData.Records = records
142 } else {
143 var records []models.RecordSP
144 sql = `SELECT id, user_id, users.user_name, users.avatar_link, score_count, score_time, demo_id, record_date
145 FROM (
146 SELECT id, user_id, score_count, score_time, demo_id, record_date,
147 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn
148 FROM records_sp
149 WHERE map_id = $1
150 ) sub
151 INNER JOIN users ON user_id = users.steam_id
152 WHERE rn = 1`
153 rows, err := database.DB.Query(sql, id)
154 if err != nil {
155 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
156 return
157 }
158 placement := 1
159 ties := 0
160 for rows.Next() {
161 var record models.RecordSP
162 err := rows.Scan(&record.RecordID, &record.UserID, &record.UserName, &record.UserAvatar, &record.ScoreCount, &record.ScoreTime, &record.DemoID, &record.RecordDate)
163 if err != nil {
164 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
165 return
166 }
167 if len(records) != 0 && records[len(records)-1].ScoreTime == record.ScoreTime {
168 ties++
169 record.Placement = placement - ties
170 } else {
171 record.Placement = placement
172 }
173 records = append(records, record)
174 placement++
175 }
176 mapRecordsData.Records = records
177 }
178 // mapData.Data = mapRecordsData
179 // Return response
180 c.JSON(http.StatusOK, models.Response{
181 Success: true,
182 Message: "Successfully retrieved map leaderboards.",
183 Data: mapData,
184 })
185}
186
187// GET Games
188//
189// @Description Get games from the leaderboards.
190// @Tags games & chapters
191// @Produce json
192// @Success 200 {object} models.Response{data=[]models.Game}
193// @Failure 400 {object} models.Response
194// @Router /games [get]
195func FetchGames(c *gin.Context) {
196 rows, err := database.DB.Query(`SELECT id, name, is_coop FROM games`)
197 if err != nil {
198 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
199 return
200 }
201 var games []models.Game
202 for rows.Next() {
203 var game models.Game
204 if err := rows.Scan(&game.ID, &game.Name, &game.IsCoop); err != nil {
205 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
206 return
207 }
208 games = append(games, game)
209 }
210 c.JSON(http.StatusOK, models.Response{
211 Success: true,
212 Message: "Successfully retrieved games.",
213 Data: games,
214 })
215}
216
217// GET Chapters of a Game
218//
219// @Description Get chapters from the specified game id.
220// @Tags games & chapters
221// @Produce json
222// @Param id path int true "Game ID"
223// @Success 200 {object} models.Response{data=models.ChaptersResponse}
224// @Failure 400 {object} models.Response
225// @Router /games/{id} [get]
226func FetchChapters(c *gin.Context) {
227 gameID := c.Param("id")
228 intID, err := strconv.Atoi(gameID)
229 if err != nil {
230 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
231 return
232 }
233 var response models.ChaptersResponse
234 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)
235 if err != nil {
236 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
237 return
238 }
239 var chapters []models.Chapter
240 var gameName string
241 for rows.Next() {
242 var chapter models.Chapter
243 if err := rows.Scan(&chapter.ID, &chapter.Name, &gameName); err != nil {
244 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
245 return
246 }
247 chapters = append(chapters, chapter)
248 }
249 response.Game.ID = intID
250 response.Game.Name = gameName
251 response.Chapters = chapters
252 c.JSON(http.StatusOK, models.Response{
253 Success: true,
254 Message: "Successfully retrieved chapters.",
255 Data: response,
256 })
257}
258
259// GET Maps of a Chapter
260//
261// @Description Get maps from the specified chapter id.
262// @Tags games & chapters
263// @Produce json
264// @Param id path int true "Chapter ID"
265// @Success 200 {object} models.Response{data=models.ChapterMapsResponse}
266// @Failure 400 {object} models.Response
267// @Router /chapters/{id} [get]
268func FetchChapterMaps(c *gin.Context) {
269 chapterID := c.Param("id")
270 intID, err := strconv.Atoi(chapterID)
271 if err != nil {
272 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
273 return
274 }
275 var response models.ChapterMapsResponse
276 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)
277 if err != nil {
278 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
279 return
280 }
281 var maps []models.MapShort
282 var chapterName string
283 for rows.Next() {
284 var mapShort models.MapShort
285 if err := rows.Scan(&mapShort.ID, &mapShort.Name, &chapterName); err != nil {
286 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
287 return
288 }
289 maps = append(maps, mapShort)
290 }
291 response.Chapter.ID = intID
292 response.Chapter.Name = chapterName
293 response.Maps = maps
294 c.JSON(http.StatusOK, models.Response{
295 Success: true,
296 Message: "Successfully retrieved maps.",
297 Data: response,
298 })
299}