diff options
| author | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2024-10-31 22:06:00 +0300 |
|---|---|---|
| committer | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2024-10-31 22:06:00 +0300 |
| commit | 4210c9b38f9053f6720a6bebaadefd24c542eaa9 (patch) | |
| tree | 5b0061e23cf91291ed9e5f387766148d45103591 | |
| parent | chore: change repo name to lphub (diff) | |
| download | lphub-4210c9b38f9053f6720a6bebaadefd24c542eaa9.tar.gz lphub-4210c9b38f9053f6720a6bebaadefd24c542eaa9.tar.bz2 lphub-4210c9b38f9053f6720a6bebaadefd24c542eaa9.zip | |
backend: better auth check, audit logging
| -rw-r--r-- | backend/api/auth.go | 19 | ||||
| -rw-r--r-- | backend/api/routes.go | 98 | ||||
| -rw-r--r-- | backend/database/functions.sql | 14 | ||||
| -rw-r--r-- | backend/database/init.sql | 45 | ||||
| -rw-r--r-- | backend/docs/docs.go | 68 | ||||
| -rw-r--r-- | backend/docs/swagger.json | 68 | ||||
| -rw-r--r-- | backend/docs/swagger.yaml | 41 | ||||
| -rw-r--r-- | backend/handlers/discussions.go | 24 | ||||
| -rw-r--r-- | backend/handlers/login.go | 3 | ||||
| -rw-r--r-- | backend/handlers/logs.go | 98 | ||||
| -rw-r--r-- | backend/handlers/mod.go | 36 | ||||
| -rw-r--r-- | backend/handlers/record.go | 31 | ||||
| -rw-r--r-- | backend/handlers/user.go | 28 |
13 files changed, 106 insertions, 467 deletions
diff --git a/backend/api/auth.go b/backend/api/auth.go index 621a68b..a1f859c 100644 --- a/backend/api/auth.go +++ b/backend/api/auth.go | |||
| @@ -2,6 +2,7 @@ package api | |||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "net/http" | ||
| 5 | "os" | 6 | "os" |
| 6 | "time" | 7 | "time" |
| 7 | 8 | ||
| @@ -12,7 +13,7 @@ import ( | |||
| 12 | "github.com/golang-jwt/jwt/v4" | 13 | "github.com/golang-jwt/jwt/v4" |
| 13 | ) | 14 | ) |
| 14 | 15 | ||
| 15 | func CheckAuth(c *gin.Context) { | 16 | func IsAuthenticated(c *gin.Context) { |
| 16 | tokenString := c.GetHeader("Authorization") | 17 | tokenString := c.GetHeader("Authorization") |
| 17 | // Validate token | 18 | // Validate token |
| 18 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | 19 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { |
| @@ -22,17 +23,17 @@ func CheckAuth(c *gin.Context) { | |||
| 22 | return []byte(os.Getenv("SECRET_KEY")), nil | 23 | return []byte(os.Getenv("SECRET_KEY")), nil |
| 23 | }) | 24 | }) |
| 24 | if token == nil { | 25 | if token == nil { |
| 25 | c.Next() | 26 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Token is nil.")) |
| 26 | return | 27 | return |
| 27 | } | 28 | } |
| 28 | if err != nil { | 29 | if err != nil { |
| 29 | c.Next() | 30 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Token is invalid.")) |
| 30 | return | 31 | return |
| 31 | } | 32 | } |
| 32 | if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { | 33 | if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { |
| 33 | // Check exp | 34 | // Check exp |
| 34 | if float64(time.Now().Unix()) > claims["exp"].(float64) { | 35 | if float64(time.Now().Unix()) > claims["exp"].(float64) { |
| 35 | c.Next() | 36 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Token expired.")) |
| 36 | return | 37 | return |
| 37 | } | 38 | } |
| 38 | // Get user from DB | 39 | // Get user from DB |
| @@ -41,7 +42,7 @@ func CheckAuth(c *gin.Context) { | |||
| 41 | &user.SteamID, &user.UserName, &user.AvatarLink, | 42 | &user.SteamID, &user.UserName, &user.AvatarLink, |
| 42 | &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) | 43 | &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) |
| 43 | if user.SteamID == "" { | 44 | if user.SteamID == "" { |
| 44 | c.Next() | 45 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Token does not match a user.")) |
| 45 | return | 46 | return |
| 46 | } | 47 | } |
| 47 | // Get user titles from DB | 48 | // Get user titles from DB |
| @@ -56,11 +57,17 @@ func CheckAuth(c *gin.Context) { | |||
| 56 | } | 57 | } |
| 57 | user.Titles = append(user.Titles, title) | 58 | user.Titles = append(user.Titles, title) |
| 58 | } | 59 | } |
| 60 | // Set user id variable in db session for audit logging | ||
| 61 | _, err = database.DB.Exec(fmt.Sprintf("SET app.user_id = '%s';", user.SteamID)) | ||
| 62 | if err != nil { | ||
| 63 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Session failed to start.")) | ||
| 64 | return | ||
| 65 | } | ||
| 59 | c.Set("user", user) | 66 | c.Set("user", user) |
| 60 | c.Set("mod", moderator) | 67 | c.Set("mod", moderator) |
| 61 | c.Next() | 68 | c.Next() |
| 62 | } else { | 69 | } else { |
| 63 | c.Next() | 70 | c.AbortWithStatusJSON(http.StatusOK, models.ErrorResponse("Token is invalid.")) |
| 64 | return | 71 | return |
| 65 | } | 72 | } |
| 66 | } | 73 | } |
diff --git a/backend/api/routes.go b/backend/api/routes.go index 81f1ec6..ecfb54b 100644 --- a/backend/api/routes.go +++ b/backend/api/routes.go | |||
| @@ -8,82 +8,54 @@ import ( | |||
| 8 | ginSwagger "github.com/swaggo/gin-swagger" | 8 | ginSwagger "github.com/swaggo/gin-swagger" |
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | const ( | ||
| 12 | apiPath string = "/api" | ||
| 13 | v1Path string = "/v1" | ||
| 14 | swaggerPath string = "/swagger/*any" | ||
| 15 | indexPath string = "/" | ||
| 16 | tokenPath string = "/token" | ||
| 17 | loginPath string = "/login" | ||
| 18 | profilePath string = "/profile" | ||
| 19 | usersPath string = "/users/:userid" | ||
| 20 | demosPath string = "/demos" | ||
| 21 | mapSummaryPath string = "/maps/:mapid/summary" | ||
| 22 | mapImagePath string = "/maps/:mapid/image" | ||
| 23 | mapLeaderboardsPath string = "/maps/:mapid/leaderboards" | ||
| 24 | mapRecordPath string = "/maps/:mapid/record" | ||
| 25 | mapRecordIDPath string = "/maps/:mapid/record/:recordid" | ||
| 26 | mapDiscussionsPath string = "/maps/:mapid/discussions" | ||
| 27 | mapDiscussionIDPath string = "/maps/:mapid/discussions/:discussionid" | ||
| 28 | rankingsLPHUBPath string = "/rankings/lphub" | ||
| 29 | rankingsSteamPath string = "/rankings/steam" | ||
| 30 | searchPath string = "/search" | ||
| 31 | gamesPath string = "/games" | ||
| 32 | chaptersPath string = "/games/:gameid" | ||
| 33 | gameMapsPath string = "/games/:gameid/maps" | ||
| 34 | chapterMapsPath string = "/chapters/:chapterid" | ||
| 35 | scoreLogsPath string = "/logs/score" | ||
| 36 | modLogsPath string = "/logs/mod" | ||
| 37 | ) | ||
| 38 | |||
| 39 | func InitRoutes(router *gin.Engine) { | 11 | func InitRoutes(router *gin.Engine) { |
| 40 | api := router.Group(apiPath) | 12 | api := router.Group("/api") |
| 41 | { | 13 | { |
| 42 | v1 := api.Group(v1Path) | 14 | v1 := api.Group("/v1") |
| 43 | // Swagger | 15 | // Swagger |
| 44 | v1.GET(swaggerPath, ginSwagger.WrapHandler(swaggerfiles.Handler)) | 16 | v1.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) |
| 45 | v1.GET(indexPath, func(c *gin.Context) { | 17 | v1.GET("/", func(c *gin.Context) { |
| 46 | c.File("docs/index.html") | 18 | c.File("docs/index.html") |
| 47 | }) | 19 | }) |
| 48 | // Tokens, login | 20 | // Tokens, login |
| 49 | v1.GET(tokenPath, handlers.GetCookie) | 21 | v1.GET("/token", handlers.GetCookie) |
| 50 | v1.DELETE(tokenPath, handlers.DeleteCookie) | 22 | v1.DELETE("/token", handlers.DeleteCookie) |
| 51 | v1.GET(loginPath, handlers.Login) | 23 | v1.GET("/login", handlers.Login) |
| 52 | // Users, profiles | 24 | // Users, profiles |
| 53 | v1.GET(profilePath, CheckAuth, handlers.Profile) | 25 | v1.GET("/profile", IsAuthenticated, handlers.Profile) |
| 54 | v1.PUT(profilePath, CheckAuth, handlers.UpdateCountryCode) | 26 | v1.PUT("/profile", IsAuthenticated, handlers.UpdateCountryCode) |
| 55 | v1.POST(profilePath, CheckAuth, handlers.UpdateUser) | 27 | v1.POST("/profile", IsAuthenticated, handlers.UpdateUser) |
| 56 | v1.GET(usersPath, CheckAuth, handlers.FetchUser) | 28 | v1.GET("/users/:userid", IsAuthenticated, handlers.FetchUser) |
| 57 | // Maps | 29 | // Maps |
| 58 | // - Summary | 30 | // - Summary |
| 59 | v1.GET(mapSummaryPath, handlers.FetchMapSummary) | 31 | v1.GET("/maps/:mapid/summary", handlers.FetchMapSummary) |
| 60 | v1.POST(mapSummaryPath, CheckAuth, handlers.CreateMapSummary) | 32 | v1.POST("/maps/:mapid/summary", IsAuthenticated, handlers.CreateMapSummary) |
| 61 | v1.PUT(mapSummaryPath, CheckAuth, handlers.EditMapSummary) | 33 | v1.PUT("/maps/:mapid/summary", IsAuthenticated, handlers.EditMapSummary) |
| 62 | v1.DELETE(mapSummaryPath, CheckAuth, handlers.DeleteMapSummary) | 34 | v1.DELETE("/maps/:mapid/summary", IsAuthenticated, handlers.DeleteMapSummary) |
| 63 | v1.PUT(mapImagePath, CheckAuth, handlers.EditMapImage) | 35 | v1.PUT("/maps/:mapid/image", IsAuthenticated, handlers.EditMapImage) |
| 64 | // - Leaderboards | 36 | // - Leaderboards |
| 65 | v1.GET(mapLeaderboardsPath, handlers.FetchMapLeaderboards) | 37 | v1.GET("/maps/:mapid/leaderboards", handlers.FetchMapLeaderboards) |
| 66 | v1.POST(mapRecordPath, CheckAuth, handlers.CreateRecordWithDemo) | 38 | v1.POST("/maps/:mapid/record", IsAuthenticated, handlers.CreateRecordWithDemo) |
| 67 | v1.DELETE(mapRecordIDPath, CheckAuth, handlers.DeleteRecord) | 39 | v1.DELETE("/maps/:mapid/record/:recordid", IsAuthenticated, handlers.DeleteRecord) |
| 68 | v1.GET(demosPath, handlers.DownloadDemoWithID) | 40 | v1.GET("/demos", handlers.DownloadDemoWithID) |
| 69 | // - Discussions | 41 | // - Discussions |
| 70 | v1.GET(mapDiscussionsPath, handlers.FetchMapDiscussions) | 42 | v1.GET("/maps/:mapid/discussions", handlers.FetchMapDiscussions) |
| 71 | v1.GET(mapDiscussionIDPath, handlers.FetchMapDiscussion) | 43 | v1.GET("/maps/:mapid/discussions/:discussionid", handlers.FetchMapDiscussion) |
| 72 | v1.POST(mapDiscussionsPath, CheckAuth, handlers.CreateMapDiscussion) | 44 | v1.POST("/maps/:mapid/discussions", IsAuthenticated, handlers.CreateMapDiscussion) |
| 73 | v1.POST(mapDiscussionIDPath, CheckAuth, handlers.CreateMapDiscussionComment) | 45 | v1.POST("/maps/:mapid/discussions/:discussionid", IsAuthenticated, handlers.CreateMapDiscussionComment) |
| 74 | v1.PUT(mapDiscussionIDPath, CheckAuth, handlers.EditMapDiscussion) | 46 | v1.PUT("/maps/:mapid/discussions/:discussionid", IsAuthenticated, handlers.EditMapDiscussion) |
| 75 | v1.DELETE(mapDiscussionIDPath, CheckAuth, handlers.DeleteMapDiscussion) | 47 | v1.DELETE("/maps/:mapid/discussions/:discussionid", IsAuthenticated, handlers.DeleteMapDiscussion) |
| 76 | // Rankings, search | 48 | // Rankings, search |
| 77 | v1.GET(rankingsLPHUBPath, handlers.RankingsLPHUB) | 49 | v1.GET("/rankings/lphub", handlers.RankingsLPHUB) |
| 78 | v1.GET(rankingsSteamPath, handlers.RankingsSteam) | 50 | v1.GET("/rankings/steam", handlers.RankingsSteam) |
| 79 | v1.GET(searchPath, handlers.SearchWithQuery) | 51 | v1.GET("/search", handlers.SearchWithQuery) |
| 80 | // Games, chapters, maps | 52 | // Games, chapters, maps |
| 81 | v1.GET(gamesPath, handlers.FetchGames) | 53 | v1.GET("/games", handlers.FetchGames) |
| 82 | v1.GET(chaptersPath, handlers.FetchChapters) | 54 | v1.GET("/games/:gameid", handlers.FetchChapters) |
| 83 | v1.GET(chapterMapsPath, handlers.FetchChapterMaps) | 55 | v1.GET("/chapters/:chapterid", handlers.FetchChapterMaps) |
| 84 | v1.GET(gameMapsPath, handlers.FetchMaps) | 56 | v1.GET("/games/:gameid/maps", handlers.FetchMaps) |
| 85 | // Logs | 57 | // Logs |
| 86 | v1.GET(scoreLogsPath, handlers.ScoreLogs) | 58 | v1.GET("/logs/score", handlers.ScoreLogs) |
| 87 | v1.GET(modLogsPath, CheckAuth, handlers.ModLogs) | 59 | // v1.GET("/logs/mod", IsAuthenticated, handlers.ModLogs) |
| 88 | } | 60 | } |
| 89 | } | 61 | } |
diff --git a/backend/database/functions.sql b/backend/database/functions.sql index ca33a60..6a6f6d2 100644 --- a/backend/database/functions.sql +++ b/backend/database/functions.sql | |||
| @@ -1,3 +1,17 @@ | |||
| 1 | CREATE OR REPLACE FUNCTION log_audit() RETURNS TRIGGER AS $$ | ||
| 2 | BEGIN | ||
| 3 | INSERT INTO audit (table_name, operation_type, old_data, new_data, changed_by) | ||
| 4 | VALUES ( | ||
| 5 | TG_TABLE_NAME, | ||
| 6 | TG_OP, | ||
| 7 | CASE WHEN TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN row_to_json(OLD) ELSE NULL END, | ||
| 8 | CASE WHEN TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN row_to_json(NEW) ELSE NULL END, | ||
| 9 | current_setting('app.user_id')::TEXT | ||
| 10 | ); | ||
| 11 | RETURN NULL; | ||
| 12 | END; | ||
| 13 | $$ LANGUAGE plpgsql; | ||
| 14 | |||
| 1 | CREATE OR REPLACE FUNCTION get_rankings_singleplayer() | 15 | CREATE OR REPLACE FUNCTION get_rankings_singleplayer() |
| 2 | RETURNS TABLE ( | 16 | RETURNS TABLE ( |
| 3 | steam_id TEXT, | 17 | steam_id TEXT, |
diff --git a/backend/database/init.sql b/backend/database/init.sql index 77a88f5..51bf2af 100644 --- a/backend/database/init.sql +++ b/backend/database/init.sql | |||
| @@ -12,6 +12,10 @@ CREATE TABLE users ( | |||
| 12 | PRIMARY KEY (steam_id) | 12 | PRIMARY KEY (steam_id) |
| 13 | ); | 13 | ); |
| 14 | 14 | ||
| 15 | CREATE TRIGGER "users" | ||
| 16 | AFTER INSERT OR UPDATE OR DELETE ON "users" | ||
| 17 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 18 | |||
| 15 | CREATE TABLE games ( | 19 | CREATE TABLE games ( |
| 16 | id SERIAL, | 20 | id SERIAL, |
| 17 | name TEXT NOT NULL, | 21 | name TEXT NOT NULL, |
| @@ -72,6 +76,10 @@ CREATE TABLE map_history ( | |||
| 72 | UNIQUE (map_id, category_id, score_count) | 76 | UNIQUE (map_id, category_id, score_count) |
| 73 | ); | 77 | ); |
| 74 | 78 | ||
| 79 | CREATE TRIGGER "map_history" | ||
| 80 | AFTER INSERT OR UPDATE OR DELETE ON "map_history" | ||
| 81 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 82 | |||
| 75 | CREATE TABLE map_ratings ( | 83 | CREATE TABLE map_ratings ( |
| 76 | id SERIAL, | 84 | id SERIAL, |
| 77 | map_id SMALLINT NOT NULL, | 85 | map_id SMALLINT NOT NULL, |
| @@ -98,6 +106,10 @@ CREATE TABLE map_discussions ( | |||
| 98 | FOREIGN KEY (user_id) REFERENCES users(steam_id) | 106 | FOREIGN KEY (user_id) REFERENCES users(steam_id) |
| 99 | ); | 107 | ); |
| 100 | 108 | ||
| 109 | CREATE TRIGGER "map_discussions" | ||
| 110 | AFTER INSERT OR UPDATE OR DELETE ON "map_discussions" | ||
| 111 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 112 | |||
| 101 | CREATE TABLE map_discussions_comments ( | 113 | CREATE TABLE map_discussions_comments ( |
| 102 | id SERIAL, | 114 | id SERIAL, |
| 103 | discussion_id INT NOT NULL, | 115 | discussion_id INT NOT NULL, |
| @@ -109,6 +121,10 @@ CREATE TABLE map_discussions_comments ( | |||
| 109 | FOREIGN KEY (user_id) REFERENCES users(steam_id) | 121 | FOREIGN KEY (user_id) REFERENCES users(steam_id) |
| 110 | ); | 122 | ); |
| 111 | 123 | ||
| 124 | CREATE TRIGGER "map_discussions_comments" | ||
| 125 | AFTER INSERT OR UPDATE OR DELETE ON "map_discussions_comments" | ||
| 126 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 127 | |||
| 112 | CREATE TABLE map_discussions_upvotes ( | 128 | CREATE TABLE map_discussions_upvotes ( |
| 113 | id SERIAL, | 129 | id SERIAL, |
| 114 | discussion_id INT NOT NULL, | 130 | discussion_id INT NOT NULL, |
| @@ -140,6 +156,10 @@ CREATE TABLE records_sp ( | |||
| 140 | FOREIGN KEY (demo_id) REFERENCES demos(id) | 156 | FOREIGN KEY (demo_id) REFERENCES demos(id) |
| 141 | ); | 157 | ); |
| 142 | 158 | ||
| 159 | CREATE TRIGGER "records_sp" | ||
| 160 | AFTER INSERT OR UPDATE OR DELETE ON "records_sp" | ||
| 161 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 162 | |||
| 143 | CREATE TABLE records_mp ( | 163 | CREATE TABLE records_mp ( |
| 144 | id SERIAL, | 164 | id SERIAL, |
| 145 | map_id SMALLINT NOT NULL, | 165 | map_id SMALLINT NOT NULL, |
| @@ -159,6 +179,10 @@ CREATE TABLE records_mp ( | |||
| 159 | FOREIGN KEY (partner_demo_id) REFERENCES demos(id) | 179 | FOREIGN KEY (partner_demo_id) REFERENCES demos(id) |
| 160 | ); | 180 | ); |
| 161 | 181 | ||
| 182 | CREATE TRIGGER "records_mp" | ||
| 183 | AFTER INSERT OR UPDATE OR DELETE ON "records_mp" | ||
| 184 | FOR EACH ROW EXECUTE FUNCTION log_audit(); | ||
| 185 | |||
| 162 | CREATE TABLE titles ( | 186 | CREATE TABLE titles ( |
| 163 | id SERIAL, | 187 | id SERIAL, |
| 164 | title_name TEXT NOT NULL, | 188 | title_name TEXT NOT NULL, |
| @@ -179,13 +203,14 @@ CREATE TABLE countries ( | |||
| 179 | PRIMARY KEY (country_code) | 203 | PRIMARY KEY (country_code) |
| 180 | ); | 204 | ); |
| 181 | 205 | ||
| 182 | CREATE TABLE logs ( | 206 | CREATE TABLE audit ( |
| 183 | id SERIAL, | 207 | id SERIAL, |
| 184 | user_id TEXT NOT NULL, | 208 | table_name TEXT NOT NULL, |
| 185 | type TEXT NOT NULL, | 209 | operation_type TEXT NOT NULL, -- 'INSERT', 'UPDATE', or 'DELETE' |
| 186 | description TEXT NOT NULL, | 210 | old_data JSONB, |
| 187 | message TEXT NOT NULL DEFAULT, | 211 | new_data JSONB, |
| 188 | date TIMESTAMP NOT NULL DEFAULT now(), | 212 | changed_by TEXT NOT NULL, |
| 189 | PRIMARY KEY (id), | 213 | changed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, |
| 190 | FOREIGN KEY (user_id) REFERENCES users(steam_id) | 214 | PRIMARY KEY (id), |
| 191 | ); \ No newline at end of file | 215 | FOREIGN KEY (changed_by) REFERENCES users(steam_id) |
| 216 | ); | ||
diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 71bd68e..44d53e1 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go | |||
| @@ -250,46 +250,6 @@ const docTemplate = `{ | |||
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | }, | 252 | }, |
| 253 | "/logs/mod": { | ||
| 254 | "get": { | ||
| 255 | "description": "Get mod logs.", | ||
| 256 | "produces": [ | ||
| 257 | "application/json" | ||
| 258 | ], | ||
| 259 | "tags": [ | ||
| 260 | "logs" | ||
| 261 | ], | ||
| 262 | "parameters": [ | ||
| 263 | { | ||
| 264 | "type": "string", | ||
| 265 | "description": "JWT Token", | ||
| 266 | "name": "Authorization", | ||
| 267 | "in": "header", | ||
| 268 | "required": true | ||
| 269 | } | ||
| 270 | ], | ||
| 271 | "responses": { | ||
| 272 | "200": { | ||
| 273 | "description": "OK", | ||
| 274 | "schema": { | ||
| 275 | "allOf": [ | ||
| 276 | { | ||
| 277 | "$ref": "#/definitions/models.Response" | ||
| 278 | }, | ||
| 279 | { | ||
| 280 | "type": "object", | ||
| 281 | "properties": { | ||
| 282 | "data": { | ||
| 283 | "$ref": "#/definitions/handlers.LogsResponse" | ||
| 284 | } | ||
| 285 | } | ||
| 286 | } | ||
| 287 | ] | ||
| 288 | } | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | }, | ||
| 293 | "/logs/score": { | 253 | "/logs/score": { |
| 294 | "get": { | 254 | "get": { |
| 295 | "description": "Get score logs of every player.", | 255 | "description": "Get score logs of every player.", |
| @@ -1536,34 +1496,6 @@ const docTemplate = `{ | |||
| 1536 | } | 1496 | } |
| 1537 | } | 1497 | } |
| 1538 | }, | 1498 | }, |
| 1539 | "handlers.LogsResponse": { | ||
| 1540 | "type": "object", | ||
| 1541 | "properties": { | ||
| 1542 | "logs": { | ||
| 1543 | "type": "array", | ||
| 1544 | "items": { | ||
| 1545 | "$ref": "#/definitions/handlers.LogsResponseDetails" | ||
| 1546 | } | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | }, | ||
| 1550 | "handlers.LogsResponseDetails": { | ||
| 1551 | "type": "object", | ||
| 1552 | "properties": { | ||
| 1553 | "date": { | ||
| 1554 | "type": "string" | ||
| 1555 | }, | ||
| 1556 | "detail": { | ||
| 1557 | "type": "string" | ||
| 1558 | }, | ||
| 1559 | "message": { | ||
| 1560 | "type": "string" | ||
| 1561 | }, | ||
| 1562 | "user": { | ||
| 1563 | "$ref": "#/definitions/models.UserShort" | ||
| 1564 | } | ||
| 1565 | } | ||
| 1566 | }, | ||
| 1567 | "handlers.MapDiscussion": { | 1499 | "handlers.MapDiscussion": { |
| 1568 | "type": "object", | 1500 | "type": "object", |
| 1569 | "properties": { | 1501 | "properties": { |
diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 879f35f..6c10cfc 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json | |||
| @@ -244,46 +244,6 @@ | |||
| 244 | } | 244 | } |
| 245 | } | 245 | } |
| 246 | }, | 246 | }, |
| 247 | "/logs/mod": { | ||
| 248 | "get": { | ||
| 249 | "description": "Get mod logs.", | ||
| 250 | "produces": [ | ||
| 251 | "application/json" | ||
| 252 | ], | ||
| 253 | "tags": [ | ||
| 254 | "logs" | ||
| 255 | ], | ||
| 256 | "parameters": [ | ||
| 257 | { | ||
| 258 | "type": "string", | ||
| 259 | "description": "JWT Token", | ||
| 260 | "name": "Authorization", | ||
| 261 | "in": "header", | ||
| 262 | "required": true | ||
| 263 | } | ||
| 264 | ], | ||
| 265 | "responses": { | ||
| 266 | "200": { | ||
| 267 | "description": "OK", | ||
| 268 | "schema": { | ||
| 269 | "allOf": [ | ||
| 270 | { | ||
| 271 | "$ref": "#/definitions/models.Response" | ||
| 272 | }, | ||
| 273 | { | ||
| 274 | "type": "object", | ||
| 275 | "properties": { | ||
| 276 | "data": { | ||
| 277 | "$ref": "#/definitions/handlers.LogsResponse" | ||
| 278 | } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | ] | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | }, | ||
| 287 | "/logs/score": { | 247 | "/logs/score": { |
| 288 | "get": { | 248 | "get": { |
| 289 | "description": "Get score logs of every player.", | 249 | "description": "Get score logs of every player.", |
| @@ -1530,34 +1490,6 @@ | |||
| 1530 | } | 1490 | } |
| 1531 | } | 1491 | } |
| 1532 | }, | 1492 | }, |
| 1533 | "handlers.LogsResponse": { | ||
| 1534 | "type": "object", | ||
| 1535 | "properties": { | ||
| 1536 | "logs": { | ||
| 1537 | "type": "array", | ||
| 1538 | "items": { | ||
| 1539 | "$ref": "#/definitions/handlers.LogsResponseDetails" | ||
| 1540 | } | ||
| 1541 | } | ||
| 1542 | } | ||
| 1543 | }, | ||
| 1544 | "handlers.LogsResponseDetails": { | ||
| 1545 | "type": "object", | ||
| 1546 | "properties": { | ||
| 1547 | "date": { | ||
| 1548 | "type": "string" | ||
| 1549 | }, | ||
| 1550 | "detail": { | ||
| 1551 | "type": "string" | ||
| 1552 | }, | ||
| 1553 | "message": { | ||
| 1554 | "type": "string" | ||
| 1555 | }, | ||
| 1556 | "user": { | ||
| 1557 | "$ref": "#/definitions/models.UserShort" | ||
| 1558 | } | ||
| 1559 | } | ||
| 1560 | }, | ||
| 1561 | "handlers.MapDiscussion": { | 1493 | "handlers.MapDiscussion": { |
| 1562 | "type": "object", | 1494 | "type": "object", |
| 1563 | "properties": { | 1495 | "properties": { |
diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 2dee421..8f33b94 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml | |||
| @@ -106,24 +106,6 @@ definitions: | |||
| 106 | token: | 106 | token: |
| 107 | type: string | 107 | type: string |
| 108 | type: object | 108 | type: object |
| 109 | handlers.LogsResponse: | ||
| 110 | properties: | ||
| 111 | logs: | ||
| 112 | items: | ||
| 113 | $ref: '#/definitions/handlers.LogsResponseDetails' | ||
| 114 | type: array | ||
| 115 | type: object | ||
| 116 | handlers.LogsResponseDetails: | ||
| 117 | properties: | ||
| 118 | date: | ||
| 119 | type: string | ||
| 120 | detail: | ||
| 121 | type: string | ||
| 122 | message: | ||
| 123 | type: string | ||
| 124 | user: | ||
| 125 | $ref: '#/definitions/models.UserShort' | ||
| 126 | type: object | ||
| 127 | handlers.MapDiscussion: | 109 | handlers.MapDiscussion: |
| 128 | properties: | 110 | properties: |
| 129 | comments: | 111 | comments: |
| @@ -690,29 +672,6 @@ paths: | |||
| 690 | type: object | 672 | type: object |
| 691 | tags: | 673 | tags: |
| 692 | - login | 674 | - login |
| 693 | /logs/mod: | ||
| 694 | get: | ||
| 695 | description: Get mod logs. | ||
| 696 | parameters: | ||
| 697 | - description: JWT Token | ||
| 698 | in: header | ||
| 699 | name: Authorization | ||
| 700 | required: true | ||
| 701 | type: string | ||
| 702 | produces: | ||
| 703 | - application/json | ||
| 704 | responses: | ||
| 705 | "200": | ||
| 706 | description: OK | ||
| 707 | schema: | ||
| 708 | allOf: | ||
| 709 | - $ref: '#/definitions/models.Response' | ||
| 710 | - properties: | ||
| 711 | data: | ||
| 712 | $ref: '#/definitions/handlers.LogsResponse' | ||
| 713 | type: object | ||
| 714 | tags: | ||
| 715 | - logs | ||
| 716 | /logs/score: | 675 | /logs/score: |
| 717 | get: | 676 | get: |
| 718 | description: Get score logs of every player. | 677 | description: Get score logs of every player. |
diff --git a/backend/handlers/discussions.go b/backend/handlers/discussions.go index 604eb39..6267695 100644 --- a/backend/handlers/discussions.go +++ b/backend/handlers/discussions.go | |||
| @@ -160,11 +160,7 @@ func CreateMapDiscussion(c *gin.Context) { | |||
| 160 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 160 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 161 | return | 161 | return |
| 162 | } | 162 | } |
| 163 | user, exists := c.Get("user") | 163 | user, _ := c.Get("user") |
| 164 | if !exists { | ||
| 165 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 166 | return | ||
| 167 | } | ||
| 168 | var request CreateMapDiscussionRequest | 164 | var request CreateMapDiscussionRequest |
| 169 | if err := c.BindJSON(&request); err != nil { | 165 | if err := c.BindJSON(&request); err != nil { |
| 170 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 166 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -206,11 +202,7 @@ func CreateMapDiscussionComment(c *gin.Context) { | |||
| 206 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 202 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 207 | return | 203 | return |
| 208 | } | 204 | } |
| 209 | user, exists := c.Get("user") | 205 | user, _ := c.Get("user") |
| 210 | if !exists { | ||
| 211 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 212 | return | ||
| 213 | } | ||
| 214 | var request CreateMapDiscussionCommentRequest | 206 | var request CreateMapDiscussionCommentRequest |
| 215 | if err := c.BindJSON(&request); err != nil { | 207 | if err := c.BindJSON(&request); err != nil { |
| 216 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 208 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -258,11 +250,7 @@ func EditMapDiscussion(c *gin.Context) { | |||
| 258 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 250 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 259 | return | 251 | return |
| 260 | } | 252 | } |
| 261 | user, exists := c.Get("user") | 253 | user, _ := c.Get("user") |
| 262 | if !exists { | ||
| 263 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 264 | return | ||
| 265 | } | ||
| 266 | var request EditMapDiscussionRequest | 254 | var request EditMapDiscussionRequest |
| 267 | if err := c.BindJSON(&request); err != nil { | 255 | if err := c.BindJSON(&request); err != nil { |
| 268 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 256 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -311,11 +299,7 @@ func DeleteMapDiscussion(c *gin.Context) { | |||
| 311 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 299 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 312 | return | 300 | return |
| 313 | } | 301 | } |
| 314 | user, exists := c.Get("user") | 302 | user, _ := c.Get("user") |
| 315 | if !exists { | ||
| 316 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 317 | return | ||
| 318 | } | ||
| 319 | sql := `UPDATE map_discussions SET is_deleted = true WHERE id = $1 AND map_id = $2 AND user_id = $3` | 303 | sql := `UPDATE map_discussions SET is_deleted = true WHERE id = $1 AND map_id = $2 AND user_id = $3` |
| 320 | result, err := database.DB.Exec(sql, discussionID, mapID, user.(models.User).SteamID) | 304 | result, err := database.DB.Exec(sql, discussionID, mapID, user.(models.User).SteamID) |
| 321 | if err != nil { | 305 | if err != nil { |
diff --git a/backend/handlers/login.go b/backend/handlers/login.go index 408d950..51c90d0 100644 --- a/backend/handlers/login.go +++ b/backend/handlers/login.go | |||
| @@ -40,7 +40,6 @@ func Login(c *gin.Context) { | |||
| 40 | default: | 40 | default: |
| 41 | steamID, err := openID.ValidateAndGetID() | 41 | steamID, err := openID.ValidateAndGetID() |
| 42 | if err != nil { | 42 | if err != nil { |
| 43 | CreateLog(steamID, LogTypeUser, LogDescriptionUserLoginFailValidate, err.Error()) | ||
| 44 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 43 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 45 | return | 44 | return |
| 46 | } | 45 | } |
| @@ -51,7 +50,6 @@ func Login(c *gin.Context) { | |||
| 51 | if checkSteamID == 0 { | 50 | if checkSteamID == 0 { |
| 52 | user, err := GetPlayerSummaries(steamID, os.Getenv("API_KEY")) | 51 | user, err := GetPlayerSummaries(steamID, os.Getenv("API_KEY")) |
| 53 | if err != nil { | 52 | if err != nil { |
| 54 | CreateLog(steamID, LogTypeUser, LogDescriptionUserLoginFailSummary, err.Error()) | ||
| 55 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 53 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 56 | return | 54 | return |
| 57 | } | 55 | } |
| @@ -81,7 +79,6 @@ func Login(c *gin.Context) { | |||
| 81 | // Sign and get the complete encoded token as a string using the secret | 79 | // Sign and get the complete encoded token as a string using the secret |
| 82 | tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY"))) | 80 | tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY"))) |
| 83 | if err != nil { | 81 | if err != nil { |
| 84 | CreateLog(steamID, LogTypeUser, LogDescriptionUserLoginFailToken, err.Error()) | ||
| 85 | c.JSON(http.StatusOK, models.ErrorResponse("Failed to generate token.")) | 82 | c.JSON(http.StatusOK, models.ErrorResponse("Failed to generate token.")) |
| 86 | return | 83 | return |
| 87 | } | 84 | } |
diff --git a/backend/handlers/logs.go b/backend/handlers/logs.go index 76ddac4..693c448 100644 --- a/backend/handlers/logs.go +++ b/backend/handlers/logs.go | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | package handlers | 1 | package handlers |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | ||
| 5 | "net/http" | 4 | "net/http" |
| 6 | "time" | 5 | "time" |
| 7 | 6 | ||
| @@ -11,42 +10,6 @@ import ( | |||
| 11 | "github.com/gin-gonic/gin" | 10 | "github.com/gin-gonic/gin" |
| 12 | ) | 11 | ) |
| 13 | 12 | ||
| 14 | const ( | ||
| 15 | LogTypeMod string = "Mod" | ||
| 16 | LogTypeUser string = "User" | ||
| 17 | LogTypeRecord string = "Record" | ||
| 18 | |||
| 19 | LogDescriptionUserLoginSuccess string = "LoginSuccess" | ||
| 20 | LogDescriptionUserLoginFailToken string = "LoginTokenFail" | ||
| 21 | LogDescriptionUserLoginFailValidate string = "LoginValidateFail" | ||
| 22 | LogDescriptionUserLoginFailSummary string = "LoginSummaryFail" | ||
| 23 | LogDescriptionUserUpdateSuccess string = "UpdateSuccess" | ||
| 24 | LogDescriptionUserUpdateFail string = "UpdateFail" | ||
| 25 | LogDescriptionUserUpdateSummaryFail string = "UpdateSummaryFail" | ||
| 26 | LogDescriptionUserUpdateCountrySuccess string = "UpdateCountrySuccess" | ||
| 27 | LogDescriptionUserUpdateCountryFail string = "UpdateCountryFail" | ||
| 28 | |||
| 29 | LogDescriptionMapSummaryCreateSuccess string = "MapSummaryCreateSuccess" | ||
| 30 | LogDescriptionMapSummaryCreateFail string = "MapSummaryCreateFail" | ||
| 31 | LogDescriptionMapSummaryEditSuccess string = "MapSummaryEditSuccess" | ||
| 32 | LogDescriptionMapSummaryEditFail string = "MapSummaryEditFail" | ||
| 33 | LogDescriptionMapSummaryEditImageSuccess string = "MapSummaryEditImageSuccess" | ||
| 34 | LogDescriptionMapSummaryEditImageFail string = "MapSummaryEditImageFail" | ||
| 35 | LogDescriptionMapSummaryDeleteSuccess string = "MapSummaryDeleteSuccess" | ||
| 36 | LogDescriptionMapSummaryDeleteFail string = "MapSummaryDeleteFail" | ||
| 37 | |||
| 38 | LogDescriptionCreateRecordSuccess string = "CreateRecordSuccess" | ||
| 39 | LogDescriptionCreateRecordInsertRecordFail string = "InsertRecordFail" | ||
| 40 | LogDescriptionCreateRecordInsertDemoFail string = "InsertDemoFail" | ||
| 41 | LogDescriptionCreateRecordProcessDemoFail string = "ProcessDemoFail" | ||
| 42 | LogDescriptionCreateRecordCreateDemoFail string = "CreateDemoFail" | ||
| 43 | LogDescriptionCreateRecordOpenDemoFail string = "OpenDemoFail" | ||
| 44 | LogDescriptionCreateRecordSaveDemoFail string = "SaveDemoFail" | ||
| 45 | LogDescriptionCreateRecordInvalidRequestFail string = "InvalidRequestFail" | ||
| 46 | LogDescriptionDeleteRecordSuccess string = "DeleteRecordSuccess" | ||
| 47 | LogDescriptionDeleteRecordFail string = "DeleteRecordFail" | ||
| 48 | ) | ||
| 49 | |||
| 50 | type Log struct { | 13 | type Log struct { |
| 51 | User models.UserShort `json:"user"` | 14 | User models.UserShort `json:"user"` |
| 52 | Type string `json:"type"` | 15 | Type string `json:"type"` |
| @@ -80,54 +43,6 @@ type ScoreLogsResponseDetails struct { | |||
| 80 | Date time.Time `json:"date"` | 43 | Date time.Time `json:"date"` |
| 81 | } | 44 | } |
| 82 | 45 | ||
| 83 | // GET Mod Logs | ||
| 84 | // | ||
| 85 | // @Description Get mod logs. | ||
| 86 | // @Tags logs | ||
| 87 | // @Produce json | ||
| 88 | // @Param Authorization header string true "JWT Token" | ||
| 89 | // @Success 200 {object} models.Response{data=LogsResponse} | ||
| 90 | // @Router /logs/mod [get] | ||
| 91 | func ModLogs(c *gin.Context) { | ||
| 92 | mod, exists := c.Get("mod") | ||
| 93 | if !exists || !mod.(bool) { | ||
| 94 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) | ||
| 95 | return | ||
| 96 | } | ||
| 97 | response := LogsResponse{Logs: []LogsResponseDetails{}} | ||
| 98 | sql := `SELECT u.user_name, l.user_id, l.type, l.description, l.message, l.date | ||
| 99 | FROM logs l INNER JOIN users u ON l.user_id = u.steam_id WHERE type != 'Score' | ||
| 100 | ORDER BY l.date DESC LIMIT 100;` | ||
| 101 | rows, err := database.DB.Query(sql) | ||
| 102 | if err != nil { | ||
| 103 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 104 | return | ||
| 105 | } | ||
| 106 | for rows.Next() { | ||
| 107 | log := Log{} | ||
| 108 | err = rows.Scan(&log.User.UserName, &log.User.SteamID, &log.Type, &log.Description, &log.Message, &log.Date) | ||
| 109 | if err != nil { | ||
| 110 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 111 | return | ||
| 112 | } | ||
| 113 | detail := fmt.Sprintf("%s.%s", log.Type, log.Description) | ||
| 114 | response.Logs = append(response.Logs, LogsResponseDetails{ | ||
| 115 | User: models.UserShort{ | ||
| 116 | SteamID: log.User.SteamID, | ||
| 117 | UserName: log.User.UserName, | ||
| 118 | }, | ||
| 119 | Log: detail, | ||
| 120 | Message: log.Message, | ||
| 121 | Date: log.Date, | ||
| 122 | }) | ||
| 123 | } | ||
| 124 | c.JSON(http.StatusOK, models.Response{ | ||
| 125 | Success: true, | ||
| 126 | Message: "Successfully retrieved logs.", | ||
| 127 | Data: response, | ||
| 128 | }) | ||
| 129 | } | ||
| 130 | |||
| 131 | // GET Score Logs | 46 | // GET Score Logs |
| 132 | // | 47 | // |
| 133 | // @Description Get score logs of every player. | 48 | // @Description Get score logs of every player. |
| @@ -186,16 +101,3 @@ func ScoreLogs(c *gin.Context) { | |||
| 186 | Data: response, | 101 | Data: response, |
| 187 | }) | 102 | }) |
| 188 | } | 103 | } |
| 189 | |||
| 190 | func CreateLog(userID string, logType string, logDescription string, logMessage ...string) (err error) { | ||
| 191 | message := "-" | ||
| 192 | if len(logMessage) == 1 { | ||
| 193 | message = logMessage[0] | ||
| 194 | } | ||
| 195 | sql := `INSERT INTO logs (user_id, "type", description, message) VALUES($1, $2, $3, $4)` | ||
| 196 | _, err = database.DB.Exec(sql, userID, logType, logDescription, message) | ||
| 197 | if err != nil { | ||
| 198 | return err | ||
| 199 | } | ||
| 200 | return nil | ||
| 201 | } | ||
diff --git a/backend/handlers/mod.go b/backend/handlers/mod.go index 4fdc78a..66e1437 100644 --- a/backend/handlers/mod.go +++ b/backend/handlers/mod.go | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | package handlers | 1 | package handlers |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | ||
| 5 | "net/http" | 4 | "net/http" |
| 6 | "strconv" | 5 | "strconv" |
| 7 | "time" | 6 | "time" |
| @@ -49,12 +48,6 @@ type EditMapImageRequest struct { | |||
| 49 | // @Success 200 {object} models.Response{data=CreateMapSummaryRequest} | 48 | // @Success 200 {object} models.Response{data=CreateMapSummaryRequest} |
| 50 | // @Router /maps/{mapid}/summary [post] | 49 | // @Router /maps/{mapid}/summary [post] |
| 51 | func CreateMapSummary(c *gin.Context) { | 50 | func CreateMapSummary(c *gin.Context) { |
| 52 | // Check if user exists | ||
| 53 | user, exists := c.Get("user") | ||
| 54 | if !exists { | ||
| 55 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 56 | return | ||
| 57 | } | ||
| 58 | mod, exists := c.Get("mod") | 51 | mod, exists := c.Get("mod") |
| 59 | if !exists || !mod.(bool) { | 52 | if !exists || !mod.(bool) { |
| 60 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) | 53 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) |
| @@ -69,7 +62,6 @@ func CreateMapSummary(c *gin.Context) { | |||
| 69 | } | 62 | } |
| 70 | var request CreateMapSummaryRequest | 63 | var request CreateMapSummaryRequest |
| 71 | if err := c.BindJSON(&request); err != nil { | 64 | if err := c.BindJSON(&request); err != nil { |
| 72 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryCreateFail, fmt.Sprintf("BIND: %s", err.Error())) | ||
| 73 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 65 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 74 | return | 66 | return |
| 75 | } | 67 | } |
| @@ -85,7 +77,6 @@ func CreateMapSummary(c *gin.Context) { | |||
| 85 | sql := `SELECT m.id FROM maps m WHERE m.id = $1` | 77 | sql := `SELECT m.id FROM maps m WHERE m.id = $1` |
| 86 | err = database.DB.QueryRow(sql, mapID).Scan(&checkMapID) | 78 | err = database.DB.QueryRow(sql, mapID).Scan(&checkMapID) |
| 87 | if err != nil { | 79 | if err != nil { |
| 88 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryCreateFail, fmt.Sprintf("SELECT#maps: %s", err.Error())) | ||
| 89 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 80 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 90 | return | 81 | return |
| 91 | } | 82 | } |
| @@ -98,7 +89,6 @@ func CreateMapSummary(c *gin.Context) { | |||
| 98 | VALUES ($1,$2,$3,$4,$5,$6,$7)` | 89 | VALUES ($1,$2,$3,$4,$5,$6,$7)` |
| 99 | _, err = tx.Exec(sql, mapID, request.CategoryID, request.UserName, *request.ScoreCount, request.Description, request.Showcase, request.RecordDate) | 90 | _, err = tx.Exec(sql, mapID, request.CategoryID, request.UserName, *request.ScoreCount, request.Description, request.Showcase, request.RecordDate) |
| 100 | if err != nil { | 91 | if err != nil { |
| 101 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryCreateFail, fmt.Sprintf("INSERT#map_history: %s", err.Error())) | ||
| 102 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 92 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 103 | return | 93 | return |
| 104 | } | 94 | } |
| @@ -106,7 +96,6 @@ func CreateMapSummary(c *gin.Context) { | |||
| 106 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 96 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 107 | return | 97 | return |
| 108 | } | 98 | } |
| 109 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryCreateSuccess, fmt.Sprintf("MapID: %d | CategoryID: %d | ScoreCount: %d", mapID, request.CategoryID, *request.ScoreCount)) | ||
| 110 | c.JSON(http.StatusOK, models.Response{ | 99 | c.JSON(http.StatusOK, models.Response{ |
| 111 | Success: true, | 100 | Success: true, |
| 112 | Message: "Successfully created map summary.", | 101 | Message: "Successfully created map summary.", |
| @@ -125,12 +114,6 @@ func CreateMapSummary(c *gin.Context) { | |||
| 125 | // @Success 200 {object} models.Response{data=EditMapSummaryRequest} | 114 | // @Success 200 {object} models.Response{data=EditMapSummaryRequest} |
| 126 | // @Router /maps/{mapid}/summary [put] | 115 | // @Router /maps/{mapid}/summary [put] |
| 127 | func EditMapSummary(c *gin.Context) { | 116 | func EditMapSummary(c *gin.Context) { |
| 128 | // Check if user exists | ||
| 129 | user, exists := c.Get("user") | ||
| 130 | if !exists { | ||
| 131 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 132 | return | ||
| 133 | } | ||
| 134 | mod, exists := c.Get("mod") | 117 | mod, exists := c.Get("mod") |
| 135 | if !exists || !mod.(bool) { | 118 | if !exists || !mod.(bool) { |
| 136 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) | 119 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) |
| @@ -146,7 +129,6 @@ func EditMapSummary(c *gin.Context) { | |||
| 146 | } | 129 | } |
| 147 | var request EditMapSummaryRequest | 130 | var request EditMapSummaryRequest |
| 148 | if err := c.BindJSON(&request); err != nil { | 131 | if err := c.BindJSON(&request); err != nil { |
| 149 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditFail, fmt.Sprintf("BIND: %s", err.Error())) | ||
| 150 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 132 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 151 | return | 133 | return |
| 152 | } | 134 | } |
| @@ -161,7 +143,6 @@ func EditMapSummary(c *gin.Context) { | |||
| 161 | sql := `UPDATE map_history SET user_name = $2, score_count = $3, record_date = $4, description = $5, showcase = $6 WHERE id = $1` | 143 | sql := `UPDATE map_history SET user_name = $2, score_count = $3, record_date = $4, description = $5, showcase = $6 WHERE id = $1` |
| 162 | _, err = tx.Exec(sql, request.RouteID, request.UserName, *request.ScoreCount, request.RecordDate, request.Description, request.Showcase) | 144 | _, err = tx.Exec(sql, request.RouteID, request.UserName, *request.ScoreCount, request.RecordDate, request.Description, request.Showcase) |
| 163 | if err != nil { | 145 | if err != nil { |
| 164 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditFail, fmt.Sprintf("(HistoryID: %d) UPDATE#map_history: %s", request.RouteID, err.Error())) | ||
| 165 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 146 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 166 | return | 147 | return |
| 167 | } | 148 | } |
| @@ -187,12 +168,6 @@ func EditMapSummary(c *gin.Context) { | |||
| 187 | // @Success 200 {object} models.Response{data=DeleteMapSummaryRequest} | 168 | // @Success 200 {object} models.Response{data=DeleteMapSummaryRequest} |
| 188 | // @Router /maps/{mapid}/summary [delete] | 169 | // @Router /maps/{mapid}/summary [delete] |
| 189 | func DeleteMapSummary(c *gin.Context) { | 170 | func DeleteMapSummary(c *gin.Context) { |
| 190 | // Check if user exists | ||
| 191 | user, exists := c.Get("user") | ||
| 192 | if !exists { | ||
| 193 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 194 | return | ||
| 195 | } | ||
| 196 | mod, exists := c.Get("mod") | 171 | mod, exists := c.Get("mod") |
| 197 | if !exists || !mod.(bool) { | 172 | if !exists || !mod.(bool) { |
| 198 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) | 173 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) |
| @@ -208,7 +183,6 @@ func DeleteMapSummary(c *gin.Context) { | |||
| 208 | } | 183 | } |
| 209 | var request DeleteMapSummaryRequest | 184 | var request DeleteMapSummaryRequest |
| 210 | if err := c.BindJSON(&request); err != nil { | 185 | if err := c.BindJSON(&request); err != nil { |
| 211 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditFail, fmt.Sprintf("(RouteID: %d) BIND: %s", request.RouteID, err.Error())) | ||
| 212 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 186 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 213 | return | 187 | return |
| 214 | } | 188 | } |
| @@ -223,7 +197,6 @@ func DeleteMapSummary(c *gin.Context) { | |||
| 223 | sql := `DELETE FROM map_history mh WHERE mh.id = $1` | 197 | sql := `DELETE FROM map_history mh WHERE mh.id = $1` |
| 224 | _, err = tx.Exec(sql, request.RouteID) | 198 | _, err = tx.Exec(sql, request.RouteID) |
| 225 | if err != nil { | 199 | if err != nil { |
| 226 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryDeleteFail, fmt.Sprintf("(HistoryID: %d) DELETE#map_history: %s", request.RouteID, err.Error())) | ||
| 227 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 200 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 228 | return | 201 | return |
| 229 | } | 202 | } |
| @@ -249,12 +222,6 @@ func DeleteMapSummary(c *gin.Context) { | |||
| 249 | // @Success 200 {object} models.Response{data=EditMapImageRequest} | 222 | // @Success 200 {object} models.Response{data=EditMapImageRequest} |
| 250 | // @Router /maps/{mapid}/image [put] | 223 | // @Router /maps/{mapid}/image [put] |
| 251 | func EditMapImage(c *gin.Context) { | 224 | func EditMapImage(c *gin.Context) { |
| 252 | // Check if user exists | ||
| 253 | user, exists := c.Get("user") | ||
| 254 | if !exists { | ||
| 255 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 256 | return | ||
| 257 | } | ||
| 258 | mod, exists := c.Get("mod") | 225 | mod, exists := c.Get("mod") |
| 259 | if !exists || !mod.(bool) { | 226 | if !exists || !mod.(bool) { |
| 260 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) | 227 | c.JSON(http.StatusOK, models.ErrorResponse("Insufficient permissions.")) |
| @@ -269,7 +236,6 @@ func EditMapImage(c *gin.Context) { | |||
| 269 | } | 236 | } |
| 270 | var request EditMapImageRequest | 237 | var request EditMapImageRequest |
| 271 | if err := c.BindJSON(&request); err != nil { | 238 | if err := c.BindJSON(&request); err != nil { |
| 272 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditImageFail, fmt.Sprintf("BIND: %s", err.Error())) | ||
| 273 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 239 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 274 | return | 240 | return |
| 275 | } | 241 | } |
| @@ -277,11 +243,9 @@ func EditMapImage(c *gin.Context) { | |||
| 277 | sql := `UPDATE maps SET image = $2 WHERE id = $1` | 243 | sql := `UPDATE maps SET image = $2 WHERE id = $1` |
| 278 | _, err = database.DB.Exec(sql, mapID, request.Image) | 244 | _, err = database.DB.Exec(sql, mapID, request.Image) |
| 279 | if err != nil { | 245 | if err != nil { |
| 280 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditImageFail, fmt.Sprintf("UPDATE#maps: %s", err.Error())) | ||
| 281 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 246 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 282 | return | 247 | return |
| 283 | } | 248 | } |
| 284 | CreateLog(user.(models.User).SteamID, LogTypeMod, LogDescriptionMapSummaryEditImageSuccess) | ||
| 285 | c.JSON(http.StatusOK, models.Response{ | 249 | c.JSON(http.StatusOK, models.Response{ |
| 286 | Success: true, | 250 | Success: true, |
| 287 | Message: "Successfully updated map image.", | 251 | Message: "Successfully updated map image.", |
diff --git a/backend/handlers/record.go b/backend/handlers/record.go index e43cc61..bedde57 100644 --- a/backend/handlers/record.go +++ b/backend/handlers/record.go | |||
| @@ -53,12 +53,7 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 53 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 53 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 54 | return | 54 | return |
| 55 | } | 55 | } |
| 56 | // Check if user exists | 56 | user, _ := c.Get("user") |
| 57 | user, exists := c.Get("user") | ||
| 58 | if !exists { | ||
| 59 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 60 | return | ||
| 61 | } | ||
| 62 | // Check if map is sp or mp | 57 | // Check if map is sp or mp |
| 63 | var gameName string | 58 | var gameName string |
| 64 | var isCoop bool | 59 | var isCoop bool |
| @@ -76,12 +71,10 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 76 | // Get record request | 71 | // Get record request |
| 77 | var record RecordRequest | 72 | var record RecordRequest |
| 78 | if err := c.ShouldBind(&record); err != nil { | 73 | if err := c.ShouldBind(&record); err != nil { |
| 79 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInvalidRequestFail, "BIND: "+err.Error()) | ||
| 80 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 74 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 81 | return | 75 | return |
| 82 | } | 76 | } |
| 83 | if isCoop && record.PartnerDemo == nil { | 77 | if isCoop && record.PartnerDemo == nil { |
| 84 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInvalidRequestFail) | ||
| 85 | c.JSON(http.StatusOK, models.ErrorResponse("Missing partner demo for coop submission.")) | 78 | c.JSON(http.StatusOK, models.ErrorResponse("Missing partner demo for coop submission.")) |
| 86 | return | 79 | return |
| 87 | } | 80 | } |
| @@ -112,21 +105,18 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 112 | // Upload & insert into demos | 105 | // Upload & insert into demos |
| 113 | err = c.SaveUploadedFile(header, "parser/"+uuid+".dem") | 106 | err = c.SaveUploadedFile(header, "parser/"+uuid+".dem") |
| 114 | if err != nil { | 107 | if err != nil { |
| 115 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordSaveDemoFail, err.Error()) | ||
| 116 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 108 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 117 | return | 109 | return |
| 118 | } | 110 | } |
| 119 | defer os.Remove("parser/" + uuid + ".dem") | 111 | defer os.Remove("parser/" + uuid + ".dem") |
| 120 | f, err := os.Open("parser/" + uuid + ".dem") | 112 | f, err := os.Open("parser/" + uuid + ".dem") |
| 121 | if err != nil { | 113 | if err != nil { |
| 122 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordOpenDemoFail, err.Error()) | ||
| 123 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 114 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 124 | return | 115 | return |
| 125 | } | 116 | } |
| 126 | defer f.Close() | 117 | defer f.Close() |
| 127 | parserResult, err := parser.ProcessDemo("parser/" + uuid + ".dem") | 118 | parserResult, err := parser.ProcessDemo("parser/" + uuid + ".dem") |
| 128 | if err != nil { | 119 | if err != nil { |
| 129 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) | ||
| 130 | c.JSON(http.StatusOK, models.ErrorResponse("Error while processing demo: "+err.Error())) | 120 | c.JSON(http.StatusOK, models.ErrorResponse("Error while processing demo: "+err.Error())) |
| 131 | return | 121 | return |
| 132 | } | 122 | } |
| @@ -139,7 +129,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 139 | hostSteamID = parserResult.HostSteamID | 129 | hostSteamID = parserResult.HostSteamID |
| 140 | partnerSteamID = parserResult.PartnerSteamID | 130 | partnerSteamID = parserResult.PartnerSteamID |
| 141 | if hostDemoScoreCount == 0 && hostDemoScoreTime == 0 { | 131 | if hostDemoScoreCount == 0 && hostDemoScoreTime == 0 { |
| 142 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) | ||
| 143 | c.JSON(http.StatusOK, models.ErrorResponse("Processing demo went wrong. Please contact a web admin and provide the demo in question.")) | 132 | c.JSON(http.StatusOK, models.ErrorResponse("Processing demo went wrong. Please contact a web admin and provide the demo in question.")) |
| 144 | return | 133 | return |
| 145 | } | 134 | } |
| @@ -161,7 +150,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 161 | } | 150 | } |
| 162 | file, err := createFile(srv, uuid+".dem", "application/octet-stream", f, os.Getenv("GOOGLE_FOLDER_ID")) | 151 | file, err := createFile(srv, uuid+".dem", "application/octet-stream", f, os.Getenv("GOOGLE_FOLDER_ID")) |
| 163 | if err != nil { | 152 | if err != nil { |
| 164 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordCreateDemoFail, err.Error()) | ||
| 165 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 153 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 166 | return | 154 | return |
| 167 | } | 155 | } |
| @@ -177,7 +165,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 177 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) | 165 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) |
| 178 | if err != nil { | 166 | if err != nil { |
| 179 | deleteFile(srv, file.Id) | 167 | deleteFile(srv, file.Id) |
| 180 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInsertDemoFail, err.Error()) | ||
| 181 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 168 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 182 | return | 169 | return |
| 183 | } | 170 | } |
| @@ -229,7 +216,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 229 | if err != nil { | 216 | if err != nil { |
| 230 | deleteFile(srv, hostDemoFileID) | 217 | deleteFile(srv, hostDemoFileID) |
| 231 | deleteFile(srv, partnerDemoFileID) | 218 | deleteFile(srv, partnerDemoFileID) |
| 232 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInsertRecordFail, err.Error()) | ||
| 233 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 219 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 234 | return | 220 | return |
| 235 | } | 221 | } |
| @@ -239,7 +225,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 239 | _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) | 225 | _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) |
| 240 | if err != nil { | 226 | if err != nil { |
| 241 | deleteFile(srv, hostDemoFileID) | 227 | deleteFile(srv, hostDemoFileID) |
| 242 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInsertRecordFail, err.Error()) | ||
| 243 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 228 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 244 | return | 229 | return |
| 245 | } | 230 | } |
| @@ -248,7 +233,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 248 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 233 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 249 | return | 234 | return |
| 250 | } | 235 | } |
| 251 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordSuccess) | ||
| 252 | c.JSON(http.StatusOK, models.Response{ | 236 | c.JSON(http.StatusOK, models.Response{ |
| 253 | Success: true, | 237 | Success: true, |
| 254 | Message: "Successfully created record.", | 238 | Message: "Successfully created record.", |
| @@ -277,11 +261,7 @@ func DeleteRecord(c *gin.Context) { | |||
| 277 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 261 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 278 | return | 262 | return |
| 279 | } | 263 | } |
| 280 | user, exists := c.Get("user") | 264 | user, _ := c.Get("user") |
| 281 | if !exists { | ||
| 282 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 283 | return | ||
| 284 | } | ||
| 285 | // Validate map | 265 | // Validate map |
| 286 | var validateMapID int | 266 | var validateMapID int |
| 287 | var isCoop bool | 267 | var isCoop bool |
| @@ -302,12 +282,10 @@ func DeleteRecord(c *gin.Context) { | |||
| 302 | 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` | 282 | 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` |
| 303 | err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID) | 283 | err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID) |
| 304 | if err != nil { | 284 | if err != nil { |
| 305 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "SELECT#records_mp: "+err.Error()) | ||
| 306 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 285 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 307 | return | 286 | return |
| 308 | } | 287 | } |
| 309 | if recordID != validateRecordID { | 288 | if recordID != validateRecordID { |
| 310 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "recordID != validateRecordID") | ||
| 311 | c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist.")) | 289 | c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist.")) |
| 312 | return | 290 | return |
| 313 | } | 291 | } |
| @@ -315,7 +293,6 @@ func DeleteRecord(c *gin.Context) { | |||
| 315 | sql = `UPDATE records_mp SET is_deleted = true WHERE id = $1` | 293 | sql = `UPDATE records_mp SET is_deleted = true WHERE id = $1` |
| 316 | _, err = database.DB.Exec(sql, recordID) | 294 | _, err = database.DB.Exec(sql, recordID) |
| 317 | if err != nil { | 295 | if err != nil { |
| 318 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "UPDATE#records_mp: "+err.Error()) | ||
| 319 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 296 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 320 | return | 297 | return |
| 321 | } | 298 | } |
| @@ -325,12 +302,10 @@ func DeleteRecord(c *gin.Context) { | |||
| 325 | 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` | 302 | 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` |
| 326 | err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID) | 303 | err = database.DB.QueryRow(sql, recordID, mapID, user.(models.User).SteamID).Scan(&validateRecordID) |
| 327 | if err != nil { | 304 | if err != nil { |
| 328 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "SELECT#records_sp: "+err.Error()) | ||
| 329 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 305 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 330 | return | 306 | return |
| 331 | } | 307 | } |
| 332 | if recordID != validateRecordID { | 308 | if recordID != validateRecordID { |
| 333 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "recordID != validateRecordID") | ||
| 334 | c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist.")) | 309 | c.JSON(http.StatusOK, models.ErrorResponse("Selected record does not exist.")) |
| 335 | return | 310 | return |
| 336 | } | 311 | } |
| @@ -338,12 +313,10 @@ func DeleteRecord(c *gin.Context) { | |||
| 338 | sql = `UPDATE records_sp SET is_deleted = true WHERE id = $1` | 313 | sql = `UPDATE records_sp SET is_deleted = true WHERE id = $1` |
| 339 | _, err = database.DB.Exec(sql, recordID) | 314 | _, err = database.DB.Exec(sql, recordID) |
| 340 | if err != nil { | 315 | if err != nil { |
| 341 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordFail, "UPDATE#records_sp: "+err.Error()) | ||
| 342 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 316 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 343 | return | 317 | return |
| 344 | } | 318 | } |
| 345 | } | 319 | } |
| 346 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionDeleteRecordSuccess) | ||
| 347 | c.JSON(http.StatusOK, models.Response{ | 320 | c.JSON(http.StatusOK, models.Response{ |
| 348 | Success: true, | 321 | Success: true, |
| 349 | Message: "Successfully deleted record.", | 322 | Message: "Successfully deleted record.", |
diff --git a/backend/handlers/user.go b/backend/handlers/user.go index 021a47f..53f0d06 100644 --- a/backend/handlers/user.go +++ b/backend/handlers/user.go | |||
| @@ -69,12 +69,7 @@ type ScoreResponse struct { | |||
| 69 | // @Success 200 {object} models.Response{data=ProfileResponse} | 69 | // @Success 200 {object} models.Response{data=ProfileResponse} |
| 70 | // @Router /profile [get] | 70 | // @Router /profile [get] |
| 71 | func Profile(c *gin.Context) { | 71 | func Profile(c *gin.Context) { |
| 72 | // Check if user exists | 72 | user, _ := c.Get("user") |
| 73 | user, exists := c.Get("user") | ||
| 74 | if !exists { | ||
| 75 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 76 | return | ||
| 77 | } | ||
| 78 | // Get user links | 73 | // Get user links |
| 79 | links := models.Links{} | 74 | links := models.Links{} |
| 80 | sql := `SELECT u.p2sr, u.steam, u.youtube, u.twitch FROM users u WHERE u.steam_id = $1` | 75 | sql := `SELECT u.p2sr, u.steam, u.youtube, u.twitch FROM users u WHERE u.steam_id = $1` |
| @@ -699,15 +694,9 @@ func FetchUser(c *gin.Context) { | |||
| 699 | // @Success 200 {object} models.Response{data=ProfileResponse} | 694 | // @Success 200 {object} models.Response{data=ProfileResponse} |
| 700 | // @Router /profile [post] | 695 | // @Router /profile [post] |
| 701 | func UpdateUser(c *gin.Context) { | 696 | func UpdateUser(c *gin.Context) { |
| 702 | // Check if user exists | 697 | user, _ := c.Get("user") |
| 703 | user, exists := c.Get("user") | ||
| 704 | if !exists { | ||
| 705 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 706 | return | ||
| 707 | } | ||
| 708 | profile, err := GetPlayerSummaries(user.(models.User).SteamID, os.Getenv("API_KEY")) | 698 | profile, err := GetPlayerSummaries(user.(models.User).SteamID, os.Getenv("API_KEY")) |
| 709 | if err != nil { | 699 | if err != nil { |
| 710 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateSummaryFail, err.Error()) | ||
| 711 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 700 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 712 | return | 701 | return |
| 713 | } | 702 | } |
| @@ -715,11 +704,9 @@ func UpdateUser(c *gin.Context) { | |||
| 715 | sql := `UPDATE users SET user_name = $1, avatar_link = $2, country_code = $3, updated_at = $4 WHERE steam_id = $5` | 704 | sql := `UPDATE users SET user_name = $1, avatar_link = $2, country_code = $3, updated_at = $4 WHERE steam_id = $5` |
| 716 | _, err = database.DB.Exec(sql, profile.PersonaName, profile.AvatarFull, profile.LocCountryCode, time.Now().UTC(), user.(models.User).SteamID) | 705 | _, err = database.DB.Exec(sql, profile.PersonaName, profile.AvatarFull, profile.LocCountryCode, time.Now().UTC(), user.(models.User).SteamID) |
| 717 | if err != nil { | 706 | if err != nil { |
| 718 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateFail, "UPDATE#users: "+err.Error()) | ||
| 719 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 707 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 720 | return | 708 | return |
| 721 | } | 709 | } |
| 722 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateSuccess) | ||
| 723 | c.JSON(http.StatusOK, models.Response{ | 710 | c.JSON(http.StatusOK, models.Response{ |
| 724 | Success: true, | 711 | Success: true, |
| 725 | Message: "Successfully updated user.", | 712 | Message: "Successfully updated user.", |
| @@ -744,33 +731,24 @@ func UpdateUser(c *gin.Context) { | |||
| 744 | // @Success 200 {object} models.Response | 731 | // @Success 200 {object} models.Response |
| 745 | // @Router /profile [put] | 732 | // @Router /profile [put] |
| 746 | func UpdateCountryCode(c *gin.Context) { | 733 | func UpdateCountryCode(c *gin.Context) { |
| 747 | // Check if user exists | 734 | user, _ := c.Get("user") |
| 748 | user, exists := c.Get("user") | ||
| 749 | if !exists { | ||
| 750 | c.JSON(http.StatusOK, models.ErrorResponse("User not logged in.")) | ||
| 751 | return | ||
| 752 | } | ||
| 753 | code := c.Query("country_code") | 735 | code := c.Query("country_code") |
| 754 | if code == "" { | 736 | if code == "" { |
| 755 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateCountryFail) | ||
| 756 | c.JSON(http.StatusOK, models.ErrorResponse("Enter a valid country code.")) | 737 | c.JSON(http.StatusOK, models.ErrorResponse("Enter a valid country code.")) |
| 757 | return | 738 | return |
| 758 | } | 739 | } |
| 759 | var validCode string | 740 | var validCode string |
| 760 | err := database.DB.QueryRow(`SELECT country_code FROM countries WHERE country_code = $1`, code).Scan(&validCode) | 741 | err := database.DB.QueryRow(`SELECT country_code FROM countries WHERE country_code = $1`, code).Scan(&validCode) |
| 761 | if err != nil { | 742 | if err != nil { |
| 762 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateCountryFail) | ||
| 763 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 743 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 764 | return | 744 | return |
| 765 | } | 745 | } |
| 766 | // Valid code, update profile | 746 | // Valid code, update profile |
| 767 | _, err = database.DB.Exec(`UPDATE users SET country_code = $1 WHERE steam_id = $2`, validCode, user.(models.User).SteamID) | 747 | _, err = database.DB.Exec(`UPDATE users SET country_code = $1 WHERE steam_id = $2`, validCode, user.(models.User).SteamID) |
| 768 | if err != nil { | 748 | if err != nil { |
| 769 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateCountryFail) | ||
| 770 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 749 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 771 | return | 750 | return |
| 772 | } | 751 | } |
| 773 | CreateLog(user.(models.User).SteamID, LogTypeUser, LogDescriptionUserUpdateCountrySuccess) | ||
| 774 | c.JSON(http.StatusOK, models.Response{ | 752 | c.JSON(http.StatusOK, models.Response{ |
| 775 | Success: true, | 753 | Success: true, |
| 776 | Message: "Successfully updated country code.", | 754 | Message: "Successfully updated country code.", |