aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-01-06 23:55:12 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-01-06 23:55:12 +0300
commit4820c7696db3c54959258b1a5b00c77e1246cbd7 (patch)
tree179edfca03618395939df1c3afccf2c90c64d424 /backend
parent(#20) successful integration of demo upload to drive (diff)
downloadlphub-4820c7696db3c54959258b1a5b00c77e1246cbd7.tar.gz
lphub-4820c7696db3c54959258b1a5b00c77e1246cbd7.tar.bz2
lphub-4820c7696db3c54959258b1a5b00c77e1246cbd7.zip
what the fuck is this mess (#21)
Diffstat (limited to 'backend')
-rw-r--r--backend/controllers/demoController.go2
-rw-r--r--backend/controllers/homeController.go (renamed from backend/controllers/controllers.go)53
-rw-r--r--backend/controllers/userController.go168
-rw-r--r--backend/database/init.sql52
-rw-r--r--backend/middleware/auth.go19
-rw-r--r--backend/models/models.go25
-rw-r--r--backend/models/responses.go27
-rw-r--r--backend/routes/routes.go2
8 files changed, 144 insertions, 204 deletions
diff --git a/backend/controllers/demoController.go b/backend/controllers/demoController.go
index fdabbae..85f6ede 100644
--- a/backend/controllers/demoController.go
+++ b/backend/controllers/demoController.go
@@ -40,7 +40,7 @@ func UploadDemo(c *gin.Context) {
40 }) 40 })
41 return 41 return
42 }*/ 42 }*/
43 f, err := os.Open("test.txt") 43 f, err := os.Open("pgun_2280.dem")
44 if err != nil { 44 if err != nil {
45 panic(fmt.Sprintf("cannot open file: %v", err)) 45 panic(fmt.Sprintf("cannot open file: %v", err))
46 } 46 }
diff --git a/backend/controllers/controllers.go b/backend/controllers/homeController.go
index 5237ccd..8d81eef 100644
--- a/backend/controllers/controllers.go
+++ b/backend/controllers/homeController.go
@@ -1,7 +1,6 @@
1package controllers 1package controllers
2 2
3import ( 3import (
4 "log"
5 "net/http" 4 "net/http"
6 "os" 5 "os"
7 "time" 6 "time"
@@ -9,6 +8,7 @@ import (
9 "github.com/gin-gonic/gin" 8 "github.com/gin-gonic/gin"
10 "github.com/golang-jwt/jwt/v4" 9 "github.com/golang-jwt/jwt/v4"
11 "github.com/pektezol/leastportals/backend/database" 10 "github.com/pektezol/leastportals/backend/database"
11 "github.com/pektezol/leastportals/backend/models"
12 "github.com/solovev/steam_go" 12 "github.com/solovev/steam_go"
13) 13)
14 14
@@ -33,56 +33,45 @@ func Login(c *gin.Context) {
33 default: 33 default:
34 steamID, err := openID.ValidateAndGetId() 34 steamID, err := openID.ValidateAndGetId()
35 if err != nil { 35 if err != nil {
36 http.Error(c.Writer, err.Error(), http.StatusInternalServerError) 36 c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error()))
37 return
37 } 38 }
38 // Create user if new 39 // Create user if new
39 var checkSteamID int64 40 var checkSteamID int64
40 database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", steamID).Scan(&checkSteamID) 41 err = database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", steamID).Scan(&checkSteamID)
42 if err != nil {
43 c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error()))
44 return
45 }
41 // User does not exist 46 // User does not exist
42 if checkSteamID == 0 { 47 if checkSteamID == 0 {
43 user, err := steam_go.GetPlayerSummaries(steamID, os.Getenv("API_KEY")) 48 user, err := steam_go.GetPlayerSummaries(steamID, os.Getenv("API_KEY"))
44 if err != nil { 49 if err != nil {
45 log.Panic(err) 50 c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error()))
51 return
46 } 52 }
47 // Insert new user to database 53 // Insert new user to database
48 database.DB.Exec(`INSERT INTO users (steam_id, username, avatar_link, country_code, created_at, updated_at, user_type) 54 database.DB.Exec(`INSERT INTO users (steam_id, username, avatar_link, country_code)
49 VALUES ($1, $2, $3, $4, $5, $6, $7)`, steamID, user.PersonaName, user.AvatarFull, user.LocCountryCode, time.Now().UTC(), time.Now().UTC(), 0) 55 VALUES ($1, $2, $3, $4)`, steamID, user.PersonaName, user.AvatarFull, user.LocCountryCode)
50 } 56 }
51 // Update updated_at
52 database.DB.Exec(`UPDATE users SET updated_at = $1 WHERE steam_id = $2`, time.Now().UTC(), steamID)
53 // Generate JWT token 57 // Generate JWT token
54 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ 58 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
55 "sub": steamID, 59 "sub": steamID,
56 "exp": time.Now().Add(time.Hour * 24 * 30).Unix(), 60 "exp": time.Now().Add(time.Hour * 24 * 365).Unix(),
57 }) 61 })
58 // Sign and get the complete encoded token as a string using the secret 62 // Sign and get the complete encoded token as a string using the secret
59 tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY"))) 63 tokenString, err := token.SignedString([]byte(os.Getenv("SECRET_KEY")))
60 if err != nil { 64 if err != nil {
61 c.JSON(http.StatusBadRequest, gin.H{ 65 c.JSON(http.StatusBadRequest, models.ErrorResponse("Failed to generate token."))
62 "error": "failed to create token",
63 })
64 return 66 return
65 } 67 }
66 // Create auth cookie 68 c.JSON(http.StatusOK, models.Response{
67 c.SetSameSite(http.SameSiteLaxMode) 69 Success: true,
68 c.SetCookie("auth", tokenString, 3600*24*30, "/", "", true, true) 70 Message: "Successfully generated token.",
69 c.Redirect(http.StatusMovedPermanently, "/") 71 Data: models.LoginResponse{
70 } 72 Token: tokenString,
71} 73 },
72
73func Logout(c *gin.Context) {
74 // Check if user exists
75 _, exists := c.Get("user")
76 if !exists {
77 c.JSON(http.StatusBadRequest, gin.H{
78 "error": "not logged in",
79 })
80 } else {
81 // Set auth cookie to die
82 tokenString, _ := c.Cookie("auth")
83 c.SetCookie("auth", tokenString, -1, "/", "", true, true)
84 c.JSON(http.StatusOK, gin.H{
85 "output": "logout success",
86 }) 74 })
75 return
87 } 76 }
88} 77}
diff --git a/backend/controllers/userController.go b/backend/controllers/userController.go
index 87a9427..70a2a34 100644
--- a/backend/controllers/userController.go
+++ b/backend/controllers/userController.go
@@ -13,161 +13,57 @@ func Profile(c *gin.Context) {
13 // Check if user exists 13 // Check if user exists
14 user, exists := c.Get("user") 14 user, exists := c.Get("user")
15 if !exists { 15 if !exists {
16 c.JSON(http.StatusUnauthorized, gin.H{ 16 c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in."))
17 "code": http.StatusUnauthorized,
18 "output": gin.H{
19 "error": "User not logged in. Could be invalid token.",
20 },
21 })
22 return
23 } else {
24 user := user.(models.User)
25 c.JSON(http.StatusOK, gin.H{
26 "code": http.StatusOK,
27 "output": gin.H{
28 "avatar": user.AvatarLink,
29 "country": user.CountryCode,
30 "types": user.TypeToString(),
31 "username": user.Username,
32 },
33 "profile": true,
34 })
35 return
36 }
37}
38
39func FetchUser(c *gin.Context) {
40 id := c.Param("id")
41 // Check if id is all numbers and 17 length
42 match, _ := regexp.MatchString("^[0-9]{17}$", id)
43 if !match {
44 c.JSON(http.StatusNotFound, gin.H{
45 "code": http.StatusNotFound,
46 "output": gin.H{
47 "error": "User not found.",
48 },
49 })
50 return
51 }
52 // Check if user exists
53 var targetUser models.User
54 database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, id).Scan(
55 &targetUser.SteamID, &targetUser.Username, &targetUser.AvatarLink, &targetUser.CountryCode,
56 &targetUser.CreatedAt, &targetUser.UpdatedAt, &targetUser.UserType)
57 if targetUser.SteamID == "" {
58 // User does not exist
59 c.JSON(http.StatusNotFound, gin.H{
60 "code": http.StatusNotFound,
61 "output": gin.H{
62 "error": "User not found.",
63 },
64 })
65 return 17 return
66 } 18 }
67 // Target user exists 19 c.JSON(http.StatusOK, models.Response{
68 _, exists := c.Get("user") 20 Success: true,
69 if exists { 21 Message: "",
70 c.Redirect(http.StatusFound, "/api/v1/profile") 22 Data: models.ProfileResponse{
71 return 23 Profile: true,
72 } 24 SteamID: user.(models.User).SteamID,
73 c.JSON(http.StatusOK, gin.H{ 25 Username: user.(models.User).Username,
74 "code": http.StatusOK, 26 AvatarLink: user.(models.User).AvatarLink,
75 "output": gin.H{ 27 CountryCode: user.(models.User).CountryCode,
76 "avatar": targetUser.AvatarLink,
77 "country": targetUser.CountryCode,
78 "types": targetUser.TypeToString(),
79 "username": targetUser.Username,
80 }, 28 },
81 "profile": false,
82 }) 29 })
83 return 30 return
84} 31}
85 32
86/*func UpdateUserCountry(c *gin.Context) { 33func FetchUser(c *gin.Context) {
87 id := c.Param("id") 34 id := c.Param("id")
88 cc := c.Param("country")
89 // Check if id is all numbers and 17 length 35 // Check if id is all numbers and 17 length
90 match, _ := regexp.MatchString("^[0-9]{17}$", id) 36 match, _ := regexp.MatchString("^[0-9]{17}$", id)
91 if !match { 37 if !match {
92 c.JSON(http.StatusNotFound, gin.H{ 38 c.JSON(http.StatusNotFound, models.ErrorResponse("User not found."))
93 "code": http.StatusNotFound,
94 "output": gin.H{
95 "error": "User not found.",
96 },
97 })
98 return
99 }
100 // Check if valid country code length
101 match, _ = regexp.MatchString("^[A-Z]{2}$", cc)
102 if !match {
103 c.JSON(http.StatusNotFound, gin.H{
104 "code": http.StatusNotFound,
105 "output": gin.H{
106 "error": "Invalid country code.",
107 },
108 })
109 return 39 return
110 } 40 }
111 // Check if user exists 41 // Check if user exists
112 var targetUser models.User 42 var user models.User
113 database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, id).Scan( 43 err := database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, id).Scan(
114 &targetUser.SteamID, &targetUser.Username, &targetUser.AvatarLink, &targetUser.CountryCode, 44 &user.SteamID, &user.Username, &user.AvatarLink, &user.CountryCode,
115 &targetUser.CreatedAt, &targetUser.UpdatedAt, &targetUser.UserType) 45 &user.CreatedAt, &user.UpdatedAt)
116 if targetUser.SteamID == "" { 46 if user.SteamID == "" {
117 // User does not exist 47 // User does not exist
118 c.JSON(http.StatusNotFound, gin.H{ 48 c.JSON(http.StatusNotFound, models.ErrorResponse("User not found."))
119 "code": http.StatusNotFound,
120 "output": gin.H{
121 "error": "User not found.",
122 },
123 })
124 return 49 return
125 } 50 }
126 // Target user exists 51 if err != nil {
127 user, exists := c.Get("user") 52 c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error()))
128 if exists {
129 user := user.(models.User)
130 if user.SteamID == targetUser.SteamID {
131 // Can change because it's our own profile
132 // TODO:Check if country code exists in database // ADD countries TABLE
133 var existingCC string
134 database.DB.QueryRow(`SELECT country_code FROM countries WHERE country_code = $1;`, cc).Scan(&existingCC)
135 if existingCC == "" {
136 c.JSON(http.StatusNotFound, gin.H{
137 "code": http.StatusForbidden,
138 "output": gin.H{
139 "error": "Given country code is not found.",
140 },
141 })
142 return
143 }
144 // Valid to change
145 database.DB.Exec(`UPDATE users SET country_code = $1 WHERE steam_id = $2`, cc, user.SteamID)
146 c.JSON(http.StatusOK, gin.H{
147 "code": http.StatusOK,
148 "output": gin.H{
149 "avatar": user.AvatarLink,
150 "country": user.CountryCode,
151 "types": user.TypeToString(),
152 "username": user.Username,
153 },
154 "profile": true,
155 })
156 return
157 }
158 c.JSON(http.StatusForbidden, gin.H{
159 "code": http.StatusForbidden,
160 "output": gin.H{
161 "error": "Can not change country of another user.",
162 },
163 })
164 return 53 return
165 } 54 }
166 c.JSON(http.StatusUnauthorized, gin.H{ 55 // Target user exists
167 "code": http.StatusUnauthorized, 56 _, exists := c.Get("user")
168 "output": gin.H{ 57 c.JSON(http.StatusOK, models.Response{
169 "error": "User not logged in. Could be invalid token.", 58 Success: true,
59 Message: "",
60 Data: models.ProfileResponse{
61 Profile: exists,
62 SteamID: user.SteamID,
63 Username: user.Username,
64 AvatarLink: user.AvatarLink,
65 CountryCode: user.CountryCode,
170 }, 66 },
171 }) 67 })
172 return 68 return
173}*/ 69}
diff --git a/backend/database/init.sql b/backend/database/init.sql
index e877db3..1585e33 100644
--- a/backend/database/init.sql
+++ b/backend/database/init.sql
@@ -1,11 +1,51 @@
1DROP TABLE IF EXISTS showcases;
2DROP TABLE IF EXISTS titles;
3DROP TABLE IF EXISTS records;
4DROP TABLE IF EXISTS maps;
1DROP TABLE IF EXISTS users; 5DROP TABLE IF EXISTS users;
6
2CREATE TABLE users ( 7CREATE TABLE users (
3 steam_id BIGINT, 8 steam_id TEXT,
4 username VARCHAR(128) NOT NULL, 9 username TEXT NOT NULL,
5 avatar_link VARCHAR(128) NOT NULL, 10 avatar_link TEXT NOT NULL,
6 country_code CHAR(2) NOT NULL DEFAULT 'XX', 11 country_code CHAR(2) NOT NULL DEFAULT 'XX',
7 created_at TIMESTAMP NOT NULL, 12 created_at TIMESTAMP NOT NULL DEFAULT now(),
8 updated_at TIMESTAMP, 13 updated_at TIMESTAMP NOT NULL DEFAULT now(),
9 user_type SMALLINT NOT NULL,
10 PRIMARY KEY (steam_id) 14 PRIMARY KEY (steam_id)
15);
16
17CREATE TABLE maps (
18 id SMALLSERIAL,
19 map_name TEXT NOT NULL,
20 wr_score SMALLINT NOT NULL,
21 is_coop BOOLEAN NOT NULL,
22 PRIMARY KEY (id)
23);
24
25CREATE TABLE records (
26 id SERIAL,
27 map_id SMALLINT,
28 host_id TEXT NOT NULL,
29 score_count SMALLINT NOT NULL,
30 score_time INTEGER NOT NULL,
31 is_coop BOOLEAN NOT NULL DEFAULT false,
32 partner_id TEXT NOT NULL DEFAULT '',
33 PRIMARY KEY (id),
34 FOREIGN KEY (map_id) REFERENCES maps(id),
35 FOREIGN KEY (host_id) REFERENCES users(steam_id),
36 FOREIGN KEY (partner_id) REFERENCES users(steam_id)
37);
38
39CREATE TABLE titles (
40 user_id TEXT,
41 title_name TEXT NOT NULL,
42 PRIMARY KEY (user_id),
43 FOREIGN KEY (user_id) REFERENCES users(steam_id)
44);
45
46CREATE TABLE showcases (
47 record_id INT,
48 video_id TEXT NOT NULL,
49 PRIMARY KEY (record_id),
50 FOREIGN KEY (record_id) REFERENCES records(id)
11); \ No newline at end of file 51); \ No newline at end of file
diff --git a/backend/middleware/auth.go b/backend/middleware/auth.go
index 21e62e3..b5ad762 100644
--- a/backend/middleware/auth.go
+++ b/backend/middleware/auth.go
@@ -12,12 +12,7 @@ import (
12) 12)
13 13
14func CheckAuth(c *gin.Context) { 14func CheckAuth(c *gin.Context) {
15 // Get auth cookie 15 tokenString := c.GetHeader("Authorization")
16 tokenString, err := c.Cookie("auth")
17 if err != nil {
18 c.Next()
19 return
20 }
21 // Validate token 16 // Validate token
22 token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { 17 token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
23 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 18 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
@@ -25,6 +20,14 @@ func CheckAuth(c *gin.Context) {
25 } 20 }
26 return []byte(os.Getenv("SECRET_KEY")), nil 21 return []byte(os.Getenv("SECRET_KEY")), nil
27 }) 22 })
23 if token == nil {
24 c.Next()
25 return
26 }
27 if err != nil {
28 c.Next()
29 return
30 }
28 if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { 31 if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
29 // Check exp 32 // Check exp
30 if float64(time.Now().Unix()) > claims["exp"].(float64) { 33 if float64(time.Now().Unix()) > claims["exp"].(float64) {
@@ -34,8 +37,8 @@ func CheckAuth(c *gin.Context) {
34 // Get user from DB 37 // Get user from DB
35 var user models.User 38 var user models.User
36 database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, claims["sub"]).Scan( 39 database.DB.QueryRow(`SELECT * FROM users WHERE steam_id = $1;`, claims["sub"]).Scan(
37 &user.SteamID, &user.Username, &user.AvatarLink, &user.CountryCode, 40 &user.SteamID, &user.Username, &user.AvatarLink,
38 &user.CreatedAt, &user.UpdatedAt, &user.UserType) 41 &user.CountryCode, &user.CreatedAt, &user.UpdatedAt)
39 if user.SteamID == "" { 42 if user.SteamID == "" {
40 c.Next() 43 c.Next()
41 return 44 return
diff --git a/backend/models/models.go b/backend/models/models.go
index 2be8765..c49eaeb 100644
--- a/backend/models/models.go
+++ b/backend/models/models.go
@@ -3,23 +3,10 @@ package models
3import "time" 3import "time"
4 4
5type User struct { 5type User struct {
6 SteamID string 6 SteamID string `json:"steam_id"`
7 Username string 7 Username string `json:"username"`
8 AvatarLink string 8 AvatarLink string `json:"avatar_link"`
9 CountryCode string 9 CountryCode string `json:"country_code"`
10 CreatedAt time.Time 10 CreatedAt time.Time `json:"created_at"`
11 UpdatedAt time.Time 11 UpdatedAt time.Time `json:"updated_at"`
12 UserType int16
13}
14
15func (user *User) TypeToString() []string {
16 var list []string
17 switch user.UserType {
18 case 0:
19 list = append(list, "Normal")
20 }
21 if len(list) == 0 {
22 list = append(list, "Unknown")
23 }
24 return list
25} 12}
diff --git a/backend/models/responses.go b/backend/models/responses.go
new file mode 100644
index 0000000..70ee1b6
--- /dev/null
+++ b/backend/models/responses.go
@@ -0,0 +1,27 @@
1package models
2
3type Response struct {
4 Success bool `json:"success"`
5 Message string `json:"message"`
6 Data any `json:"data"`
7}
8
9type LoginResponse struct {
10 Token string `json:"token"`
11}
12
13type ProfileResponse struct {
14 Profile bool `json:"profile"`
15 SteamID string `json:"steam_id"`
16 Username string `json:"username"`
17 AvatarLink string `json:"avatar_link"`
18 CountryCode string `json:"country_code"`
19}
20
21func ErrorResponse(message string) Response {
22 return Response{
23 Success: false,
24 Message: message,
25 Data: nil,
26 }
27}
diff --git a/backend/routes/routes.go b/backend/routes/routes.go
index 4c6ba87..6ca1d46 100644
--- a/backend/routes/routes.go
+++ b/backend/routes/routes.go
@@ -15,10 +15,8 @@ func InitRoutes(router *gin.Engine) {
15 v1.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) 15 v1.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
16 v1.GET("/", middleware.CheckAuth, controllers.Home) 16 v1.GET("/", middleware.CheckAuth, controllers.Home)
17 v1.GET("/login", controllers.Login) 17 v1.GET("/login", controllers.Login)
18 v1.GET("/logout", middleware.CheckAuth, controllers.Logout)
19 v1.GET("/profile", middleware.CheckAuth, controllers.Profile) 18 v1.GET("/profile", middleware.CheckAuth, controllers.Profile)
20 v1.GET("/user/:id", middleware.CheckAuth, controllers.FetchUser) 19 v1.GET("/user/:id", middleware.CheckAuth, controllers.FetchUser)
21 v1.POST("/demo/", middleware.CheckAuth, controllers.UploadDemo) 20 v1.POST("/demo/", middleware.CheckAuth, controllers.UploadDemo)
22 //v1.PUT("user/:id/:country", middleware.CheckAuth, controllers.UpdateUserCountry)
23 } 21 }
24} 22}