diff options
Diffstat (limited to '')
| -rw-r--r-- | FUNDING.yml | 1 | ||||
| -rw-r--r-- | README.md | 34 | ||||
| -rw-r--r-- | backend/controllers/homeController.go | 59 | ||||
| -rw-r--r-- | backend/controllers/loginController.go | 48 | ||||
| -rw-r--r-- | backend/controllers/mapController.go | 146 | ||||
| -rw-r--r-- | backend/controllers/modController.go | 327 | ||||
| -rw-r--r-- | backend/controllers/recordController.go | 134 | ||||
| -rw-r--r-- | backend/controllers/userController.go | 74 | ||||
| -rw-r--r-- | backend/database/chapters.sql | 32 | ||||
| -rw-r--r-- | backend/database/games.sql | 6 | ||||
| -rw-r--r-- | backend/database/history.sql | 524 | ||||
| -rw-r--r-- | backend/database/init.sql | 44 | ||||
| -rw-r--r-- | backend/database/route.sql | 279 | ||||
| -rw-r--r-- | backend/middleware/auth.go | 10 | ||||
| -rw-r--r-- | backend/models/models.go | 150 | ||||
| -rw-r--r-- | backend/models/requests.go | 39 | ||||
| -rw-r--r-- | backend/models/responses.go | 64 | ||||
| -rw-r--r-- | backend/parser/parser.REMOVED.git-id | 1 | ||||
| -rw-r--r-- | backend/parser/parser.go | 43 | ||||
| -rw-r--r-- | backend/routes/routes.go | 12 | ||||
| -rw-r--r-- | docs/docs.go | 641 | ||||
| -rw-r--r-- | docs/swagger.json | 641 | ||||
| -rw-r--r-- | docs/swagger.yaml | 422 | ||||
| -rw-r--r-- | go.mod | 1 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | main.go | 2 |
26 files changed, 2623 insertions, 1113 deletions
diff --git a/FUNDING.yml b/FUNDING.yml new file mode 100644 index 0000000..bd67f90 --- /dev/null +++ b/FUNDING.yml | |||
| @@ -0,0 +1 @@ | |||
| github: pektezol \ No newline at end of file | |||
| @@ -1,6 +1,12 @@ | |||
| 1 | # Portal 2 Least Portals Database | 1 | # Portal 2 Least Portals Hub |
| 2 | 2 | ||
| 3 | This project is work in progress. | 3 | ## About LPHUB |
| 4 | |||
| 5 | Least Portals Hub (LPHUB) is a community-driven platform that aims to gather knowledge and competition of the Portal 2 Least Portals (LP) category in one place. LPHUB is dedicated to bringing together users who love the challenge of LP, where the goal is to complete a level using the fewest number of portals possible that is placed by the player. | ||
| 6 | |||
| 7 | Our comprehensive map library contains detailed, wiki-style information for maps from Portal 2 and their mods, including strategies and routes for achieving specific portal counts. These guides are designed to assist players of all levels in improving their skills, understanding the game's mechanics better, and finding innovative ways to lower their portal usage. | ||
| 8 | |||
| 9 | In addition, we host a leaderboard section for each map where users can compare their accomplishments and compete for having the lowest amount of portals possible. Users can upload their records, along with demo proof in order to get on to the leaderboards. | ||
| 4 | 10 | ||
| 5 | ## Project Team | 11 | ## Project Team |
| 6 | 12 | ||
| @@ -9,6 +15,10 @@ This project is work in progress. | |||
| 9 | * [@Nidboj132](https://github.com/Nidboj132) - Frontend | 15 | * [@Nidboj132](https://github.com/Nidboj132) - Frontend |
| 10 | * [@Oryn](https://github.com/Oryn-Goia) - Subject Expert | 16 | * [@Oryn](https://github.com/Oryn-Goia) - Subject Expert |
| 11 | 17 | ||
| 18 | ## Special Thanks | ||
| 19 | |||
| 20 | * [@UncraftedName](https://github.com/UncraftedName) - For providing the parser that retrieves total portal count and elapsed time from the CM counter. | ||
| 21 | |||
| 12 | ## Documentation | 22 | ## Documentation |
| 13 | 23 | ||
| 14 | Full documentation can be found at https://lp.ardapektezol.com/api/v1/ | 24 | Full documentation can be found at https://lp.ardapektezol.com/api/v1/ |
| @@ -19,4 +29,22 @@ This project is licensed under the GNU General Public License v2.0 - see the [LI | |||
| 19 | 29 | ||
| 20 | ## Contact | 30 | ## Contact |
| 21 | 31 | ||
| 22 | If you have any questions or feedback, please feel free to contact us at our [Discord](https://discord.gg/xq6TySyA4c). \ No newline at end of file | 32 | If you have any questions or feedback, please feel free to contact us at our [Discord](https://discord.gg/xq6TySyA4c). |
| 33 | |||
| 34 | ## Support | ||
| 35 | |||
| 36 | If you want to support the creator, you can do so by using GitHub sponsorships by [clicking here](https://github.com/sponsors/pektezol). | ||
| 37 | |||
| 38 | ## Disclaimer | ||
| 39 | |||
| 40 | This project, "Portal 2 Least Portals Hub" (hereafter referred to as "LPHUB"), is an unofficial community-driven resource providing strategies, routes, leaderboards, and other information related to the "Least Portals" category of the game "Portal 2". LPHUB is not affiliated with or endorsed by the creators, developers, or publishers of "Portal 2", including but not limited to Valve Corporation. | ||
| 41 | |||
| 42 | The strategies, routes, leaderboard entries, and other information presented on LPHUB are provided by members of the community and are not guaranteed to be correct, accurate, or applicable to all versions or modes of "Portal 2". Users are encouraged to verify information and submit corrections or additions as necessary. | ||
| 43 | |||
| 44 | Leaderboard entries must include demo proof, which is subject to review by LPHUB administrators and moderators. While every effort is made to ensure the integrity of the leaderboard, LPHUB cannot guarantee the authenticity or accuracy of any submitted record or demo. | ||
| 45 | |||
| 46 | The source code for LPHUB is licensed under the GNU General Public License version 2.0 (GPL-2.0). By using LPHUB, you agree to abide by the terms and conditions of this license. The source code is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software. | ||
| 47 | |||
| 48 | Your use of LPHUB is at your own risk. LPHUB and its administrators and moderators disclaim all liability for any damages, whether direct, indirect, incidental, or consequential, that may result from your use of LPHUB or the strategies, routes, or other information provided therein. | ||
| 49 | |||
| 50 | By using LPHUB, you acknowledge that you have read and understood this disclaimer and agree to its terms. \ No newline at end of file | ||
diff --git a/backend/controllers/homeController.go b/backend/controllers/homeController.go index edb770f..2780e63 100644 --- a/backend/controllers/homeController.go +++ b/backend/controllers/homeController.go | |||
| @@ -3,6 +3,7 @@ package controllers | |||
| 3 | import ( | 3 | import ( |
| 4 | "log" | 4 | "log" |
| 5 | "net/http" | 5 | "net/http" |
| 6 | "strings" | ||
| 6 | 7 | ||
| 7 | "github.com/gin-gonic/gin" | 8 | "github.com/gin-gonic/gin" |
| 8 | "github.com/pektezol/leastportals/backend/database" | 9 | "github.com/pektezol/leastportals/backend/database" |
| @@ -22,12 +23,12 @@ func Home(c *gin.Context) { | |||
| 22 | 23 | ||
| 23 | // GET Rankings | 24 | // GET Rankings |
| 24 | // | 25 | // |
| 25 | // @Summary Get rankings of every player. | 26 | // @Description Get rankings of every player. |
| 26 | // @Tags rankings | 27 | // @Tags rankings |
| 27 | // @Produce json | 28 | // @Produce json |
| 28 | // @Success 200 {object} models.Response{data=models.RankingsResponse} | 29 | // @Success 200 {object} models.Response{data=models.RankingsResponse} |
| 29 | // @Failure 400 {object} models.Response | 30 | // @Failure 400 {object} models.Response |
| 30 | // @Router /demo [get] | 31 | // @Router /rankings [get] |
| 31 | func Rankings(c *gin.Context) { | 32 | func Rankings(c *gin.Context) { |
| 32 | rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) | 33 | rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) |
| 33 | if err != nil { | 34 | if err != nil { |
| @@ -122,21 +123,22 @@ func Rankings(c *gin.Context) { | |||
| 122 | }) | 123 | }) |
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | // GET Search | 126 | // GET Search With Query |
| 126 | // | 127 | // |
| 127 | // @Summary Get all user and map data. | 128 | // @Description Get all user and map data matching to the query. |
| 128 | // @Tags search | 129 | // @Tags search |
| 129 | // @Produce json | 130 | // @Produce json |
| 130 | // @Success 200 {object} models.Response{data=models.SearchResponse} | 131 | // @Param q query string false "Search user or map name." |
| 131 | // @Failure 400 {object} models.Response | 132 | // @Success 200 {object} models.Response{data=models.SearchResponse} |
| 132 | // @Router /search [get] | 133 | // @Failure 400 {object} models.Response |
| 133 | func Search(c *gin.Context) { | 134 | // @Router /search [get] |
| 135 | func SearchWithQuery(c *gin.Context) { | ||
| 136 | query := c.Query("q") | ||
| 137 | query = strings.ToLower(query) | ||
| 138 | log.Println(query) | ||
| 134 | var response models.SearchResponse | 139 | var response models.SearchResponse |
| 135 | // Cache all maps for faster response | 140 | // Cache all maps for faster response |
| 136 | var maps = []struct { | 141 | var maps = []models.MapShort{ |
| 137 | ID int `json:"id"` | ||
| 138 | Name string `json:"name"` | ||
| 139 | }{ | ||
| 140 | {ID: 1, Name: "Container Ride"}, | 142 | {ID: 1, Name: "Container Ride"}, |
| 141 | {ID: 2, Name: "Portal Carousel"}, | 143 | {ID: 2, Name: "Portal Carousel"}, |
| 142 | {ID: 3, Name: "Portal Gun"}, | 144 | {ID: 3, Name: "Portal Gun"}, |
| @@ -248,23 +250,32 @@ func Search(c *gin.Context) { | |||
| 248 | {ID: 109, Name: "Gel Maze"}, | 250 | {ID: 109, Name: "Gel Maze"}, |
| 249 | {ID: 110, Name: "Crazier Box"}, | 251 | {ID: 110, Name: "Crazier Box"}, |
| 250 | } | 252 | } |
| 251 | response.Maps = maps | 253 | var filteredMaps []models.MapShort |
| 252 | rows, err := database.DB.Query("SELECT steam_id, user_name FROM users") //WHERE player_name LIKE ?", "%"+query+"%") | 254 | for _, m := range maps { |
| 255 | if strings.Contains(strings.ToLower(m.Name), strings.ToLower(query)) { | ||
| 256 | filteredMaps = append(filteredMaps, m) | ||
| 257 | } | ||
| 258 | } | ||
| 259 | response.Maps = filteredMaps | ||
| 260 | if len(response.Maps) == 0 { | ||
| 261 | response.Maps = []models.MapShort{} | ||
| 262 | } | ||
| 263 | rows, err := database.DB.Query("SELECT steam_id, user_name FROM users WHERE lower(user_name) LIKE $1", "%"+query+"%") | ||
| 253 | if err != nil { | 264 | if err != nil { |
| 254 | log.Fatal(err) | 265 | log.Fatal(err) |
| 255 | } | 266 | } |
| 256 | defer rows.Close() | 267 | defer rows.Close() |
| 257 | for rows.Next() { | 268 | for rows.Next() { |
| 258 | var user struct { | 269 | var user models.UserShort |
| 259 | SteamID string `json:"steam_id"` | ||
| 260 | UserName string `json:"user_name"` | ||
| 261 | } | ||
| 262 | if err := rows.Scan(&user.SteamID, &user.UserName); err != nil { | 270 | if err := rows.Scan(&user.SteamID, &user.UserName); err != nil { |
| 263 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 271 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 264 | return | 272 | return |
| 265 | } | 273 | } |
| 266 | response.Players = append(response.Players, user) | 274 | response.Players = append(response.Players, user) |
| 267 | } | 275 | } |
| 276 | if len(response.Players) == 0 { | ||
| 277 | response.Players = []models.UserShort{} | ||
| 278 | } | ||
| 268 | c.JSON(http.StatusOK, models.Response{ | 279 | c.JSON(http.StatusOK, models.Response{ |
| 269 | Success: true, | 280 | Success: true, |
| 270 | Message: "Search successfully retrieved.", | 281 | Message: "Search successfully retrieved.", |
diff --git a/backend/controllers/loginController.go b/backend/controllers/loginController.go index cfe086d..ae6e957 100644 --- a/backend/controllers/loginController.go +++ b/backend/controllers/loginController.go | |||
| @@ -17,13 +17,13 @@ import ( | |||
| 17 | 17 | ||
| 18 | // Login | 18 | // Login |
| 19 | // | 19 | // |
| 20 | // @Summary Get (redirect) login page for Steam auth. | 20 | // @Description Get (redirect) login page for Steam auth. |
| 21 | // @Tags login | 21 | // @Tags login |
| 22 | // @Accept json | 22 | // @Accept json |
| 23 | // @Produce json | 23 | // @Produce json |
| 24 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 24 | // @Success 200 {object} models.Response{data=models.LoginResponse} |
| 25 | // @Failure 400 {object} models.Response | 25 | // @Failure 400 {object} models.Response |
| 26 | // @Router /login [get] | 26 | // @Router /login [get] |
| 27 | func Login(c *gin.Context) { | 27 | func Login(c *gin.Context) { |
| 28 | openID := steam_go.NewOpenId(c.Request) | 28 | openID := steam_go.NewOpenId(c.Request) |
| 29 | switch openID.Mode() { | 29 | switch openID.Mode() { |
| @@ -59,10 +59,20 @@ func Login(c *gin.Context) { | |||
| 59 | database.DB.Exec(`INSERT INTO users (steam_id, user_name, avatar_link, country_code) | 59 | database.DB.Exec(`INSERT INTO users (steam_id, user_name, avatar_link, country_code) |
| 60 | VALUES ($1, $2, $3, $4)`, steamID, user.PersonaName, user.AvatarFull, user.LocCountryCode) | 60 | VALUES ($1, $2, $3, $4)`, steamID, user.PersonaName, user.AvatarFull, user.LocCountryCode) |
| 61 | } | 61 | } |
| 62 | moderator := false | ||
| 63 | rows, _ := database.DB.Query("SELECT title_name FROM titles WHERE user_id = $1", steamID) | ||
| 64 | for rows.Next() { | ||
| 65 | var title string | ||
| 66 | rows.Scan(&title) | ||
| 67 | if title == "Moderator" { | ||
| 68 | moderator = true | ||
| 69 | } | ||
| 70 | } | ||
| 62 | // Generate JWT token | 71 | // Generate JWT token |
| 63 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ | 72 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ |
| 64 | "sub": steamID, | 73 | "sub": steamID, |
| 65 | "exp": time.Now().Add(time.Hour * 24 * 30).Unix(), | 74 | "exp": time.Now().Add(time.Hour * 24 * 30).Unix(), |
| 75 | "mod": moderator, | ||
| 66 | }) | 76 | }) |
| 67 | // Sign and get the complete encoded token as a string using the secret | 77 | // Sign and get the complete encoded token as a string using the secret |
| 68 | tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY"))) | 78 | tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY"))) |
| @@ -85,13 +95,13 @@ func Login(c *gin.Context) { | |||
| 85 | 95 | ||
| 86 | // GET Token | 96 | // GET Token |
| 87 | // | 97 | // |
| 88 | // @Summary Gets the token cookie value from the user. | 98 | // @Description Gets the token cookie value from the user. |
| 89 | // @Tags auth | 99 | // @Tags auth |
| 90 | // @Produce json | 100 | // @Produce json |
| 91 | // | 101 | // |
| 92 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 102 | // @Success 200 {object} models.Response{data=models.LoginResponse} |
| 93 | // @Failure 404 {object} models.Response | 103 | // @Failure 404 {object} models.Response |
| 94 | // @Router /token [get] | 104 | // @Router /token [get] |
| 95 | func GetCookie(c *gin.Context) { | 105 | func GetCookie(c *gin.Context) { |
| 96 | cookie, err := c.Cookie("token") | 106 | cookie, err := c.Cookie("token") |
| 97 | if err != nil { | 107 | if err != nil { |
| @@ -109,13 +119,13 @@ func GetCookie(c *gin.Context) { | |||
| 109 | 119 | ||
| 110 | // DELETE Token | 120 | // DELETE Token |
| 111 | // | 121 | // |
| 112 | // @Summary Deletes the token cookie from the user. | 122 | // @Description Deletes the token cookie from the user. |
| 113 | // @Tags auth | 123 | // @Tags auth |
| 114 | // @Produce json | 124 | // @Produce json |
| 115 | // | 125 | // |
| 116 | // @Success 200 {object} models.Response{data=models.LoginResponse} | 126 | // @Success 200 {object} models.Response{data=models.LoginResponse} |
| 117 | // @Failure 404 {object} models.Response | 127 | // @Failure 404 {object} models.Response |
| 118 | // @Router /token [delete] | 128 | // @Router /token [delete] |
| 119 | func DeleteCookie(c *gin.Context) { | 129 | func DeleteCookie(c *gin.Context) { |
| 120 | cookie, err := c.Cookie("token") | 130 | cookie, err := c.Cookie("token") |
| 121 | if err != nil { | 131 | if err != nil { |
diff --git a/backend/controllers/mapController.go b/backend/controllers/mapController.go index d8783b7..e7c5566 100644 --- a/backend/controllers/mapController.go +++ b/backend/controllers/mapController.go | |||
| @@ -3,111 +3,81 @@ package controllers | |||
| 3 | import ( | 3 | import ( |
| 4 | "net/http" | 4 | "net/http" |
| 5 | "strconv" | 5 | "strconv" |
| 6 | "time" | ||
| 7 | 6 | ||
| 8 | "github.com/gin-gonic/gin" | 7 | "github.com/gin-gonic/gin" |
| 9 | "github.com/lib/pq" | ||
| 10 | "github.com/pektezol/leastportals/backend/database" | 8 | "github.com/pektezol/leastportals/backend/database" |
| 11 | "github.com/pektezol/leastportals/backend/models" | 9 | "github.com/pektezol/leastportals/backend/models" |
| 12 | ) | 10 | ) |
| 13 | 11 | ||
| 14 | // GET Map Summary | 12 | // GET Map Summary |
| 15 | // | 13 | // |
| 16 | // @Summary Get map summary with specified id. | 14 | // @Description Get map summary with specified id. |
| 17 | // @Tags maps | 15 | // @Tags maps |
| 18 | // @Produce json | 16 | // @Produce json |
| 19 | // @Param id path int true "Map ID" | 17 | // @Param id path int true "Map ID" |
| 20 | // @Success 200 {object} models.Response{data=models.Map{data=models.MapSummary}} | 18 | // @Success 200 {object} models.Response{data=models.MapSummaryResponse} |
| 21 | // @Failure 400 {object} models.Response | 19 | // @Failure 400 {object} models.Response |
| 22 | // @Router /maps/{id}/summary [get] | 20 | // @Router /maps/{id}/summary [get] |
| 23 | func FetchMapSummary(c *gin.Context) { | 21 | func FetchMapSummary(c *gin.Context) { |
| 24 | id := c.Param("id") | 22 | id := c.Param("id") |
| 25 | // Get map data | 23 | response := models.MapSummaryResponse{Map: models.Map{}, Summary: models.MapSummary{Routes: []models.MapRoute{}}} |
| 26 | var mapData models.Map | ||
| 27 | var mapSummaryData models.MapSummary | ||
| 28 | var mapHistoryData []models.MapHistory | ||
| 29 | intID, err := strconv.Atoi(id) | 24 | intID, err := strconv.Atoi(id) |
| 30 | if err != nil { | 25 | if err != nil { |
| 31 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 26 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 32 | return | 27 | return |
| 33 | } | 28 | } |
| 34 | mapData.ID = intID | 29 | // Get map data |
| 35 | var routers pq.StringArray | 30 | response.Map.ID = intID |
| 36 | sql := `SELECT g.name, c.name, m.name, m.description, m.showcase, | 31 | sql := `SELECT m.id, g.name, c.name, m.name, m.image, g.is_coop |
| 37 | ( | ||
| 38 | SELECT array_agg(user_name) | ||
| 39 | FROM map_routers | ||
| 40 | WHERE map_id = $1 | ||
| 41 | AND score_count = ( | ||
| 42 | SELECT score_count | ||
| 43 | FROM map_history | ||
| 44 | WHERE map_id = $1 | ||
| 45 | ORDER BY score_count | ||
| 46 | LIMIT 1 | ||
| 47 | ) | ||
| 48 | GROUP BY map_routers.user_name | ||
| 49 | ORDER BY user_name | ||
| 50 | ), | ||
| 51 | ( | ||
| 52 | SELECT COALESCE(avg(rating), 0.0) | ||
| 53 | FROM map_ratings | ||
| 54 | WHERE map_id = $1 | ||
| 55 | ) | ||
| 56 | FROM maps m | 32 | FROM maps m |
| 57 | INNER JOIN games g ON m.game_id = g.id | 33 | INNER JOIN games g ON m.game_id = g.id |
| 58 | INNER JOIN chapters c ON m.chapter_id = c.id | 34 | INNER JOIN chapters c ON m.chapter_id = c.id |
| 59 | WHERE m.id = $1` | 35 | WHERE m.id = $1` |
| 60 | // TODO: CategoryScores | 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) |
| 61 | err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &mapSummaryData.Description, &mapSummaryData.Showcase, &routers, &mapSummaryData.Rating) | ||
| 62 | if err != nil { | 37 | if err != nil { |
| 63 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 38 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 64 | return | 39 | return |
| 65 | } | 40 | } |
| 66 | var historyNames pq.StringArray | 41 | // Get map routes and histories |
| 67 | var historyScores pq.Int32Array | 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 |
| 68 | var historyDates pq.StringArray | 43 | INNER JOIN categories c ON r.category_id = c.id |
| 69 | sql = `SELECT array_agg(user_name), array_agg(score_count), array_agg(record_date) | 44 | INNER JOIN map_history h ON r.map_id = h.map_id AND r.category_id = h.category_id |
| 70 | FROM map_history | 45 | LEFT JOIN map_ratings rt ON r.map_id = rt.map_id AND r.category_id = rt.category_id |
| 71 | WHERE map_id = $1` | 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 |
| 72 | err = database.DB.QueryRow(sql, id).Scan(&historyNames, &historyScores, &historyDates) | 47 | ORDER BY h.record_date ASC;` |
| 48 | rows, err := database.DB.Query(sql, id) | ||
| 73 | if err != nil { | 49 | if err != nil { |
| 74 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 50 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 75 | return | 51 | return |
| 76 | } | 52 | } |
| 77 | for i := 0; i < len(historyNames); i++ { | 53 | for rows.Next() { |
| 78 | var history models.MapHistory | 54 | route := models.MapRoute{Category: models.Category{}, History: models.MapHistory{}} |
| 79 | history.RunnerName = historyNames[i] | 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) |
| 80 | history.ScoreCount = int(historyScores[i]) | ||
| 81 | layout := "2006-01-02 15:04:05" | ||
| 82 | date, err := time.Parse(layout, historyDates[i]) | ||
| 83 | if err != nil { | 56 | if err != nil { |
| 84 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 57 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 85 | return | 58 | return |
| 86 | } | 59 | } |
| 87 | history.Date = date | 60 | response.Summary.Routes = append(response.Summary.Routes, route) |
| 88 | mapHistoryData = append(mapHistoryData, history) | ||
| 89 | } | 61 | } |
| 90 | mapSummaryData.History = mapHistoryData | ||
| 91 | mapSummaryData.Routers = routers | ||
| 92 | mapData.Data = mapSummaryData | ||
| 93 | // Return response | 62 | // Return response |
| 94 | c.JSON(http.StatusOK, models.Response{ | 63 | c.JSON(http.StatusOK, models.Response{ |
| 95 | Success: true, | 64 | Success: true, |
| 96 | Message: "Successfully retrieved map summary.", | 65 | Message: "Successfully retrieved map summary.", |
| 97 | Data: mapData, | 66 | Data: response, |
| 98 | }) | 67 | }) |
| 99 | } | 68 | } |
| 100 | 69 | ||
| 101 | // GET Map Leaderboards | 70 | // GET Map Leaderboards |
| 102 | // | 71 | // |
| 103 | // @Summary Get map leaderboards with specified id. | 72 | // @Description Get map leaderboards with specified id. |
| 104 | // @Tags maps | 73 | // @Tags maps |
| 105 | // @Produce json | 74 | // @Produce json |
| 106 | // @Param id path int true "Map ID" | 75 | // @Param id path int true "Map ID" |
| 107 | // @Success 200 {object} models.Response{data=models.Map{data=models.MapRecords}} | 76 | // @Success 200 {object} models.Response{data=models.Map{data=models.MapRecords}} |
| 108 | // @Failure 400 {object} models.Response | 77 | // @Failure 400 {object} models.Response |
| 109 | // @Router /maps/{id}/leaderboards [get] | 78 | // @Router /maps/{id}/leaderboards [get] |
| 110 | func FetchMapLeaderboards(c *gin.Context) { | 79 | func FetchMapLeaderboards(c *gin.Context) { |
| 80 | // TODO: make new response type | ||
| 111 | id := c.Param("id") | 81 | id := c.Param("id") |
| 112 | // Get map data | 82 | // Get map data |
| 113 | var mapData models.Map | 83 | var mapData models.Map |
| @@ -119,12 +89,12 @@ func FetchMapLeaderboards(c *gin.Context) { | |||
| 119 | return | 89 | return |
| 120 | } | 90 | } |
| 121 | mapData.ID = intID | 91 | mapData.ID = intID |
| 122 | sql := `SELECT g.name, c.name, m.name, is_disabled | 92 | sql := `SELECT g.name, c.name, m.name, is_disabled, m.image |
| 123 | FROM maps m | 93 | FROM maps m |
| 124 | INNER JOIN games g ON m.game_id = g.id | 94 | INNER JOIN games g ON m.game_id = g.id |
| 125 | INNER JOIN chapters c ON m.chapter_id = c.id | 95 | INNER JOIN chapters c ON m.chapter_id = c.id |
| 126 | WHERE m.id = $1` | 96 | WHERE m.id = $1` |
| 127 | err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled) | 97 | err = database.DB.QueryRow(sql, id).Scan(&mapData.GameName, &mapData.ChapterName, &mapData.MapName, &isDisabled, &mapData.Image) |
| 128 | if err != nil { | 98 | if err != nil { |
| 129 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 99 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 130 | return | 100 | return |
| @@ -205,7 +175,7 @@ func FetchMapLeaderboards(c *gin.Context) { | |||
| 205 | } | 175 | } |
| 206 | mapRecordsData.Records = records | 176 | mapRecordsData.Records = records |
| 207 | } | 177 | } |
| 208 | mapData.Data = mapRecordsData | 178 | // mapData.Data = mapRecordsData |
| 209 | // Return response | 179 | // Return response |
| 210 | c.JSON(http.StatusOK, models.Response{ | 180 | c.JSON(http.StatusOK, models.Response{ |
| 211 | Success: true, | 181 | Success: true, |
| @@ -216,14 +186,14 @@ func FetchMapLeaderboards(c *gin.Context) { | |||
| 216 | 186 | ||
| 217 | // GET Games | 187 | // GET Games |
| 218 | // | 188 | // |
| 219 | // @Summary Get games from the leaderboards. | 189 | // @Description Get games from the leaderboards. |
| 220 | // @Tags games & chapters | 190 | // @Tags games & chapters |
| 221 | // @Produce json | 191 | // @Produce json |
| 222 | // @Success 200 {object} models.Response{data=[]models.Game} | 192 | // @Success 200 {object} models.Response{data=[]models.Game} |
| 223 | // @Failure 400 {object} models.Response | 193 | // @Failure 400 {object} models.Response |
| 224 | // @Router /games [get] | 194 | // @Router /games [get] |
| 225 | func FetchGames(c *gin.Context) { | 195 | func FetchGames(c *gin.Context) { |
| 226 | rows, err := database.DB.Query(`SELECT id, name FROM games`) | 196 | rows, err := database.DB.Query(`SELECT id, name, is_coop FROM games`) |
| 227 | if err != nil { | 197 | if err != nil { |
| 228 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 198 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 229 | return | 199 | return |
| @@ -231,7 +201,7 @@ func FetchGames(c *gin.Context) { | |||
| 231 | var games []models.Game | 201 | var games []models.Game |
| 232 | for rows.Next() { | 202 | for rows.Next() { |
| 233 | var game models.Game | 203 | var game models.Game |
| 234 | if err := rows.Scan(&game.ID, &game.Name); err != nil { | 204 | if err := rows.Scan(&game.ID, &game.Name, &game.IsCoop); err != nil { |
| 235 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 205 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 236 | return | 206 | return |
| 237 | } | 207 | } |
| @@ -246,13 +216,13 @@ func FetchGames(c *gin.Context) { | |||
| 246 | 216 | ||
| 247 | // GET Chapters of a Game | 217 | // GET Chapters of a Game |
| 248 | // | 218 | // |
| 249 | // @Summary Get chapters from the specified game id. | 219 | // @Description Get chapters from the specified game id. |
| 250 | // @Tags games & chapters | 220 | // @Tags games & chapters |
| 251 | // @Produce json | 221 | // @Produce json |
| 252 | // @Param id path int true "Game ID" | 222 | // @Param id path int true "Game ID" |
| 253 | // @Success 200 {object} models.Response{data=models.ChaptersResponse} | 223 | // @Success 200 {object} models.Response{data=models.ChaptersResponse} |
| 254 | // @Failure 400 {object} models.Response | 224 | // @Failure 400 {object} models.Response |
| 255 | // @Router /games/{id} [get] | 225 | // @Router /games/{id} [get] |
| 256 | func FetchChapters(c *gin.Context) { | 226 | func FetchChapters(c *gin.Context) { |
| 257 | gameID := c.Param("id") | 227 | gameID := c.Param("id") |
| 258 | intID, err := strconv.Atoi(gameID) | 228 | intID, err := strconv.Atoi(gameID) |
| @@ -288,13 +258,13 @@ func FetchChapters(c *gin.Context) { | |||
| 288 | 258 | ||
| 289 | // GET Maps of a Chapter | 259 | // GET Maps of a Chapter |
| 290 | // | 260 | // |
| 291 | // @Summary Get maps from the specified chapter id. | 261 | // @Description Get maps from the specified chapter id. |
| 292 | // @Tags games & chapters | 262 | // @Tags games & chapters |
| 293 | // @Produce json | 263 | // @Produce json |
| 294 | // @Param id path int true "Chapter ID" | 264 | // @Param id path int true "Chapter ID" |
| 295 | // @Success 200 {object} models.Response{data=models.ChapterMapsResponse} | 265 | // @Success 200 {object} models.Response{data=models.ChapterMapsResponse} |
| 296 | // @Failure 400 {object} models.Response | 266 | // @Failure 400 {object} models.Response |
| 297 | // @Router /chapters/{id} [get] | 267 | // @Router /chapters/{id} [get] |
| 298 | func FetchChapterMaps(c *gin.Context) { | 268 | func FetchChapterMaps(c *gin.Context) { |
| 299 | chapterID := c.Param("id") | 269 | chapterID := c.Param("id") |
| 300 | intID, err := strconv.Atoi(chapterID) | 270 | intID, err := strconv.Atoi(chapterID) |
diff --git a/backend/controllers/modController.go b/backend/controllers/modController.go new file mode 100644 index 0000000..07edff5 --- /dev/null +++ b/backend/controllers/modController.go | |||
| @@ -0,0 +1,327 @@ | |||
| 1 | package controllers | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "net/http" | ||
| 5 | "strconv" | ||
| 6 | |||
| 7 | "github.com/gin-gonic/gin" | ||
| 8 | "github.com/pektezol/leastportals/backend/database" | ||
| 9 | "github.com/pektezol/leastportals/backend/models" | ||
| 10 | ) | ||
| 11 | |||
| 12 | // POST Map Summary | ||
| 13 | // | ||
| 14 | // @Description Create map summary with specified map id. | ||
| 15 | // @Tags maps | ||
| 16 | // @Produce json | ||
| 17 | // @Param Authorization header string true "JWT Token" | ||
| 18 | // @Param id path int true "Map ID" | ||
| 19 | // @Param request body models.CreateMapSummaryRequest true "Body" | ||
| 20 | // @Success 200 {object} models.Response{data=models.CreateMapSummaryRequest} | ||
| 21 | // @Failure 400 {object} models.Response | ||
| 22 | // @Router /maps/{id}/summary [post] | ||
| 23 | func CreateMapSummary(c *gin.Context) { | ||
| 24 | // Check if user exists | ||
| 25 | user, exists := c.Get("user") | ||
| 26 | if !exists { | ||
| 27 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in.")) | ||
| 28 | return | ||
| 29 | } | ||
| 30 | var moderator bool | ||
| 31 | for _, title := range user.(models.User).Titles { | ||
| 32 | if title == "Moderator" { | ||
| 33 | moderator = true | ||
| 34 | } | ||
| 35 | } | ||
| 36 | if !moderator { | ||
| 37 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("Insufficient permissions.")) | ||
| 38 | return | ||
| 39 | } | ||
| 40 | // Bind parameter and body | ||
| 41 | id := c.Param("id") | ||
| 42 | mapID, err := strconv.Atoi(id) | ||
| 43 | if err != nil { | ||
| 44 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 45 | return | ||
| 46 | } | ||
| 47 | var request models.CreateMapSummaryRequest | ||
| 48 | if err := c.BindJSON(&request); err != nil { | ||
| 49 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 50 | return | ||
| 51 | } | ||
| 52 | // Start database transaction | ||
| 53 | tx, err := database.DB.Begin() | ||
| 54 | if err != nil { | ||
| 55 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 56 | return | ||
| 57 | } | ||
| 58 | defer tx.Rollback() | ||
| 59 | // Fetch route category and score count | ||
| 60 | var checkMapID int | ||
| 61 | sql := `SELECT m.id FROM maps m WHERE m.id = $1` | ||
| 62 | err = database.DB.QueryRow(sql, mapID).Scan(&checkMapID) | ||
| 63 | if err != nil { | ||
| 64 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 65 | return | ||
| 66 | } | ||
| 67 | if mapID != checkMapID { | ||
| 68 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Map ID does not exist.")) | ||
| 69 | return | ||
| 70 | } | ||
| 71 | // Update database with new data | ||
| 72 | sql = `INSERT INTO map_routes (map_id,category_id,score_count,description,showcase) | ||
| 73 | VALUES ($1,$2,$3,$4,$5)` | ||
| 74 | _, err = tx.Exec(sql, mapID, request.CategoryID, request.ScoreCount, request.Description, request.Showcase) | ||
| 75 | if err != nil { | ||
| 76 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 77 | return | ||
| 78 | } | ||
| 79 | sql = `INSERT INTO map_history (map_id,category_id,user_name,score_count,record_date) | ||
| 80 | VALUES ($1,$2,$3,$4,$5)` | ||
| 81 | _, err = tx.Exec(sql, mapID, request.CategoryID, request.UserName, request.ScoreCount, request.RecordDate) | ||
| 82 | if err != nil { | ||
| 83 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 84 | return | ||
| 85 | } | ||
| 86 | if err = tx.Commit(); err != nil { | ||
| 87 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 88 | return | ||
| 89 | } | ||
| 90 | // Return response | ||
| 91 | c.JSON(http.StatusOK, models.Response{ | ||
| 92 | Success: true, | ||
| 93 | Message: "Successfully created map summary.", | ||
| 94 | Data: request, | ||
| 95 | }) | ||
| 96 | } | ||
| 97 | |||
| 98 | // PUT Map Summary | ||
| 99 | // | ||
| 100 | // @Description Edit map summary with specified map id. | ||
| 101 | // @Tags maps | ||
| 102 | // @Produce json | ||
| 103 | // @Param Authorization header string true "JWT Token" | ||
| 104 | // @Param id path int true "Map ID" | ||
| 105 | // @Param request body models.EditMapSummaryRequest true "Body" | ||
| 106 | // @Success 200 {object} models.Response{data=models.EditMapSummaryRequest} | ||
| 107 | // @Failure 400 {object} models.Response | ||
| 108 | // @Router /maps/{id}/summary [put] | ||
| 109 | func EditMapSummary(c *gin.Context) { | ||
| 110 | // Check if user exists | ||
| 111 | user, exists := c.Get("user") | ||
| 112 | if !exists { | ||
| 113 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in.")) | ||
| 114 | return | ||
| 115 | } | ||
| 116 | var moderator bool | ||
| 117 | for _, title := range user.(models.User).Titles { | ||
| 118 | if title == "Moderator" { | ||
| 119 | moderator = true | ||
| 120 | } | ||
| 121 | } | ||
| 122 | if !moderator { | ||
| 123 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("Insufficient permissions.")) | ||
| 124 | return | ||
| 125 | } | ||
| 126 | // Bind parameter and body | ||
| 127 | id := c.Param("id") | ||
| 128 | mapID, err := strconv.Atoi(id) | ||
| 129 | if err != nil { | ||
| 130 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 131 | return | ||
| 132 | } | ||
| 133 | var request models.EditMapSummaryRequest | ||
| 134 | if err := c.BindJSON(&request); err != nil { | ||
| 135 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 136 | return | ||
| 137 | } | ||
| 138 | // Start database transaction | ||
| 139 | tx, err := database.DB.Begin() | ||
| 140 | if err != nil { | ||
| 141 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 142 | return | ||
| 143 | } | ||
| 144 | defer tx.Rollback() | ||
| 145 | // Fetch route category and score count | ||
| 146 | var categoryID, scoreCount, historyID int | ||
| 147 | sql := `SELECT mr.category_id, mr.score_count FROM map_routes mr INNER JOIN maps m ON m.id = mr.map_id WHERE m.id = $1 AND mr.id = $2` | ||
| 148 | err = database.DB.QueryRow(sql, mapID, request.RouteID).Scan(&categoryID, &scoreCount) | ||
| 149 | if err != nil { | ||
| 150 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 151 | return | ||
| 152 | } | ||
| 153 | sql = `SELECT mh.id FROM map_history mh WHERE mh.score_count = $1 AND mh.category_id = $2 AND mh.map_id = $3` | ||
| 154 | err = database.DB.QueryRow(sql, scoreCount, categoryID, mapID).Scan(&historyID) | ||
| 155 | if err != nil { | ||
| 156 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 157 | return | ||
| 158 | } | ||
| 159 | // Update database with new data | ||
| 160 | sql = `UPDATE map_routes SET score_count = $2, description = $3, showcase = $4 WHERE id = $1` | ||
| 161 | _, err = tx.Exec(sql, request.RouteID, request.ScoreCount, request.Description, request.Showcase) | ||
| 162 | if err != nil { | ||
| 163 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 164 | return | ||
| 165 | } | ||
| 166 | sql = `UPDATE map_history SET user_name = $2, score_count = $3, record_date = $4 WHERE id = $1` | ||
| 167 | _, err = tx.Exec(sql, historyID, request.UserName, request.ScoreCount, request.RecordDate) | ||
| 168 | if err != nil { | ||
| 169 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 170 | return | ||
| 171 | } | ||
| 172 | if err = tx.Commit(); err != nil { | ||
| 173 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 174 | return | ||
| 175 | } | ||
| 176 | // Return response | ||
| 177 | c.JSON(http.StatusOK, models.Response{ | ||
| 178 | Success: true, | ||
| 179 | Message: "Successfully updated map summary.", | ||
| 180 | Data: request, | ||
| 181 | }) | ||
| 182 | } | ||
| 183 | |||
| 184 | // DELETE Map Summary | ||
| 185 | // | ||
| 186 | // @Description Delete map summary with specified map id. | ||
| 187 | // @Tags maps | ||
| 188 | // @Produce json | ||
| 189 | // @Param Authorization header string true "JWT Token" | ||
| 190 | // @Param id path int true "Map ID" | ||
| 191 | // @Param request body models.DeleteMapSummaryRequest true "Body" | ||
| 192 | // @Success 200 {object} models.Response{data=models.DeleteMapSummaryRequest} | ||
| 193 | // @Failure 400 {object} models.Response | ||
| 194 | // @Router /maps/{id}/summary [delete] | ||
| 195 | func DeleteMapSummary(c *gin.Context) { | ||
| 196 | // Check if user exists | ||
| 197 | user, exists := c.Get("user") | ||
| 198 | if !exists { | ||
| 199 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in.")) | ||
| 200 | return | ||
| 201 | } | ||
| 202 | var moderator bool | ||
| 203 | for _, title := range user.(models.User).Titles { | ||
| 204 | if title == "Moderator" { | ||
| 205 | moderator = true | ||
| 206 | } | ||
| 207 | } | ||
| 208 | if !moderator { | ||
| 209 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("Insufficient permissions.")) | ||
| 210 | return | ||
| 211 | } | ||
| 212 | // Bind parameter and body | ||
| 213 | id := c.Param("id") | ||
| 214 | mapID, err := strconv.Atoi(id) | ||
| 215 | if err != nil { | ||
| 216 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 217 | return | ||
| 218 | } | ||
| 219 | var request models.DeleteMapSummaryRequest | ||
| 220 | if err := c.BindJSON(&request); err != nil { | ||
| 221 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 222 | return | ||
| 223 | } | ||
| 224 | // Start database transaction | ||
| 225 | tx, err := database.DB.Begin() | ||
| 226 | if err != nil { | ||
| 227 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 228 | return | ||
| 229 | } | ||
| 230 | defer tx.Rollback() | ||
| 231 | // Fetch route category and score count | ||
| 232 | var checkMapID, scoreCount, mapHistoryID int | ||
| 233 | sql := `SELECT m.id, mr.score_count FROM maps m INNER JOIN map_routes mr ON m.id=mr.map_id WHERE m.id = $1 AND mr.id = $2` | ||
| 234 | err = database.DB.QueryRow(sql, mapID, request.RouteID).Scan(&checkMapID, &scoreCount) | ||
| 235 | if err != nil { | ||
| 236 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 237 | return | ||
| 238 | } | ||
| 239 | if mapID != checkMapID { | ||
| 240 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Map ID does not exist.")) | ||
| 241 | return | ||
| 242 | } | ||
| 243 | sql = `SELECT mh.id FROM maps m INNER JOIN map_routes mr ON m.id=mr.map_id INNER JOIN map_history mh ON m.id=mh.map_id WHERE m.id = $1 AND mr.id = $2 AND mh.score_count = $3` | ||
| 244 | err = database.DB.QueryRow(sql, mapID, request.RouteID, scoreCount).Scan(&mapHistoryID) | ||
| 245 | if err != nil { | ||
| 246 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 247 | return | ||
| 248 | } | ||
| 249 | // Update database with new data | ||
| 250 | sql = `DELETE FROM map_routes mr WHERE mr.id = $1 ` | ||
| 251 | _, err = tx.Exec(sql, request.RouteID) | ||
| 252 | if err != nil { | ||
| 253 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 254 | return | ||
| 255 | } | ||
| 256 | sql = `DELETE FROM map_history mh WHERE mh.id = $1` | ||
| 257 | _, err = tx.Exec(sql, mapHistoryID) | ||
| 258 | if err != nil { | ||
| 259 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 260 | return | ||
| 261 | } | ||
| 262 | if err = tx.Commit(); err != nil { | ||
| 263 | c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) | ||
| 264 | return | ||
| 265 | } | ||
| 266 | // Return response | ||
| 267 | c.JSON(http.StatusOK, models.Response{ | ||
| 268 | Success: true, | ||
| 269 | Message: "Successfully delete map summary.", | ||
| 270 | Data: request, | ||
| 271 | }) | ||
| 272 | } | ||
| 273 | |||
| 274 | // PUT Map Image | ||
| 275 | // | ||
| 276 | // @Description Edit map image with specified map id. | ||
| 277 | // @Tags maps | ||
| 278 | // @Produce json | ||
| 279 | // @Param Authorization header string true "JWT Token" | ||
| 280 | // @Param id path int true "Map ID" | ||
| 281 | // @Param request body models.EditMapImageRequest true "Body" | ||
| 282 | // @Success 200 {object} models.Response{data=models.EditMapImageRequest} | ||
| 283 | // @Failure 400 {object} models.Response | ||
| 284 | // @Router /maps/{id}/image [put] | ||
| 285 | func EditMapImage(c *gin.Context) { | ||
| 286 | // Check if user exists | ||
| 287 | user, exists := c.Get("user") | ||
| 288 | if !exists { | ||
| 289 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in.")) | ||
| 290 | return | ||
| 291 | } | ||
| 292 | var moderator bool | ||
| 293 | for _, title := range user.(models.User).Titles { | ||
| 294 | if title == "Moderator" { | ||
| 295 | moderator = true | ||
| 296 | } | ||
| 297 | } | ||
| 298 | if !moderator { | ||
| 299 | c.JSON(http.StatusUnauthorized, models.ErrorResponse("Insufficient permissions.")) | ||
| 300 | return | ||
| 301 | } | ||
| 302 | // Bind parameter and body | ||
| 303 | id := c.Param("id") | ||
| 304 | mapID, err := strconv.Atoi(id) | ||
| 305 | if err != nil { | ||
| 306 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 307 | return | ||
| 308 | } | ||
| 309 | var request models.EditMapImageRequest | ||
| 310 | if err := c.BindJSON(&request); err != nil { | ||
| 311 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 312 | return | ||
| 313 | } | ||
| 314 | // Update database with new data | ||
| 315 | sql := `UPDATE maps SET image = $2 WHERE id = $1` | ||
| 316 | _, err = database.DB.Exec(sql, mapID, request.Image) | ||
| 317 | if err != nil { | ||
| 318 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 319 | return | ||
| 320 | } | ||
| 321 | // Return response | ||
| 322 | c.JSON(http.StatusOK, models.Response{ | ||
| 323 | Success: true, | ||
| 324 | Message: "Successfully updated map image.", | ||
| 325 | Data: request, | ||
| 326 | }) | ||
| 327 | } | ||
diff --git a/backend/controllers/recordController.go b/backend/controllers/recordController.go index 627be57..d1404f4 100644 --- a/backend/controllers/recordController.go +++ b/backend/controllers/recordController.go | |||
| @@ -2,17 +2,18 @@ package controllers | |||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "context" | 4 | "context" |
| 5 | b64 "encoding/base64" | 5 | "encoding/base64" |
| 6 | "io" | 6 | "io" |
| 7 | "log" | 7 | "log" |
| 8 | "mime/multipart" | ||
| 8 | "net/http" | 9 | "net/http" |
| 9 | "os" | 10 | "os" |
| 10 | "strconv" | ||
| 11 | 11 | ||
| 12 | "github.com/gin-gonic/gin" | 12 | "github.com/gin-gonic/gin" |
| 13 | "github.com/google/uuid" | 13 | "github.com/google/uuid" |
| 14 | "github.com/pektezol/leastportals/backend/database" | 14 | "github.com/pektezol/leastportals/backend/database" |
| 15 | "github.com/pektezol/leastportals/backend/models" | 15 | "github.com/pektezol/leastportals/backend/models" |
| 16 | "github.com/pektezol/leastportals/backend/parser" | ||
| 16 | "golang.org/x/oauth2/google" | 17 | "golang.org/x/oauth2/google" |
| 17 | "golang.org/x/oauth2/jwt" | 18 | "golang.org/x/oauth2/jwt" |
| 18 | "google.golang.org/api/drive/v3" | 19 | "google.golang.org/api/drive/v3" |
| @@ -20,20 +21,20 @@ import ( | |||
| 20 | 21 | ||
| 21 | // POST Record | 22 | // POST Record |
| 22 | // | 23 | // |
| 23 | // @Summary Post record with demo of a specific map. | 24 | // @Description Post record with demo of a specific map. |
| 24 | // @Tags maps | 25 | // @Tags maps |
| 25 | // @Accept mpfd | 26 | // @Accept mpfd |
| 26 | // @Produce json | 27 | // @Produce json |
| 27 | // @Param Authorization header string true "JWT Token" | 28 | // @Param id path int true "Map ID" |
| 28 | // @Param demos formData []file true "Demos" | 29 | // @Param Authorization header string true "JWT Token" |
| 29 | // @Param score_count formData int true "Score Count" | 30 | // @Param host_demo formData file true "Host Demo" |
| 30 | // @Param score_time formData int true "Score Time" | 31 | // @Param partner_demo formData file false "Partner Demo" |
| 31 | // @Param is_partner_orange formData boolean true "Is Partner Orange" | 32 | // @Param is_partner_orange formData boolean false "Is Partner Orange" |
| 32 | // @Param partner_id formData string true "Partner ID" | 33 | // @Param partner_id formData string false "Partner ID" |
| 33 | // @Success 200 {object} models.Response{data=models.RecordRequest} | 34 | // @Success 200 {object} models.Response{data=models.RecordResponse} |
| 34 | // @Failure 400 {object} models.Response | 35 | // @Failure 400 {object} models.Response |
| 35 | // @Failure 401 {object} models.Response | 36 | // @Failure 401 {object} models.Response |
| 36 | // @Router /maps/{id}/record [post] | 37 | // @Router /maps/{id}/record [post] |
| 37 | func CreateRecordWithDemo(c *gin.Context) { | 38 | func CreateRecordWithDemo(c *gin.Context) { |
| 38 | mapId := c.Param("id") | 39 | mapId := c.Param("id") |
| 39 | // Check if user exists | 40 | // Check if user exists |
| @@ -43,11 +44,11 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 43 | return | 44 | return |
| 44 | } | 45 | } |
| 45 | // Check if map is sp or mp | 46 | // Check if map is sp or mp |
| 46 | var gameID int | 47 | var gameName string |
| 47 | var isCoop bool | 48 | var isCoop bool |
| 48 | var isDisabled bool | 49 | var isDisabled bool |
| 49 | sql := `SELECT game_id, is_disabled FROM maps WHERE id = $1` | 50 | sql := `SELECT g.name, m.is_disabled FROM maps m INNER JOIN games g ON m.game_id=g.id WHERE m.id = $1` |
| 50 | err := database.DB.QueryRow(sql, mapId).Scan(&gameID, &isDisabled) | 51 | err := database.DB.QueryRow(sql, mapId).Scan(&gameName, &isDisabled) |
| 51 | if err != nil { | 52 | if err != nil { |
| 52 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 53 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 53 | return | 54 | return |
| @@ -56,51 +57,26 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 56 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Map is not available for competitive boards.")) | 57 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Map is not available for competitive boards.")) |
| 57 | return | 58 | return |
| 58 | } | 59 | } |
| 59 | if gameID == 2 { | 60 | if gameName == "Portal 2 - Cooperative" { |
| 60 | isCoop = true | 61 | isCoop = true |
| 61 | } | 62 | } |
| 62 | // Get record request | 63 | // Get record request |
| 63 | var record models.RecordRequest | 64 | var record models.RecordRequest |
| 64 | score_count, err := strconv.Atoi(c.PostForm("score_count")) | 65 | if err := c.ShouldBind(&record); err != nil { |
| 65 | if err != nil { | ||
| 66 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 67 | return | ||
| 68 | } | ||
| 69 | score_time, err := strconv.Atoi(c.PostForm("score_time")) | ||
| 70 | if err != nil { | ||
| 71 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 72 | return | ||
| 73 | } | ||
| 74 | is_partner_orange, err := strconv.ParseBool(c.PostForm("is_partner_orange")) | ||
| 75 | if err != nil { | ||
| 76 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 77 | return | ||
| 78 | } | ||
| 79 | record.ScoreCount = score_count | ||
| 80 | record.ScoreTime = score_time | ||
| 81 | record.PartnerID = c.PostForm("partner_id") | ||
| 82 | record.IsPartnerOrange = is_partner_orange | ||
| 83 | if record.PartnerID == "" { | ||
| 84 | c.JSON(http.StatusBadRequest, models.ErrorResponse("No partner id given.")) | ||
| 85 | return | ||
| 86 | } | ||
| 87 | // Multipart form | ||
| 88 | form, err := c.MultipartForm() | ||
| 89 | if err != nil { | ||
| 90 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 66 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 91 | return | 67 | return |
| 92 | } | 68 | } |
| 93 | files := form.File["demos"] | 69 | if isCoop && (record.PartnerDemo == nil || record.PartnerID == "") { |
| 94 | if len(files) != 2 && isCoop { | 70 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Invalid entry for coop record submission.")) |
| 95 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Not enough demos for coop submission.")) | ||
| 96 | return | 71 | return |
| 97 | } | 72 | } |
| 98 | if len(files) != 1 && !isCoop { | 73 | // Demo files |
| 99 | c.JSON(http.StatusBadRequest, models.ErrorResponse("Too many demos for singleplayer submission.")) | 74 | demoFiles := []*multipart.FileHeader{record.HostDemo} |
| 100 | return | 75 | if isCoop { |
| 76 | demoFiles = append(demoFiles, record.PartnerDemo) | ||
| 101 | } | 77 | } |
| 102 | var hostDemoUUID string | 78 | var hostDemoUUID, hostDemoFileID, partnerDemoUUID, partnerDemoFileID string |
| 103 | var partnerDemoUUID string | 79 | var hostDemoScoreCount, hostDemoScoreTime int |
| 104 | client := serviceAccount() | 80 | client := serviceAccount() |
| 105 | srv, err := drive.New(client) | 81 | srv, err := drive.New(client) |
| 106 | if err != nil { | 82 | if err != nil { |
| @@ -115,16 +91,16 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 115 | } | 91 | } |
| 116 | // Defer to a rollback in case anything fails | 92 | // Defer to a rollback in case anything fails |
| 117 | defer tx.Rollback() | 93 | defer tx.Rollback() |
| 118 | fileID := "" | 94 | for i, header := range demoFiles { |
| 119 | for i, header := range files { | ||
| 120 | uuid := uuid.New().String() | 95 | uuid := uuid.New().String() |
| 121 | // Upload & insert into demos | 96 | // Upload & insert into demos |
| 122 | err = c.SaveUploadedFile(header, "docs/"+header.Filename) | 97 | err = c.SaveUploadedFile(header, "backend/parser/"+uuid+".dem") |
| 123 | if err != nil { | 98 | if err != nil { |
| 124 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 99 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 125 | return | 100 | return |
| 126 | } | 101 | } |
| 127 | f, err := os.Open("docs/" + header.Filename) | 102 | defer os.Remove("backend/parser/" + uuid + ".dem") |
| 103 | f, err := os.Open("backend/parser/" + uuid + ".dem") | ||
| 128 | if err != nil { | 104 | if err != nil { |
| 129 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 105 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 130 | return | 106 | return |
| @@ -135,11 +111,16 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 135 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 111 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 136 | return | 112 | return |
| 137 | } | 113 | } |
| 138 | fileID = file.Id | 114 | hostDemoScoreCount, hostDemoScoreTime, err = parser.ProcessDemo("backend/parser/" + uuid + ".dem") |
| 115 | if err != nil { | ||
| 116 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | ||
| 117 | return | ||
| 118 | } | ||
| 139 | if i == 0 { | 119 | if i == 0 { |
| 120 | hostDemoFileID = file.Id | ||
| 140 | hostDemoUUID = uuid | 121 | hostDemoUUID = uuid |
| 141 | } | 122 | } else if i == 1 { |
| 142 | if i == 1 { | 123 | partnerDemoFileID = file.Id |
| 143 | partnerDemoUUID = uuid | 124 | partnerDemoUUID = uuid |
| 144 | } | 125 | } |
| 145 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) | 126 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) |
| @@ -148,7 +129,6 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 148 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 129 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 149 | return | 130 | return |
| 150 | } | 131 | } |
| 151 | os.Remove("docs/" + header.Filename) | ||
| 152 | } | 132 | } |
| 153 | // Insert into records | 133 | // Insert into records |
| 154 | if isCoop { | 134 | if isCoop { |
| @@ -163,9 +143,10 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 163 | partnerID = user.(models.User).SteamID | 143 | partnerID = user.(models.User).SteamID |
| 164 | hostID = record.PartnerID | 144 | hostID = record.PartnerID |
| 165 | } | 145 | } |
| 166 | _, err := tx.Exec(sql, mapId, record.ScoreCount, record.ScoreTime, hostID, partnerID, hostDemoUUID, partnerDemoUUID) | 146 | _, err := tx.Exec(sql, mapId, hostDemoScoreCount, hostDemoScoreTime, hostID, partnerID, hostDemoUUID, partnerDemoUUID) |
| 167 | if err != nil { | 147 | if err != nil { |
| 168 | deleteFile(srv, fileID) | 148 | deleteFile(srv, hostDemoFileID) |
| 149 | deleteFile(srv, partnerDemoFileID) | ||
| 169 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 150 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 170 | return | 151 | return |
| 171 | } | 152 | } |
| @@ -180,9 +161,9 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 180 | } else { | 161 | } else { |
| 181 | sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) | 162 | sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) |
| 182 | VALUES($1, $2, $3, $4, $5)` | 163 | VALUES($1, $2, $3, $4, $5)` |
| 183 | _, err := tx.Exec(sql, mapId, record.ScoreCount, record.ScoreTime, user.(models.User).SteamID, hostDemoUUID) | 164 | _, err := tx.Exec(sql, mapId, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) |
| 184 | if err != nil { | 165 | if err != nil { |
| 185 | deleteFile(srv, fileID) | 166 | deleteFile(srv, hostDemoFileID) |
| 186 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) | 167 | c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) |
| 187 | return | 168 | return |
| 188 | } | 169 | } |
| @@ -202,21 +183,20 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 202 | c.JSON(http.StatusOK, models.Response{ | 183 | c.JSON(http.StatusOK, models.Response{ |
| 203 | Success: true, | 184 | Success: true, |
| 204 | Message: "Successfully created record.", | 185 | Message: "Successfully created record.", |
| 205 | Data: record, | 186 | Data: models.RecordResponse{ScoreCount: hostDemoScoreCount, ScoreTime: hostDemoScoreTime}, |
| 206 | }) | 187 | }) |
| 207 | return | ||
| 208 | } | 188 | } |
| 209 | 189 | ||
| 210 | // GET Demo | 190 | // GET Demo |
| 211 | // | 191 | // |
| 212 | // @Summary Get demo with specified demo uuid. | 192 | // @Description Get demo with specified demo uuid. |
| 213 | // @Tags demo | 193 | // @Tags demo |
| 214 | // @Accept json | 194 | // @Accept json |
| 215 | // @Produce octet-stream | 195 | // @Produce octet-stream |
| 216 | // @Param uuid query int true "Demo UUID" | 196 | // @Param uuid query string true "Demo UUID" |
| 217 | // @Success 200 {file} binary "Demo File" | 197 | // @Success 200 {file} binary "Demo File" |
| 218 | // @Failure 400 {object} models.Response | 198 | // @Failure 400 {object} models.Response |
| 219 | // @Router /demos [get] | 199 | // @Router /demos [get] |
| 220 | func DownloadDemoWithID(c *gin.Context) { | 200 | func DownloadDemoWithID(c *gin.Context) { |
| 221 | uuid := c.Query("uuid") | 201 | uuid := c.Query("uuid") |
| 222 | var locationID string | 202 | var locationID string |
| @@ -260,7 +240,7 @@ func DownloadDemoWithID(c *gin.Context) { | |||
| 260 | 240 | ||
| 261 | // Use Service account | 241 | // Use Service account |
| 262 | func serviceAccount() *http.Client { | 242 | func serviceAccount() *http.Client { |
| 263 | privateKey, _ := b64.StdEncoding.DecodeString(os.Getenv("GOOGLE_PRIVATE_KEY_BASE64")) | 243 | privateKey, _ := base64.StdEncoding.DecodeString(os.Getenv("GOOGLE_PRIVATE_KEY_BASE64")) |
| 264 | config := &jwt.Config{ | 244 | config := &jwt.Config{ |
| 265 | Email: os.Getenv("GOOGLE_CLIENT_EMAIL"), | 245 | Email: os.Getenv("GOOGLE_CLIENT_EMAIL"), |
| 266 | PrivateKey: []byte(privateKey), | 246 | PrivateKey: []byte(privateKey), |
diff --git a/backend/controllers/userController.go b/backend/controllers/userController.go index adf936b..e73b1fe 100644 --- a/backend/controllers/userController.go +++ b/backend/controllers/userController.go | |||
| @@ -13,15 +13,15 @@ import ( | |||
| 13 | 13 | ||
| 14 | // GET Profile | 14 | // GET Profile |
| 15 | // | 15 | // |
| 16 | // @Summary Get profile page of session user. | 16 | // @Description Get profile page of session user. |
| 17 | // @Tags users | 17 | // @Tags users |
| 18 | // @Accept json | 18 | // @Accept json |
| 19 | // @Produce json | 19 | // @Produce json |
| 20 | // @Param Authorization header string true "JWT Token" | 20 | // @Param Authorization header string true "JWT Token" |
| 21 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 21 | // @Success 200 {object} models.Response{data=models.ProfileResponse} |
| 22 | // @Failure 400 {object} models.Response | 22 | // @Failure 400 {object} models.Response |
| 23 | // @Failure 401 {object} models.Response | 23 | // @Failure 401 {object} models.Response |
| 24 | // @Router /profile [get] | 24 | // @Router /profile [get] |
| 25 | func Profile(c *gin.Context) { | 25 | func Profile(c *gin.Context) { |
| 26 | // Check if user exists | 26 | // Check if user exists |
| 27 | user, exists := c.Get("user") | 27 | user, exists := c.Get("user") |
| @@ -100,15 +100,15 @@ func Profile(c *gin.Context) { | |||
| 100 | 100 | ||
| 101 | // GET User | 101 | // GET User |
| 102 | // | 102 | // |
| 103 | // @Summary Get profile page of another user. | 103 | // @Description Get profile page of another user. |
| 104 | // @Tags users | 104 | // @Tags users |
| 105 | // @Accept json | 105 | // @Accept json |
| 106 | // @Produce json | 106 | // @Produce json |
| 107 | // @Param id path int true "User ID" | 107 | // @Param id path int true "User ID" |
| 108 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 108 | // @Success 200 {object} models.Response{data=models.ProfileResponse} |
| 109 | // @Failure 400 {object} models.Response | 109 | // @Failure 400 {object} models.Response |
| 110 | // @Failure 404 {object} models.Response | 110 | // @Failure 404 {object} models.Response |
| 111 | // @Router /users/{id} [get] | 111 | // @Router /users/{id} [get] |
| 112 | func FetchUser(c *gin.Context) { | 112 | func FetchUser(c *gin.Context) { |
| 113 | id := c.Param("id") | 113 | id := c.Param("id") |
| 114 | // Check if id is all numbers and 17 length | 114 | // Check if id is all numbers and 17 length |
| @@ -202,15 +202,15 @@ func FetchUser(c *gin.Context) { | |||
| 202 | 202 | ||
| 203 | // PUT Profile | 203 | // PUT Profile |
| 204 | // | 204 | // |
| 205 | // @Summary Update profile page of session user. | 205 | // @Description Update profile page of session user. |
| 206 | // @Tags users | 206 | // @Tags users |
| 207 | // @Accept json | 207 | // @Accept json |
| 208 | // @Produce json | 208 | // @Produce json |
| 209 | // @Param Authorization header string true "JWT Token" | 209 | // @Param Authorization header string true "JWT Token" |
| 210 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 210 | // @Success 200 {object} models.Response{data=models.ProfileResponse} |
| 211 | // @Failure 400 {object} models.Response | 211 | // @Failure 400 {object} models.Response |
| 212 | // @Failure 401 {object} models.Response | 212 | // @Failure 401 {object} models.Response |
| 213 | // @Router /profile [post] | 213 | // @Router /profile [post] |
| 214 | func UpdateUser(c *gin.Context) { | 214 | func UpdateUser(c *gin.Context) { |
| 215 | // Check if user exists | 215 | // Check if user exists |
| 216 | user, exists := c.Get("user") | 216 | user, exists := c.Get("user") |
| @@ -245,16 +245,16 @@ func UpdateUser(c *gin.Context) { | |||
| 245 | 245 | ||
| 246 | // PUT Profile/CountryCode | 246 | // PUT Profile/CountryCode |
| 247 | // | 247 | // |
| 248 | // @Summary Update country code of session user. | 248 | // @Description Update country code of session user. |
| 249 | // @Tags users | 249 | // @Tags users |
| 250 | // @Accept json | 250 | // @Accept json |
| 251 | // @Produce json | 251 | // @Produce json |
| 252 | // @Param Authorization header string true "JWT Token" | 252 | // @Param Authorization header string true "JWT Token" |
| 253 | // @Param country_code query string true "Country Code [XX]" | 253 | // @Param country_code query string true "Country Code [XX]" |
| 254 | // @Success 200 {object} models.Response{data=models.ProfileResponse} | 254 | // @Success 200 {object} models.Response |
| 255 | // @Failure 400 {object} models.Response | 255 | // @Failure 400 {object} models.Response |
| 256 | // @Failure 401 {object} models.Response | 256 | // @Failure 401 {object} models.Response |
| 257 | // @Router /profile [put] | 257 | // @Router /profile [put] |
| 258 | func UpdateCountryCode(c *gin.Context) { | 258 | func UpdateCountryCode(c *gin.Context) { |
| 259 | // Check if user exists | 259 | // Check if user exists |
| 260 | user, exists := c.Get("user") | 260 | user, exists := c.Get("user") |
diff --git a/backend/database/chapters.sql b/backend/database/chapters.sql index f01ae9c..9538bed 100644 --- a/backend/database/chapters.sql +++ b/backend/database/chapters.sql | |||
| @@ -1,17 +1,17 @@ | |||
| 1 | INSERT INTO chapters(id, game_id, name) VALUES | 1 | INSERT INTO chapters(id, game_id, name) VALUES |
| 2 | (1, 1, 'The Coutesy Call'), | 2 | (1, 1, 'Chapter 1 - The Coutesy Call'), |
| 3 | (2, 1, 'The Cold Boot'), | 3 | (2, 1, 'Chapter 2 - The Cold Boot'), |
| 4 | (3, 1, 'The Return'), | 4 | (3, 1, 'Chapter 3 - The Return'), |
| 5 | (4, 1, 'The Surprise'), | 5 | (4, 1, 'Chapter 4 - The Surprise'), |
| 6 | (5, 1, 'The Escape'), | 6 | (5, 1, 'Chapter 5 - The Escape'), |
| 7 | (6, 1, 'The Fall'), | 7 | (6, 1, 'Chapter 6 - The Fall'), |
| 8 | (7, 1, 'The Reunion'), | 8 | (7, 1, 'Chapter 7 - The Reunion'), |
| 9 | (8, 1, 'The Itch'), | 9 | (8, 1, 'Chapter 8 - The Itch'), |
| 10 | (9, 1, 'The Part Where He Kills You'), | 10 | (9, 1, 'Chapter 9 - The Part Where He Kills You'), |
| 11 | (10, 2, 'Introduction'), | 11 | (10, 2, 'Course 0 - Introduction'), |
| 12 | (11, 2, 'Team Building'), | 12 | (11, 2, 'Course 1 - Team Building'), |
| 13 | (12, 2, 'Mass And Velocity'), | 13 | (12, 2, 'Course 2 - Mass And Velocity'), |
| 14 | (13, 2, 'Hard-Light Surfaces'), | 14 | (13, 2, 'Course 3 - Hard-Light Surfaces'), |
| 15 | (14, 2, 'Excursion Funnels'), | 15 | (14, 2, 'Course 4 - Excursion Funnels'), |
| 16 | (15, 2, 'Mobility Gels'), | 16 | (15, 2, 'Course 5 - Mobility Gels'), |
| 17 | (16, 2, 'Art Therapy'); \ No newline at end of file | 17 | (16, 2, 'Course 6 - Art Therapy'); \ No newline at end of file |
diff --git a/backend/database/games.sql b/backend/database/games.sql index 5e2f4ee..0c2374c 100644 --- a/backend/database/games.sql +++ b/backend/database/games.sql | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | INSERT INTO games(id, name) VALUES | 1 | INSERT INTO games(id, name, is_coop) VALUES |
| 2 | (1, 'Portal 2 - Singleplayer'), | 2 | (1, 'Portal 2 - Singleplayer', false), |
| 3 | (2, 'Portal 2 - Cooperative'); \ No newline at end of file | 3 | (2, 'Portal 2 - Cooperative', true); \ No newline at end of file |
diff --git a/backend/database/history.sql b/backend/database/history.sql index 0840bf3..320d72f 100644 --- a/backend/database/history.sql +++ b/backend/database/history.sql | |||
| @@ -1,279 +1,279 @@ | |||
| 1 | INSERT INTO map_history(map_id,user_name,score_count,record_date) VALUES | 1 | INSERT INTO map_history(map_id,category_id,user_name,score_count,record_date) VALUES |
| 2 | -- Portal 2 Singleplayer | 2 | -- Portal 2 Singleplayer |
| 3 | -- 1 | 3 | -- 1 |
| 4 | (3,'slmid1995',3,'2011-10-05 00:00:00'), | 4 | (3,1,'slmid1995',3,'2011-10-05 00:00:00'), |
| 5 | (3,'LookLikeAKango',1,'2011-10-06 00:00:00'), | 5 | (3,1,'LookLikeAKango',1,'2011-10-06 00:00:00'), |
| 6 | (3,'Bananasaurus Rex',0,'2011-10-24 00:00:00'), | 6 | (3,1,'Bananasaurus Rex',0,'2011-10-24 00:00:00'), |
| 7 | (4,'Tyronis',1,'2011-10-05 00:00:00'), | 7 | (4,1,'Tyronis',1,'2011-10-05 00:00:00'), |
| 8 | (4,'Krzyhau',0,'2019-05-10 00:00:00'), | 8 | (4,1,'Krzyhau',0,'2019-05-10 00:00:00'), |
| 9 | (5,'LookLikeAKango',2,'2011-10-05 00:00:00'), | 9 | (5,1,'LookLikeAKango',2,'2011-10-05 00:00:00'), |
| 10 | (5,'Jetwash',1,'2013-12-03 00:00:00'), | 10 | (5,1,'Jetwash',1,'2013-12-03 00:00:00'), |
| 11 | (6,'Stimich',4,'2011-10-08 00:00:00'), | 11 | (6,1,'Stimich',4,'2011-10-08 00:00:00'), |
| 12 | (6,'aepaePolakrn',3,'2011-10-19 00:00:00'), | 12 | (6,1,'aepaePolakrn',3,'2011-10-19 00:00:00'), |
| 13 | (6,'Krzyhau',2,'2020-10-10 00:00:00'), | 13 | (6,1,'Krzyhau',2,'2020-10-10 00:00:00'), |
| 14 | (9,'slmid1995',4,'2011-10-05 00:00:00'), | 14 | (9,1,'slmid1995',4,'2011-10-05 00:00:00'), |
| 15 | (9,'Jokie',3,'2011-10-05 00:00:00'), | 15 | (9,1,'Jokie',3,'2011-10-05 00:00:00'), |
| 16 | (9,'Tyronis',2,'2011-10-05 00:00:00'), | 16 | (9,1,'Tyronis',2,'2011-10-05 00:00:00'), |
| 17 | (9,'sicklebrick',0,'2013-03-13 00:00:00'), | 17 | (9,1,'sicklebrick',0,'2013-03-13 00:00:00'), |
| 18 | -- 2 | 18 | -- 2 |
| 19 | (10,'Paraxade0',2,'2011-04-21 00:00:00'), | 19 | (10,1,'Paraxade0',2,'2011-04-21 00:00:00'), |
| 20 | (10,'PerOculos',0,'2011-04-21 00:00:00'), | 20 | (10,1,'PerOculos',0,'2011-04-21 00:00:00'), |
| 21 | (11,'Tyronis',2,'2011-10-05 00:00:00'), | 21 | (11,1,'Tyronis',2,'2011-10-05 00:00:00'), |
| 22 | (11,'Krzyhau',0,'2018-06-09 00:00:00'), | 22 | (11,1,'Krzyhau',0,'2018-06-09 00:00:00'), |
| 23 | (12,'slmid1995',2,'2011-10-04 00:00:00'), | 23 | (12,1,'slmid1995',2,'2011-10-04 00:00:00'), |
| 24 | (13,'LookLikeAKango',3,'2011-10-05 00:00:00'), | 24 | (13,1,'LookLikeAKango',3,'2011-10-05 00:00:00'), |
| 25 | (13,'Imanex',2,'2011-12-08 00:00:00'), | 25 | (13,1,'Imanex',2,'2011-12-08 00:00:00'), |
| 26 | (13,'jyjey',0,'2012-08-22 00:00:00'), | 26 | (13,1,'jyjey',0,'2012-08-22 00:00:00'), |
| 27 | (15,'Tyronis',2,'2011-10-05 00:00:00'), | 27 | (15,1,'Tyronis',2,'2011-10-05 00:00:00'), |
| 28 | (16,'LookLikeAKango',2,'2011-10-05 00:00:00'), | 28 | (16,1,'LookLikeAKango',2,'2011-10-05 00:00:00'), |
| 29 | (16,'jyjey',0,'2012-08-25 00:00:00'), | 29 | (16,1,'jyjey',0,'2012-08-25 00:00:00'), |
| 30 | (17,'rocoty',0,'2011-10-05 00:00:00'), | 30 | (17,1,'rocoty',2,'2011-10-05 00:00:00'), |
| 31 | (17,'Nidboj132',0,'2023-02-05 00:00:00'), | 31 | (17,1,'Nidboj132',0,'2023-02-05 00:00:00'), |
| 32 | -- 3 | 32 | -- 3 |
| 33 | (18,'The Last Tofus',5,'2011-05-08 00:00:00'), | 33 | (18,1,'The Last Tofus',5,'2011-05-08 00:00:00'), |
| 34 | (18,'Schlepian',4,'2011-10-08 00:00:00'), | 34 | (18,1,'Schlepian',4,'2011-10-08 00:00:00'), |
| 35 | (18,'szeimartin',3,'2013-10-08 00:00:00'), | 35 | (18,1,'szeimartin',3,'2013-10-08 00:00:00'), |
| 36 | (18,'Krzyhau',2,'2020-05-15 00:00:00'), | 36 | (18,1,'Krzyhau',2,'2020-05-15 00:00:00'), |
| 37 | (18,'Krzyhau',0,'2022-07-02 00:00:00'), | 37 | (18,1,'Krzyhau',0,'2022-07-02 00:00:00'), |
| 38 | (19,'LookLikeAKango',2,'2011-10-06 00:00:00'), | 38 | (19,1,'LookLikeAKango',2,'2011-10-06 00:00:00'), |
| 39 | (20,'Djinndrache',5,'2011-10-20 00:00:00'), | 39 | (20,1,'Djinndrache',5,'2011-10-20 00:00:00'), |
| 40 | (20,'Schlepian',4,'2011-10-30 00:00:00'), | 40 | (20,1,'Schlepian',4,'2011-10-30 00:00:00'), |
| 41 | (20,'Jetwash',3,'2014-09-04 00:00:00'), | 41 | (20,1,'Jetwash',3,'2014-09-04 00:00:00'), |
| 42 | (20,'Krzyhau',2,'2022-04-24 00:00:00'), | 42 | (20,1,'Krzyhau',2,'2022-04-24 00:00:00'), |
| 43 | (21,'LookLikeAKango',4,'2011-10-06 00:00:00'), | 43 | (21,1,'LookLikeAKango',4,'2011-10-06 00:00:00'), |
| 44 | (21,'ncla',2,'2011-10-30 00:00:00'), | 44 | (21,1,'ncla',2,'2011-10-30 00:00:00'), |
| 45 | (21,'PerOculos',0,'2019-07-08 00:00:00'), | 45 | (21,1,'PerOculos',0,'2019-07-08 00:00:00'), |
| 46 | (22,'Tyronis',0,'2011-10-05 00:00:00'), | 46 | (22,1,'Tyronis',0,'2011-10-05 00:00:00'), |
| 47 | (23,'LookLikeAKango',2,'2011-10-06 00:00:00'), | 47 | (23,1,'LookLikeAKango',2,'2011-10-06 00:00:00'), |
| 48 | (23,'Krzyhau',0,'2018-08-01 00:00:00'), | 48 | (23,1,'Krzyhau',0,'2018-08-01 00:00:00'), |
| 49 | (24,'LeviHB',0,'2011-04-30 00:00:00'), | 49 | (24,1,'LeviHB',0,'2011-04-30 00:00:00'), |
| 50 | (25,'Tyronis',0,'2011-10-06 00:00:00'), | 50 | (25,1,'Tyronis',0,'2011-10-06 00:00:00'), |
| 51 | (26,'Schlepian',3,'2011-10-30 00:00:00'), | 51 | (26,1,'Schlepian',3,'2011-10-30 00:00:00'), |
| 52 | (26,'Tyronis',2,'2012-01-08 00:00:00'), | 52 | (26,1,'Tyronis',2,'2012-01-08 00:00:00'), |
| 53 | (26,'PerOculos',0,'2016-06-08 00:00:00'), | 53 | (26,1,'PerOculos',0,'2016-06-08 00:00:00'), |
| 54 | -- 4 | 54 | -- 4 |
| 55 | (27,'LeviHB',2,'2011-05-01 00:00:00'), | 55 | (27,1,'LeviHB',2,'2011-05-01 00:00:00'), |
| 56 | (27,'PerOculos',0,'2020-07-13 00:00:00'), | 56 | (27,1,'PerOculos',0,'2020-07-13 00:00:00'), |
| 57 | (28,'LeviHB',7,'2011-05-01 00:00:00'), | 57 | (28,1,'LeviHB',7,'2011-05-01 00:00:00'), |
| 58 | (28,'Andy M.J.',2,'2011-10-07 00:00:00'), | 58 | (28,1,'Andy M.J.',2,'2011-10-07 00:00:00'), |
| 59 | (28,'Krzyhau',0,'2018-05-19 00:00:00'), | 59 | (28,1,'Krzyhau',0,'2018-05-19 00:00:00'), |
| 60 | (29,'LeviHB',0,'2011-05-01 00:00:00'), | 60 | (29,1,'LeviHB',0,'2011-05-01 00:00:00'), |
| 61 | (30,'Schlepian',2,'2011-10-30 00:00:00'), | 61 | (30,1,'Schlepian',2,'2011-10-30 00:00:00'), |
| 62 | (31,'Tyronis',0,'2011-10-06 00:00:00'), | 62 | (31,1,'Tyronis',0,'2011-10-06 00:00:00'), |
| 63 | -- 5 | 63 | -- 5 |
| 64 | (32,'Tyronis',6,'2011-10-21 00:00:00'), | 64 | (32,1,'Tyronis',6,'2011-10-21 00:00:00'), |
| 65 | (32,'Nidboj132',5,'2022-04-24 00:00:00'), | 65 | (32,1,'Nidboj132',5,'2022-04-24 00:00:00'), |
| 66 | (33,'Tyronis',7,'2011-10-06 00:00:00'), | 66 | (33,1,'Tyronis',7,'2011-10-06 00:00:00'), |
| 67 | (33,'ISimmo',5,'2011-11-02 00:00:00'), | 67 | (33,1,'ISimmo',5,'2011-11-02 00:00:00'), |
| 68 | (33,'PerOculos',4,'2017-05-30 00:00:00'), | 68 | (33,1,'PerOculos',4,'2017-05-30 00:00:00'), |
| 69 | (34,'Schlepian',3,'2011-11-01 00:00:00'), | 69 | (34,1,'Schlepian',3,'2011-11-01 00:00:00'), |
| 70 | (34,'Krzyhau',2,'2020-10-14 00:00:00'), | 70 | (34,1,'Krzyhau',2,'2020-10-14 00:00:00'), |
| 71 | (34,'zach',0,'2022-11-02 00:00:00'), | 71 | (34,1,'zach',0,'2022-11-02 00:00:00'), |
| 72 | (35,'Krank',2,'2012-07-28 00:00:00'), | 72 | (35,1,'Krank',2,'2012-07-28 00:00:00'), |
| 73 | -- 6 | 73 | -- 6 |
| 74 | (36,'Tyronis',6,'2011-10-06 00:00:00'), | 74 | (36,1,'Tyronis',6,'2011-10-06 00:00:00'), |
| 75 | (36,'CalmlyFrenetic',5,'2011-10-09 00:00:00'), | 75 | (36,1,'CalmlyFrenetic',5,'2011-10-09 00:00:00'), |
| 76 | (36,'sicklebrick',4,'2012-09-13 00:00:00'), | 76 | (36,1,'sicklebrick',4,'2012-09-13 00:00:00'), |
| 77 | (36,'Nidboj132',2,'2023-03-04 00:00:00'), | 77 | (36,1,'Nidboj132',2,'2023-03-04 00:00:00'), |
| 78 | (37,'LookLikeAKango',7,'2011-10-06 00:00:00'), | 78 | (37,1,'LookLikeAKango',7,'2011-10-06 00:00:00'), |
| 79 | (37,'Schlepian',6,'2011-11-01 00:00:00'), | 79 | (37,1,'Schlepian',6,'2011-11-01 00:00:00'), |
| 80 | (37,'Tyronis',5,'2012-01-28 00:00:00'), | 80 | (37,1,'Tyronis',5,'2012-01-28 00:00:00'), |
| 81 | (37,'Nidboj132',4,'2021-08-22 00:00:00'), | 81 | (37,1,'Nidboj132',4,'2021-08-22 00:00:00'), |
| 82 | (38,'Andy M.J.',2,'2011-10-06 00:00:00'), | 82 | (38,1,'Andy M.J.',2,'2011-10-06 00:00:00'), |
| 83 | (38,'Sanguine Dagger',0,'2012-03-19 00:00:00'), | 83 | (38,1,'Sanguine Dagger',0,'2012-03-19 00:00:00'), |
| 84 | (39,'Lambda Core',6,'2011-05-13 00:00:00'), | 84 | (39,1,'Lambda Core',6,'2011-05-13 00:00:00'), |
| 85 | (39,'The Last Tofus',5,'2011-05-13 00:00:00'), | 85 | (39,1,'The Last Tofus',5,'2011-05-13 00:00:00'), |
| 86 | (39,'LookLikeAKango',4,'2011-10-16 00:00:00'), | 86 | (39,1,'LookLikeAKango',4,'2011-10-16 00:00:00'), |
| 87 | (39,'Kittaye',3,'2013-03-25 00:00:00'), | 87 | (39,1,'Kittaye',3,'2013-03-25 00:00:00'), |
| 88 | (40,'LookLikeAKango',7,'2011-10-07 00:00:00'), | 88 | (40,1,'LookLikeAKango',7,'2011-10-07 00:00:00'), |
| 89 | (40,'Schlepian',6,'2011-11-05 00:00:00'), | 89 | (40,1,'Schlepian',6,'2011-11-05 00:00:00'), |
| 90 | (40,'Kittaye',4,'2013-04-01 00:00:00'), | 90 | (40,1,'Kittaye',4,'2013-04-01 00:00:00'), |
| 91 | (40,'Kittaye',3,'2014-09-13 00:00:00'), | 91 | (40,1,'Kittaye',3,'2014-09-13 00:00:00'), |
| 92 | (40,'szeimartin',2,'2014-09-13 00:00:00'), | 92 | (40,1,'szeimartin',2,'2014-09-13 00:00:00'), |
| 93 | (40,'Kittaye',0,'2014-09-15 00:00:00'), | 93 | (40,1,'Kittaye',0,'2014-09-15 00:00:00'), |
| 94 | (41,'CalmlyFrenetic',7,'2011-10-09 00:00:00'), | 94 | (41,1,'CalmlyFrenetic',7,'2011-10-09 00:00:00'), |
| 95 | (41,'Jaso',6,'2011-10-11 00:00:00'), | 95 | (41,1,'Jaso',6,'2011-10-11 00:00:00'), |
| 96 | (41,'Krank',5,'2012-07-17 00:00:00'), | 96 | (41,1,'Krank',5,'2012-07-17 00:00:00'), |
| 97 | -- 7 | 97 | -- 7 |
| 98 | (42,'LookLikeAKango',4,'2011-05-17 00:00:00'), | 98 | (42,1,'LookLikeAKango',4,'2011-05-17 00:00:00'), |
| 99 | (42,'ISimmo',2,'2011-11-07 00:00:00'), | 99 | (42,1,'ISimmo',2,'2011-11-07 00:00:00'), |
| 100 | (43,'lmao4ever',5,'2011-10-30 00:00:00'), | 100 | (43,1,'lmao4ever',5,'2011-10-30 00:00:00'), |
| 101 | (43,'Jaso',2,'2011-11-09 00:00:00'), | 101 | (43,1,'Jaso',2,'2011-11-09 00:00:00'), |
| 102 | (43,'feliser',0,'2022-06-26 00:00:00'), | 102 | (43,1,'feliser',0,'2022-06-26 00:00:00'), |
| 103 | (44,'LookLikeAKango',18,'2011-10-07 00:00:00'), | 103 | (44,1,'LookLikeAKango',18,'2011-10-07 00:00:00'), |
| 104 | (44,'Tyronis',13,'2011-10-30 00:00:00'), | 104 | (44,1,'Tyronis',13,'2011-10-30 00:00:00'), |
| 105 | (44,'Tyronis',12,'2011-11-10 00:00:00'), | 105 | (44,1,'Tyronis',12,'2011-11-10 00:00:00'), |
| 106 | (44,'Jetwash',11,'2017-06-12 00:00:00'), | 106 | (44,1,'Jetwash',11,'2017-06-12 00:00:00'), |
| 107 | (44,'Krzyhau',9,'2022-01-02 00:00:00'), | 107 | (44,1,'Krzyhau',9,'2022-01-02 00:00:00'), |
| 108 | (45,'LookLikeAKango',23,'2011-10-08 00:00:00'), | 108 | (45,1,'LookLikeAKango',23,'2011-10-08 00:00:00'), |
| 109 | (45,'CalmlyFrenetic',22,'2011-10-09 00:00:00'), | 109 | (45,1,'CalmlyFrenetic',22,'2011-10-09 00:00:00'), |
| 110 | (45,'cgreactor',17,'2011-10-09 00:00:00'), | 110 | (45,1,'cgreactor',17,'2011-10-09 00:00:00'), |
| 111 | (45,'CalmlyFrenetic',16,'2011-10-10 00:00:00'), | 111 | (45,1,'CalmlyFrenetic',16,'2011-10-10 00:00:00'), |
| 112 | (45,'LookLikeAKango',15,'2011-10-19 00:00:00'), | 112 | (45,1,'LookLikeAKango',15,'2011-10-19 00:00:00'), |
| 113 | (45,'Jaso',12,'2012-07-19 00:00:00'), | 113 | (45,1,'Jaso',12,'2012-07-19 00:00:00'), |
| 114 | (45,'Krank',10,'2013-01-31 00:00:00'), | 114 | (45,1,'Krank',10,'2013-01-31 00:00:00'), |
| 115 | (45,'Kittaye',7,'2013-04-04 00:00:00'), | 115 | (45,1,'Kittaye',7,'2013-04-04 00:00:00'), |
| 116 | (45,'PerOculos',4,'2014-09-13 00:00:00'), | 116 | (45,1,'PerOculos',4,'2014-09-13 00:00:00'), |
| 117 | -- 8 | 117 | -- 8 |
| 118 | (46,'sparkle1princess',6,'2012-03-24 00:00:00'), | 118 | (46,1,'sparkle1princess',6,'2012-03-24 00:00:00'), |
| 119 | (46,'Krzyhau',2,'2019-11-21 00:00:00'), | 119 | (46,1,'Krzyhau',2,'2019-11-21 00:00:00'), |
| 120 | (47,'holydevel',2,'2011-10-06 00:00:00'), | 120 | (47,1,'holydevel',2,'2011-10-06 00:00:00'), |
| 121 | (47,'JesusCatFace',0,'2015-01-16 00:00:00'), | 121 | (47,1,'JesusCatFace',0,'2015-01-16 00:00:00'), |
| 122 | (48,'LookLikeAKango',5,'2011-10-08 00:00:00'), | 122 | (48,1,'LookLikeAKango',5,'2011-10-08 00:00:00'), |
| 123 | (48,'Tyronis',2,'2011-10-08 00:00:00'), | 123 | (48,1,'Tyronis',2,'2011-10-08 00:00:00'), |
| 124 | (48,'adzicents',0,'2011-10-09 00:00:00'), | 124 | (48,1,'adzicents',0,'2011-10-09 00:00:00'), |
| 125 | (49,'adzicents',4,'2011-10-07 00:00:00'), | 125 | (49,1,'adzicents',4,'2011-10-07 00:00:00'), |
| 126 | (49,'Schlepian',2,'2011-10-08 00:00:00'), | 126 | (49,1,'Schlepian',2,'2011-10-08 00:00:00'), |
| 127 | (49,'Nidboj132',0,'2022-09-26 00:00:00'), | 127 | (49,1,'Nidboj132',0,'2022-09-26 00:00:00'), |
| 128 | (50,'LookLikeAKango',4,'2011-10-08 00:00:00'), | 128 | (50,1,'LookLikeAKango',4,'2011-10-08 00:00:00'), |
| 129 | (50,'Tyronis',2,'2011-10-11 00:00:00'), | 129 | (50,1,'Tyronis',2,'2011-10-11 00:00:00'), |
| 130 | (50,'sicklebrick',0,'2013-03-20 00:00:00'), | 130 | (50,1,'sicklebrick',0,'2013-03-20 00:00:00'), |
| 131 | (51,'Andy M.J.',3,'2011-10-08 00:00:00'), | 131 | (51,1,'Andy M.J.',3,'2011-10-08 00:00:00'), |
| 132 | (51,'LookLikeAKango',2,'2011-10-20 00:00:00'), | 132 | (51,1,'LookLikeAKango',2,'2011-10-20 00:00:00'), |
| 133 | (52,'Jaso',0,'2011-10-10 00:00:00'), | 133 | (52,1,'Jaso',0,'2011-10-10 00:00:00'), |
| 134 | (53,'LookLikeAKango',9,'2011-10-08 00:00:00'), | 134 | (53,1,'LookLikeAKango',9,'2011-10-08 00:00:00'), |
| 135 | (53,'LookLikeAKango',2,'2011-10-20 00:00:00'), | 135 | (53,1,'LookLikeAKango',2,'2011-10-20 00:00:00'), |
| 136 | (53,'Schlepian',0,'2011-11-06 00:00:00'), | 136 | (53,1,'Schlepian',0,'2011-11-06 00:00:00'), |
| 137 | (54,'LookLikeAKango',7,'2011-06-01 00:00:00'), | 137 | (54,1,'LookLikeAKango',7,'2011-06-01 00:00:00'), |
| 138 | (54,'Jaso',6,'2011-10-09 00:00:00'), | 138 | (54,1,'Jaso',6,'2011-10-09 00:00:00'), |
| 139 | (54,'Schlepian',5,'2011-11-06 00:00:00'), | 139 | (54,1,'Schlepian',5,'2011-11-06 00:00:00'), |
| 140 | (54,'Spyrunite',4,'2012-08-30 00:00:00'), | 140 | (54,1,'Spyrunite',4,'2012-08-30 00:00:00'), |
| 141 | (54,'Krzyhau',3,'2019-04-22 00:00:00'), | 141 | (54,1,'Krzyhau',3,'2019-04-22 00:00:00'), |
| 142 | (55,'LookLikeAKango',7,'2011-10-08 00:00:00'), | 142 | (55,1,'LookLikeAKango',7,'2011-10-08 00:00:00'), |
| 143 | (55,'CalmlyFrenetic',3,'2011-10-09 00:00:00'), | 143 | (55,1,'CalmlyFrenetic',3,'2011-10-09 00:00:00'), |
| 144 | (55,'Jaso',2,'2011-11-26 00:00:00'), | 144 | (55,1,'Jaso',2,'2011-11-26 00:00:00'), |
| 145 | (55,'PerOculos',0,'2021-02-06 00:00:00'), | 145 | (55,1,'PerOculos',0,'2021-02-06 00:00:00'), |
| 146 | (56,'CalmlyFrenetic',9,'2011-10-08 00:00:00'), | 146 | (56,1,'CalmlyFrenetic',9,'2011-10-08 00:00:00'), |
| 147 | (56,'LookLikeAKango',5,'2011-10-09 00:00:00'), | 147 | (56,1,'LookLikeAKango',5,'2011-10-09 00:00:00'), |
| 148 | (56,'CalmlyFrenetic',4,'2011-10-09 00:00:00'), | 148 | (56,1,'CalmlyFrenetic',4,'2011-10-09 00:00:00'), |
| 149 | (56,'Jetwash',2,'2014-09-05 00:00:00'), | 149 | (56,1,'Jetwash',2,'2014-09-05 00:00:00'), |
| 150 | -- 9 | 150 | -- 9 |
| 151 | (57,'JNS',7,'2011-07-21 00:00:00'), | 151 | (57,1,'JNS',7,'2011-07-21 00:00:00'), |
| 152 | (57,'Krank',5,'2012-07-29 00:00:00'), | 152 | (57,1,'Krank',5,'2012-07-29 00:00:00'), |
| 153 | (57,'Krzyhau',0,'2017-10-29 00:00:00'), | 153 | (57,1,'Krzyhau',0,'2017-10-29 00:00:00'), |
| 154 | (58,'Stimich',2,'2011-10-11 00:00:00'), | 154 | (58,1,'Stimich',2,'2011-10-11 00:00:00'), |
| 155 | (59,'Isimmo',7,'2011-11-04 00:00:00'), | 155 | (59,1,'Isimmo',7,'2011-11-04 00:00:00'), |
| 156 | (59,'sicklebrick',6,'2013-03-20 00:00:00'), | 156 | (59,1,'sicklebrick',6,'2013-03-20 00:00:00'), |
| 157 | (60,'CalmlyFrenetic',7,'2011-10-19 00:00:00'), | 157 | (60,1,'CalmlyFrenetic',7,'2011-10-19 00:00:00'), |
| 158 | (60,'Tyronis',6,'2011-11-01 00:00:00'), | 158 | (60,1,'Tyronis',6,'2011-11-01 00:00:00'), |
| 159 | -- Portal 2 Cooperative | 159 | -- Portal 2 Cooperative |
| 160 | -- 1 | 160 | -- 1 |
| 161 | (63,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), | 161 | (63,1,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), |
| 162 | (64,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 162 | (64,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 163 | (64,'Chubfish & Exhale',2,'2011-11-01 00:00:00'), | 163 | (64,1,'Chubfish & Exhale',2,'2011-11-01 00:00:00'), |
| 164 | (65,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 164 | (65,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 165 | (65,'Nidboj132 & Oryn',3,'2022-02-03 00:00:00'), | 165 | (65,1,'Nidboj132 & Oryn',3,'2022-02-03 00:00:00'), |
| 166 | (66,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 166 | (66,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 167 | (66,'Schlepian & Chubfish',2,'2011-10-01 00:00:00'), | 167 | (66,1,'Schlepian & Chubfish',2,'2011-10-01 00:00:00'), |
| 168 | (67,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), | 168 | (67,1,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), |
| 169 | (68,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), | 169 | (68,1,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), |
| 170 | -- 2 | 170 | -- 2 |
| 171 | (69,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 171 | (69,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 172 | (70,'Mathias123961 & Sir Spawn Alot',6,'2011-08-01 00:00:00'), | 172 | (70,1,'Mathias123961 & Sir Spawn Alot',6,'2011-08-01 00:00:00'), |
| 173 | (70,'Schlepian & Chubfish',4,'2011-10-01 00:00:00'), | 173 | (70,1,'Schlepian & Chubfish',4,'2011-10-01 00:00:00'), |
| 174 | (70,'Gocnak & z1mb0bw4y',2,'2012-08-03 00:00:00'), | 174 | (70,1,'Gocnak & z1mb0bw4y',2,'2012-08-03 00:00:00'), |
| 175 | (70,'DM_ & VEGA',0,'2017-10-01 00:00:00'), | 175 | (70,1,'DM_ & VEGA',0,'2017-10-01 00:00:00'), |
| 176 | (71,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 176 | (71,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 177 | (71,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), | 177 | (71,1,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), |
| 178 | (72,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 178 | (72,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 179 | (72,'Schlepian & LongJohnDickWeed',2,'2011-10-01 00:00:00'), | 179 | (72,1,'Schlepian & LongJohnDickWeed',2,'2011-10-01 00:00:00'), |
| 180 | (73,'Stimich & HiTMaRkS',9,'2011-05-09 00:00:00'), | 180 | (73,1,'Stimich & HiTMaRkS',9,'2011-05-09 00:00:00'), |
| 181 | (73,'Mathias123961 & Sir Spawn Alot',8,'2011-08-01 00:00:00'), | 181 | (73,1,'Mathias123961 & Sir Spawn Alot',8,'2011-08-01 00:00:00'), |
| 182 | (73,'Schlepian & Lemonsunshine',7,'2011-11-01 00:00:00'), | 182 | (73,1,'Schlepian & Lemonsunshine',7,'2011-11-01 00:00:00'), |
| 183 | (73,'DM_ & LsDK_',6,'2018-01-01 00:00:00'), | 183 | (73,1,'DM_ & LsDK_',6,'2018-01-01 00:00:00'), |
| 184 | (73,'Krzyhau & Klooger',4,'2018-11-01 00:00:00'), | 184 | (73,1,'Krzyhau & Klooger',4,'2018-11-01 00:00:00'), |
| 185 | (74,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), | 185 | (74,1,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), |
| 186 | (74,'Stimich & Pitkakorva',7,'2011-10-11 00:00:00'), | 186 | (74,1,'Stimich & Pitkakorva',7,'2011-10-11 00:00:00'), |
| 187 | (74,'Schlepian & Isimmo',3,'2011-10-28 00:00:00'), | 187 | (74,1,'Schlepian & Isimmo',3,'2011-10-28 00:00:00'), |
| 188 | (74,'Zypeh & szeimartin',2,'2013-11-01 00:00:00'), | 188 | (74,1,'Zypeh & szeimartin',2,'2013-11-01 00:00:00'), |
| 189 | (75,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), | 189 | (75,1,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), |
| 190 | (75,'Schlepian & Urination',4,'2011-10-01 00:00:00'), | 190 | (75,1,'Schlepian & Urination',4,'2011-10-01 00:00:00'), |
| 191 | (75,'Schlepian & Lemonsunshine',2,'2012-02-01 00:00:00'), | 191 | (75,1,'Schlepian & Lemonsunshine',2,'2012-02-01 00:00:00'), |
| 192 | (75,'DM_ & follon',0,'2015-04-01 00:00:00'), | 192 | (75,1,'DM_ & follon',0,'2015-04-01 00:00:00'), |
| 193 | (76,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 193 | (76,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 194 | (76,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), | 194 | (76,1,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), |
| 195 | -- 3 | 195 | -- 3 |
| 196 | (77,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 196 | (77,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 197 | (78,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 197 | (78,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 198 | (78,'DM_ & marK',3,'2016-11-01 00:00:00'), | 198 | (78,1,'DM_ & marK',3,'2016-11-01 00:00:00'), |
| 199 | (78,'Nidboj132 & Oryn',2,'2021-09-04 00:00:00'), | 199 | (78,1,'Nidboj132 & Oryn',2,'2021-09-04 00:00:00'), |
| 200 | (79,'ganonscrub & ?',5,'2011-04-01 00:00:00'), | 200 | (79,1,'ganonscrub & ?',5,'2011-04-01 00:00:00'), |
| 201 | (79,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 201 | (79,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 202 | (79,'Chubfish & Exhale',2,'2012-08-04 00:00:00'), | 202 | (79,1,'Chubfish & Exhale',2,'2012-08-04 00:00:00'), |
| 203 | (80,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), | 203 | (80,1,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), |
| 204 | (80,'Chubfish & Exhale',4,'2011-12-01 00:00:00'), | 204 | (80,1,'Chubfish & Exhale',4,'2011-12-01 00:00:00'), |
| 205 | (81,'Mathias123961 & Sir Spawn Alot',7,'2011-08-01 00:00:00'), | 205 | (81,1,'Mathias123961 & Sir Spawn Alot',7,'2011-08-01 00:00:00'), |
| 206 | (81,'Schlepian & Lemonsunshine',6,'2011-10-01 00:00:00'), | 206 | (81,1,'Schlepian & Lemonsunshine',6,'2011-10-01 00:00:00'), |
| 207 | (81,'takz & dawn',5,'2011-11-01 00:00:00'), | 207 | (81,1,'takz & dawn',5,'2011-11-01 00:00:00'), |
| 208 | (81,'Nidboj132 & Oryn',4,'2021-03-25 00:00:00'), | 208 | (81,1,'Nidboj132 & Oryn',4,'2021-03-25 00:00:00'), |
| 209 | (82,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 209 | (82,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 210 | (83,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), | 210 | (83,1,'Mathias123961 & Sir Spawn Alot',5,'2011-08-01 00:00:00'), |
| 211 | (83,'Schlepian & Lemonsunshine',2,'2011-10-01 00:00:00'), | 211 | (83,1,'Schlepian & Lemonsunshine',2,'2011-10-01 00:00:00'), |
| 212 | (83,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), | 212 | (83,1,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), |
| 213 | (84,'Mathias123961 & Sir Spawn Alot',6,'2011-08-01 00:00:00'), | 213 | (84,1,'Mathias123961 & Sir Spawn Alot',6,'2011-08-01 00:00:00'), |
| 214 | (84,'Schlepian & Chubfish',4,'2011-10-01 00:00:00'), | 214 | (84,1,'Schlepian & Chubfish',4,'2011-10-01 00:00:00'), |
| 215 | (84,'Chubfish & Exhale',2,'2012-01-01 00:00:00'), | 215 | (84,1,'Chubfish & Exhale',2,'2012-01-01 00:00:00'), |
| 216 | (84,'DM_ & wS',0,'2015-05-01 00:00:00'), | 216 | (84,1,'DM_ & wS',0,'2015-05-01 00:00:00'), |
| 217 | -- 4 | 217 | -- 4 |
| 218 | (85,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 218 | (85,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 219 | (85,'Chubfish & Exhale',0,'2011-10-01 00:00:00'), | 219 | (85,1,'Chubfish & Exhale',0,'2011-10-01 00:00:00'), |
| 220 | (86,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 220 | (86,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 221 | (86,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), | 221 | (86,1,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), |
| 222 | (87,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), | 222 | (87,1,'Mathias123961 & Sir Spawn Alot',3,'2011-08-01 00:00:00'), |
| 223 | (87,'Schlepian & Gopherdude',2,'2011-10-01 00:00:00'), | 223 | (87,1,'Schlepian & Gopherdude',2,'2011-10-01 00:00:00'), |
| 224 | (87,'DM_ & follon',0,'2015-04-01 00:00:00'), | 224 | (87,1,'DM_ & follon',0,'2015-04-01 00:00:00'), |
| 225 | (88,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 225 | (88,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 226 | (88,'Schlepian & Gopherdude',0,'2011-10-01 00:00:00'), | 226 | (88,1,'Schlepian & Gopherdude',0,'2011-10-01 00:00:00'), |
| 227 | (89,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), | 227 | (89,1,'Mathias123961 & Sir Spawn Alot',0,'2011-08-01 00:00:00'), |
| 228 | (90,'Mathias123961 & Sir Spawn Alot',4,'2011-09-01 00:00:00'), | 228 | (90,1,'Mathias123961 & Sir Spawn Alot',4,'2011-09-01 00:00:00'), |
| 229 | (90,'Schlepian & Urination',2,'2011-10-01 00:00:00'), | 229 | (90,1,'Schlepian & Urination',2,'2011-10-01 00:00:00'), |
| 230 | (90,'Klooger & Jetwash',0,'2016-08-01 00:00:00'), | 230 | (90,1,'Klooger & Jetwash',0,'2016-08-01 00:00:00'), |
| 231 | (91,'Mathias123961 & Sir Spawn Alot',2,'2011-08-01 00:00:00'), | 231 | (91,1,'Mathias123961 & Sir Spawn Alot',2,'2011-08-01 00:00:00'), |
| 232 | (91,'Undead & Zypeh',0,'2013-05-19 00:00:00'), | 232 | (91,1,'Undead & Zypeh',0,'2013-05-19 00:00:00'), |
| 233 | (92,'txx478 & ?',5,'2011-05-01 00:00:00'), | 233 | (92,1,'txx478 & ?',5,'2011-05-01 00:00:00'), |
| 234 | (92,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), | 234 | (92,1,'Mathias123961 & Sir Spawn Alot',4,'2011-08-01 00:00:00'), |
| 235 | (92,'Schlepian & Gopherdude',2,'2011-10-01 00:00:00'), | 235 | (92,1,'Schlepian & Gopherdude',2,'2011-10-01 00:00:00'), |
| 236 | (92,'ncla & takz',0,'2012-02-01 00:00:00'), | 236 | (92,1,'ncla & takz',0,'2012-02-01 00:00:00'), |
| 237 | (93,'Mathias123961 & Sir Spawn Alot',2,'2011-08-01 00:00:00'), | 237 | (93,1,'Mathias123961 & Sir Spawn Alot',2,'2011-08-01 00:00:00'), |
| 238 | (93,'Schlepian & Gopherdude',0,'2011-10-01 00:00:00'), | 238 | (93,1,'Schlepian & Gopherdude',0,'2011-10-01 00:00:00'), |
| 239 | -- 5 | 239 | -- 5 |
| 240 | (94,'Chubfish & Exhale',2,'2011-10-01 00:00:00'), | 240 | (94,1,'Chubfish & Exhale',2,'2011-10-01 00:00:00'), |
| 241 | (94,'Klooger & Imanex',0,'2013-08-01 00:00:00'), | 241 | (94,1,'Klooger & Imanex',0,'2013-08-01 00:00:00'), |
| 242 | (95,'Schlepian & Issimoi',2,'2011-10-01 00:00:00'), | 242 | (95,1,'Schlepian & Issimoi',2,'2011-10-01 00:00:00'), |
| 243 | (96,'ThePortalPatrol & ?',4,'2011-04-01 00:00:00'), | 243 | (96,1,'ThePortalPatrol & ?',4,'2011-04-01 00:00:00'), |
| 244 | (96,'sparkle1princess & Zypeh',2,'2014-01-01 00:00:00'), | 244 | (96,1,'sparkle1princess & Zypeh',2,'2014-01-01 00:00:00'), |
| 245 | (97,'Stimich & HiTMaRkS',7,'2011-05-13 00:00:00'), | 245 | (97,1,'Stimich & HiTMaRkS',7,'2011-05-13 00:00:00'), |
| 246 | (97,'Schlepian & Lemonsunshine',4,'2011-10-01 00:00:00'), | 246 | (97,1,'Schlepian & Lemonsunshine',4,'2011-10-01 00:00:00'), |
| 247 | (97,'DM_ & wS',2,'2014-05-01 00:00:00'), | 247 | (97,1,'DM_ & wS',2,'2014-05-01 00:00:00'), |
| 248 | (98,'Imanex & 00svo',0,'2011-11-01 00:00:00'), | 248 | (98,1,'Imanex & 00svo',0,'2011-11-01 00:00:00'), |
| 249 | (99,'Schlepian & Gopherdude',3,'2011-10-01 00:00:00'), | 249 | (99,1,'Schlepian & Gopherdude',3,'2011-10-01 00:00:00'), |
| 250 | (99,'Imanex & Klooger',2,'2013-08-01 00:00:00'), | 250 | (99,1,'Imanex & Klooger',2,'2013-08-01 00:00:00'), |
| 251 | (99,'DM_ & wS',0,'2015-05-01 00:00:00'), | 251 | (99,1,'DM_ & wS',0,'2015-05-01 00:00:00'), |
| 252 | (100,'Schlepian & Bananasaurus Rex',0,'2011-10-01 00:00:00'), | 252 | (100,1,'Schlepian & Bananasaurus Rex',0,'2011-10-01 00:00:00'), |
| 253 | (101,'Chubfish & Exhale',2,'2011-12-01 00:00:00'), | 253 | (101,1,'Chubfish & Exhale',2,'2011-12-01 00:00:00'), |
| 254 | (101,'DM_ & follon',0,'2015-04-01 00:00:00'), | 254 | (101,1,'DM_ & follon',0,'2015-04-01 00:00:00'), |
| 255 | -- 6 | 255 | -- 6 |
| 256 | (102,'dawn & takz',3,'2011-11-18 00:00:00'), | 256 | (102,1,'dawn & takz',3,'2011-11-18 00:00:00'), |
| 257 | (102,'Chubfish & Exhale',2,'2012-01-01 00:00:00'), | 257 | (102,1,'Chubfish & Exhale',2,'2012-01-01 00:00:00'), |
| 258 | (102,'Imanex & Klooger',0,'2013-08-01 00:00:00'), | 258 | (102,1,'Imanex & Klooger',0,'2013-08-01 00:00:00'), |
| 259 | (103,'Schlepian & Lemonsunshine',0,'2011-10-01 00:00:00'), | 259 | (103,1,'Schlepian & Lemonsunshine',0,'2011-10-01 00:00:00'), |
| 260 | (104,'Schlepian & Lemonsunshine',0,'2011-10-01 00:00:00'), | 260 | (104,1,'Schlepian & Lemonsunshine',0,'2011-10-01 00:00:00'), |
| 261 | (105,'Blaizerazer & ?',8,'2011-10-01 00:00:00'), | 261 | (105,1,'Blaizerazer & ?',8,'2011-10-01 00:00:00'), |
| 262 | (105,'Schlepian & Lemonsunshine',5,'2011-11-01 00:00:00'), | 262 | (105,1,'Schlepian & Lemonsunshine',5,'2011-11-01 00:00:00'), |
| 263 | (105,'Imanex & Klooger',4,'2013-08-01 00:00:00'), | 263 | (105,1,'Imanex & Klooger',4,'2013-08-01 00:00:00'), |
| 264 | (105,'DM_ & wS',3,'2014-05-01 00:00:00'), | 264 | (105,1,'DM_ & wS',3,'2014-05-01 00:00:00'), |
| 265 | (105,'DM_ & follon',2,'2015-04-01 00:00:00'), | 265 | (105,1,'DM_ & follon',2,'2015-04-01 00:00:00'), |
| 266 | (106,'Schlepian & Bananasaurus Rex',4,'2011-10-01 00:00:00'), | 266 | (106,1,'Schlepian & Bananasaurus Rex',4,'2011-10-01 00:00:00'), |
| 267 | (106,'Gig & takz',3,'2012-06-01 00:00:00'), | 267 | (106,1,'Gig & takz',3,'2012-06-01 00:00:00'), |
| 268 | (106,'Imanex & Klooger',0,'2013-06-01 00:00:00'), | 268 | (106,1,'Imanex & Klooger',0,'2013-06-01 00:00:00'), |
| 269 | (107,'Chubfish & Exhale',2,'2011-10-01 00:00:00'), | 269 | (107,1,'Chubfish & Exhale',2,'2011-10-01 00:00:00'), |
| 270 | (107,'DM_ & follon',0,'2015-04-01 00:00:00'), | 270 | (107,1,'DM_ & follon',0,'2015-04-01 00:00:00'), |
| 271 | (108,'DaFox & P',0,'2011-12-01 00:00:00'), | 271 | (108,1,'DaFox & P',0,'2011-12-01 00:00:00'), |
| 272 | (109,'Schlepian & Tyronis',5,'2011-10-01 00:00:00'), | 272 | (109,1,'Schlepian & Tyronis',5,'2011-10-01 00:00:00'), |
| 273 | (109,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), | 273 | (109,1,'Chubfish & Exhale',0,'2011-12-01 00:00:00'), |
| 274 | (110,'Tyronis & mr.bob806',15,'2011-10-01 00:00:00'), | 274 | (110,1,'Tyronis & mr.bob806',15,'2011-10-01 00:00:00'), |
| 275 | (110,'Schlepian & Chubfish',6,'2011-11-01 00:00:00'), | 275 | (110,1,'Schlepian & Chubfish',6,'2011-11-01 00:00:00'), |
| 276 | (110,'00svo & z1mb0bw4y',5,'2012-08-08 00:00:00'), | 276 | (110,1,'00svo & z1mb0bw4y',5,'2012-08-08 00:00:00'), |
| 277 | (110,'00svo & z1mb0bw4y',4,'2012-08-10 00:00:00'), | 277 | (110,1,'00svo & z1mb0bw4y',4,'2012-08-10 00:00:00'), |
| 278 | (110,'Klooger & z1mb0bw4y',2,'2014-02-01 00:00:00'), | 278 | (110,1,'Klooger & z1mb0bw4y',2,'2014-02-01 00:00:00'), |
| 279 | (110,'DM_ & follon',0,'2015-04-01 00:00:00'); \ No newline at end of file | 279 | (110,1,'DM_ & follon',0,'2015-04-01 00:00:00'); \ No newline at end of file |
diff --git a/backend/database/init.sql b/backend/database/init.sql index 51a4881..50e7c15 100644 --- a/backend/database/init.sql +++ b/backend/database/init.sql | |||
| @@ -9,13 +9,14 @@ CREATE TABLE users ( | |||
| 9 | ); | 9 | ); |
| 10 | 10 | ||
| 11 | CREATE TABLE games ( | 11 | CREATE TABLE games ( |
| 12 | id SMALLSERIAL, | 12 | id SERIAL, |
| 13 | name TEXT NOT NULL, | 13 | name TEXT NOT NULL, |
| 14 | is_coop BOOLEAN NOT NULL, | ||
| 14 | PRIMARY KEY (id) | 15 | PRIMARY KEY (id) |
| 15 | ); | 16 | ); |
| 16 | 17 | ||
| 17 | CREATE TABLE chapters ( | 18 | CREATE TABLE chapters ( |
| 18 | id SMALLSERIAL, | 19 | id SERIAL, |
| 19 | game_id SMALLINT NOT NULL, | 20 | game_id SMALLINT NOT NULL, |
| 20 | name TEXT NOT NULL, | 21 | name TEXT NOT NULL, |
| 21 | PRIMARY KEY (id), | 22 | PRIMARY KEY (id), |
| @@ -23,52 +24,57 @@ CREATE TABLE chapters ( | |||
| 23 | ); | 24 | ); |
| 24 | 25 | ||
| 25 | CREATE TABLE categories ( | 26 | CREATE TABLE categories ( |
| 26 | id SMALLSERIAL, | 27 | id SERIAL, |
| 27 | name TEXT NOT NULL, | 28 | name TEXT NOT NULL, |
| 28 | PRIMARY KEY (id) | 29 | PRIMARY KEY (id) |
| 29 | ); | 30 | ); |
| 30 | 31 | ||
| 31 | CREATE TABLE maps ( | 32 | CREATE TABLE maps ( |
| 32 | id SMALLSERIAL, | 33 | id SERIAL, |
| 33 | game_id SMALLINT NOT NULL, | 34 | game_id SMALLINT NOT NULL, |
| 34 | chapter_id SMALLINT NOT NULL, | 35 | chapter_id SMALLINT NOT NULL, |
| 35 | name TEXT NOT NULL, | 36 | name TEXT NOT NULL, |
| 36 | description TEXT NOT NULL, | ||
| 37 | showcase TEXT NOT NULL, | ||
| 38 | is_disabled BOOLEAN NOT NULL DEFAULT false, | 37 | is_disabled BOOLEAN NOT NULL DEFAULT false, |
| 39 | PRIMARY KEY (id), | 38 | PRIMARY KEY (id), |
| 40 | FOREIGN KEY (game_id) REFERENCES games(id), | 39 | FOREIGN KEY (game_id) REFERENCES games(id), |
| 41 | FOREIGN KEY (chapter_id) REFERENCES chapters(id) | 40 | FOREIGN KEY (chapter_id) REFERENCES chapters(id) |
| 42 | ); | 41 | ); |
| 43 | 42 | ||
| 43 | CREATE TABLE map_routes ( | ||
| 44 | id SERIAL, | ||
| 45 | map_id SMALLINT NOT NULL, | ||
| 46 | category_id SMALLINT NOT NULL, | ||
| 47 | score_count SMALLINT NOT NULL, | ||
| 48 | description TEXT NOT NULL, | ||
| 49 | showcase TEXT NOT NULL, | ||
| 50 | PRIMARY KEY (id), | ||
| 51 | FOREIGN KEY (map_id) REFERENCES maps(id), | ||
| 52 | FOREIGN KEY (category_id) REFERENCES categories(id), | ||
| 53 | UNIQUE (map_id, category_id, score_count) | ||
| 54 | ); | ||
| 55 | |||
| 44 | CREATE TABLE map_history ( | 56 | CREATE TABLE map_history ( |
| 45 | id SMALLSERIAL, | 57 | id SERIAL, |
| 46 | map_id SMALLINT NOT NULL, | 58 | map_id SMALLINT NOT NULL, |
| 59 | category_id SMALLINT NOT NULL, | ||
| 47 | user_name TEXT NOT NULL, | 60 | user_name TEXT NOT NULL, |
| 48 | score_count SMALLINT NOT NULL, | 61 | score_count SMALLINT NOT NULL, |
| 49 | record_date TIMESTAMP NOT NULL, | 62 | record_date TIMESTAMP NOT NULL, |
| 50 | PRIMARY KEY (id), | 63 | PRIMARY KEY (id), |
| 51 | FOREIGN KEY (map_id) REFERENCES maps(id) | 64 | FOREIGN KEY (category_id) REFERENCES categories(id), |
| 65 | FOREIGN KEY (map_id) REFERENCES maps(id), | ||
| 66 | UNIQUE (map_id, category_id, score_count) | ||
| 52 | ); | 67 | ); |
| 53 | 68 | ||
| 54 | CREATE TABLE map_ratings ( | 69 | CREATE TABLE map_ratings ( |
| 55 | id SERIAL, | 70 | id SERIAL, |
| 56 | map_id SMALLINT NOT NULL, | 71 | map_id SMALLINT NOT NULL, |
| 72 | category_id SMALLINT NOT NULL, | ||
| 57 | user_id TEXT NOT NULL, | 73 | user_id TEXT NOT NULL, |
| 58 | rating SMALLINT NOT NULL, | 74 | rating SMALLINT NOT NULL, |
| 59 | PRIMARY KEY (id), | 75 | PRIMARY KEY (id), |
| 60 | FOREIGN KEY (map_id) REFERENCES maps(id), | 76 | FOREIGN KEY (map_id) REFERENCES maps(id), |
| 61 | FOREIGN KEY (user_id) REFERENCES users(steam_id) | 77 | FOREIGN KEY (category_id) REFERENCES categories(id), |
| 62 | ); | ||
| 63 | |||
| 64 | CREATE TABLE map_routers ( | ||
| 65 | id SMALLSERIAL, | ||
| 66 | map_id SMALLINT NOT NULL, | ||
| 67 | user_id TEXT, | ||
| 68 | user_name TEXT NOT NULL, | ||
| 69 | score_count SMALLINT NOT NULL, | ||
| 70 | PRIMARY KEY (id), | ||
| 71 | FOREIGN KEY (map_id) REFERENCES maps(id), | ||
| 72 | FOREIGN KEY (user_id) REFERENCES users(steam_id) | 78 | FOREIGN KEY (user_id) REFERENCES users(steam_id) |
| 73 | ); | 79 | ); |
| 74 | 80 | ||
diff --git a/backend/database/route.sql b/backend/database/route.sql new file mode 100644 index 0000000..f26180e --- /dev/null +++ b/backend/database/route.sql | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | INSERT INTO map_routes(map_id,category_id,score_count,description,showcase) VALUES | ||
| 2 | -- Portal 2 Singleplayer | ||
| 3 | -- 1 | ||
| 4 | (3,1,3,'',''), | ||
| 5 | (3,1,1,'',''), | ||
| 6 | (3,1,0,'',''), | ||
| 7 | (4,1,1,'',''), | ||
| 8 | (4,1,0,'',''), | ||
| 9 | (5,1,2,'',''), | ||
| 10 | (5,1,1,'',''), | ||
| 11 | (6,1,4,'',''), | ||
| 12 | (6,1,3,'',''), | ||
| 13 | (6,1,2,'',''), | ||
| 14 | (9,1,4,'',''), | ||
| 15 | (9,1,3,'',''), | ||
| 16 | (9,1,2,'',''), | ||
| 17 | (9,1,0,'',''), | ||
| 18 | -- 2 | ||
| 19 | (10,1,2,'',''), | ||
| 20 | (10,1,0,'',''), | ||
| 21 | (11,1,2,'',''), | ||
| 22 | (11,1,0,'',''), | ||
| 23 | (12,1,2,'',''), | ||
| 24 | (13,1,3,'',''), | ||
| 25 | (13,1,2,'',''), | ||
| 26 | (13,1,0,'',''), | ||
| 27 | (15,1,2,'',''), | ||
| 28 | (16,1,2,'',''), | ||
| 29 | (16,1,0,'',''), | ||
| 30 | (17,1,2,'',''), | ||
| 31 | (17,1,0,'',''), | ||
| 32 | -- 3 | ||
| 33 | (18,1,5,'',''), | ||
| 34 | (18,1,4,'',''), | ||
| 35 | (18,1,3,'',''), | ||
| 36 | (18,1,2,'',''), | ||
| 37 | (18,1,0,'',''), | ||
| 38 | (19,1,2,'',''), | ||
| 39 | (20,1,5,'',''), | ||
| 40 | (20,1,4,'',''), | ||
| 41 | (20,1,3,'',''), | ||
| 42 | (20,1,2,'',''), | ||
| 43 | (21,1,4,'',''), | ||
| 44 | (21,1,2,'',''), | ||
| 45 | (21,1,0,'',''), | ||
| 46 | (22,1,0,'',''), | ||
| 47 | (23,1,2,'',''), | ||
| 48 | (23,1,0,'',''), | ||
| 49 | (24,1,0,'',''), | ||
| 50 | (25,1,0,'',''), | ||
| 51 | (26,1,3,'',''), | ||
| 52 | (26,1,2,'',''), | ||
| 53 | (26,1,0,'',''), | ||
| 54 | -- 4 | ||
| 55 | (27,1,2,'',''), | ||
| 56 | (27,1,0,'',''), | ||
| 57 | (28,1,7,'',''), | ||
| 58 | (28,1,2,'',''), | ||
| 59 | (28,1,0,'',''), | ||
| 60 | (29,1,0,'',''), | ||
| 61 | (30,1,2,'',''), | ||
| 62 | (31,1,0,'',''), | ||
| 63 | -- 5 | ||
| 64 | (32,1,6,'',''), | ||
| 65 | (32,1,5,'',''), | ||
| 66 | (33,1,7,'',''), | ||
| 67 | (33,1,5,'',''), | ||
| 68 | (33,1,4,'',''), | ||
| 69 | (34,1,3,'',''), | ||
| 70 | (34,1,2,'',''), | ||
| 71 | (34,1,0,'',''), | ||
| 72 | (35,1,2,'',''), | ||
| 73 | -- 6 | ||
| 74 | (36,1,6,'',''), | ||
| 75 | (36,1,5,'',''), | ||
| 76 | (36,1,4,'',''), | ||
| 77 | (36,1,2,'',''), | ||
| 78 | (37,1,7,'',''), | ||
| 79 | (37,1,6,'',''), | ||
| 80 | (37,1,5,'',''), | ||
| 81 | (37,1,4,'',''), | ||
| 82 | (38,1,2,'',''), | ||
| 83 | (38,1,0,'',''), | ||
| 84 | (39,1,6,'',''), | ||
| 85 | (39,1,5,'',''), | ||
| 86 | (39,1,4,'',''), | ||
| 87 | (39,1,3,'',''), | ||
| 88 | (40,1,7,'',''), | ||
| 89 | (40,1,6,'',''), | ||
| 90 | (40,1,4,'',''), | ||
| 91 | (40,1,3,'',''), | ||
| 92 | (40,1,2,'',''), | ||
| 93 | (40,1,0,'',''), | ||
| 94 | (41,1,7,'',''), | ||
| 95 | (41,1,6,'',''), | ||
| 96 | (41,1,5,'',''), | ||
| 97 | -- 7 | ||
| 98 | (42,1,4,'',''), | ||
| 99 | (42,1,2,'',''), | ||
| 100 | (43,1,5,'',''), | ||
| 101 | (43,1,2,'',''), | ||
| 102 | (43,1,0,'',''), | ||
| 103 | (44,1,18,'',''), | ||
| 104 | (44,1,13,'',''), | ||
| 105 | (44,1,12,'',''), | ||
| 106 | (44,1,11,'',''), | ||
| 107 | (44,1,9,'',''), | ||
| 108 | (45,1,23,'',''), | ||
| 109 | (45,1,22,'',''), | ||
| 110 | (45,1,17,'',''), | ||
| 111 | (45,1,16,'',''), | ||
| 112 | (45,1,15,'',''), | ||
| 113 | (45,1,12,'',''), | ||
| 114 | (45,1,10,'',''), | ||
| 115 | (45,1,7,'',''), | ||
| 116 | (45,1,4,'',''), | ||
| 117 | -- 8 | ||
| 118 | (46,1,6,'',''), | ||
| 119 | (46,1,2,'',''), | ||
| 120 | (47,1,2,'',''), | ||
| 121 | (47,1,0,'',''), | ||
| 122 | (48,1,5,'',''), | ||
| 123 | (48,1,2,'',''), | ||
| 124 | (48,1,0,'',''), | ||
| 125 | (49,1,4,'',''), | ||
| 126 | (49,1,2,'',''), | ||
| 127 | (49,1,0,'',''), | ||
| 128 | (50,1,4,'',''), | ||
| 129 | (50,1,2,'',''), | ||
| 130 | (50,1,0,'',''), | ||
| 131 | (51,1,3,'',''), | ||
| 132 | (51,1,2,'',''), | ||
| 133 | (52,1,0,'',''), | ||
| 134 | (53,1,9,'',''), | ||
| 135 | (53,1,2,'',''), | ||
| 136 | (53,1,0,'',''), | ||
| 137 | (54,1,7,'',''), | ||
| 138 | (54,1,6,'',''), | ||
| 139 | (54,1,5,'',''), | ||
| 140 | (54,1,4,'',''), | ||
| 141 | (54,1,3,'',''), | ||
| 142 | (55,1,7,'',''), | ||
| 143 | (55,1,3,'',''), | ||
| 144 | (55,1,2,'',''), | ||
| 145 | (55,1,0,'',''), | ||
| 146 | (56,1,9,'',''), | ||
| 147 | (56,1,5,'',''), | ||
| 148 | (56,1,4,'',''), | ||
| 149 | (56,1,2,'',''), | ||
| 150 | -- 9 | ||
| 151 | (57,1,7,'',''), | ||
| 152 | (57,1,5,'',''), | ||
| 153 | (57,1,0,'',''), | ||
| 154 | (58,1,2,'',''), | ||
| 155 | (59,1,7,'',''), | ||
| 156 | (59,1,6,'',''), | ||
| 157 | (60,1,7,'',''), | ||
| 158 | (60,1,6,'',''), | ||
| 159 | -- Portal 2 Cooperative | ||
| 160 | -- 1 | ||
| 161 | (63,1,0,'',''), | ||
| 162 | (64,1,3,'',''), | ||
| 163 | (64,1,2,'',''), | ||
| 164 | (65,1,4,'',''), | ||
| 165 | (65,1,3,'',''), | ||
| 166 | (66,1,3,'',''), | ||
| 167 | (66,1,2,'',''), | ||
| 168 | (67,1,0,'',''), | ||
| 169 | (68,1,0,'',''), | ||
| 170 | -- 2 | ||
| 171 | (69,1,4,'',''), | ||
| 172 | (70,1,6,'',''), | ||
| 173 | (70,1,4,'',''), | ||
| 174 | (70,1,2,'',''), | ||
| 175 | (70,1,0,'',''), | ||
| 176 | (71,1,3,'',''), | ||
| 177 | (71,1,0,'',''), | ||
| 178 | (72,1,4,'',''), | ||
| 179 | (72,1,2,'',''), | ||
| 180 | (73,1,9,'',''), | ||
| 181 | (73,1,8,'',''), | ||
| 182 | (73,1,7,'',''), | ||
| 183 | (73,1,6,'',''), | ||
| 184 | (73,1,4,'',''), | ||
| 185 | (74,1,5,'',''), | ||
| 186 | (74,1,7,'',''), | ||
| 187 | (74,1,3,'',''), | ||
| 188 | (74,1,2,'',''), | ||
| 189 | (75,1,5,'',''), | ||
| 190 | (75,1,4,'',''), | ||
| 191 | (75,1,2,'',''), | ||
| 192 | (75,1,0,'',''), | ||
| 193 | (76,1,3,'',''), | ||
| 194 | (76,1,0,'',''), | ||
| 195 | -- 3 | ||
| 196 | (77,1,3,'',''), | ||
| 197 | (78,1,4,'',''), | ||
| 198 | (78,1,3,'',''), | ||
| 199 | (78,1,2,'',''), | ||
| 200 | (79,1,5,'',''), | ||
| 201 | (79,1,4,'',''), | ||
| 202 | (79,1,2,'',''), | ||
| 203 | (80,1,5,'',''), | ||
| 204 | (80,1,4,'',''), | ||
| 205 | (81,1,7,'',''), | ||
| 206 | (81,1,6,'',''), | ||
| 207 | (81,1,5,'',''), | ||
| 208 | (81,1,4,'',''), | ||
| 209 | (82,1,4,'',''), | ||
| 210 | (83,1,5,'',''), | ||
| 211 | (83,1,2,'',''), | ||
| 212 | (83,1,0,'',''), | ||
| 213 | (84,1,6,'',''), | ||
| 214 | (84,1,4,'',''), | ||
| 215 | (84,1,2,'',''), | ||
| 216 | (84,1,0,'',''), | ||
| 217 | -- 4 | ||
| 218 | (85,1,3,'',''), | ||
| 219 | (85,1,0,'',''), | ||
| 220 | (86,1,3,'',''), | ||
| 221 | (86,1,0,'',''), | ||
| 222 | (87,1,3,'',''), | ||
| 223 | (87,1,2,'',''), | ||
| 224 | (87,1,0,'',''), | ||
| 225 | (88,1,4,'',''), | ||
| 226 | (88,1,0,'',''), | ||
| 227 | (89,1,0,'',''), | ||
| 228 | (90,1,4,'',''), | ||
| 229 | (90,1,2,'',''), | ||
| 230 | (90,1,0,'',''), | ||
| 231 | (91,1,2,'',''), | ||
| 232 | (91,1,0,'',''), | ||
| 233 | (92,1,5,'',''), | ||
| 234 | (92,1,4,'',''), | ||
| 235 | (92,1,2,'',''), | ||
| 236 | (92,1,0,'',''), | ||
| 237 | (93,1,2,'',''), | ||
| 238 | (93,1,0,'',''), | ||
| 239 | -- 5 | ||
| 240 | (94,1,2,'',''), | ||
| 241 | (94,1,0,'',''), | ||
| 242 | (95,1,2,'',''), | ||
| 243 | (96,1,4,'',''), | ||
| 244 | (96,1,2,'',''), | ||
| 245 | (97,1,7,'',''), | ||
| 246 | (97,1,4,'',''), | ||
| 247 | (97,1,2,'',''), | ||
| 248 | (98,1,0,'',''), | ||
| 249 | (99,1,3,'',''), | ||
| 250 | (99,1,2,'',''), | ||
| 251 | (99,1,0,'',''), | ||
| 252 | (100,1,0,'',''), | ||
| 253 | (101,1,2,'',''), | ||
| 254 | (101,1,0,'',''), | ||
| 255 | -- 6 | ||
| 256 | (102,1,3,'',''), | ||
| 257 | (102,1,2,'',''), | ||
| 258 | (102,1,0,'',''), | ||
| 259 | (103,1,0,'',''), | ||
| 260 | (104,1,0,'',''), | ||
| 261 | (105,1,8,'',''), | ||
| 262 | (105,1,5,'',''), | ||
| 263 | (105,1,4,'',''), | ||
| 264 | (105,1,3,'',''), | ||
| 265 | (105,1,2,'',''), | ||
| 266 | (106,1,4,'',''), | ||
| 267 | (106,1,3,'',''), | ||
| 268 | (106,1,0,'',''), | ||
| 269 | (107,1,2,'',''), | ||
| 270 | (107,1,0,'',''), | ||
| 271 | (108,1,0,'',''), | ||
| 272 | (109,1,5,'',''), | ||
| 273 | (109,1,0,'',''), | ||
| 274 | (110,1,15,'',''), | ||
| 275 | (110,1,6,'',''), | ||
| 276 | (110,1,5,'',''), | ||
| 277 | (110,1,4,'',''), | ||
| 278 | (110,1,2,'',''), | ||
| 279 | (110,1,0,'',''); \ No newline at end of file | ||
diff --git a/backend/middleware/auth.go b/backend/middleware/auth.go index 14a0b78..0698f0a 100644 --- a/backend/middleware/auth.go +++ b/backend/middleware/auth.go | |||
| @@ -36,13 +36,21 @@ func CheckAuth(c *gin.Context) { | |||
| 36 | } | 36 | } |
| 37 | // Get user from DB | 37 | // Get user from DB |
| 38 | var user models.User | 38 | var user models.User |
| 39 | database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1`, claims["sub"]).Scan( | 39 | database.DB.QueryRow(`SELECT u.steam_id, u.user_name, u.avatar_link, u.country_code, u.created_at, u.updated_at FROM users u WHERE steam_id = $1`, claims["sub"]).Scan( |
| 40 | &user.SteamID, &user.UserName, &user.AvatarLink, | 40 | &user.SteamID, &user.UserName, &user.AvatarLink, |
| 41 | &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) | 41 | &user.CountryCode, &user.CreatedAt, &user.UpdatedAt) |
| 42 | if user.SteamID == "" { | 42 | if user.SteamID == "" { |
| 43 | c.Next() | 43 | c.Next() |
| 44 | return | 44 | return |
| 45 | } | 45 | } |
| 46 | // Get user titles from DB | ||
| 47 | user.Titles = []string{} | ||
| 48 | rows, _ := database.DB.Query(`SELECT t.title_name FROM titles t WHERE t.user_id = $1`, user.SteamID) | ||
| 49 | for rows.Next() { | ||
| 50 | var title string | ||
| 51 | rows.Scan(&title) | ||
| 52 | user.Titles = append(user.Titles, title) | ||
| 53 | } | ||
| 46 | c.Set("user", user) | 54 | c.Set("user", user) |
| 47 | c.Next() | 55 | c.Next() |
| 48 | } else { | 56 | } else { |
diff --git a/backend/models/models.go b/backend/models/models.go index 6f5173a..1231cb1 100644 --- a/backend/models/models.go +++ b/backend/models/models.go | |||
| @@ -4,16 +4,6 @@ import ( | |||
| 4 | "time" | 4 | "time" |
| 5 | ) | 5 | ) |
| 6 | 6 | ||
| 7 | type Response struct { | ||
| 8 | Success bool `json:"success"` | ||
| 9 | Message string `json:"message"` | ||
| 10 | Data any `json:"data"` | ||
| 11 | } | ||
| 12 | |||
| 13 | type LoginResponse struct { | ||
| 14 | Token string `json:"token"` | ||
| 15 | } | ||
| 16 | |||
| 17 | type User struct { | 7 | type User struct { |
| 18 | SteamID string `json:"steam_id"` | 8 | SteamID string `json:"steam_id"` |
| 19 | UserName string `json:"user_name"` | 9 | UserName string `json:"user_name"` |
| @@ -21,6 +11,12 @@ type User struct { | |||
| 21 | CountryCode string `json:"country_code"` | 11 | CountryCode string `json:"country_code"` |
| 22 | CreatedAt time.Time `json:"created_at"` | 12 | CreatedAt time.Time `json:"created_at"` |
| 23 | UpdatedAt time.Time `json:"updated_at"` | 13 | UpdatedAt time.Time `json:"updated_at"` |
| 14 | Titles []string `json:"titles"` | ||
| 15 | } | ||
| 16 | |||
| 17 | type UserShort struct { | ||
| 18 | SteamID string `json:"steam_id"` | ||
| 19 | UserName string `json:"user_name"` | ||
| 24 | } | 20 | } |
| 25 | 21 | ||
| 26 | type Map struct { | 22 | type Map struct { |
| @@ -28,33 +24,58 @@ type Map struct { | |||
| 28 | GameName string `json:"game_name"` | 24 | GameName string `json:"game_name"` |
| 29 | ChapterName string `json:"chapter_name"` | 25 | ChapterName string `json:"chapter_name"` |
| 30 | MapName string `json:"map_name"` | 26 | MapName string `json:"map_name"` |
| 31 | Data any `json:"data"` | 27 | Image string `json:"image"` |
| 28 | IsCoop bool `json:"is_coop"` | ||
| 29 | } | ||
| 30 | |||
| 31 | type MapShort struct { | ||
| 32 | ID int `json:"id"` | ||
| 33 | Name string `json:"name"` | ||
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | type MapSummary struct { | 36 | type MapSummary struct { |
| 35 | Description string `json:"description"` | 37 | Routes []MapRoute `json:"routes"` |
| 36 | Showcase string `json:"showcase"` | ||
| 37 | CategoryScores MapCategoryScores `json:"category_scores"` | ||
| 38 | Rating float32 `json:"rating"` | ||
| 39 | Routers []string `json:"routers"` | ||
| 40 | History []MapHistory `json:"history"` | ||
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | type MapCategoryScores struct { | 40 | type MapHistory struct { |
| 44 | CM int `json:"cm"` | 41 | RunnerName string `json:"runner_name"` |
| 45 | NoSLA int `json:"no_sla"` | 42 | ScoreCount int `json:"score_count"` |
| 46 | InboundsSLA int `json:"inbounds_sla"` | 43 | Date time.Time `json:"date"` |
| 47 | Any int `json:"any"` | 44 | } |
| 45 | |||
| 46 | type MapRoute struct { | ||
| 47 | RouteID int `json:"route_id"` | ||
| 48 | Category Category `json:"category"` | ||
| 49 | History MapHistory `json:"history"` | ||
| 50 | Rating float32 `json:"rating"` | ||
| 51 | Description string `json:"description"` | ||
| 52 | Showcase string `json:"showcase"` | ||
| 48 | } | 53 | } |
| 49 | 54 | ||
| 50 | type MapRecords struct { | 55 | type MapRecords struct { |
| 51 | Records any `json:"records"` | 56 | Records any `json:"records"` |
| 52 | } | 57 | } |
| 53 | 58 | ||
| 54 | type MapHistory struct { | 59 | type UserRanking struct { |
| 55 | RunnerName string `json:"runner_name"` | 60 | UserID string `json:"user_id"` |
| 56 | ScoreCount int `json:"score_count"` | 61 | UserName string `json:"user_name"` |
| 57 | Date time.Time `json:"date"` | 62 | TotalScore int `json:"total_score"` |
| 63 | } | ||
| 64 | |||
| 65 | type Game struct { | ||
| 66 | ID int `json:"id"` | ||
| 67 | Name string `json:"name"` | ||
| 68 | IsCoop bool `json:"is_coop"` | ||
| 69 | } | ||
| 70 | |||
| 71 | type Chapter struct { | ||
| 72 | ID int `json:"id"` | ||
| 73 | Name string `json:"name"` | ||
| 74 | } | ||
| 75 | |||
| 76 | type Category struct { | ||
| 77 | ID int `json:"id"` | ||
| 78 | Name string `json:"name"` | ||
| 58 | } | 79 | } |
| 59 | 80 | ||
| 60 | type RecordSP struct { | 81 | type RecordSP struct { |
| @@ -85,50 +106,6 @@ type RecordMP struct { | |||
| 85 | RecordDate time.Time `json:"record_date"` | 106 | RecordDate time.Time `json:"record_date"` |
| 86 | } | 107 | } |
| 87 | 108 | ||
| 88 | type RecordRequest struct { | ||
| 89 | ScoreCount int `json:"score_count" form:"score_count" binding:"required"` | ||
| 90 | ScoreTime int `json:"score_time" form:"score_time" binding:"required"` | ||
| 91 | PartnerID string `json:"partner_id" form:"partner_id" binding:"required"` | ||
| 92 | IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange" binding:"required"` | ||
| 93 | } | ||
| 94 | |||
| 95 | type UserRanking struct { | ||
| 96 | UserID string `json:"user_id"` | ||
| 97 | UserName string `json:"user_name"` | ||
| 98 | TotalScore int `json:"total_score"` | ||
| 99 | } | ||
| 100 | |||
| 101 | type RankingsResponse struct { | ||
| 102 | RankingsSP []UserRanking `json:"rankings_sp"` | ||
| 103 | RankingsMP []UserRanking `json:"rankings_mp"` | ||
| 104 | } | ||
| 105 | |||
| 106 | type ProfileResponse struct { | ||
| 107 | Profile bool `json:"profile"` | ||
| 108 | SteamID string `json:"steam_id"` | ||
| 109 | UserName string `json:"user_name"` | ||
| 110 | AvatarLink string `json:"avatar_link"` | ||
| 111 | CountryCode string `json:"country_code"` | ||
| 112 | ScoresSP []ScoreResponse `json:"scores_sp"` | ||
| 113 | ScoresMP []ScoreResponse `json:"scores_mp"` | ||
| 114 | } | ||
| 115 | |||
| 116 | type ScoreResponse struct { | ||
| 117 | MapID int `json:"map_id"` | ||
| 118 | Records any `json:"records"` | ||
| 119 | } | ||
| 120 | |||
| 121 | type SearchResponse struct { | ||
| 122 | Players []struct { | ||
| 123 | SteamID string `json:"steam_id"` | ||
| 124 | UserName string `json:"user_name"` | ||
| 125 | } `json:"players"` | ||
| 126 | Maps []struct { | ||
| 127 | ID int `json:"id"` | ||
| 128 | Name string `json:"name"` | ||
| 129 | } `json:"maps"` | ||
| 130 | } | ||
| 131 | |||
| 132 | type PlayerSummaries struct { | 109 | type PlayerSummaries struct { |
| 133 | SteamId string `json:"steamid"` | 110 | SteamId string `json:"steamid"` |
| 134 | CommunityVisibilityState int `json:"communityvisibilitystate"` | 111 | CommunityVisibilityState int `json:"communityvisibilitystate"` |
| @@ -152,36 +129,3 @@ type PlayerSummaries struct { | |||
| 152 | GameExtraInfo string `json:"gameextrainfo"` | 129 | GameExtraInfo string `json:"gameextrainfo"` |
| 153 | GameServerIp string `json:"gameserverip"` | 130 | GameServerIp string `json:"gameserverip"` |
| 154 | } | 131 | } |
| 155 | |||
| 156 | type Game struct { | ||
| 157 | ID int `json:"id"` | ||
| 158 | Name string `json:"name"` | ||
| 159 | } | ||
| 160 | |||
| 161 | type ChaptersResponse struct { | ||
| 162 | Game Game `json:"game"` | ||
| 163 | Chapters []Chapter `json:"chapters"` | ||
| 164 | } | ||
| 165 | |||
| 166 | type Chapter struct { | ||
| 167 | ID int `json:"id"` | ||
| 168 | Name string `json:"name"` | ||
| 169 | } | ||
| 170 | |||
| 171 | type MapShort struct { | ||
| 172 | ID int `json:"id"` | ||
| 173 | Name string `json:"name"` | ||
| 174 | } | ||
| 175 | |||
| 176 | type ChapterMapsResponse struct { | ||
| 177 | Chapter Chapter `json:"chapter"` | ||
| 178 | Maps []MapShort `json:"maps"` | ||
| 179 | } | ||
| 180 | |||
| 181 | func ErrorResponse(message string) Response { | ||
| 182 | return Response{ | ||
| 183 | Success: false, | ||
| 184 | Message: message, | ||
| 185 | Data: nil, | ||
| 186 | } | ||
| 187 | } | ||
diff --git a/backend/models/requests.go b/backend/models/requests.go new file mode 100644 index 0000000..0113597 --- /dev/null +++ b/backend/models/requests.go | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | package models | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "mime/multipart" | ||
| 5 | "time" | ||
| 6 | ) | ||
| 7 | |||
| 8 | type CreateMapSummaryRequest struct { | ||
| 9 | CategoryID int `json:"category_id" binding:"required"` | ||
| 10 | Description string `json:"description" binding:"required"` | ||
| 11 | Showcase string `json:"showcase"` | ||
| 12 | UserName string `json:"user_name" binding:"required"` | ||
| 13 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 14 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 15 | } | ||
| 16 | |||
| 17 | type EditMapSummaryRequest struct { | ||
| 18 | RouteID int `json:"route_id" binding:"required"` | ||
| 19 | Description string `json:"description" binding:"required"` | ||
| 20 | Showcase string `json:"showcase"` | ||
| 21 | UserName string `json:"user_name" binding:"required"` | ||
| 22 | ScoreCount *int `json:"score_count" binding:"required"` | ||
| 23 | RecordDate time.Time `json:"record_date" binding:"required"` | ||
| 24 | } | ||
| 25 | |||
| 26 | type DeleteMapSummaryRequest struct { | ||
| 27 | RouteID int `json:"route_id" binding:"required"` | ||
| 28 | } | ||
| 29 | |||
| 30 | type EditMapImageRequest struct { | ||
| 31 | Image string `json:"image" binding:"required"` | ||
| 32 | } | ||
| 33 | |||
| 34 | type RecordRequest struct { | ||
| 35 | HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` | ||
| 36 | PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` | ||
| 37 | IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange"` | ||
| 38 | PartnerID string `json:"partner_id" form:"partner_id"` | ||
| 39 | } | ||
diff --git a/backend/models/responses.go b/backend/models/responses.go new file mode 100644 index 0000000..459911c --- /dev/null +++ b/backend/models/responses.go | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | package models | ||
| 2 | |||
| 3 | type Response struct { | ||
| 4 | Success bool `json:"success"` | ||
| 5 | Message string `json:"message"` | ||
| 6 | Data any `json:"data"` | ||
| 7 | } | ||
| 8 | |||
| 9 | type LoginResponse struct { | ||
| 10 | Token string `json:"token"` | ||
| 11 | } | ||
| 12 | |||
| 13 | type RankingsResponse struct { | ||
| 14 | RankingsSP []UserRanking `json:"rankings_sp"` | ||
| 15 | RankingsMP []UserRanking `json:"rankings_mp"` | ||
| 16 | } | ||
| 17 | |||
| 18 | type ProfileResponse struct { | ||
| 19 | Profile bool `json:"profile"` | ||
| 20 | SteamID string `json:"steam_id"` | ||
| 21 | UserName string `json:"user_name"` | ||
| 22 | AvatarLink string `json:"avatar_link"` | ||
| 23 | CountryCode string `json:"country_code"` | ||
| 24 | ScoresSP []ScoreResponse `json:"scores_sp"` | ||
| 25 | ScoresMP []ScoreResponse `json:"scores_mp"` | ||
| 26 | } | ||
| 27 | |||
| 28 | type ScoreResponse struct { | ||
| 29 | MapID int `json:"map_id"` | ||
| 30 | Records any `json:"records"` | ||
| 31 | } | ||
| 32 | |||
| 33 | type MapSummaryResponse struct { | ||
| 34 | Map Map `json:"map"` | ||
| 35 | Summary MapSummary `json:"summary"` | ||
| 36 | } | ||
| 37 | |||
| 38 | type SearchResponse struct { | ||
| 39 | Players []UserShort `json:"players"` | ||
| 40 | Maps []MapShort `json:"maps"` | ||
| 41 | } | ||
| 42 | |||
| 43 | type ChaptersResponse struct { | ||
| 44 | Game Game `json:"game"` | ||
| 45 | Chapters []Chapter `json:"chapters"` | ||
| 46 | } | ||
| 47 | |||
| 48 | type ChapterMapsResponse struct { | ||
| 49 | Chapter Chapter `json:"chapter"` | ||
| 50 | Maps []MapShort `json:"maps"` | ||
| 51 | } | ||
| 52 | |||
| 53 | type RecordResponse struct { | ||
| 54 | ScoreCount int `json:"score_count"` | ||
| 55 | ScoreTime int `json:"score_time"` | ||
| 56 | } | ||
| 57 | |||
| 58 | func ErrorResponse(message string) Response { | ||
| 59 | return Response{ | ||
| 60 | Success: false, | ||
| 61 | Message: message, | ||
| 62 | Data: nil, | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/backend/parser/parser.REMOVED.git-id b/backend/parser/parser.REMOVED.git-id new file mode 100644 index 0000000..b09611f --- /dev/null +++ b/backend/parser/parser.REMOVED.git-id | |||
| @@ -0,0 +1 @@ | |||
| 72bd63d0667a78d35f643f1f8fcf71d9269d2719 \ No newline at end of file | |||
diff --git a/backend/parser/parser.go b/backend/parser/parser.go new file mode 100644 index 0000000..562b8c0 --- /dev/null +++ b/backend/parser/parser.go | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | package parser | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bufio" | ||
| 5 | "fmt" | ||
| 6 | "log" | ||
| 7 | "os/exec" | ||
| 8 | "strconv" | ||
| 9 | "strings" | ||
| 10 | ) | ||
| 11 | |||
| 12 | func ProcessDemo(demoPath string) (int, int, error) { | ||
| 13 | cmd := exec.Command("bash", "-c", fmt.Sprintf(`echo "FEXBash" && ./backend/parser/parser %s`, demoPath)) | ||
| 14 | stdout, err := cmd.StdoutPipe() | ||
| 15 | if err != nil { | ||
| 16 | log.Println(err) | ||
| 17 | return 0, 0, err | ||
| 18 | } | ||
| 19 | cmd.Start() | ||
| 20 | scanner := bufio.NewScanner(stdout) | ||
| 21 | var cmTicks, portalCount int | ||
| 22 | for scanner.Scan() { | ||
| 23 | line := scanner.Text() | ||
| 24 | if strings.Contains(line, "CM ticks") { | ||
| 25 | cmTicksStr := strings.TrimSpace(strings.Split(line, ":")[1]) | ||
| 26 | cmTicks, err = strconv.Atoi(cmTicksStr) | ||
| 27 | if err != nil { | ||
| 28 | return 0, 0, err | ||
| 29 | } | ||
| 30 | } | ||
| 31 | if strings.Contains(line, "Portal count") { | ||
| 32 | portalCountStr := strings.TrimSpace(strings.Split(line, ":")[1]) | ||
| 33 | portalCount, err = strconv.Atoi(portalCountStr) | ||
| 34 | if err != nil { | ||
| 35 | return 0, 0, err | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | ||
| 39 | cmd.Wait() | ||
| 40 | // We don't check for error in wait, since FEXBash always gives segmentation fault | ||
| 41 | // Wanted output is retrieved, so it's okay (i think) | ||
| 42 | return portalCount, cmTicks, nil | ||
| 43 | } | ||
diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 96da1ce..1377d32 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go | |||
| @@ -25,11 +25,15 @@ func InitRoutes(router *gin.Engine) { | |||
| 25 | v1.POST("/profile", middleware.CheckAuth, controllers.UpdateUser) | 25 | v1.POST("/profile", middleware.CheckAuth, controllers.UpdateUser) |
| 26 | v1.GET("/users/:id", middleware.CheckAuth, controllers.FetchUser) | 26 | v1.GET("/users/:id", middleware.CheckAuth, controllers.FetchUser) |
| 27 | v1.GET("/demos", controllers.DownloadDemoWithID) | 27 | v1.GET("/demos", controllers.DownloadDemoWithID) |
| 28 | v1.GET("/maps/:id/summary", middleware.CheckAuth, controllers.FetchMapSummary) | 28 | v1.GET("/maps/:id/summary", controllers.FetchMapSummary) |
| 29 | v1.GET("/maps/:id/leaderboards", middleware.CheckAuth, controllers.FetchMapLeaderboards) | 29 | v1.POST("/maps/:id/summary", middleware.CheckAuth, controllers.CreateMapSummary) |
| 30 | v1.PUT("/maps/:id/summary", middleware.CheckAuth, controllers.EditMapSummary) | ||
| 31 | v1.DELETE("/maps/:id/summary", middleware.CheckAuth, controllers.DeleteMapSummary) | ||
| 32 | v1.PUT("/maps/:id/image", middleware.CheckAuth, controllers.EditMapImage) | ||
| 33 | v1.GET("/maps/:id/leaderboards", controllers.FetchMapLeaderboards) | ||
| 30 | v1.POST("/maps/:id/record", middleware.CheckAuth, controllers.CreateRecordWithDemo) | 34 | v1.POST("/maps/:id/record", middleware.CheckAuth, controllers.CreateRecordWithDemo) |
| 31 | v1.GET("/rankings", middleware.CheckAuth, controllers.Rankings) | 35 | v1.GET("/rankings", controllers.Rankings) |
| 32 | v1.GET("/search", controllers.Search) | 36 | v1.GET("/search", controllers.SearchWithQuery) |
| 33 | v1.GET("/games", controllers.FetchGames) | 37 | v1.GET("/games", controllers.FetchGames) |
| 34 | v1.GET("/games/:id", controllers.FetchChapters) | 38 | v1.GET("/games/:id", controllers.FetchChapters) |
| 35 | v1.GET("/chapters/:id", controllers.FetchChapterMaps) | 39 | v1.GET("/chapters/:id", controllers.FetchChapterMaps) |
diff --git a/docs/docs.go b/docs/docs.go index d39fd1c..423afad 100644 --- a/docs/docs.go +++ b/docs/docs.go | |||
| @@ -22,13 +22,13 @@ const docTemplate = `{ | |||
| 22 | "paths": { | 22 | "paths": { |
| 23 | "/chapters/{id}": { | 23 | "/chapters/{id}": { |
| 24 | "get": { | 24 | "get": { |
| 25 | "description": "Get maps from the specified chapter id.", | ||
| 25 | "produces": [ | 26 | "produces": [ |
| 26 | "application/json" | 27 | "application/json" |
| 27 | ], | 28 | ], |
| 28 | "tags": [ | 29 | "tags": [ |
| 29 | "games \u0026 chapters" | 30 | "games \u0026 chapters" |
| 30 | ], | 31 | ], |
| 31 | "summary": "Get maps from the specified chapter id.", | ||
| 32 | "parameters": [ | 32 | "parameters": [ |
| 33 | { | 33 | { |
| 34 | "type": "integer", | 34 | "type": "integer", |
| @@ -66,45 +66,9 @@ const docTemplate = `{ | |||
| 66 | } | 66 | } |
| 67 | } | 67 | } |
| 68 | }, | 68 | }, |
| 69 | "/demo": { | ||
| 70 | "get": { | ||
| 71 | "produces": [ | ||
| 72 | "application/json" | ||
| 73 | ], | ||
| 74 | "tags": [ | ||
| 75 | "rankings" | ||
| 76 | ], | ||
| 77 | "summary": "Get rankings of every player.", | ||
| 78 | "responses": { | ||
| 79 | "200": { | ||
| 80 | "description": "OK", | ||
| 81 | "schema": { | ||
| 82 | "allOf": [ | ||
| 83 | { | ||
| 84 | "$ref": "#/definitions/models.Response" | ||
| 85 | }, | ||
| 86 | { | ||
| 87 | "type": "object", | ||
| 88 | "properties": { | ||
| 89 | "data": { | ||
| 90 | "$ref": "#/definitions/models.RankingsResponse" | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | ] | ||
| 95 | } | ||
| 96 | }, | ||
| 97 | "400": { | ||
| 98 | "description": "Bad Request", | ||
| 99 | "schema": { | ||
| 100 | "$ref": "#/definitions/models.Response" | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | }, | ||
| 106 | "/demos": { | 69 | "/demos": { |
| 107 | "get": { | 70 | "get": { |
| 71 | "description": "Get demo with specified demo uuid.", | ||
| 108 | "consumes": [ | 72 | "consumes": [ |
| 109 | "application/json" | 73 | "application/json" |
| 110 | ], | 74 | ], |
| @@ -114,10 +78,9 @@ const docTemplate = `{ | |||
| 114 | "tags": [ | 78 | "tags": [ |
| 115 | "demo" | 79 | "demo" |
| 116 | ], | 80 | ], |
| 117 | "summary": "Get demo with specified demo uuid.", | ||
| 118 | "parameters": [ | 81 | "parameters": [ |
| 119 | { | 82 | { |
| 120 | "type": "integer", | 83 | "type": "string", |
| 121 | "description": "Demo UUID", | 84 | "description": "Demo UUID", |
| 122 | "name": "uuid", | 85 | "name": "uuid", |
| 123 | "in": "query", | 86 | "in": "query", |
| @@ -142,13 +105,13 @@ const docTemplate = `{ | |||
| 142 | }, | 105 | }, |
| 143 | "/games": { | 106 | "/games": { |
| 144 | "get": { | 107 | "get": { |
| 108 | "description": "Get games from the leaderboards.", | ||
| 145 | "produces": [ | 109 | "produces": [ |
| 146 | "application/json" | 110 | "application/json" |
| 147 | ], | 111 | ], |
| 148 | "tags": [ | 112 | "tags": [ |
| 149 | "games \u0026 chapters" | 113 | "games \u0026 chapters" |
| 150 | ], | 114 | ], |
| 151 | "summary": "Get games from the leaderboards.", | ||
| 152 | "responses": { | 115 | "responses": { |
| 153 | "200": { | 116 | "200": { |
| 154 | "description": "OK", | 117 | "description": "OK", |
| @@ -182,13 +145,13 @@ const docTemplate = `{ | |||
| 182 | }, | 145 | }, |
| 183 | "/games/{id}": { | 146 | "/games/{id}": { |
| 184 | "get": { | 147 | "get": { |
| 148 | "description": "Get chapters from the specified game id.", | ||
| 185 | "produces": [ | 149 | "produces": [ |
| 186 | "application/json" | 150 | "application/json" |
| 187 | ], | 151 | ], |
| 188 | "tags": [ | 152 | "tags": [ |
| 189 | "games \u0026 chapters" | 153 | "games \u0026 chapters" |
| 190 | ], | 154 | ], |
| 191 | "summary": "Get chapters from the specified game id.", | ||
| 192 | "parameters": [ | 155 | "parameters": [ |
| 193 | { | 156 | { |
| 194 | "type": "integer", | 157 | "type": "integer", |
| @@ -228,6 +191,7 @@ const docTemplate = `{ | |||
| 228 | }, | 191 | }, |
| 229 | "/login": { | 192 | "/login": { |
| 230 | "get": { | 193 | "get": { |
| 194 | "description": "Get (redirect) login page for Steam auth.", | ||
| 231 | "consumes": [ | 195 | "consumes": [ |
| 232 | "application/json" | 196 | "application/json" |
| 233 | ], | 197 | ], |
| @@ -237,7 +201,6 @@ const docTemplate = `{ | |||
| 237 | "tags": [ | 201 | "tags": [ |
| 238 | "login" | 202 | "login" |
| 239 | ], | 203 | ], |
| 240 | "summary": "Get (redirect) login page for Steam auth.", | ||
| 241 | "responses": { | 204 | "responses": { |
| 242 | "200": { | 205 | "200": { |
| 243 | "description": "OK", | 206 | "description": "OK", |
| @@ -266,15 +229,77 @@ const docTemplate = `{ | |||
| 266 | } | 229 | } |
| 267 | } | 230 | } |
| 268 | }, | 231 | }, |
| 232 | "/maps/{id}/image": { | ||
| 233 | "put": { | ||
| 234 | "description": "Edit map image with specified map id.", | ||
| 235 | "produces": [ | ||
| 236 | "application/json" | ||
| 237 | ], | ||
| 238 | "tags": [ | ||
| 239 | "maps" | ||
| 240 | ], | ||
| 241 | "parameters": [ | ||
| 242 | { | ||
| 243 | "type": "string", | ||
| 244 | "description": "JWT Token", | ||
| 245 | "name": "Authorization", | ||
| 246 | "in": "header", | ||
| 247 | "required": true | ||
| 248 | }, | ||
| 249 | { | ||
| 250 | "type": "integer", | ||
| 251 | "description": "Map ID", | ||
| 252 | "name": "id", | ||
| 253 | "in": "path", | ||
| 254 | "required": true | ||
| 255 | }, | ||
| 256 | { | ||
| 257 | "description": "Body", | ||
| 258 | "name": "request", | ||
| 259 | "in": "body", | ||
| 260 | "required": true, | ||
| 261 | "schema": { | ||
| 262 | "$ref": "#/definitions/models.EditMapImageRequest" | ||
| 263 | } | ||
| 264 | } | ||
| 265 | ], | ||
| 266 | "responses": { | ||
| 267 | "200": { | ||
| 268 | "description": "OK", | ||
| 269 | "schema": { | ||
| 270 | "allOf": [ | ||
| 271 | { | ||
| 272 | "$ref": "#/definitions/models.Response" | ||
| 273 | }, | ||
| 274 | { | ||
| 275 | "type": "object", | ||
| 276 | "properties": { | ||
| 277 | "data": { | ||
| 278 | "$ref": "#/definitions/models.EditMapImageRequest" | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } | ||
| 282 | ] | ||
| 283 | } | ||
| 284 | }, | ||
| 285 | "400": { | ||
| 286 | "description": "Bad Request", | ||
| 287 | "schema": { | ||
| 288 | "$ref": "#/definitions/models.Response" | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | }, | ||
| 269 | "/maps/{id}/leaderboards": { | 294 | "/maps/{id}/leaderboards": { |
| 270 | "get": { | 295 | "get": { |
| 296 | "description": "Get map leaderboards with specified id.", | ||
| 271 | "produces": [ | 297 | "produces": [ |
| 272 | "application/json" | 298 | "application/json" |
| 273 | ], | 299 | ], |
| 274 | "tags": [ | 300 | "tags": [ |
| 275 | "maps" | 301 | "maps" |
| 276 | ], | 302 | ], |
| 277 | "summary": "Get map leaderboards with specified id.", | ||
| 278 | "parameters": [ | 303 | "parameters": [ |
| 279 | { | 304 | { |
| 280 | "type": "integer", | 305 | "type": "integer", |
| @@ -326,6 +351,7 @@ const docTemplate = `{ | |||
| 326 | }, | 351 | }, |
| 327 | "/maps/{id}/record": { | 352 | "/maps/{id}/record": { |
| 328 | "post": { | 353 | "post": { |
| 354 | "description": "Post record with demo of a specific map.", | ||
| 329 | "consumes": [ | 355 | "consumes": [ |
| 330 | "multipart/form-data" | 356 | "multipart/form-data" |
| 331 | ], | 357 | ], |
| @@ -335,9 +361,15 @@ const docTemplate = `{ | |||
| 335 | "tags": [ | 361 | "tags": [ |
| 336 | "maps" | 362 | "maps" |
| 337 | ], | 363 | ], |
| 338 | "summary": "Post record with demo of a specific map.", | ||
| 339 | "parameters": [ | 364 | "parameters": [ |
| 340 | { | 365 | { |
| 366 | "type": "integer", | ||
| 367 | "description": "Map ID", | ||
| 368 | "name": "id", | ||
| 369 | "in": "path", | ||
| 370 | "required": true | ||
| 371 | }, | ||
| 372 | { | ||
| 341 | "type": "string", | 373 | "type": "string", |
| 342 | "description": "JWT Token", | 374 | "description": "JWT Token", |
| 343 | "name": "Authorization", | 375 | "name": "Authorization", |
| @@ -345,42 +377,29 @@ const docTemplate = `{ | |||
| 345 | "required": true | 377 | "required": true |
| 346 | }, | 378 | }, |
| 347 | { | 379 | { |
| 348 | "type": "array", | 380 | "type": "file", |
| 349 | "items": { | 381 | "description": "Host Demo", |
| 350 | "type": "file" | 382 | "name": "host_demo", |
| 351 | }, | ||
| 352 | "description": "Demos", | ||
| 353 | "name": "demos", | ||
| 354 | "in": "formData", | 383 | "in": "formData", |
| 355 | "required": true | 384 | "required": true |
| 356 | }, | 385 | }, |
| 357 | { | 386 | { |
| 358 | "type": "integer", | 387 | "type": "file", |
| 359 | "description": "Score Count", | 388 | "description": "Partner Demo", |
| 360 | "name": "score_count", | 389 | "name": "partner_demo", |
| 361 | "in": "formData", | 390 | "in": "formData" |
| 362 | "required": true | ||
| 363 | }, | ||
| 364 | { | ||
| 365 | "type": "integer", | ||
| 366 | "description": "Score Time", | ||
| 367 | "name": "score_time", | ||
| 368 | "in": "formData", | ||
| 369 | "required": true | ||
| 370 | }, | 391 | }, |
| 371 | { | 392 | { |
| 372 | "type": "boolean", | 393 | "type": "boolean", |
| 373 | "description": "Is Partner Orange", | 394 | "description": "Is Partner Orange", |
| 374 | "name": "is_partner_orange", | 395 | "name": "is_partner_orange", |
| 375 | "in": "formData", | 396 | "in": "formData" |
| 376 | "required": true | ||
| 377 | }, | 397 | }, |
| 378 | { | 398 | { |
| 379 | "type": "string", | 399 | "type": "string", |
| 380 | "description": "Partner ID", | 400 | "description": "Partner ID", |
| 381 | "name": "partner_id", | 401 | "name": "partner_id", |
| 382 | "in": "formData", | 402 | "in": "formData" |
| 383 | "required": true | ||
| 384 | } | 403 | } |
| 385 | ], | 404 | ], |
| 386 | "responses": { | 405 | "responses": { |
| @@ -395,7 +414,7 @@ const docTemplate = `{ | |||
| 395 | "type": "object", | 414 | "type": "object", |
| 396 | "properties": { | 415 | "properties": { |
| 397 | "data": { | 416 | "data": { |
| 398 | "$ref": "#/definitions/models.RecordRequest" | 417 | "$ref": "#/definitions/models.RecordResponse" |
| 399 | } | 418 | } |
| 400 | } | 419 | } |
| 401 | } | 420 | } |
| @@ -419,13 +438,13 @@ const docTemplate = `{ | |||
| 419 | }, | 438 | }, |
| 420 | "/maps/{id}/summary": { | 439 | "/maps/{id}/summary": { |
| 421 | "get": { | 440 | "get": { |
| 441 | "description": "Get map summary with specified id.", | ||
| 422 | "produces": [ | 442 | "produces": [ |
| 423 | "application/json" | 443 | "application/json" |
| 424 | ], | 444 | ], |
| 425 | "tags": [ | 445 | "tags": [ |
| 426 | "maps" | 446 | "maps" |
| 427 | ], | 447 | ], |
| 428 | "summary": "Get map summary with specified id.", | ||
| 429 | "parameters": [ | 448 | "parameters": [ |
| 430 | { | 449 | { |
| 431 | "type": "integer", | 450 | "type": "integer", |
| @@ -447,19 +466,187 @@ const docTemplate = `{ | |||
| 447 | "type": "object", | 466 | "type": "object", |
| 448 | "properties": { | 467 | "properties": { |
| 449 | "data": { | 468 | "data": { |
| 450 | "allOf": [ | 469 | "$ref": "#/definitions/models.MapSummaryResponse" |
| 451 | { | 470 | } |
| 452 | "$ref": "#/definitions/models.Map" | 471 | } |
| 453 | }, | 472 | } |
| 454 | { | 473 | ] |
| 455 | "type": "object", | 474 | } |
| 456 | "properties": { | 475 | }, |
| 457 | "data": { | 476 | "400": { |
| 458 | "$ref": "#/definitions/models.MapSummary" | 477 | "description": "Bad Request", |
| 459 | } | 478 | "schema": { |
| 460 | } | 479 | "$ref": "#/definitions/models.Response" |
| 461 | } | 480 | } |
| 462 | ] | 481 | } |
| 482 | } | ||
| 483 | }, | ||
| 484 | "put": { | ||
| 485 | "description": "Edit map summary with specified map id.", | ||
| 486 | "produces": [ | ||
| 487 | "application/json" | ||
| 488 | ], | ||
| 489 | "tags": [ | ||
| 490 | "maps" | ||
| 491 | ], | ||
| 492 | "parameters": [ | ||
| 493 | { | ||
| 494 | "type": "string", | ||
| 495 | "description": "JWT Token", | ||
| 496 | "name": "Authorization", | ||
| 497 | "in": "header", | ||
| 498 | "required": true | ||
| 499 | }, | ||
| 500 | { | ||
| 501 | "type": "integer", | ||
| 502 | "description": "Map ID", | ||
| 503 | "name": "id", | ||
| 504 | "in": "path", | ||
| 505 | "required": true | ||
| 506 | }, | ||
| 507 | { | ||
| 508 | "description": "Body", | ||
| 509 | "name": "request", | ||
| 510 | "in": "body", | ||
| 511 | "required": true, | ||
| 512 | "schema": { | ||
| 513 | "$ref": "#/definitions/models.EditMapSummaryRequest" | ||
| 514 | } | ||
| 515 | } | ||
| 516 | ], | ||
| 517 | "responses": { | ||
| 518 | "200": { | ||
| 519 | "description": "OK", | ||
| 520 | "schema": { | ||
| 521 | "allOf": [ | ||
| 522 | { | ||
| 523 | "$ref": "#/definitions/models.Response" | ||
| 524 | }, | ||
| 525 | { | ||
| 526 | "type": "object", | ||
| 527 | "properties": { | ||
| 528 | "data": { | ||
| 529 | "$ref": "#/definitions/models.EditMapSummaryRequest" | ||
| 530 | } | ||
| 531 | } | ||
| 532 | } | ||
| 533 | ] | ||
| 534 | } | ||
| 535 | }, | ||
| 536 | "400": { | ||
| 537 | "description": "Bad Request", | ||
| 538 | "schema": { | ||
| 539 | "$ref": "#/definitions/models.Response" | ||
| 540 | } | ||
| 541 | } | ||
| 542 | } | ||
| 543 | }, | ||
| 544 | "post": { | ||
| 545 | "description": "Create map summary with specified map id.", | ||
| 546 | "produces": [ | ||
| 547 | "application/json" | ||
| 548 | ], | ||
| 549 | "tags": [ | ||
| 550 | "maps" | ||
| 551 | ], | ||
| 552 | "parameters": [ | ||
| 553 | { | ||
| 554 | "type": "string", | ||
| 555 | "description": "JWT Token", | ||
| 556 | "name": "Authorization", | ||
| 557 | "in": "header", | ||
| 558 | "required": true | ||
| 559 | }, | ||
| 560 | { | ||
| 561 | "type": "integer", | ||
| 562 | "description": "Map ID", | ||
| 563 | "name": "id", | ||
| 564 | "in": "path", | ||
| 565 | "required": true | ||
| 566 | }, | ||
| 567 | { | ||
| 568 | "description": "Body", | ||
| 569 | "name": "request", | ||
| 570 | "in": "body", | ||
| 571 | "required": true, | ||
| 572 | "schema": { | ||
| 573 | "$ref": "#/definitions/models.CreateMapSummaryRequest" | ||
| 574 | } | ||
| 575 | } | ||
| 576 | ], | ||
| 577 | "responses": { | ||
| 578 | "200": { | ||
| 579 | "description": "OK", | ||
| 580 | "schema": { | ||
| 581 | "allOf": [ | ||
| 582 | { | ||
| 583 | "$ref": "#/definitions/models.Response" | ||
| 584 | }, | ||
| 585 | { | ||
| 586 | "type": "object", | ||
| 587 | "properties": { | ||
| 588 | "data": { | ||
| 589 | "$ref": "#/definitions/models.CreateMapSummaryRequest" | ||
| 590 | } | ||
| 591 | } | ||
| 592 | } | ||
| 593 | ] | ||
| 594 | } | ||
| 595 | }, | ||
| 596 | "400": { | ||
| 597 | "description": "Bad Request", | ||
| 598 | "schema": { | ||
| 599 | "$ref": "#/definitions/models.Response" | ||
| 600 | } | ||
| 601 | } | ||
| 602 | } | ||
| 603 | }, | ||
| 604 | "delete": { | ||
| 605 | "description": "Delete map summary with specified map id.", | ||
| 606 | "produces": [ | ||
| 607 | "application/json" | ||
| 608 | ], | ||
| 609 | "tags": [ | ||
| 610 | "maps" | ||
| 611 | ], | ||
| 612 | "parameters": [ | ||
| 613 | { | ||
| 614 | "type": "string", | ||
| 615 | "description": "JWT Token", | ||
| 616 | "name": "Authorization", | ||
| 617 | "in": "header", | ||
| 618 | "required": true | ||
| 619 | }, | ||
| 620 | { | ||
| 621 | "type": "integer", | ||
| 622 | "description": "Map ID", | ||
| 623 | "name": "id", | ||
| 624 | "in": "path", | ||
| 625 | "required": true | ||
| 626 | }, | ||
| 627 | { | ||
| 628 | "description": "Body", | ||
| 629 | "name": "request", | ||
| 630 | "in": "body", | ||
| 631 | "required": true, | ||
| 632 | "schema": { | ||
| 633 | "$ref": "#/definitions/models.DeleteMapSummaryRequest" | ||
| 634 | } | ||
| 635 | } | ||
| 636 | ], | ||
| 637 | "responses": { | ||
| 638 | "200": { | ||
| 639 | "description": "OK", | ||
| 640 | "schema": { | ||
| 641 | "allOf": [ | ||
| 642 | { | ||
| 643 | "$ref": "#/definitions/models.Response" | ||
| 644 | }, | ||
| 645 | { | ||
| 646 | "type": "object", | ||
| 647 | "properties": { | ||
| 648 | "data": { | ||
| 649 | "$ref": "#/definitions/models.DeleteMapSummaryRequest" | ||
| 463 | } | 650 | } |
| 464 | } | 651 | } |
| 465 | } | 652 | } |
| @@ -477,6 +664,7 @@ const docTemplate = `{ | |||
| 477 | }, | 664 | }, |
| 478 | "/profile": { | 665 | "/profile": { |
| 479 | "get": { | 666 | "get": { |
| 667 | "description": "Get profile page of session user.", | ||
| 480 | "consumes": [ | 668 | "consumes": [ |
| 481 | "application/json" | 669 | "application/json" |
| 482 | ], | 670 | ], |
| @@ -486,7 +674,6 @@ const docTemplate = `{ | |||
| 486 | "tags": [ | 674 | "tags": [ |
| 487 | "users" | 675 | "users" |
| 488 | ], | 676 | ], |
| 489 | "summary": "Get profile page of session user.", | ||
| 490 | "parameters": [ | 677 | "parameters": [ |
| 491 | { | 678 | { |
| 492 | "type": "string", | 679 | "type": "string", |
| @@ -530,6 +717,7 @@ const docTemplate = `{ | |||
| 530 | } | 717 | } |
| 531 | }, | 718 | }, |
| 532 | "put": { | 719 | "put": { |
| 720 | "description": "Update country code of session user.", | ||
| 533 | "consumes": [ | 721 | "consumes": [ |
| 534 | "application/json" | 722 | "application/json" |
| 535 | ], | 723 | ], |
| @@ -539,7 +727,6 @@ const docTemplate = `{ | |||
| 539 | "tags": [ | 727 | "tags": [ |
| 540 | "users" | 728 | "users" |
| 541 | ], | 729 | ], |
| 542 | "summary": "Update country code of session user.", | ||
| 543 | "parameters": [ | 730 | "parameters": [ |
| 544 | { | 731 | { |
| 545 | "type": "string", | 732 | "type": "string", |
| @@ -560,19 +747,7 @@ const docTemplate = `{ | |||
| 560 | "200": { | 747 | "200": { |
| 561 | "description": "OK", | 748 | "description": "OK", |
| 562 | "schema": { | 749 | "schema": { |
| 563 | "allOf": [ | 750 | "$ref": "#/definitions/models.Response" |
| 564 | { | ||
| 565 | "$ref": "#/definitions/models.Response" | ||
| 566 | }, | ||
| 567 | { | ||
| 568 | "type": "object", | ||
| 569 | "properties": { | ||
| 570 | "data": { | ||
| 571 | "$ref": "#/definitions/models.ProfileResponse" | ||
| 572 | } | ||
| 573 | } | ||
| 574 | } | ||
| 575 | ] | ||
| 576 | } | 751 | } |
| 577 | }, | 752 | }, |
| 578 | "400": { | 753 | "400": { |
| @@ -590,6 +765,7 @@ const docTemplate = `{ | |||
| 590 | } | 765 | } |
| 591 | }, | 766 | }, |
| 592 | "post": { | 767 | "post": { |
| 768 | "description": "Update profile page of session user.", | ||
| 593 | "consumes": [ | 769 | "consumes": [ |
| 594 | "application/json" | 770 | "application/json" |
| 595 | ], | 771 | ], |
| @@ -599,7 +775,6 @@ const docTemplate = `{ | |||
| 599 | "tags": [ | 775 | "tags": [ |
| 600 | "users" | 776 | "users" |
| 601 | ], | 777 | ], |
| 602 | "summary": "Update profile page of session user.", | ||
| 603 | "parameters": [ | 778 | "parameters": [ |
| 604 | { | 779 | { |
| 605 | "type": "string", | 780 | "type": "string", |
| @@ -643,15 +818,60 @@ const docTemplate = `{ | |||
| 643 | } | 818 | } |
| 644 | } | 819 | } |
| 645 | }, | 820 | }, |
| 821 | "/rankings": { | ||
| 822 | "get": { | ||
| 823 | "description": "Get rankings of every player.", | ||
| 824 | "produces": [ | ||
| 825 | "application/json" | ||
| 826 | ], | ||
| 827 | "tags": [ | ||
| 828 | "rankings" | ||
| 829 | ], | ||
| 830 | "responses": { | ||
| 831 | "200": { | ||
| 832 | "description": "OK", | ||
| 833 | "schema": { | ||
| 834 | "allOf": [ | ||
| 835 | { | ||
| 836 | "$ref": "#/definitions/models.Response" | ||
| 837 | }, | ||
| 838 | { | ||
| 839 | "type": "object", | ||
| 840 | "properties": { | ||
| 841 | "data": { | ||
| 842 | "$ref": "#/definitions/models.RankingsResponse" | ||
| 843 | } | ||
| 844 | } | ||
| 845 | } | ||
| 846 | ] | ||
| 847 | } | ||
| 848 | }, | ||
| 849 | "400": { | ||
| 850 | "description": "Bad Request", | ||
| 851 | "schema": { | ||
| 852 | "$ref": "#/definitions/models.Response" | ||
| 853 | } | ||
| 854 | } | ||
| 855 | } | ||
| 856 | } | ||
| 857 | }, | ||
| 646 | "/search": { | 858 | "/search": { |
| 647 | "get": { | 859 | "get": { |
| 860 | "description": "Get all user and map data matching to the query.", | ||
| 648 | "produces": [ | 861 | "produces": [ |
| 649 | "application/json" | 862 | "application/json" |
| 650 | ], | 863 | ], |
| 651 | "tags": [ | 864 | "tags": [ |
| 652 | "search" | 865 | "search" |
| 653 | ], | 866 | ], |
| 654 | "summary": "Get all user and map data.", | 867 | "parameters": [ |
| 868 | { | ||
| 869 | "type": "string", | ||
| 870 | "description": "Search user or map name.", | ||
| 871 | "name": "q", | ||
| 872 | "in": "query" | ||
| 873 | } | ||
| 874 | ], | ||
| 655 | "responses": { | 875 | "responses": { |
| 656 | "200": { | 876 | "200": { |
| 657 | "description": "OK", | 877 | "description": "OK", |
| @@ -682,13 +902,13 @@ const docTemplate = `{ | |||
| 682 | }, | 902 | }, |
| 683 | "/token": { | 903 | "/token": { |
| 684 | "get": { | 904 | "get": { |
| 905 | "description": "Gets the token cookie value from the user.", | ||
| 685 | "produces": [ | 906 | "produces": [ |
| 686 | "application/json" | 907 | "application/json" |
| 687 | ], | 908 | ], |
| 688 | "tags": [ | 909 | "tags": [ |
| 689 | "auth" | 910 | "auth" |
| 690 | ], | 911 | ], |
| 691 | "summary": "Gets the token cookie value from the user.", | ||
| 692 | "responses": { | 912 | "responses": { |
| 693 | "200": { | 913 | "200": { |
| 694 | "description": "OK", | 914 | "description": "OK", |
| @@ -717,13 +937,13 @@ const docTemplate = `{ | |||
| 717 | } | 937 | } |
| 718 | }, | 938 | }, |
| 719 | "delete": { | 939 | "delete": { |
| 940 | "description": "Deletes the token cookie from the user.", | ||
| 720 | "produces": [ | 941 | "produces": [ |
| 721 | "application/json" | 942 | "application/json" |
| 722 | ], | 943 | ], |
| 723 | "tags": [ | 944 | "tags": [ |
| 724 | "auth" | 945 | "auth" |
| 725 | ], | 946 | ], |
| 726 | "summary": "Deletes the token cookie from the user.", | ||
| 727 | "responses": { | 947 | "responses": { |
| 728 | "200": { | 948 | "200": { |
| 729 | "description": "OK", | 949 | "description": "OK", |
| @@ -754,6 +974,7 @@ const docTemplate = `{ | |||
| 754 | }, | 974 | }, |
| 755 | "/users/{id}": { | 975 | "/users/{id}": { |
| 756 | "get": { | 976 | "get": { |
| 977 | "description": "Get profile page of another user.", | ||
| 757 | "consumes": [ | 978 | "consumes": [ |
| 758 | "application/json" | 979 | "application/json" |
| 759 | ], | 980 | ], |
| @@ -763,7 +984,6 @@ const docTemplate = `{ | |||
| 763 | "tags": [ | 984 | "tags": [ |
| 764 | "users" | 985 | "users" |
| 765 | ], | 986 | ], |
| 766 | "summary": "Get profile page of another user.", | ||
| 767 | "parameters": [ | 987 | "parameters": [ |
| 768 | { | 988 | { |
| 769 | "type": "integer", | 989 | "type": "integer", |
| @@ -809,6 +1029,17 @@ const docTemplate = `{ | |||
| 809 | } | 1029 | } |
| 810 | }, | 1030 | }, |
| 811 | "definitions": { | 1031 | "definitions": { |
| 1032 | "models.Category": { | ||
| 1033 | "type": "object", | ||
| 1034 | "properties": { | ||
| 1035 | "id": { | ||
| 1036 | "type": "integer" | ||
| 1037 | }, | ||
| 1038 | "name": { | ||
| 1039 | "type": "string" | ||
| 1040 | } | ||
| 1041 | } | ||
| 1042 | }, | ||
| 812 | "models.Chapter": { | 1043 | "models.Chapter": { |
| 813 | "type": "object", | 1044 | "type": "object", |
| 814 | "properties": { | 1045 | "properties": { |
| @@ -848,12 +1079,97 @@ const docTemplate = `{ | |||
| 848 | } | 1079 | } |
| 849 | } | 1080 | } |
| 850 | }, | 1081 | }, |
| 1082 | "models.CreateMapSummaryRequest": { | ||
| 1083 | "type": "object", | ||
| 1084 | "required": [ | ||
| 1085 | "category_id", | ||
| 1086 | "description", | ||
| 1087 | "record_date", | ||
| 1088 | "score_count", | ||
| 1089 | "user_name" | ||
| 1090 | ], | ||
| 1091 | "properties": { | ||
| 1092 | "category_id": { | ||
| 1093 | "type": "integer" | ||
| 1094 | }, | ||
| 1095 | "description": { | ||
| 1096 | "type": "string" | ||
| 1097 | }, | ||
| 1098 | "record_date": { | ||
| 1099 | "type": "string" | ||
| 1100 | }, | ||
| 1101 | "score_count": { | ||
| 1102 | "type": "integer" | ||
| 1103 | }, | ||
| 1104 | "showcase": { | ||
| 1105 | "type": "string" | ||
| 1106 | }, | ||
| 1107 | "user_name": { | ||
| 1108 | "type": "string" | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | }, | ||
| 1112 | "models.DeleteMapSummaryRequest": { | ||
| 1113 | "type": "object", | ||
| 1114 | "required": [ | ||
| 1115 | "route_id" | ||
| 1116 | ], | ||
| 1117 | "properties": { | ||
| 1118 | "route_id": { | ||
| 1119 | "type": "integer" | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | }, | ||
| 1123 | "models.EditMapImageRequest": { | ||
| 1124 | "type": "object", | ||
| 1125 | "required": [ | ||
| 1126 | "image" | ||
| 1127 | ], | ||
| 1128 | "properties": { | ||
| 1129 | "image": { | ||
| 1130 | "type": "string" | ||
| 1131 | } | ||
| 1132 | } | ||
| 1133 | }, | ||
| 1134 | "models.EditMapSummaryRequest": { | ||
| 1135 | "type": "object", | ||
| 1136 | "required": [ | ||
| 1137 | "description", | ||
| 1138 | "record_date", | ||
| 1139 | "route_id", | ||
| 1140 | "score_count", | ||
| 1141 | "user_name" | ||
| 1142 | ], | ||
| 1143 | "properties": { | ||
| 1144 | "description": { | ||
| 1145 | "type": "string" | ||
| 1146 | }, | ||
| 1147 | "record_date": { | ||
| 1148 | "type": "string" | ||
| 1149 | }, | ||
| 1150 | "route_id": { | ||
| 1151 | "type": "integer" | ||
| 1152 | }, | ||
| 1153 | "score_count": { | ||
| 1154 | "type": "integer" | ||
| 1155 | }, | ||
| 1156 | "showcase": { | ||
| 1157 | "type": "string" | ||
| 1158 | }, | ||
| 1159 | "user_name": { | ||
| 1160 | "type": "string" | ||
| 1161 | } | ||
| 1162 | } | ||
| 1163 | }, | ||
| 851 | "models.Game": { | 1164 | "models.Game": { |
| 852 | "type": "object", | 1165 | "type": "object", |
| 853 | "properties": { | 1166 | "properties": { |
| 854 | "id": { | 1167 | "id": { |
| 855 | "type": "integer" | 1168 | "type": "integer" |
| 856 | }, | 1169 | }, |
| 1170 | "is_coop": { | ||
| 1171 | "type": "boolean" | ||
| 1172 | }, | ||
| 857 | "name": { | 1173 | "name": { |
| 858 | "type": "string" | 1174 | "type": "string" |
| 859 | } | 1175 | } |
| @@ -873,32 +1189,20 @@ const docTemplate = `{ | |||
| 873 | "chapter_name": { | 1189 | "chapter_name": { |
| 874 | "type": "string" | 1190 | "type": "string" |
| 875 | }, | 1191 | }, |
| 876 | "data": {}, | ||
| 877 | "game_name": { | 1192 | "game_name": { |
| 878 | "type": "string" | 1193 | "type": "string" |
| 879 | }, | 1194 | }, |
| 880 | "id": { | 1195 | "id": { |
| 881 | "type": "integer" | 1196 | "type": "integer" |
| 882 | }, | 1197 | }, |
| 883 | "map_name": { | 1198 | "image": { |
| 884 | "type": "string" | 1199 | "type": "string" |
| 885 | } | ||
| 886 | } | ||
| 887 | }, | ||
| 888 | "models.MapCategoryScores": { | ||
| 889 | "type": "object", | ||
| 890 | "properties": { | ||
| 891 | "any": { | ||
| 892 | "type": "integer" | ||
| 893 | }, | 1200 | }, |
| 894 | "cm": { | 1201 | "is_coop": { |
| 895 | "type": "integer" | 1202 | "type": "boolean" |
| 896 | }, | ||
| 897 | "inbounds_sla": { | ||
| 898 | "type": "integer" | ||
| 899 | }, | 1203 | }, |
| 900 | "no_sla": { | 1204 | "map_name": { |
| 901 | "type": "integer" | 1205 | "type": "string" |
| 902 | } | 1206 | } |
| 903 | } | 1207 | } |
| 904 | }, | 1208 | }, |
| @@ -922,6 +1226,29 @@ const docTemplate = `{ | |||
| 922 | "records": {} | 1226 | "records": {} |
| 923 | } | 1227 | } |
| 924 | }, | 1228 | }, |
| 1229 | "models.MapRoute": { | ||
| 1230 | "type": "object", | ||
| 1231 | "properties": { | ||
| 1232 | "category": { | ||
| 1233 | "$ref": "#/definitions/models.Category" | ||
| 1234 | }, | ||
| 1235 | "description": { | ||
| 1236 | "type": "string" | ||
| 1237 | }, | ||
| 1238 | "history": { | ||
| 1239 | "$ref": "#/definitions/models.MapHistory" | ||
| 1240 | }, | ||
| 1241 | "rating": { | ||
| 1242 | "type": "number" | ||
| 1243 | }, | ||
| 1244 | "route_id": { | ||
| 1245 | "type": "integer" | ||
| 1246 | }, | ||
| 1247 | "showcase": { | ||
| 1248 | "type": "string" | ||
| 1249 | } | ||
| 1250 | } | ||
| 1251 | }, | ||
| 925 | "models.MapShort": { | 1252 | "models.MapShort": { |
| 926 | "type": "object", | 1253 | "type": "object", |
| 927 | "properties": { | 1254 | "properties": { |
| @@ -936,29 +1263,22 @@ const docTemplate = `{ | |||
| 936 | "models.MapSummary": { | 1263 | "models.MapSummary": { |
| 937 | "type": "object", | 1264 | "type": "object", |
| 938 | "properties": { | 1265 | "properties": { |
| 939 | "category_scores": { | 1266 | "routes": { |
| 940 | "$ref": "#/definitions/models.MapCategoryScores" | ||
| 941 | }, | ||
| 942 | "description": { | ||
| 943 | "type": "string" | ||
| 944 | }, | ||
| 945 | "history": { | ||
| 946 | "type": "array", | ||
| 947 | "items": { | ||
| 948 | "$ref": "#/definitions/models.MapHistory" | ||
| 949 | } | ||
| 950 | }, | ||
| 951 | "rating": { | ||
| 952 | "type": "number" | ||
| 953 | }, | ||
| 954 | "routers": { | ||
| 955 | "type": "array", | 1267 | "type": "array", |
| 956 | "items": { | 1268 | "items": { |
| 957 | "type": "string" | 1269 | "$ref": "#/definitions/models.MapRoute" |
| 958 | } | 1270 | } |
| 1271 | } | ||
| 1272 | } | ||
| 1273 | }, | ||
| 1274 | "models.MapSummaryResponse": { | ||
| 1275 | "type": "object", | ||
| 1276 | "properties": { | ||
| 1277 | "map": { | ||
| 1278 | "$ref": "#/definitions/models.Map" | ||
| 959 | }, | 1279 | }, |
| 960 | "showcase": { | 1280 | "summary": { |
| 961 | "type": "string" | 1281 | "$ref": "#/definitions/models.MapSummary" |
| 962 | } | 1282 | } |
| 963 | } | 1283 | } |
| 964 | }, | 1284 | }, |
| @@ -1011,21 +1331,9 @@ const docTemplate = `{ | |||
| 1011 | } | 1331 | } |
| 1012 | } | 1332 | } |
| 1013 | }, | 1333 | }, |
| 1014 | "models.RecordRequest": { | 1334 | "models.RecordResponse": { |
| 1015 | "type": "object", | 1335 | "type": "object", |
| 1016 | "required": [ | ||
| 1017 | "is_partner_orange", | ||
| 1018 | "partner_id", | ||
| 1019 | "score_count", | ||
| 1020 | "score_time" | ||
| 1021 | ], | ||
| 1022 | "properties": { | 1336 | "properties": { |
| 1023 | "is_partner_orange": { | ||
| 1024 | "type": "boolean" | ||
| 1025 | }, | ||
| 1026 | "partner_id": { | ||
| 1027 | "type": "string" | ||
| 1028 | }, | ||
| 1029 | "score_count": { | 1337 | "score_count": { |
| 1030 | "type": "integer" | 1338 | "type": "integer" |
| 1031 | }, | 1339 | }, |
| @@ -1061,29 +1369,13 @@ const docTemplate = `{ | |||
| 1061 | "maps": { | 1369 | "maps": { |
| 1062 | "type": "array", | 1370 | "type": "array", |
| 1063 | "items": { | 1371 | "items": { |
| 1064 | "type": "object", | 1372 | "$ref": "#/definitions/models.MapShort" |
| 1065 | "properties": { | ||
| 1066 | "id": { | ||
| 1067 | "type": "integer" | ||
| 1068 | }, | ||
| 1069 | "name": { | ||
| 1070 | "type": "string" | ||
| 1071 | } | ||
| 1072 | } | ||
| 1073 | } | 1373 | } |
| 1074 | }, | 1374 | }, |
| 1075 | "players": { | 1375 | "players": { |
| 1076 | "type": "array", | 1376 | "type": "array", |
| 1077 | "items": { | 1377 | "items": { |
| 1078 | "type": "object", | 1378 | "$ref": "#/definitions/models.UserShort" |
| 1079 | "properties": { | ||
| 1080 | "steam_id": { | ||
| 1081 | "type": "string" | ||
| 1082 | }, | ||
| 1083 | "user_name": { | ||
| 1084 | "type": "string" | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | } | 1379 | } |
| 1088 | } | 1380 | } |
| 1089 | } | 1381 | } |
| @@ -1101,6 +1393,17 @@ const docTemplate = `{ | |||
| 1101 | "type": "string" | 1393 | "type": "string" |
| 1102 | } | 1394 | } |
| 1103 | } | 1395 | } |
| 1396 | }, | ||
| 1397 | "models.UserShort": { | ||
| 1398 | "type": "object", | ||
| 1399 | "properties": { | ||
| 1400 | "steam_id": { | ||
| 1401 | "type": "string" | ||
| 1402 | }, | ||
| 1403 | "user_name": { | ||
| 1404 | "type": "string" | ||
| 1405 | } | ||
| 1406 | } | ||
| 1104 | } | 1407 | } |
| 1105 | } | 1408 | } |
| 1106 | }` | 1409 | }` |
diff --git a/docs/swagger.json b/docs/swagger.json index ad2a659..2e1a789 100644 --- a/docs/swagger.json +++ b/docs/swagger.json | |||
| @@ -15,13 +15,13 @@ | |||
| 15 | "paths": { | 15 | "paths": { |
| 16 | "/chapters/{id}": { | 16 | "/chapters/{id}": { |
| 17 | "get": { | 17 | "get": { |
| 18 | "description": "Get maps from the specified chapter id.", | ||
| 18 | "produces": [ | 19 | "produces": [ |
| 19 | "application/json" | 20 | "application/json" |
| 20 | ], | 21 | ], |
| 21 | "tags": [ | 22 | "tags": [ |
| 22 | "games \u0026 chapters" | 23 | "games \u0026 chapters" |
| 23 | ], | 24 | ], |
| 24 | "summary": "Get maps from the specified chapter id.", | ||
| 25 | "parameters": [ | 25 | "parameters": [ |
| 26 | { | 26 | { |
| 27 | "type": "integer", | 27 | "type": "integer", |
| @@ -59,45 +59,9 @@ | |||
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | }, | 61 | }, |
| 62 | "/demo": { | ||
| 63 | "get": { | ||
| 64 | "produces": [ | ||
| 65 | "application/json" | ||
| 66 | ], | ||
| 67 | "tags": [ | ||
| 68 | "rankings" | ||
| 69 | ], | ||
| 70 | "summary": "Get rankings of every player.", | ||
| 71 | "responses": { | ||
| 72 | "200": { | ||
| 73 | "description": "OK", | ||
| 74 | "schema": { | ||
| 75 | "allOf": [ | ||
| 76 | { | ||
| 77 | "$ref": "#/definitions/models.Response" | ||
| 78 | }, | ||
| 79 | { | ||
| 80 | "type": "object", | ||
| 81 | "properties": { | ||
| 82 | "data": { | ||
| 83 | "$ref": "#/definitions/models.RankingsResponse" | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | ] | ||
| 88 | } | ||
| 89 | }, | ||
| 90 | "400": { | ||
| 91 | "description": "Bad Request", | ||
| 92 | "schema": { | ||
| 93 | "$ref": "#/definitions/models.Response" | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | }, | ||
| 99 | "/demos": { | 62 | "/demos": { |
| 100 | "get": { | 63 | "get": { |
| 64 | "description": "Get demo with specified demo uuid.", | ||
| 101 | "consumes": [ | 65 | "consumes": [ |
| 102 | "application/json" | 66 | "application/json" |
| 103 | ], | 67 | ], |
| @@ -107,10 +71,9 @@ | |||
| 107 | "tags": [ | 71 | "tags": [ |
| 108 | "demo" | 72 | "demo" |
| 109 | ], | 73 | ], |
| 110 | "summary": "Get demo with specified demo uuid.", | ||
| 111 | "parameters": [ | 74 | "parameters": [ |
| 112 | { | 75 | { |
| 113 | "type": "integer", | 76 | "type": "string", |
| 114 | "description": "Demo UUID", | 77 | "description": "Demo UUID", |
| 115 | "name": "uuid", | 78 | "name": "uuid", |
| 116 | "in": "query", | 79 | "in": "query", |
| @@ -135,13 +98,13 @@ | |||
| 135 | }, | 98 | }, |
| 136 | "/games": { | 99 | "/games": { |
| 137 | "get": { | 100 | "get": { |
| 101 | "description": "Get games from the leaderboards.", | ||
| 138 | "produces": [ | 102 | "produces": [ |
| 139 | "application/json" | 103 | "application/json" |
| 140 | ], | 104 | ], |
| 141 | "tags": [ | 105 | "tags": [ |
| 142 | "games \u0026 chapters" | 106 | "games \u0026 chapters" |
| 143 | ], | 107 | ], |
| 144 | "summary": "Get games from the leaderboards.", | ||
| 145 | "responses": { | 108 | "responses": { |
| 146 | "200": { | 109 | "200": { |
| 147 | "description": "OK", | 110 | "description": "OK", |
| @@ -175,13 +138,13 @@ | |||
| 175 | }, | 138 | }, |
| 176 | "/games/{id}": { | 139 | "/games/{id}": { |
| 177 | "get": { | 140 | "get": { |
| 141 | "description": "Get chapters from the specified game id.", | ||
| 178 | "produces": [ | 142 | "produces": [ |
| 179 | "application/json" | 143 | "application/json" |
| 180 | ], | 144 | ], |
| 181 | "tags": [ | 145 | "tags": [ |
| 182 | "games \u0026 chapters" | 146 | "games \u0026 chapters" |
| 183 | ], | 147 | ], |
| 184 | "summary": "Get chapters from the specified game id.", | ||
| 185 | "parameters": [ | 148 | "parameters": [ |
| 186 | { | 149 | { |
| 187 | "type": "integer", | 150 | "type": "integer", |
| @@ -221,6 +184,7 @@ | |||
| 221 | }, | 184 | }, |
| 222 | "/login": { | 185 | "/login": { |
| 223 | "get": { | 186 | "get": { |
| 187 | "description": "Get (redirect) login page for Steam auth.", | ||
| 224 | "consumes": [ | 188 | "consumes": [ |
| 225 | "application/json" | 189 | "application/json" |
| 226 | ], | 190 | ], |
| @@ -230,7 +194,6 @@ | |||
| 230 | "tags": [ | 194 | "tags": [ |
| 231 | "login" | 195 | "login" |
| 232 | ], | 196 | ], |
| 233 | "summary": "Get (redirect) login page for Steam auth.", | ||
| 234 | "responses": { | 197 | "responses": { |
| 235 | "200": { | 198 | "200": { |
| 236 | "description": "OK", | 199 | "description": "OK", |
| @@ -259,15 +222,77 @@ | |||
| 259 | } | 222 | } |
| 260 | } | 223 | } |
| 261 | }, | 224 | }, |
| 225 | "/maps/{id}/image": { | ||
| 226 | "put": { | ||
| 227 | "description": "Edit map image with specified map id.", | ||
| 228 | "produces": [ | ||
| 229 | "application/json" | ||
| 230 | ], | ||
| 231 | "tags": [ | ||
| 232 | "maps" | ||
| 233 | ], | ||
| 234 | "parameters": [ | ||
| 235 | { | ||
| 236 | "type": "string", | ||
| 237 | "description": "JWT Token", | ||
| 238 | "name": "Authorization", | ||
| 239 | "in": "header", | ||
| 240 | "required": true | ||
| 241 | }, | ||
| 242 | { | ||
| 243 | "type": "integer", | ||
| 244 | "description": "Map ID", | ||
| 245 | "name": "id", | ||
| 246 | "in": "path", | ||
| 247 | "required": true | ||
| 248 | }, | ||
| 249 | { | ||
| 250 | "description": "Body", | ||
| 251 | "name": "request", | ||
| 252 | "in": "body", | ||
| 253 | "required": true, | ||
| 254 | "schema": { | ||
| 255 | "$ref": "#/definitions/models.EditMapImageRequest" | ||
| 256 | } | ||
| 257 | } | ||
| 258 | ], | ||
| 259 | "responses": { | ||
| 260 | "200": { | ||
| 261 | "description": "OK", | ||
| 262 | "schema": { | ||
| 263 | "allOf": [ | ||
| 264 | { | ||
| 265 | "$ref": "#/definitions/models.Response" | ||
| 266 | }, | ||
| 267 | { | ||
| 268 | "type": "object", | ||
| 269 | "properties": { | ||
| 270 | "data": { | ||
| 271 | "$ref": "#/definitions/models.EditMapImageRequest" | ||
| 272 | } | ||
| 273 | } | ||
| 274 | } | ||
| 275 | ] | ||
| 276 | } | ||
| 277 | }, | ||
| 278 | "400": { | ||
| 279 | "description": "Bad Request", | ||
| 280 | "schema": { | ||
| 281 | "$ref": "#/definitions/models.Response" | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | }, | ||
| 262 | "/maps/{id}/leaderboards": { | 287 | "/maps/{id}/leaderboards": { |
| 263 | "get": { | 288 | "get": { |
| 289 | "description": "Get map leaderboards with specified id.", | ||
| 264 | "produces": [ | 290 | "produces": [ |
| 265 | "application/json" | 291 | "application/json" |
| 266 | ], | 292 | ], |
| 267 | "tags": [ | 293 | "tags": [ |
| 268 | "maps" | 294 | "maps" |
| 269 | ], | 295 | ], |
| 270 | "summary": "Get map leaderboards with specified id.", | ||
| 271 | "parameters": [ | 296 | "parameters": [ |
| 272 | { | 297 | { |
| 273 | "type": "integer", | 298 | "type": "integer", |
| @@ -319,6 +344,7 @@ | |||
| 319 | }, | 344 | }, |
| 320 | "/maps/{id}/record": { | 345 | "/maps/{id}/record": { |
| 321 | "post": { | 346 | "post": { |
| 347 | "description": "Post record with demo of a specific map.", | ||
| 322 | "consumes": [ | 348 | "consumes": [ |
| 323 | "multipart/form-data" | 349 | "multipart/form-data" |
| 324 | ], | 350 | ], |
| @@ -328,9 +354,15 @@ | |||
| 328 | "tags": [ | 354 | "tags": [ |
| 329 | "maps" | 355 | "maps" |
| 330 | ], | 356 | ], |
| 331 | "summary": "Post record with demo of a specific map.", | ||
| 332 | "parameters": [ | 357 | "parameters": [ |
| 333 | { | 358 | { |
| 359 | "type": "integer", | ||
| 360 | "description": "Map ID", | ||
| 361 | "name": "id", | ||
| 362 | "in": "path", | ||
| 363 | "required": true | ||
| 364 | }, | ||
| 365 | { | ||
| 334 | "type": "string", | 366 | "type": "string", |
| 335 | "description": "JWT Token", | 367 | "description": "JWT Token", |
| 336 | "name": "Authorization", | 368 | "name": "Authorization", |
| @@ -338,42 +370,29 @@ | |||
| 338 | "required": true | 370 | "required": true |
| 339 | }, | 371 | }, |
| 340 | { | 372 | { |
| 341 | "type": "array", | 373 | "type": "file", |
| 342 | "items": { | 374 | "description": "Host Demo", |
| 343 | "type": "file" | 375 | "name": "host_demo", |
| 344 | }, | ||
| 345 | "description": "Demos", | ||
| 346 | "name": "demos", | ||
| 347 | "in": "formData", | 376 | "in": "formData", |
| 348 | "required": true | 377 | "required": true |
| 349 | }, | 378 | }, |
| 350 | { | 379 | { |
| 351 | "type": "integer", | 380 | "type": "file", |
| 352 | "description": "Score Count", | 381 | "description": "Partner Demo", |
| 353 | "name": "score_count", | 382 | "name": "partner_demo", |
| 354 | "in": "formData", | 383 | "in": "formData" |
| 355 | "required": true | ||
| 356 | }, | ||
| 357 | { | ||
| 358 | "type": "integer", | ||
| 359 | "description": "Score Time", | ||
| 360 | "name": "score_time", | ||
| 361 | "in": "formData", | ||
| 362 | "required": true | ||
| 363 | }, | 384 | }, |
| 364 | { | 385 | { |
| 365 | "type": "boolean", | 386 | "type": "boolean", |
| 366 | "description": "Is Partner Orange", | 387 | "description": "Is Partner Orange", |
| 367 | "name": "is_partner_orange", | 388 | "name": "is_partner_orange", |
| 368 | "in": "formData", | 389 | "in": "formData" |
| 369 | "required": true | ||
| 370 | }, | 390 | }, |
| 371 | { | 391 | { |
| 372 | "type": "string", | 392 | "type": "string", |
| 373 | "description": "Partner ID", | 393 | "description": "Partner ID", |
| 374 | "name": "partner_id", | 394 | "name": "partner_id", |
| 375 | "in": "formData", | 395 | "in": "formData" |
| 376 | "required": true | ||
| 377 | } | 396 | } |
| 378 | ], | 397 | ], |
| 379 | "responses": { | 398 | "responses": { |
| @@ -388,7 +407,7 @@ | |||
| 388 | "type": "object", | 407 | "type": "object", |
| 389 | "properties": { | 408 | "properties": { |
| 390 | "data": { | 409 | "data": { |
| 391 | "$ref": "#/definitions/models.RecordRequest" | 410 | "$ref": "#/definitions/models.RecordResponse" |
| 392 | } | 411 | } |
| 393 | } | 412 | } |
| 394 | } | 413 | } |
| @@ -412,13 +431,13 @@ | |||
| 412 | }, | 431 | }, |
| 413 | "/maps/{id}/summary": { | 432 | "/maps/{id}/summary": { |
| 414 | "get": { | 433 | "get": { |
| 434 | "description": "Get map summary with specified id.", | ||
| 415 | "produces": [ | 435 | "produces": [ |
| 416 | "application/json" | 436 | "application/json" |
| 417 | ], | 437 | ], |
| 418 | "tags": [ | 438 | "tags": [ |
| 419 | "maps" | 439 | "maps" |
| 420 | ], | 440 | ], |
| 421 | "summary": "Get map summary with specified id.", | ||
| 422 | "parameters": [ | 441 | "parameters": [ |
| 423 | { | 442 | { |
| 424 | "type": "integer", | 443 | "type": "integer", |
| @@ -440,19 +459,187 @@ | |||
| 440 | "type": "object", | 459 | "type": "object", |
| 441 | "properties": { | 460 | "properties": { |
| 442 | "data": { | 461 | "data": { |
| 443 | "allOf": [ | 462 | "$ref": "#/definitions/models.MapSummaryResponse" |
| 444 | { | 463 | } |
| 445 | "$ref": "#/definitions/models.Map" | 464 | } |
| 446 | }, | 465 | } |
| 447 | { | 466 | ] |
| 448 | "type": "object", | 467 | } |
| 449 | "properties": { | 468 | }, |
| 450 | "data": { | 469 | "400": { |
| 451 | "$ref": "#/definitions/models.MapSummary" | 470 | "description": "Bad Request", |
| 452 | } | 471 | "schema": { |
| 453 | } | 472 | "$ref": "#/definitions/models.Response" |
| 454 | } | 473 | } |
| 455 | ] | 474 | } |
| 475 | } | ||
| 476 | }, | ||
| 477 | "put": { | ||
| 478 | "description": "Edit map summary with specified map id.", | ||
| 479 | "produces": [ | ||
| 480 | "application/json" | ||
| 481 | ], | ||
| 482 | "tags": [ | ||
| 483 | "maps" | ||
| 484 | ], | ||
| 485 | "parameters": [ | ||
| 486 | { | ||
| 487 | "type": "string", | ||
| 488 | "description": "JWT Token", | ||
| 489 | "name": "Authorization", | ||
| 490 | "in": "header", | ||
| 491 | "required": true | ||
| 492 | }, | ||
| 493 | { | ||
| 494 | "type": "integer", | ||
| 495 | "description": "Map ID", | ||
| 496 | "name": "id", | ||
| 497 | "in": "path", | ||
| 498 | "required": true | ||
| 499 | }, | ||
| 500 | { | ||
| 501 | "description": "Body", | ||
| 502 | "name": "request", | ||
| 503 | "in": "body", | ||
| 504 | "required": true, | ||
| 505 | "schema": { | ||
| 506 | "$ref": "#/definitions/models.EditMapSummaryRequest" | ||
| 507 | } | ||
| 508 | } | ||
| 509 | ], | ||
| 510 | "responses": { | ||
| 511 | "200": { | ||
| 512 | "description": "OK", | ||
| 513 | "schema": { | ||
| 514 | "allOf": [ | ||
| 515 | { | ||
| 516 | "$ref": "#/definitions/models.Response" | ||
| 517 | }, | ||
| 518 | { | ||
| 519 | "type": "object", | ||
| 520 | "properties": { | ||
| 521 | "data": { | ||
| 522 | "$ref": "#/definitions/models.EditMapSummaryRequest" | ||
| 523 | } | ||
| 524 | } | ||
| 525 | } | ||
| 526 | ] | ||
| 527 | } | ||
| 528 | }, | ||
| 529 | "400": { | ||
| 530 | "description": "Bad Request", | ||
| 531 | "schema": { | ||
| 532 | "$ref": "#/definitions/models.Response" | ||
| 533 | } | ||
| 534 | } | ||
| 535 | } | ||
| 536 | }, | ||
| 537 | "post": { | ||
| 538 | "description": "Create map summary with specified map id.", | ||
| 539 | "produces": [ | ||
| 540 | "application/json" | ||
| 541 | ], | ||
| 542 | "tags": [ | ||
| 543 | "maps" | ||
| 544 | ], | ||
| 545 | "parameters": [ | ||
| 546 | { | ||
| 547 | "type": "string", | ||
| 548 | "description": "JWT Token", | ||
| 549 | "name": "Authorization", | ||
| 550 | "in": "header", | ||
| 551 | "required": true | ||
| 552 | }, | ||
| 553 | { | ||
| 554 | "type": "integer", | ||
| 555 | "description": "Map ID", | ||
| 556 | "name": "id", | ||
| 557 | "in": "path", | ||
| 558 | "required": true | ||
| 559 | }, | ||
| 560 | { | ||
| 561 | "description": "Body", | ||
| 562 | "name": "request", | ||
| 563 | "in": "body", | ||
| 564 | "required": true, | ||
| 565 | "schema": { | ||
| 566 | "$ref": "#/definitions/models.CreateMapSummaryRequest" | ||
| 567 | } | ||
| 568 | } | ||
| 569 | ], | ||
| 570 | "responses": { | ||
| 571 | "200": { | ||
| 572 | "description": "OK", | ||
| 573 | "schema": { | ||
| 574 | "allOf": [ | ||
| 575 | { | ||
| 576 | "$ref": "#/definitions/models.Response" | ||
| 577 | }, | ||
| 578 | { | ||
| 579 | "type": "object", | ||
| 580 | "properties": { | ||
| 581 | "data": { | ||
| 582 | "$ref": "#/definitions/models.CreateMapSummaryRequest" | ||
| 583 | } | ||
| 584 | } | ||
| 585 | } | ||
| 586 | ] | ||
| 587 | } | ||
| 588 | }, | ||
| 589 | "400": { | ||
| 590 | "description": "Bad Request", | ||
| 591 | "schema": { | ||
| 592 | "$ref": "#/definitions/models.Response" | ||
| 593 | } | ||
| 594 | } | ||
| 595 | } | ||
| 596 | }, | ||
| 597 | "delete": { | ||
| 598 | "description": "Delete map summary with specified map id.", | ||
| 599 | "produces": [ | ||
| 600 | "application/json" | ||
| 601 | ], | ||
| 602 | "tags": [ | ||
| 603 | "maps" | ||
| 604 | ], | ||
| 605 | "parameters": [ | ||
| 606 | { | ||
| 607 | "type": "string", | ||
| 608 | "description": "JWT Token", | ||
| 609 | "name": "Authorization", | ||
| 610 | "in": "header", | ||
| 611 | "required": true | ||
| 612 | }, | ||
| 613 | { | ||
| 614 | "type": "integer", | ||
| 615 | "description": "Map ID", | ||
| 616 | "name": "id", | ||
| 617 | "in": "path", | ||
| 618 | "required": true | ||
| 619 | }, | ||
| 620 | { | ||
| 621 | "description": "Body", | ||
| 622 | "name": "request", | ||
| 623 | "in": "body", | ||
| 624 | "required": true, | ||
| 625 | "schema": { | ||
| 626 | "$ref": "#/definitions/models.DeleteMapSummaryRequest" | ||
| 627 | } | ||
| 628 | } | ||
| 629 | ], | ||
| 630 | "responses": { | ||
| 631 | "200": { | ||
| 632 | "description": "OK", | ||
| 633 | "schema": { | ||
| 634 | "allOf": [ | ||
| 635 | { | ||
| 636 | "$ref": "#/definitions/models.Response" | ||
| 637 | }, | ||
| 638 | { | ||
| 639 | "type": "object", | ||
| 640 | "properties": { | ||
| 641 | "data": { | ||
| 642 | "$ref": "#/definitions/models.DeleteMapSummaryRequest" | ||
| 456 | } | 643 | } |
| 457 | } | 644 | } |
| 458 | } | 645 | } |
| @@ -470,6 +657,7 @@ | |||
| 470 | }, | 657 | }, |
| 471 | "/profile": { | 658 | "/profile": { |
| 472 | "get": { | 659 | "get": { |
| 660 | "description": "Get profile page of session user.", | ||
| 473 | "consumes": [ | 661 | "consumes": [ |
| 474 | "application/json" | 662 | "application/json" |
| 475 | ], | 663 | ], |
| @@ -479,7 +667,6 @@ | |||
| 479 | "tags": [ | 667 | "tags": [ |
| 480 | "users" | 668 | "users" |
| 481 | ], | 669 | ], |
| 482 | "summary": "Get profile page of session user.", | ||
| 483 | "parameters": [ | 670 | "parameters": [ |
| 484 | { | 671 | { |
| 485 | "type": "string", | 672 | "type": "string", |
| @@ -523,6 +710,7 @@ | |||
| 523 | } | 710 | } |
| 524 | }, | 711 | }, |
| 525 | "put": { | 712 | "put": { |
| 713 | "description": "Update country code of session user.", | ||
| 526 | "consumes": [ | 714 | "consumes": [ |
| 527 | "application/json" | 715 | "application/json" |
| 528 | ], | 716 | ], |
| @@ -532,7 +720,6 @@ | |||
| 532 | "tags": [ | 720 | "tags": [ |
| 533 | "users" | 721 | "users" |
| 534 | ], | 722 | ], |
| 535 | "summary": "Update country code of session user.", | ||
| 536 | "parameters": [ | 723 | "parameters": [ |
| 537 | { | 724 | { |
| 538 | "type": "string", | 725 | "type": "string", |
| @@ -553,19 +740,7 @@ | |||
| 553 | "200": { | 740 | "200": { |
| 554 | "description": "OK", | 741 | "description": "OK", |
| 555 | "schema": { | 742 | "schema": { |
| 556 | "allOf": [ | 743 | "$ref": "#/definitions/models.Response" |
| 557 | { | ||
| 558 | "$ref": "#/definitions/models.Response" | ||
| 559 | }, | ||
| 560 | { | ||
| 561 | "type": "object", | ||
| 562 | "properties": { | ||
| 563 | "data": { | ||
| 564 | "$ref": "#/definitions/models.ProfileResponse" | ||
| 565 | } | ||
| 566 | } | ||
| 567 | } | ||
| 568 | ] | ||
| 569 | } | 744 | } |
| 570 | }, | 745 | }, |
| 571 | "400": { | 746 | "400": { |
| @@ -583,6 +758,7 @@ | |||
| 583 | } | 758 | } |
| 584 | }, | 759 | }, |
| 585 | "post": { | 760 | "post": { |
| 761 | "description": "Update profile page of session user.", | ||
| 586 | "consumes": [ | 762 | "consumes": [ |
| 587 | "application/json" | 763 | "application/json" |
| 588 | ], | 764 | ], |
| @@ -592,7 +768,6 @@ | |||
| 592 | "tags": [ | 768 | "tags": [ |
| 593 | "users" | 769 | "users" |
| 594 | ], | 770 | ], |
| 595 | "summary": "Update profile page of session user.", | ||
| 596 | "parameters": [ | 771 | "parameters": [ |
| 597 | { | 772 | { |
| 598 | "type": "string", | 773 | "type": "string", |
| @@ -636,15 +811,60 @@ | |||
| 636 | } | 811 | } |
| 637 | } | 812 | } |
| 638 | }, | 813 | }, |
| 814 | "/rankings": { | ||
| 815 | "get": { | ||
| 816 | "description": "Get rankings of every player.", | ||
| 817 | "produces": [ | ||
| 818 | "application/json" | ||
| 819 | ], | ||
| 820 | "tags": [ | ||
| 821 | "rankings" | ||
| 822 | ], | ||
| 823 | "responses": { | ||
| 824 | "200": { | ||
| 825 | "description": "OK", | ||
| 826 | "schema": { | ||
| 827 | "allOf": [ | ||
| 828 | { | ||
| 829 | "$ref": "#/definitions/models.Response" | ||
| 830 | }, | ||
| 831 | { | ||
| 832 | "type": "object", | ||
| 833 | "properties": { | ||
| 834 | "data": { | ||
| 835 | "$ref": "#/definitions/models.RankingsResponse" | ||
| 836 | } | ||
| 837 | } | ||
| 838 | } | ||
| 839 | ] | ||
| 840 | } | ||
| 841 | }, | ||
| 842 | "400": { | ||
| 843 | "description": "Bad Request", | ||
| 844 | "schema": { | ||
| 845 | "$ref": "#/definitions/models.Response" | ||
| 846 | } | ||
| 847 | } | ||
| 848 | } | ||
| 849 | } | ||
| 850 | }, | ||
| 639 | "/search": { | 851 | "/search": { |
| 640 | "get": { | 852 | "get": { |
| 853 | "description": "Get all user and map data matching to the query.", | ||
| 641 | "produces": [ | 854 | "produces": [ |
| 642 | "application/json" | 855 | "application/json" |
| 643 | ], | 856 | ], |
| 644 | "tags": [ | 857 | "tags": [ |
| 645 | "search" | 858 | "search" |
| 646 | ], | 859 | ], |
| 647 | "summary": "Get all user and map data.", | 860 | "parameters": [ |
| 861 | { | ||
| 862 | "type": "string", | ||
| 863 | "description": "Search user or map name.", | ||
| 864 | "name": "q", | ||
| 865 | "in": "query" | ||
| 866 | } | ||
| 867 | ], | ||
| 648 | "responses": { | 868 | "responses": { |
| 649 | "200": { | 869 | "200": { |
| 650 | "description": "OK", | 870 | "description": "OK", |
| @@ -675,13 +895,13 @@ | |||
| 675 | }, | 895 | }, |
| 676 | "/token": { | 896 | "/token": { |
| 677 | "get": { | 897 | "get": { |
| 898 | "description": "Gets the token cookie value from the user.", | ||
| 678 | "produces": [ | 899 | "produces": [ |
| 679 | "application/json" | 900 | "application/json" |
| 680 | ], | 901 | ], |
| 681 | "tags": [ | 902 | "tags": [ |
| 682 | "auth" | 903 | "auth" |
| 683 | ], | 904 | ], |
| 684 | "summary": "Gets the token cookie value from the user.", | ||
| 685 | "responses": { | 905 | "responses": { |
| 686 | "200": { | 906 | "200": { |
| 687 | "description": "OK", | 907 | "description": "OK", |
| @@ -710,13 +930,13 @@ | |||
| 710 | } | 930 | } |
| 711 | }, | 931 | }, |
| 712 | "delete": { | 932 | "delete": { |
| 933 | "description": "Deletes the token cookie from the user.", | ||
| 713 | "produces": [ | 934 | "produces": [ |
| 714 | "application/json" | 935 | "application/json" |
| 715 | ], | 936 | ], |
| 716 | "tags": [ | 937 | "tags": [ |
| 717 | "auth" | 938 | "auth" |
| 718 | ], | 939 | ], |
| 719 | "summary": "Deletes the token cookie from the user.", | ||
| 720 | "responses": { | 940 | "responses": { |
| 721 | "200": { | 941 | "200": { |
| 722 | "description": "OK", | 942 | "description": "OK", |
| @@ -747,6 +967,7 @@ | |||
| 747 | }, | 967 | }, |
| 748 | "/users/{id}": { | 968 | "/users/{id}": { |
| 749 | "get": { | 969 | "get": { |
| 970 | "description": "Get profile page of another user.", | ||
| 750 | "consumes": [ | 971 | "consumes": [ |
| 751 | "application/json" | 972 | "application/json" |
| 752 | ], | 973 | ], |
| @@ -756,7 +977,6 @@ | |||
| 756 | "tags": [ | 977 | "tags": [ |
| 757 | "users" | 978 | "users" |
| 758 | ], | 979 | ], |
| 759 | "summary": "Get profile page of another user.", | ||
| 760 | "parameters": [ | 980 | "parameters": [ |
| 761 | { | 981 | { |
| 762 | "type": "integer", | 982 | "type": "integer", |
| @@ -802,6 +1022,17 @@ | |||
| 802 | } | 1022 | } |
| 803 | }, | 1023 | }, |
| 804 | "definitions": { | 1024 | "definitions": { |
| 1025 | "models.Category": { | ||
| 1026 | "type": "object", | ||
| 1027 | "properties": { | ||
| 1028 | "id": { | ||
| 1029 | "type": "integer" | ||
| 1030 | }, | ||
| 1031 | "name": { | ||
| 1032 | "type": "string" | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | }, | ||
| 805 | "models.Chapter": { | 1036 | "models.Chapter": { |
| 806 | "type": "object", | 1037 | "type": "object", |
| 807 | "properties": { | 1038 | "properties": { |
| @@ -841,12 +1072,97 @@ | |||
| 841 | } | 1072 | } |
| 842 | } | 1073 | } |
| 843 | }, | 1074 | }, |
| 1075 | "models.CreateMapSummaryRequest": { | ||
| 1076 | "type": "object", | ||
| 1077 | "required": [ | ||
| 1078 | "category_id", | ||
| 1079 | "description", | ||
| 1080 | "record_date", | ||
| 1081 | "score_count", | ||
| 1082 | "user_name" | ||
| 1083 | ], | ||
| 1084 | "properties": { | ||
| 1085 | "category_id": { | ||
| 1086 | "type": "integer" | ||
| 1087 | }, | ||
| 1088 | "description": { | ||
| 1089 | "type": "string" | ||
| 1090 | }, | ||
| 1091 | "record_date": { | ||
| 1092 | "type": "string" | ||
| 1093 | }, | ||
| 1094 | "score_count": { | ||
| 1095 | "type": "integer" | ||
| 1096 | }, | ||
| 1097 | "showcase": { | ||
| 1098 | "type": "string" | ||
| 1099 | }, | ||
| 1100 | "user_name": { | ||
| 1101 | "type": "string" | ||
| 1102 | } | ||
| 1103 | } | ||
| 1104 | }, | ||
| 1105 | "models.DeleteMapSummaryRequest": { | ||
| 1106 | "type": "object", | ||
| 1107 | "required": [ | ||
| 1108 | "route_id" | ||
| 1109 | ], | ||
| 1110 | "properties": { | ||
| 1111 | "route_id": { | ||
| 1112 | "type": "integer" | ||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | }, | ||
| 1116 | "models.EditMapImageRequest": { | ||
| 1117 | "type": "object", | ||
| 1118 | "required": [ | ||
| 1119 | "image" | ||
| 1120 | ], | ||
| 1121 | "properties": { | ||
| 1122 | "image": { | ||
| 1123 | "type": "string" | ||
| 1124 | } | ||
| 1125 | } | ||
| 1126 | }, | ||
| 1127 | "models.EditMapSummaryRequest": { | ||
| 1128 | "type": "object", | ||
| 1129 | "required": [ | ||
| 1130 | "description", | ||
| 1131 | "record_date", | ||
| 1132 | "route_id", | ||
| 1133 | "score_count", | ||
| 1134 | "user_name" | ||
| 1135 | ], | ||
| 1136 | "properties": { | ||
| 1137 | "description": { | ||
| 1138 | "type": "string" | ||
| 1139 | }, | ||
| 1140 | "record_date": { | ||
| 1141 | "type": "string" | ||
| 1142 | }, | ||
| 1143 | "route_id": { | ||
| 1144 | "type": "integer" | ||
| 1145 | }, | ||
| 1146 | "score_count": { | ||
| 1147 | "type": "integer" | ||
| 1148 | }, | ||
| 1149 | "showcase": { | ||
| 1150 | "type": "string" | ||
| 1151 | }, | ||
| 1152 | "user_name": { | ||
| 1153 | "type": "string" | ||
| 1154 | } | ||
| 1155 | } | ||
| 1156 | }, | ||
| 844 | "models.Game": { | 1157 | "models.Game": { |
| 845 | "type": "object", | 1158 | "type": "object", |
| 846 | "properties": { | 1159 | "properties": { |
| 847 | "id": { | 1160 | "id": { |
| 848 | "type": "integer" | 1161 | "type": "integer" |
| 849 | }, | 1162 | }, |
| 1163 | "is_coop": { | ||
| 1164 | "type": "boolean" | ||
| 1165 | }, | ||
| 850 | "name": { | 1166 | "name": { |
| 851 | "type": "string" | 1167 | "type": "string" |
| 852 | } | 1168 | } |
| @@ -866,32 +1182,20 @@ | |||
| 866 | "chapter_name": { | 1182 | "chapter_name": { |
| 867 | "type": "string" | 1183 | "type": "string" |
| 868 | }, | 1184 | }, |
| 869 | "data": {}, | ||
| 870 | "game_name": { | 1185 | "game_name": { |
| 871 | "type": "string" | 1186 | "type": "string" |
| 872 | }, | 1187 | }, |
| 873 | "id": { | 1188 | "id": { |
| 874 | "type": "integer" | 1189 | "type": "integer" |
| 875 | }, | 1190 | }, |
| 876 | "map_name": { | 1191 | "image": { |
| 877 | "type": "string" | 1192 | "type": "string" |
| 878 | } | ||
| 879 | } | ||
| 880 | }, | ||
| 881 | "models.MapCategoryScores": { | ||
| 882 | "type": "object", | ||
| 883 | "properties": { | ||
| 884 | "any": { | ||
| 885 | "type": "integer" | ||
| 886 | }, | 1193 | }, |
| 887 | "cm": { | 1194 | "is_coop": { |
| 888 | "type": "integer" | 1195 | "type": "boolean" |
| 889 | }, | ||
| 890 | "inbounds_sla": { | ||
| 891 | "type": "integer" | ||
| 892 | }, | 1196 | }, |
| 893 | "no_sla": { | 1197 | "map_name": { |
| 894 | "type": "integer" | 1198 | "type": "string" |
| 895 | } | 1199 | } |
| 896 | } | 1200 | } |
| 897 | }, | 1201 | }, |
| @@ -915,6 +1219,29 @@ | |||
| 915 | "records": {} | 1219 | "records": {} |
| 916 | } | 1220 | } |
| 917 | }, | 1221 | }, |
| 1222 | "models.MapRoute": { | ||
| 1223 | "type": "object", | ||
| 1224 | "properties": { | ||
| 1225 | "category": { | ||
| 1226 | "$ref": "#/definitions/models.Category" | ||
| 1227 | }, | ||
| 1228 | "description": { | ||
| 1229 | "type": "string" | ||
| 1230 | }, | ||
| 1231 | "history": { | ||
| 1232 | "$ref": "#/definitions/models.MapHistory" | ||
| 1233 | }, | ||
| 1234 | "rating": { | ||
| 1235 | "type": "number" | ||
| 1236 | }, | ||
| 1237 | "route_id": { | ||
| 1238 | "type": "integer" | ||
| 1239 | }, | ||
| 1240 | "showcase": { | ||
| 1241 | "type": "string" | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | }, | ||
| 918 | "models.MapShort": { | 1245 | "models.MapShort": { |
| 919 | "type": "object", | 1246 | "type": "object", |
| 920 | "properties": { | 1247 | "properties": { |
| @@ -929,29 +1256,22 @@ | |||
| 929 | "models.MapSummary": { | 1256 | "models.MapSummary": { |
| 930 | "type": "object", | 1257 | "type": "object", |
| 931 | "properties": { | 1258 | "properties": { |
| 932 | "category_scores": { | 1259 | "routes": { |
| 933 | "$ref": "#/definitions/models.MapCategoryScores" | ||
| 934 | }, | ||
| 935 | "description": { | ||
| 936 | "type": "string" | ||
| 937 | }, | ||
| 938 | "history": { | ||
| 939 | "type": "array", | ||
| 940 | "items": { | ||
| 941 | "$ref": "#/definitions/models.MapHistory" | ||
| 942 | } | ||
| 943 | }, | ||
| 944 | "rating": { | ||
| 945 | "type": "number" | ||
| 946 | }, | ||
| 947 | "routers": { | ||
| 948 | "type": "array", | 1260 | "type": "array", |
| 949 | "items": { | 1261 | "items": { |
| 950 | "type": "string" | 1262 | "$ref": "#/definitions/models.MapRoute" |
| 951 | } | 1263 | } |
| 1264 | } | ||
| 1265 | } | ||
| 1266 | }, | ||
| 1267 | "models.MapSummaryResponse": { | ||
| 1268 | "type": "object", | ||
| 1269 | "properties": { | ||
| 1270 | "map": { | ||
| 1271 | "$ref": "#/definitions/models.Map" | ||
| 952 | }, | 1272 | }, |
| 953 | "showcase": { | 1273 | "summary": { |
| 954 | "type": "string" | 1274 | "$ref": "#/definitions/models.MapSummary" |
| 955 | } | 1275 | } |
| 956 | } | 1276 | } |
| 957 | }, | 1277 | }, |
| @@ -1004,21 +1324,9 @@ | |||
| 1004 | } | 1324 | } |
| 1005 | } | 1325 | } |
| 1006 | }, | 1326 | }, |
| 1007 | "models.RecordRequest": { | 1327 | "models.RecordResponse": { |
| 1008 | "type": "object", | 1328 | "type": "object", |
| 1009 | "required": [ | ||
| 1010 | "is_partner_orange", | ||
| 1011 | "partner_id", | ||
| 1012 | "score_count", | ||
| 1013 | "score_time" | ||
| 1014 | ], | ||
| 1015 | "properties": { | 1329 | "properties": { |
| 1016 | "is_partner_orange": { | ||
| 1017 | "type": "boolean" | ||
| 1018 | }, | ||
| 1019 | "partner_id": { | ||
| 1020 | "type": "string" | ||
| 1021 | }, | ||
| 1022 | "score_count": { | 1330 | "score_count": { |
| 1023 | "type": "integer" | 1331 | "type": "integer" |
| 1024 | }, | 1332 | }, |
| @@ -1054,29 +1362,13 @@ | |||
| 1054 | "maps": { | 1362 | "maps": { |
| 1055 | "type": "array", | 1363 | "type": "array", |
| 1056 | "items": { | 1364 | "items": { |
| 1057 | "type": "object", | 1365 | "$ref": "#/definitions/models.MapShort" |
| 1058 | "properties": { | ||
| 1059 | "id": { | ||
| 1060 | "type": "integer" | ||
| 1061 | }, | ||
| 1062 | "name": { | ||
| 1063 | "type": "string" | ||
| 1064 | } | ||
| 1065 | } | ||
| 1066 | } | 1366 | } |
| 1067 | }, | 1367 | }, |
| 1068 | "players": { | 1368 | "players": { |
| 1069 | "type": "array", | 1369 | "type": "array", |
| 1070 | "items": { | 1370 | "items": { |
| 1071 | "type": "object", | 1371 | "$ref": "#/definitions/models.UserShort" |
| 1072 | "properties": { | ||
| 1073 | "steam_id": { | ||
| 1074 | "type": "string" | ||
| 1075 | }, | ||
| 1076 | "user_name": { | ||
| 1077 | "type": "string" | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | } | 1372 | } |
| 1081 | } | 1373 | } |
| 1082 | } | 1374 | } |
| @@ -1094,6 +1386,17 @@ | |||
| 1094 | "type": "string" | 1386 | "type": "string" |
| 1095 | } | 1387 | } |
| 1096 | } | 1388 | } |
| 1389 | }, | ||
| 1390 | "models.UserShort": { | ||
| 1391 | "type": "object", | ||
| 1392 | "properties": { | ||
| 1393 | "steam_id": { | ||
| 1394 | "type": "string" | ||
| 1395 | }, | ||
| 1396 | "user_name": { | ||
| 1397 | "type": "string" | ||
| 1398 | } | ||
| 1399 | } | ||
| 1097 | } | 1400 | } |
| 1098 | } | 1401 | } |
| 1099 | } \ No newline at end of file | 1402 | } \ No newline at end of file |
diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d62b46b..7571073 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml | |||
| @@ -1,5 +1,12 @@ | |||
| 1 | basePath: /v1 | 1 | basePath: /v1 |
| 2 | definitions: | 2 | definitions: |
| 3 | models.Category: | ||
| 4 | properties: | ||
| 5 | id: | ||
| 6 | type: integer | ||
| 7 | name: | ||
| 8 | type: string | ||
| 9 | type: object | ||
| 3 | models.Chapter: | 10 | models.Chapter: |
| 4 | properties: | 11 | properties: |
| 5 | id: | 12 | id: |
| @@ -25,10 +32,68 @@ definitions: | |||
| 25 | game: | 32 | game: |
| 26 | $ref: '#/definitions/models.Game' | 33 | $ref: '#/definitions/models.Game' |
| 27 | type: object | 34 | type: object |
| 35 | models.CreateMapSummaryRequest: | ||
| 36 | properties: | ||
| 37 | category_id: | ||
| 38 | type: integer | ||
| 39 | description: | ||
| 40 | type: string | ||
| 41 | record_date: | ||
| 42 | type: string | ||
| 43 | score_count: | ||
| 44 | type: integer | ||
| 45 | showcase: | ||
| 46 | type: string | ||
| 47 | user_name: | ||
| 48 | type: string | ||
| 49 | required: | ||
| 50 | - category_id | ||
| 51 | - description | ||
| 52 | - record_date | ||
| 53 | - score_count | ||
| 54 | - user_name | ||
| 55 | type: object | ||
| 56 | models.DeleteMapSummaryRequest: | ||
| 57 | properties: | ||
| 58 | route_id: | ||
| 59 | type: integer | ||
| 60 | required: | ||
| 61 | - route_id | ||
| 62 | type: object | ||
| 63 | models.EditMapImageRequest: | ||
| 64 | properties: | ||
| 65 | image: | ||
| 66 | type: string | ||
| 67 | required: | ||
| 68 | - image | ||
| 69 | type: object | ||
| 70 | models.EditMapSummaryRequest: | ||
| 71 | properties: | ||
| 72 | description: | ||
| 73 | type: string | ||
| 74 | record_date: | ||
| 75 | type: string | ||
| 76 | route_id: | ||
| 77 | type: integer | ||
| 78 | score_count: | ||
| 79 | type: integer | ||
| 80 | showcase: | ||
| 81 | type: string | ||
| 82 | user_name: | ||
| 83 | type: string | ||
| 84 | required: | ||
| 85 | - description | ||
| 86 | - record_date | ||
| 87 | - route_id | ||
| 88 | - score_count | ||
| 89 | - user_name | ||
| 90 | type: object | ||
| 28 | models.Game: | 91 | models.Game: |
| 29 | properties: | 92 | properties: |
| 30 | id: | 93 | id: |
| 31 | type: integer | 94 | type: integer |
| 95 | is_coop: | ||
| 96 | type: boolean | ||
| 32 | name: | 97 | name: |
| 33 | type: string | 98 | type: string |
| 34 | type: object | 99 | type: object |
| @@ -41,25 +106,17 @@ definitions: | |||
| 41 | properties: | 106 | properties: |
| 42 | chapter_name: | 107 | chapter_name: |
| 43 | type: string | 108 | type: string |
| 44 | data: {} | ||
| 45 | game_name: | 109 | game_name: |
| 46 | type: string | 110 | type: string |
| 47 | id: | 111 | id: |
| 48 | type: integer | 112 | type: integer |
| 113 | image: | ||
| 114 | type: string | ||
| 115 | is_coop: | ||
| 116 | type: boolean | ||
| 49 | map_name: | 117 | map_name: |
| 50 | type: string | 118 | type: string |
| 51 | type: object | 119 | type: object |
| 52 | models.MapCategoryScores: | ||
| 53 | properties: | ||
| 54 | any: | ||
| 55 | type: integer | ||
| 56 | cm: | ||
| 57 | type: integer | ||
| 58 | inbounds_sla: | ||
| 59 | type: integer | ||
| 60 | no_sla: | ||
| 61 | type: integer | ||
| 62 | type: object | ||
| 63 | models.MapHistory: | 120 | models.MapHistory: |
| 64 | properties: | 121 | properties: |
| 65 | date: | 122 | date: |
| @@ -73,6 +130,21 @@ definitions: | |||
| 73 | properties: | 130 | properties: |
| 74 | records: {} | 131 | records: {} |
| 75 | type: object | 132 | type: object |
| 133 | models.MapRoute: | ||
| 134 | properties: | ||
| 135 | category: | ||
| 136 | $ref: '#/definitions/models.Category' | ||
| 137 | description: | ||
| 138 | type: string | ||
| 139 | history: | ||
| 140 | $ref: '#/definitions/models.MapHistory' | ||
| 141 | rating: | ||
| 142 | type: number | ||
| 143 | route_id: | ||
| 144 | type: integer | ||
| 145 | showcase: | ||
| 146 | type: string | ||
| 147 | type: object | ||
| 76 | models.MapShort: | 148 | models.MapShort: |
| 77 | properties: | 149 | properties: |
| 78 | id: | 150 | id: |
| @@ -82,22 +154,17 @@ definitions: | |||
| 82 | type: object | 154 | type: object |
| 83 | models.MapSummary: | 155 | models.MapSummary: |
| 84 | properties: | 156 | properties: |
| 85 | category_scores: | 157 | routes: |
| 86 | $ref: '#/definitions/models.MapCategoryScores' | ||
| 87 | description: | ||
| 88 | type: string | ||
| 89 | history: | ||
| 90 | items: | ||
| 91 | $ref: '#/definitions/models.MapHistory' | ||
| 92 | type: array | ||
| 93 | rating: | ||
| 94 | type: number | ||
| 95 | routers: | ||
| 96 | items: | 158 | items: |
| 97 | type: string | 159 | $ref: '#/definitions/models.MapRoute' |
| 98 | type: array | 160 | type: array |
| 99 | showcase: | 161 | type: object |
| 100 | type: string | 162 | models.MapSummaryResponse: |
| 163 | properties: | ||
| 164 | map: | ||
| 165 | $ref: '#/definitions/models.Map' | ||
| 166 | summary: | ||
| 167 | $ref: '#/definitions/models.MapSummary' | ||
| 101 | type: object | 168 | type: object |
| 102 | models.ProfileResponse: | 169 | models.ProfileResponse: |
| 103 | properties: | 170 | properties: |
| @@ -131,21 +198,12 @@ definitions: | |||
| 131 | $ref: '#/definitions/models.UserRanking' | 198 | $ref: '#/definitions/models.UserRanking' |
| 132 | type: array | 199 | type: array |
| 133 | type: object | 200 | type: object |
| 134 | models.RecordRequest: | 201 | models.RecordResponse: |
| 135 | properties: | 202 | properties: |
| 136 | is_partner_orange: | ||
| 137 | type: boolean | ||
| 138 | partner_id: | ||
| 139 | type: string | ||
| 140 | score_count: | 203 | score_count: |
| 141 | type: integer | 204 | type: integer |
| 142 | score_time: | 205 | score_time: |
| 143 | type: integer | 206 | type: integer |
| 144 | required: | ||
| 145 | - is_partner_orange | ||
| 146 | - partner_id | ||
| 147 | - score_count | ||
| 148 | - score_time | ||
| 149 | type: object | 207 | type: object |
| 150 | models.Response: | 208 | models.Response: |
| 151 | properties: | 209 | properties: |
| @@ -165,21 +223,11 @@ definitions: | |||
| 165 | properties: | 223 | properties: |
| 166 | maps: | 224 | maps: |
| 167 | items: | 225 | items: |
| 168 | properties: | 226 | $ref: '#/definitions/models.MapShort' |
| 169 | id: | ||
| 170 | type: integer | ||
| 171 | name: | ||
| 172 | type: string | ||
| 173 | type: object | ||
| 174 | type: array | 227 | type: array |
| 175 | players: | 228 | players: |
| 176 | items: | 229 | items: |
| 177 | properties: | 230 | $ref: '#/definitions/models.UserShort' |
| 178 | steam_id: | ||
| 179 | type: string | ||
| 180 | user_name: | ||
| 181 | type: string | ||
| 182 | type: object | ||
| 183 | type: array | 231 | type: array |
| 184 | type: object | 232 | type: object |
| 185 | models.UserRanking: | 233 | models.UserRanking: |
| @@ -191,6 +239,13 @@ definitions: | |||
| 191 | user_name: | 239 | user_name: |
| 192 | type: string | 240 | type: string |
| 193 | type: object | 241 | type: object |
| 242 | models.UserShort: | ||
| 243 | properties: | ||
| 244 | steam_id: | ||
| 245 | type: string | ||
| 246 | user_name: | ||
| 247 | type: string | ||
| 248 | type: object | ||
| 194 | host: lp.ardapektezol.com/api | 249 | host: lp.ardapektezol.com/api |
| 195 | info: | 250 | info: |
| 196 | contact: {} | 251 | contact: {} |
| @@ -203,6 +258,7 @@ info: | |||
| 203 | paths: | 258 | paths: |
| 204 | /chapters/{id}: | 259 | /chapters/{id}: |
| 205 | get: | 260 | get: |
| 261 | description: Get maps from the specified chapter id. | ||
| 206 | parameters: | 262 | parameters: |
| 207 | - description: Chapter ID | 263 | - description: Chapter ID |
| 208 | in: path | 264 | in: path |
| @@ -225,40 +281,19 @@ paths: | |||
| 225 | description: Bad Request | 281 | description: Bad Request |
| 226 | schema: | 282 | schema: |
| 227 | $ref: '#/definitions/models.Response' | 283 | $ref: '#/definitions/models.Response' |
| 228 | summary: Get maps from the specified chapter id. | ||
| 229 | tags: | 284 | tags: |
| 230 | - games & chapters | 285 | - games & chapters |
| 231 | /demo: | ||
| 232 | get: | ||
| 233 | produces: | ||
| 234 | - application/json | ||
| 235 | responses: | ||
| 236 | "200": | ||
| 237 | description: OK | ||
| 238 | schema: | ||
| 239 | allOf: | ||
| 240 | - $ref: '#/definitions/models.Response' | ||
| 241 | - properties: | ||
| 242 | data: | ||
| 243 | $ref: '#/definitions/models.RankingsResponse' | ||
| 244 | type: object | ||
| 245 | "400": | ||
| 246 | description: Bad Request | ||
| 247 | schema: | ||
| 248 | $ref: '#/definitions/models.Response' | ||
| 249 | summary: Get rankings of every player. | ||
| 250 | tags: | ||
| 251 | - rankings | ||
| 252 | /demos: | 286 | /demos: |
| 253 | get: | 287 | get: |
| 254 | consumes: | 288 | consumes: |
| 255 | - application/json | 289 | - application/json |
| 290 | description: Get demo with specified demo uuid. | ||
| 256 | parameters: | 291 | parameters: |
| 257 | - description: Demo UUID | 292 | - description: Demo UUID |
| 258 | in: query | 293 | in: query |
| 259 | name: uuid | 294 | name: uuid |
| 260 | required: true | 295 | required: true |
| 261 | type: integer | 296 | type: string |
| 262 | produces: | 297 | produces: |
| 263 | - application/octet-stream | 298 | - application/octet-stream |
| 264 | responses: | 299 | responses: |
| @@ -270,11 +305,11 @@ paths: | |||
| 270 | description: Bad Request | 305 | description: Bad Request |
| 271 | schema: | 306 | schema: |
| 272 | $ref: '#/definitions/models.Response' | 307 | $ref: '#/definitions/models.Response' |
| 273 | summary: Get demo with specified demo uuid. | ||
| 274 | tags: | 308 | tags: |
| 275 | - demo | 309 | - demo |
| 276 | /games: | 310 | /games: |
| 277 | get: | 311 | get: |
| 312 | description: Get games from the leaderboards. | ||
| 278 | produces: | 313 | produces: |
| 279 | - application/json | 314 | - application/json |
| 280 | responses: | 315 | responses: |
| @@ -293,11 +328,11 @@ paths: | |||
| 293 | description: Bad Request | 328 | description: Bad Request |
| 294 | schema: | 329 | schema: |
| 295 | $ref: '#/definitions/models.Response' | 330 | $ref: '#/definitions/models.Response' |
| 296 | summary: Get games from the leaderboards. | ||
| 297 | tags: | 331 | tags: |
| 298 | - games & chapters | 332 | - games & chapters |
| 299 | /games/{id}: | 333 | /games/{id}: |
| 300 | get: | 334 | get: |
| 335 | description: Get chapters from the specified game id. | ||
| 301 | parameters: | 336 | parameters: |
| 302 | - description: Game ID | 337 | - description: Game ID |
| 303 | in: path | 338 | in: path |
| @@ -320,13 +355,13 @@ paths: | |||
| 320 | description: Bad Request | 355 | description: Bad Request |
| 321 | schema: | 356 | schema: |
| 322 | $ref: '#/definitions/models.Response' | 357 | $ref: '#/definitions/models.Response' |
| 323 | summary: Get chapters from the specified game id. | ||
| 324 | tags: | 358 | tags: |
| 325 | - games & chapters | 359 | - games & chapters |
| 326 | /login: | 360 | /login: |
| 327 | get: | 361 | get: |
| 328 | consumes: | 362 | consumes: |
| 329 | - application/json | 363 | - application/json |
| 364 | description: Get (redirect) login page for Steam auth. | ||
| 330 | produces: | 365 | produces: |
| 331 | - application/json | 366 | - application/json |
| 332 | responses: | 367 | responses: |
| @@ -343,11 +378,49 @@ paths: | |||
| 343 | description: Bad Request | 378 | description: Bad Request |
| 344 | schema: | 379 | schema: |
| 345 | $ref: '#/definitions/models.Response' | 380 | $ref: '#/definitions/models.Response' |
| 346 | summary: Get (redirect) login page for Steam auth. | ||
| 347 | tags: | 381 | tags: |
| 348 | - login | 382 | - login |
| 383 | /maps/{id}/image: | ||
| 384 | put: | ||
| 385 | description: Edit map image with specified map id. | ||
| 386 | parameters: | ||
| 387 | - description: JWT Token | ||
| 388 | in: header | ||
| 389 | name: Authorization | ||
| 390 | required: true | ||
| 391 | type: string | ||
| 392 | - description: Map ID | ||
| 393 | in: path | ||
| 394 | name: id | ||
| 395 | required: true | ||
| 396 | type: integer | ||
| 397 | - description: Body | ||
| 398 | in: body | ||
| 399 | name: request | ||
| 400 | required: true | ||
| 401 | schema: | ||
| 402 | $ref: '#/definitions/models.EditMapImageRequest' | ||
| 403 | produces: | ||
| 404 | - application/json | ||
| 405 | responses: | ||
| 406 | "200": | ||
| 407 | description: OK | ||
| 408 | schema: | ||
| 409 | allOf: | ||
| 410 | - $ref: '#/definitions/models.Response' | ||
| 411 | - properties: | ||
| 412 | data: | ||
| 413 | $ref: '#/definitions/models.EditMapImageRequest' | ||
| 414 | type: object | ||
| 415 | "400": | ||
| 416 | description: Bad Request | ||
| 417 | schema: | ||
| 418 | $ref: '#/definitions/models.Response' | ||
| 419 | tags: | ||
| 420 | - maps | ||
| 349 | /maps/{id}/leaderboards: | 421 | /maps/{id}/leaderboards: |
| 350 | get: | 422 | get: |
| 423 | description: Get map leaderboards with specified id. | ||
| 351 | parameters: | 424 | parameters: |
| 352 | - description: Map ID | 425 | - description: Map ID |
| 353 | in: path | 426 | in: path |
| @@ -375,45 +448,40 @@ paths: | |||
| 375 | description: Bad Request | 448 | description: Bad Request |
| 376 | schema: | 449 | schema: |
| 377 | $ref: '#/definitions/models.Response' | 450 | $ref: '#/definitions/models.Response' |
| 378 | summary: Get map leaderboards with specified id. | ||
| 379 | tags: | 451 | tags: |
| 380 | - maps | 452 | - maps |
| 381 | /maps/{id}/record: | 453 | /maps/{id}/record: |
| 382 | post: | 454 | post: |
| 383 | consumes: | 455 | consumes: |
| 384 | - multipart/form-data | 456 | - multipart/form-data |
| 457 | description: Post record with demo of a specific map. | ||
| 385 | parameters: | 458 | parameters: |
| 459 | - description: Map ID | ||
| 460 | in: path | ||
| 461 | name: id | ||
| 462 | required: true | ||
| 463 | type: integer | ||
| 386 | - description: JWT Token | 464 | - description: JWT Token |
| 387 | in: header | 465 | in: header |
| 388 | name: Authorization | 466 | name: Authorization |
| 389 | required: true | 467 | required: true |
| 390 | type: string | 468 | type: string |
| 391 | - description: Demos | 469 | - description: Host Demo |
| 392 | in: formData | 470 | in: formData |
| 393 | items: | 471 | name: host_demo |
| 394 | type: file | ||
| 395 | name: demos | ||
| 396 | required: true | 472 | required: true |
| 397 | type: array | 473 | type: file |
| 398 | - description: Score Count | 474 | - description: Partner Demo |
| 399 | in: formData | 475 | in: formData |
| 400 | name: score_count | 476 | name: partner_demo |
| 401 | required: true | 477 | type: file |
| 402 | type: integer | ||
| 403 | - description: Score Time | ||
| 404 | in: formData | ||
| 405 | name: score_time | ||
| 406 | required: true | ||
| 407 | type: integer | ||
| 408 | - description: Is Partner Orange | 478 | - description: Is Partner Orange |
| 409 | in: formData | 479 | in: formData |
| 410 | name: is_partner_orange | 480 | name: is_partner_orange |
| 411 | required: true | ||
| 412 | type: boolean | 481 | type: boolean |
| 413 | - description: Partner ID | 482 | - description: Partner ID |
| 414 | in: formData | 483 | in: formData |
| 415 | name: partner_id | 484 | name: partner_id |
| 416 | required: true | ||
| 417 | type: string | 485 | type: string |
| 418 | produces: | 486 | produces: |
| 419 | - application/json | 487 | - application/json |
| @@ -425,7 +493,7 @@ paths: | |||
| 425 | - $ref: '#/definitions/models.Response' | 493 | - $ref: '#/definitions/models.Response' |
| 426 | - properties: | 494 | - properties: |
| 427 | data: | 495 | data: |
| 428 | $ref: '#/definitions/models.RecordRequest' | 496 | $ref: '#/definitions/models.RecordResponse' |
| 429 | type: object | 497 | type: object |
| 430 | "400": | 498 | "400": |
| 431 | description: Bad Request | 499 | description: Bad Request |
| @@ -435,11 +503,48 @@ paths: | |||
| 435 | description: Unauthorized | 503 | description: Unauthorized |
| 436 | schema: | 504 | schema: |
| 437 | $ref: '#/definitions/models.Response' | 505 | $ref: '#/definitions/models.Response' |
| 438 | summary: Post record with demo of a specific map. | ||
| 439 | tags: | 506 | tags: |
| 440 | - maps | 507 | - maps |
| 441 | /maps/{id}/summary: | 508 | /maps/{id}/summary: |
| 509 | delete: | ||
| 510 | description: Delete map summary with specified map id. | ||
| 511 | parameters: | ||
| 512 | - description: JWT Token | ||
| 513 | in: header | ||
| 514 | name: Authorization | ||
| 515 | required: true | ||
| 516 | type: string | ||
| 517 | - description: Map ID | ||
| 518 | in: path | ||
| 519 | name: id | ||
| 520 | required: true | ||
| 521 | type: integer | ||
| 522 | - description: Body | ||
| 523 | in: body | ||
| 524 | name: request | ||
| 525 | required: true | ||
| 526 | schema: | ||
| 527 | $ref: '#/definitions/models.DeleteMapSummaryRequest' | ||
| 528 | produces: | ||
| 529 | - application/json | ||
| 530 | responses: | ||
| 531 | "200": | ||
| 532 | description: OK | ||
| 533 | schema: | ||
| 534 | allOf: | ||
| 535 | - $ref: '#/definitions/models.Response' | ||
| 536 | - properties: | ||
| 537 | data: | ||
| 538 | $ref: '#/definitions/models.DeleteMapSummaryRequest' | ||
| 539 | type: object | ||
| 540 | "400": | ||
| 541 | description: Bad Request | ||
| 542 | schema: | ||
| 543 | $ref: '#/definitions/models.Response' | ||
| 544 | tags: | ||
| 545 | - maps | ||
| 442 | get: | 546 | get: |
| 547 | description: Get map summary with specified id. | ||
| 443 | parameters: | 548 | parameters: |
| 444 | - description: Map ID | 549 | - description: Map ID |
| 445 | in: path | 550 | in: path |
| @@ -456,24 +561,93 @@ paths: | |||
| 456 | - $ref: '#/definitions/models.Response' | 561 | - $ref: '#/definitions/models.Response' |
| 457 | - properties: | 562 | - properties: |
| 458 | data: | 563 | data: |
| 459 | allOf: | 564 | $ref: '#/definitions/models.MapSummaryResponse' |
| 460 | - $ref: '#/definitions/models.Map' | 565 | type: object |
| 461 | - properties: | 566 | "400": |
| 462 | data: | 567 | description: Bad Request |
| 463 | $ref: '#/definitions/models.MapSummary' | 568 | schema: |
| 464 | type: object | 569 | $ref: '#/definitions/models.Response' |
| 570 | tags: | ||
| 571 | - maps | ||
| 572 | post: | ||
| 573 | description: Create map summary with specified map id. | ||
| 574 | parameters: | ||
| 575 | - description: JWT Token | ||
| 576 | in: header | ||
| 577 | name: Authorization | ||
| 578 | required: true | ||
| 579 | type: string | ||
| 580 | - description: Map ID | ||
| 581 | in: path | ||
| 582 | name: id | ||
| 583 | required: true | ||
| 584 | type: integer | ||
| 585 | - description: Body | ||
| 586 | in: body | ||
| 587 | name: request | ||
| 588 | required: true | ||
| 589 | schema: | ||
| 590 | $ref: '#/definitions/models.CreateMapSummaryRequest' | ||
| 591 | produces: | ||
| 592 | - application/json | ||
| 593 | responses: | ||
| 594 | "200": | ||
| 595 | description: OK | ||
| 596 | schema: | ||
| 597 | allOf: | ||
| 598 | - $ref: '#/definitions/models.Response' | ||
| 599 | - properties: | ||
| 600 | data: | ||
| 601 | $ref: '#/definitions/models.CreateMapSummaryRequest' | ||
| 602 | type: object | ||
| 603 | "400": | ||
| 604 | description: Bad Request | ||
| 605 | schema: | ||
| 606 | $ref: '#/definitions/models.Response' | ||
| 607 | tags: | ||
| 608 | - maps | ||
| 609 | put: | ||
| 610 | description: Edit map summary with specified map id. | ||
| 611 | parameters: | ||
| 612 | - description: JWT Token | ||
| 613 | in: header | ||
| 614 | name: Authorization | ||
| 615 | required: true | ||
| 616 | type: string | ||
| 617 | - description: Map ID | ||
| 618 | in: path | ||
| 619 | name: id | ||
| 620 | required: true | ||
| 621 | type: integer | ||
| 622 | - description: Body | ||
| 623 | in: body | ||
| 624 | name: request | ||
| 625 | required: true | ||
| 626 | schema: | ||
| 627 | $ref: '#/definitions/models.EditMapSummaryRequest' | ||
| 628 | produces: | ||
| 629 | - application/json | ||
| 630 | responses: | ||
| 631 | "200": | ||
| 632 | description: OK | ||
| 633 | schema: | ||
| 634 | allOf: | ||
| 635 | - $ref: '#/definitions/models.Response' | ||
| 636 | - properties: | ||
| 637 | data: | ||
| 638 | $ref: '#/definitions/models.EditMapSummaryRequest' | ||
| 465 | type: object | 639 | type: object |
| 466 | "400": | 640 | "400": |
| 467 | description: Bad Request | 641 | description: Bad Request |
| 468 | schema: | 642 | schema: |
| 469 | $ref: '#/definitions/models.Response' | 643 | $ref: '#/definitions/models.Response' |
| 470 | summary: Get map summary with specified id. | ||
| 471 | tags: | 644 | tags: |
| 472 | - maps | 645 | - maps |
| 473 | /profile: | 646 | /profile: |
| 474 | get: | 647 | get: |
| 475 | consumes: | 648 | consumes: |
| 476 | - application/json | 649 | - application/json |
| 650 | description: Get profile page of session user. | ||
| 477 | parameters: | 651 | parameters: |
| 478 | - description: JWT Token | 652 | - description: JWT Token |
| 479 | in: header | 653 | in: header |
| @@ -500,12 +674,12 @@ paths: | |||
| 500 | description: Unauthorized | 674 | description: Unauthorized |
| 501 | schema: | 675 | schema: |
| 502 | $ref: '#/definitions/models.Response' | 676 | $ref: '#/definitions/models.Response' |
| 503 | summary: Get profile page of session user. | ||
| 504 | tags: | 677 | tags: |
| 505 | - users | 678 | - users |
| 506 | post: | 679 | post: |
| 507 | consumes: | 680 | consumes: |
| 508 | - application/json | 681 | - application/json |
| 682 | description: Update profile page of session user. | ||
| 509 | parameters: | 683 | parameters: |
| 510 | - description: JWT Token | 684 | - description: JWT Token |
| 511 | in: header | 685 | in: header |
| @@ -532,12 +706,12 @@ paths: | |||
| 532 | description: Unauthorized | 706 | description: Unauthorized |
| 533 | schema: | 707 | schema: |
| 534 | $ref: '#/definitions/models.Response' | 708 | $ref: '#/definitions/models.Response' |
| 535 | summary: Update profile page of session user. | ||
| 536 | tags: | 709 | tags: |
| 537 | - users | 710 | - users |
| 538 | put: | 711 | put: |
| 539 | consumes: | 712 | consumes: |
| 540 | - application/json | 713 | - application/json |
| 714 | description: Update country code of session user. | ||
| 541 | parameters: | 715 | parameters: |
| 542 | - description: JWT Token | 716 | - description: JWT Token |
| 543 | in: header | 717 | in: header |
| @@ -555,12 +729,7 @@ paths: | |||
| 555 | "200": | 729 | "200": |
| 556 | description: OK | 730 | description: OK |
| 557 | schema: | 731 | schema: |
| 558 | allOf: | 732 | $ref: '#/definitions/models.Response' |
| 559 | - $ref: '#/definitions/models.Response' | ||
| 560 | - properties: | ||
| 561 | data: | ||
| 562 | $ref: '#/definitions/models.ProfileResponse' | ||
| 563 | type: object | ||
| 564 | "400": | 733 | "400": |
| 565 | description: Bad Request | 734 | description: Bad Request |
| 566 | schema: | 735 | schema: |
| @@ -569,11 +738,37 @@ paths: | |||
| 569 | description: Unauthorized | 738 | description: Unauthorized |
| 570 | schema: | 739 | schema: |
| 571 | $ref: '#/definitions/models.Response' | 740 | $ref: '#/definitions/models.Response' |
| 572 | summary: Update country code of session user. | ||
| 573 | tags: | 741 | tags: |
| 574 | - users | 742 | - users |
| 743 | /rankings: | ||
| 744 | get: | ||
| 745 | description: Get rankings of every player. | ||
| 746 | produces: | ||
| 747 | - application/json | ||
| 748 | responses: | ||
| 749 | "200": | ||
| 750 | description: OK | ||
| 751 | schema: | ||
| 752 | allOf: | ||
| 753 | - $ref: '#/definitions/models.Response' | ||
| 754 | - properties: | ||
| 755 | data: | ||
| 756 | $ref: '#/definitions/models.RankingsResponse' | ||
| 757 | type: object | ||
| 758 | "400": | ||
| 759 | description: Bad Request | ||
| 760 | schema: | ||
| 761 | $ref: '#/definitions/models.Response' | ||
| 762 | tags: | ||
| 763 | - rankings | ||
| 575 | /search: | 764 | /search: |
| 576 | get: | 765 | get: |
| 766 | description: Get all user and map data matching to the query. | ||
| 767 | parameters: | ||
| 768 | - description: Search user or map name. | ||
| 769 | in: query | ||
| 770 | name: q | ||
| 771 | type: string | ||
| 577 | produces: | 772 | produces: |
| 578 | - application/json | 773 | - application/json |
| 579 | responses: | 774 | responses: |
| @@ -590,11 +785,11 @@ paths: | |||
| 590 | description: Bad Request | 785 | description: Bad Request |
| 591 | schema: | 786 | schema: |
| 592 | $ref: '#/definitions/models.Response' | 787 | $ref: '#/definitions/models.Response' |
| 593 | summary: Get all user and map data. | ||
| 594 | tags: | 788 | tags: |
| 595 | - search | 789 | - search |
| 596 | /token: | 790 | /token: |
| 597 | delete: | 791 | delete: |
| 792 | description: Deletes the token cookie from the user. | ||
| 598 | produces: | 793 | produces: |
| 599 | - application/json | 794 | - application/json |
| 600 | responses: | 795 | responses: |
| @@ -611,10 +806,10 @@ paths: | |||
| 611 | description: Not Found | 806 | description: Not Found |
| 612 | schema: | 807 | schema: |
| 613 | $ref: '#/definitions/models.Response' | 808 | $ref: '#/definitions/models.Response' |
| 614 | summary: Deletes the token cookie from the user. | ||
| 615 | tags: | 809 | tags: |
| 616 | - auth | 810 | - auth |
| 617 | get: | 811 | get: |
| 812 | description: Gets the token cookie value from the user. | ||
| 618 | produces: | 813 | produces: |
| 619 | - application/json | 814 | - application/json |
| 620 | responses: | 815 | responses: |
| @@ -631,13 +826,13 @@ paths: | |||
| 631 | description: Not Found | 826 | description: Not Found |
| 632 | schema: | 827 | schema: |
| 633 | $ref: '#/definitions/models.Response' | 828 | $ref: '#/definitions/models.Response' |
| 634 | summary: Gets the token cookie value from the user. | ||
| 635 | tags: | 829 | tags: |
| 636 | - auth | 830 | - auth |
| 637 | /users/{id}: | 831 | /users/{id}: |
| 638 | get: | 832 | get: |
| 639 | consumes: | 833 | consumes: |
| 640 | - application/json | 834 | - application/json |
| 835 | description: Get profile page of another user. | ||
| 641 | parameters: | 836 | parameters: |
| 642 | - description: User ID | 837 | - description: User ID |
| 643 | in: path | 838 | in: path |
| @@ -664,7 +859,6 @@ paths: | |||
| 664 | description: Not Found | 859 | description: Not Found |
| 665 | schema: | 860 | schema: |
| 666 | $ref: '#/definitions/models.Response' | 861 | $ref: '#/definitions/models.Response' |
| 667 | summary: Get profile page of another user. | ||
| 668 | tags: | 862 | tags: |
| 669 | - users | 863 | - users |
| 670 | swagger: "2.0" | 864 | swagger: "2.0" |
| @@ -3,7 +3,6 @@ module github.com/pektezol/leastportals | |||
| 3 | go 1.19 | 3 | go 1.19 |
| 4 | 4 | ||
| 5 | require ( | 5 | require ( |
| 6 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19 | ||
| 7 | github.com/gin-gonic/gin v1.8.1 | 6 | github.com/gin-gonic/gin v1.8.1 |
| 8 | github.com/joho/godotenv v1.4.0 | 7 | github.com/joho/godotenv v1.4.0 |
| 9 | github.com/solovev/steam_go v0.0.0-20170222182106-48eb5aae6c50 | 8 | github.com/solovev/steam_go v0.0.0-20170222182106-48eb5aae6c50 |
| @@ -26,8 +26,6 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d | |||
| 26 | github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= | 26 | github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= |
| 27 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | 27 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= |
| 28 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | 28 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= |
| 29 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19 h1:J2LPEOcQmWaooBnBtUDV9KHFEnP5LYTZY03GiQ0oQBw= | ||
| 30 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg= | ||
| 31 | github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= | 29 | github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= |
| 32 | github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= | 30 | github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= |
| 33 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= | 31 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= |
| @@ -31,8 +31,6 @@ func main() { | |||
| 31 | } | 31 | } |
| 32 | router := gin.Default() | 32 | router := gin.Default() |
| 33 | database.ConnectDB() | 33 | database.ConnectDB() |
| 34 | // For frontend static serving - only for local debug | ||
| 35 | // router.Use(static.Serve("/", static.LocalFile("./frontend/build", true))) | ||
| 36 | routes.InitRoutes(router) | 34 | routes.InitRoutes(router) |
| 37 | router.Run(fmt.Sprintf(":%s", os.Getenv("PORT"))) | 35 | router.Run(fmt.Sprintf(":%s", os.Getenv("PORT"))) |
| 38 | } | 36 | } |