aboutsummaryrefslogtreecommitdiff
path: root/backend/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'backend/controllers')
-rw-r--r--backend/controllers/homeController.go59
-rw-r--r--backend/controllers/loginController.go48
-rw-r--r--backend/controllers/mapController.go146
-rw-r--r--backend/controllers/modController.go327
-rw-r--r--backend/controllers/recordController.go134
-rw-r--r--backend/controllers/userController.go74
6 files changed, 543 insertions, 245 deletions
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
3import ( 3import (
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]
31func Rankings(c *gin.Context) { 32func 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
133func Search(c *gin.Context) { 134// @Router /search [get]
135func 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]
27func Login(c *gin.Context) { 27func 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]
95func GetCookie(c *gin.Context) { 105func 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]
119func DeleteCookie(c *gin.Context) { 129func 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
3import ( 3import (
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]
23func FetchMapSummary(c *gin.Context) { 21func 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]
110func FetchMapLeaderboards(c *gin.Context) { 79func 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]
225func FetchGames(c *gin.Context) { 195func 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]
256func FetchChapters(c *gin.Context) { 226func 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]
298func FetchChapterMaps(c *gin.Context) { 268func 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 @@
1package controllers
2
3import (
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]
23func 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]
109func 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]
195func 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]
285func 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
3import ( 3import (
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]
37func CreateRecordWithDemo(c *gin.Context) { 38func 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]
220func DownloadDemoWithID(c *gin.Context) { 200func 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
262func serviceAccount() *http.Client { 242func 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]
25func Profile(c *gin.Context) { 25func 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]
112func FetchUser(c *gin.Context) { 112func 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]
214func UpdateUser(c *gin.Context) { 214func 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]
258func UpdateCountryCode(c *gin.Context) { 258func 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")