aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/api/routes.go5
-rw-r--r--backend/database/init.sql2
-rw-r--r--backend/handlers/home.go8
-rw-r--r--backend/handlers/logs.go6
-rw-r--r--backend/handlers/map.go8
-rw-r--r--backend/handlers/record.go79
6 files changed, 97 insertions, 11 deletions
diff --git a/backend/api/routes.go b/backend/api/routes.go
index 339dc73..9e703f6 100644
--- a/backend/api/routes.go
+++ b/backend/api/routes.go
@@ -21,6 +21,7 @@ const (
21 mapImagePath string = "/maps/:mapid/image" 21 mapImagePath string = "/maps/:mapid/image"
22 mapLeaderboardsPath string = "/maps/:mapid/leaderboards" 22 mapLeaderboardsPath string = "/maps/:mapid/leaderboards"
23 mapRecordPath string = "/maps/:mapid/record" 23 mapRecordPath string = "/maps/:mapid/record"
24 mapRecordIDPath string = "/maps/:mapid/record/:recordid"
24 mapDiscussionsPath string = "/maps/:mapid/discussions" 25 mapDiscussionsPath string = "/maps/:mapid/discussions"
25 mapDiscussionIDPath string = "/maps/:mapid/discussions/:discussionid" 26 mapDiscussionIDPath string = "/maps/:mapid/discussions/:discussionid"
26 rankingsPath string = "/rankings" 27 rankingsPath string = "/rankings"
@@ -51,14 +52,18 @@ func InitRoutes(router *gin.Engine) {
51 v1.POST(profilePath, CheckAuth, handlers.UpdateUser) 52 v1.POST(profilePath, CheckAuth, handlers.UpdateUser)
52 v1.GET(usersPath, CheckAuth, handlers.FetchUser) 53 v1.GET(usersPath, CheckAuth, handlers.FetchUser)
53 // Maps 54 // Maps
55 // - Summary
54 v1.GET(mapSummaryPath, handlers.FetchMapSummary) 56 v1.GET(mapSummaryPath, handlers.FetchMapSummary)
55 v1.POST(mapSummaryPath, CheckAuth, handlers.CreateMapSummary) 57 v1.POST(mapSummaryPath, CheckAuth, handlers.CreateMapSummary)
56 v1.PUT(mapSummaryPath, CheckAuth, handlers.EditMapSummary) 58 v1.PUT(mapSummaryPath, CheckAuth, handlers.EditMapSummary)
57 v1.DELETE(mapSummaryPath, CheckAuth, handlers.DeleteMapSummary) 59 v1.DELETE(mapSummaryPath, CheckAuth, handlers.DeleteMapSummary)
58 v1.PUT(mapImagePath, CheckAuth, handlers.EditMapImage) 60 v1.PUT(mapImagePath, CheckAuth, handlers.EditMapImage)
61 // - Leaderboards
59 v1.GET(mapLeaderboardsPath, handlers.FetchMapLeaderboards) 62 v1.GET(mapLeaderboardsPath, handlers.FetchMapLeaderboards)
60 v1.POST(mapRecordPath, CheckAuth, handlers.CreateRecordWithDemo) 63 v1.POST(mapRecordPath, CheckAuth, handlers.CreateRecordWithDemo)
64 v1.DELETE(mapRecordIDPath, CheckAuth, handlers.DeleteRecord)
61 v1.GET(demosPath, handlers.DownloadDemoWithID) 65 v1.GET(demosPath, handlers.DownloadDemoWithID)
66 // - Discussions
62 v1.GET(mapDiscussionsPath, handlers.FetchMapDiscussions) 67 v1.GET(mapDiscussionsPath, handlers.FetchMapDiscussions)
63 v1.GET(mapDiscussionIDPath, handlers.FetchMapDiscussion) 68 v1.GET(mapDiscussionIDPath, handlers.FetchMapDiscussion)
64 v1.POST(mapDiscussionsPath, CheckAuth, handlers.CreateMapDiscussion) 69 v1.POST(mapDiscussionsPath, CheckAuth, handlers.CreateMapDiscussion)
diff --git a/backend/database/init.sql b/backend/database/init.sql
index 0f8196b..9d7b68c 100644
--- a/backend/database/init.sql
+++ b/backend/database/init.sql
@@ -130,6 +130,7 @@ CREATE TABLE records_sp (
130 score_time INTEGER NOT NULL, 130 score_time INTEGER NOT NULL,
131 demo_id UUID NOT NULL, 131 demo_id UUID NOT NULL,
132 record_date TIMESTAMP NOT NULL DEFAULT now(), 132 record_date TIMESTAMP NOT NULL DEFAULT now(),
133 is_deleted BOOLEAN NOT NULL DEFAULT false,
133 PRIMARY KEY (id), 134 PRIMARY KEY (id),
134 FOREIGN KEY (map_id) REFERENCES maps(id), 135 FOREIGN KEY (map_id) REFERENCES maps(id),
135 FOREIGN KEY (user_id) REFERENCES users(steam_id), 136 FOREIGN KEY (user_id) REFERENCES users(steam_id),
@@ -146,6 +147,7 @@ CREATE TABLE records_mp (
146 host_demo_id UUID NOT NULL, 147 host_demo_id UUID NOT NULL,
147 partner_demo_id UUID NOT NULL, 148 partner_demo_id UUID NOT NULL,
148 record_date TIMESTAMP NOT NULL DEFAULT now(), 149 record_date TIMESTAMP NOT NULL DEFAULT now(),
150 is_deleted BOOLEAN NOT NULL DEFAULT false,
149 PRIMARY KEY (id), 151 PRIMARY KEY (id),
150 FOREIGN KEY (map_id) REFERENCES maps(id), 152 FOREIGN KEY (map_id) REFERENCES maps(id),
151 FOREIGN KEY (host_id) REFERENCES users(steam_id), 153 FOREIGN KEY (host_id) REFERENCES users(steam_id),
diff --git a/backend/handlers/home.go b/backend/handlers/home.go
index c9742f2..5863218 100644
--- a/backend/handlers/home.go
+++ b/backend/handlers/home.go
@@ -49,11 +49,11 @@ func Rankings(c *gin.Context) {
49 SELECT 49 SELECT
50 user_id, 50 user_id,
51 MIN(score_count) AS min_score_count 51 MIN(score_count) AS min_score_count
52 FROM records_sp 52 FROM records_sp WHERE is_deleted = false
53 GROUP BY user_id, map_id 53 GROUP BY user_id, map_id
54 ) AS subquery 54 ) AS subquery
55 WHERE user_id = u.steam_id) 55 WHERE user_id = u.steam_id)
56 FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name` 56 FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id WHERE is_deleted = false GROUP BY u.steam_id, u.user_name`
57 rows, err := database.DB.Query(sql) 57 rows, err := database.DB.Query(sql)
58 if err != nil { 58 if err != nil {
59 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 59 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
@@ -81,11 +81,11 @@ func Rankings(c *gin.Context) {
81 host_id, 81 host_id,
82 partner_id, 82 partner_id,
83 MIN(score_count) AS min_score_count 83 MIN(score_count) AS min_score_count
84 FROM records_mp 84 FROM records_mp WHERE is_deleted = false
85 GROUP BY host_id, partner_id, map_id 85 GROUP BY host_id, partner_id, map_id
86 ) AS subquery 86 ) AS subquery
87 WHERE host_id = u.steam_id OR partner_id = u.steam_id) 87 WHERE host_id = u.steam_id OR partner_id = u.steam_id)
88 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` 88 FROM records_mp mp JOIN users u ON u.steam_id = mp.host_id OR u.steam_id = mp.partner_id WHERE is_deleted = false GROUP BY u.steam_id, u.user_name`
89 rows, err = database.DB.Query(sql) 89 rows, err = database.DB.Query(sql)
90 if err != nil { 90 if err != nil {
91 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 91 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
diff --git a/backend/handlers/logs.go b/backend/handlers/logs.go
index 6f59238..4c7b415 100644
--- a/backend/handlers/logs.go
+++ b/backend/handlers/logs.go
@@ -140,17 +140,17 @@ func ScoreLogs(c *gin.Context) {
140 rs.record_date 140 rs.record_date
141 FROM ( 141 FROM (
142 SELECT id, map_id, user_id, score_count, score_time, demo_id, record_date 142 SELECT id, map_id, user_id, score_count, score_time, demo_id, record_date
143 FROM records_sp 143 FROM records_sp WHERE is_deleted = false
144 144
145 UNION ALL 145 UNION ALL
146 146
147 SELECT id, map_id, host_id AS user_id, score_count, score_time, host_demo_id AS demo_id, record_date 147 SELECT id, map_id, host_id AS user_id, score_count, score_time, host_demo_id AS demo_id, record_date
148 FROM records_mp 148 FROM records_mp WHERE is_deleted = false
149 149
150 UNION ALL 150 UNION ALL
151 151
152 SELECT id, map_id, partner_id AS user_id, score_count, score_time, partner_demo_id AS demo_id, record_date 152 SELECT id, map_id, partner_id AS user_id, score_count, score_time, partner_demo_id AS demo_id, record_date
153 FROM records_mp 153 FROM records_mp WHERE is_deleted = false
154 ) AS rs 154 ) AS rs
155 JOIN users u ON rs.user_id = u.steam_id 155 JOIN users u ON rs.user_id = u.steam_id
156 JOIN maps m ON rs.map_id = m.id 156 JOIN maps m ON rs.map_id = m.id
diff --git a/backend/handlers/map.go b/backend/handlers/map.go
index 3bf14cd..faccee4 100644
--- a/backend/handlers/map.go
+++ b/backend/handlers/map.go
@@ -104,7 +104,7 @@ func FetchMapSummary(c *gin.Context) {
104 if response.Map.IsCoop { 104 if response.Map.IsCoop {
105 sql = `SELECT count(*) FROM ( SELECT host_id, partner_id, score_count, score_time, 105 sql = `SELECT count(*) FROM ( SELECT host_id, partner_id, score_count, score_time,
106 ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn 106 ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn
107 FROM records_mp WHERE map_id = $1 107 FROM records_mp WHERE map_id = $1 AND is_deleted = false
108 ) sub WHERE sub.rn = 1 AND score_count = $2` 108 ) sub WHERE sub.rn = 1 AND score_count = $2`
109 err = database.DB.QueryRow(sql, response.Map.ID, route.History.ScoreCount).Scan(&route.CompletionCount) 109 err = database.DB.QueryRow(sql, response.Map.ID, route.History.ScoreCount).Scan(&route.CompletionCount)
110 if err != nil { 110 if err != nil {
@@ -114,7 +114,7 @@ func FetchMapSummary(c *gin.Context) {
114 } else { 114 } else {
115 sql = `SELECT count(*) FROM ( SELECT user_id, score_count, score_time, 115 sql = `SELECT count(*) FROM ( SELECT user_id, score_count, score_time,
116 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn 116 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn
117 FROM records_sp WHERE map_id = $1 117 FROM records_sp WHERE map_id = $1 AND is_deleted = false
118 ) sub WHERE rn = 1 AND score_count = $2` 118 ) sub WHERE rn = 1 AND score_count = $2`
119 err = database.DB.QueryRow(sql, response.Map.ID, route.History.ScoreCount).Scan(&route.CompletionCount) 119 err = database.DB.QueryRow(sql, response.Map.ID, route.History.ScoreCount).Scan(&route.CompletionCount)
120 if err != nil { 120 if err != nil {
@@ -204,7 +204,7 @@ func FetchMapLeaderboards(c *gin.Context) {
204 record_date, 204 record_date,
205 ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn 205 ROW_NUMBER() OVER (PARTITION BY host_id, partner_id ORDER BY score_count, score_time) AS rn
206 FROM records_mp 206 FROM records_mp
207 WHERE map_id = $1 207 WHERE map_id = $1 AND is_deleted = false
208 ) sub 208 ) sub
209 JOIN users AS host ON sub.host_id = host.steam_id 209 JOIN users AS host ON sub.host_id = host.steam_id
210 JOIN users AS partner ON sub.partner_id = partner.steam_id 210 JOIN users AS partner ON sub.partner_id = partner.steam_id
@@ -255,7 +255,7 @@ func FetchMapLeaderboards(c *gin.Context) {
255 SELECT id, user_id, score_count, score_time, demo_id, record_date, 255 SELECT id, user_id, score_count, score_time, demo_id, record_date,
256 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn 256 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score_count, score_time) AS rn
257 FROM records_sp 257 FROM records_sp
258 WHERE map_id = $1 258 WHERE map_id = $1 AND is_deleted = false
259 ) sub 259 ) sub
260 INNER JOIN users ON user_id = users.steam_id 260 INNER JOIN users ON user_id = users.steam_id
261 WHERE rn = 1 261 WHERE rn = 1
diff --git a/backend/handlers/record.go b/backend/handlers/record.go
index 4787422..70095bf 100644
--- a/backend/handlers/record.go
+++ b/backend/handlers/record.go
@@ -8,6 +8,7 @@ import (
8 "mime/multipart" 8 "mime/multipart"
9 "net/http" 9 "net/http"
10 "os" 10 "os"
11 "strconv"
11 12
12 "github.com/gin-gonic/gin" 13 "github.com/gin-gonic/gin"
13 "github.com/google/uuid" 14 "github.com/google/uuid"
@@ -209,6 +210,84 @@ func CreateRecordWithDemo(c *gin.Context) {
209 }) 210 })
210} 211}
211 212
213func DeleteRecord(c *gin.Context) {
214 mapID, err := strconv.Atoi(c.Param("mapid"))
215 if err != nil {
216 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
217 return
218 }
219 recordID, err := strconv.Atoi(c.Param("recordid"))
220 if err != nil {
221 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
222 return
223 }
224 user, exists := c.Get("user")
225 if !exists {
226 c.JSON(http.StatusOK, models.ErrorResponse("User not logged in."))
227 return
228 }
229 // Validate map
230 var validateMapID int
231 var isCoop bool
232 sql := `SELECT m.id, g.is_coop FROM maps m INNER JOIN games g ON m.game_id = g.id
233 INNER JOIN chapters c ON m.chapter_id = c.id WHERE m.id = $1`
234 err = database.DB.QueryRow(sql, mapID).Scan(&validateMapID, &isCoop)
235 if err != nil {
236 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
237 return
238 }
239 if mapID != validateMapID {
240 c.JSON(http.StatusOK, models.ErrorResponse("Selected map does not exist."))
241 return
242 }
243 if isCoop {
244 // Validate if cooperative record does exist
245 var validateRecordID int
246 sql = `SELECT mp.id FROM records_mp mp WHERE mp.id = $1 AND mp.map_id = $2 AND (mp.host_id = $3 OR mp.partner_id = $3) AND is_deleted = false`
247 err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID)
248 if err != nil {
249 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
250 return
251 }
252 if recordID != validateRecordID {
253 c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist."))
254 return
255 }
256 // Remove record
257 sql = `UPDATE records_mp SET is_deleted = true WHERE id = $1`
258 _, err = database.DB.Exec(sql, recordID)
259 if err != nil {
260 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
261 return
262 }
263 } else {
264 // Validate if singleplayer record does exist
265 var validateRecordID int
266 sql = `SELECT sp.id FROM records_sp sp WHERE sp.id = $1 AND sp.map_id = $2 AND sp.user_id = $3 AND is_deleted = false`
267 err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID)
268 if err != nil {
269 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
270 return
271 }
272 if recordID != validateRecordID {
273 c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist."))
274 return
275 }
276 // Remove record
277 sql = `UPDATE records_sp SET is_deleted = true WHERE id = $1`
278 _, err = database.DB.Exec(sql, recordID)
279 if err != nil {
280 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
281 return
282 }
283 }
284 c.JSON(http.StatusOK, models.Response{
285 Success: true,
286 Message: "Successfully deleted record.",
287 Data: nil,
288 })
289}
290
212// GET Demo 291// GET Demo
213// 292//
214// @Description Get demo with specified demo uuid. 293// @Description Get demo with specified demo uuid.