diff options
| author | Doog <157747121+doogongithub@users.noreply.github.com> | 2024-02-29 20:13:48 -0500 |
|---|---|---|
| committer | Doog <157747121+doogongithub@users.noreply.github.com> | 2024-02-29 20:13:48 -0500 |
| commit | 9f9a33cbf55d38987a66b709284d2bb4ffea0fe9 (patch) | |
| tree | 1e0539e708983ca05bb4e07d22b9ec10b95d2473 /api | |
| parent | e37c73e33a4aaf7fb8d25b5af03627f20bcda19f (diff) | |
modify api, build additional FE components, add types
Diffstat (limited to 'api')
| -rw-r--r-- | api/go.mod | 3 | ||||
| -rw-r--r-- | api/go.sum | 2 | ||||
| -rw-r--r-- | api/lib/models.go | 38 | ||||
| -rw-r--r-- | api/main.go | 48 |
4 files changed, 62 insertions, 29 deletions
| @@ -4,7 +4,9 @@ go 1.18 | |||
| 4 | 4 | ||
| 5 | require ( | 5 | require ( |
| 6 | github.com/gin-gonic/gin v1.9.1 | 6 | github.com/gin-gonic/gin v1.9.1 |
| 7 | github.com/google/uuid v1.6.0 | ||
| 7 | github.com/mattn/go-sqlite3 v1.14.22 | 8 | github.com/mattn/go-sqlite3 v1.14.22 |
| 9 | golang.org/x/crypto v0.19.0 | ||
| 8 | ) | 10 | ) |
| 9 | 11 | ||
| 10 | require ( | 12 | require ( |
| @@ -27,7 +29,6 @@ require ( | |||
| 27 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | 29 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect |
| 28 | github.com/ugorji/go/codec v1.2.12 // indirect | 30 | github.com/ugorji/go/codec v1.2.12 // indirect |
| 29 | golang.org/x/arch v0.7.0 // indirect | 31 | golang.org/x/arch v0.7.0 // indirect |
| 30 | golang.org/x/crypto v0.19.0 // indirect | ||
| 31 | golang.org/x/net v0.21.0 // indirect | 32 | golang.org/x/net v0.21.0 // indirect |
| 32 | golang.org/x/sys v0.17.0 // indirect | 33 | golang.org/x/sys v0.17.0 // indirect |
| 33 | golang.org/x/text v0.14.0 // indirect | 34 | golang.org/x/text v0.14.0 // indirect |
| @@ -29,6 +29,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | |||
| 29 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | 29 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= |
| 30 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | 30 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= |
| 31 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | 31 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
| 32 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||
| 33 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
| 32 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | 34 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= |
| 33 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | 35 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= |
| 34 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | 36 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= |
diff --git a/api/lib/models.go b/api/lib/models.go index 92e5703..f959519 100644 --- a/api/lib/models.go +++ b/api/lib/models.go | |||
| @@ -1,23 +1,41 @@ | |||
| 1 | package models | 1 | package models |
| 2 | 2 | ||
| 3 | import "time" | 3 | import ( |
| 4 | "time" | ||
| 5 | "github.com/google/uuid" | ||
| 6 | ) | ||
| 4 | 7 | ||
| 5 | type Statistic struct { | 8 | type Statistic struct { |
| 6 | ID int64 `json:"id"` | 9 | ID int64 `json:"-"` |
| 7 | Date time.Time `json:"date"` | 10 | Date time.Time `json:"date"` |
| 8 | UserID int64 `json:"user_id"` | 11 | User User `json:"user"` |
| 9 | Quantity int `json:"quantity"` | 12 | Quantity int `json:"quantity"` |
| 10 | } | 13 | } |
| 11 | 14 | ||
| 12 | type User struct { | 15 | type User struct { |
| 13 | ID int64 | 16 | ID int64 `json:"-"` |
| 14 | Name string | 17 | Name string `json:"name"` |
| 18 | UUID uuid.UUID `json:"uuid"` | ||
| 19 | Password string `json:"-"` | ||
| 15 | } | 20 | } |
| 16 | 21 | ||
| 17 | type Token struct { | 22 | type Token struct { |
| 18 | ID int64 | 23 | ID int64 `json:"-"` |
| 19 | UserID int64 | 24 | UserID int64 `json:"user_id"` |
| 20 | Token string | 25 | Token string `json:"token"` |
| 21 | CreatedAt time.Time | 26 | CreatedAt time.Time `json:"created_at"` |
| 22 | ExpiredAt time.Time | 27 | ExpiredAt time.Time `json:"expired_at"` |
| 28 | } | ||
| 29 | |||
| 30 | type Preference struct { | ||
| 31 | ID int64 `json:"-"` | ||
| 32 | Color string `json:"color"` | ||
| 33 | UserID int64 `json:"-"` | ||
| 34 | Size Size `json:"size"` | ||
| 35 | } | ||
| 36 | |||
| 37 | type Size struct { | ||
| 38 | ID int64 `json:"-"` | ||
| 39 | Size int64 `json:"size"` | ||
| 40 | Unit string `json:"unit"` | ||
| 23 | } | 41 | } |
diff --git a/api/main.go b/api/main.go index 292a5f9..91b7929 100644 --- a/api/main.go +++ b/api/main.go | |||
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | ||
| 11 | "github.com/gin-gonic/gin" | 11 | "github.com/gin-gonic/gin" |
| 12 | _ "github.com/mattn/go-sqlite3" | 12 | _ "github.com/mattn/go-sqlite3" |
| 13 | "golang.org/x/crypto/bcrypt" | ||
| 13 | "water/api/lib" | 14 | "water/api/lib" |
| 14 | ) | 15 | ) |
| 15 | 16 | ||
| @@ -29,6 +30,7 @@ func CORSMiddleware() gin.HandlerFunc { | |||
| 29 | } | 30 | } |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 33 | // generatToken will g | ||
| 32 | func generateToken() string { | 34 | func generateToken() string { |
| 33 | token := make([]byte, 32) | 35 | token := make([]byte, 32) |
| 34 | rand.Read(token) | 36 | rand.Read(token) |
| @@ -43,6 +45,7 @@ func establishDBConnection() *sql.DB { | |||
| 43 | return db | 45 | return db |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 48 | |||
| 46 | func checkForTokenInContext(c *gin.Context) (string, error) { | 49 | func checkForTokenInContext(c *gin.Context) (string, error) { |
| 47 | authorizationHeader := c.GetHeader("Authorization") | 50 | authorizationHeader := c.GetHeader("Authorization") |
| 48 | if authorizationHeader == "" { | 51 | if authorizationHeader == "" { |
| @@ -54,6 +57,7 @@ func checkForTokenInContext(c *gin.Context) (string, error) { | |||
| 54 | if len(parts) != 2 || parts[0] != "Bearer" { | 57 | if len(parts) != 2 || parts[0] != "Bearer" { |
| 55 | return "", errors.New("Invalid Authorization header format") | 58 | return "", errors.New("Invalid Authorization header format") |
| 56 | } | 59 | } |
| 60 | |||
| 57 | 61 | ||
| 58 | return parts[1], nil | 62 | return parts[1], nil |
| 59 | } | 63 | } |
| @@ -73,15 +77,6 @@ func TokenRequired() gin.HandlerFunc { | |||
| 73 | } | 77 | } |
| 74 | } | 78 | } |
| 75 | 79 | ||
| 76 | type User struct { | ||
| 77 | Username string | ||
| 78 | Password string | ||
| 79 | } | ||
| 80 | |||
| 81 | var users = map[string]User{ | ||
| 82 | "user1": {"user1", "password1"}, | ||
| 83 | } | ||
| 84 | |||
| 85 | func setupRouter() *gin.Engine { | 80 | func setupRouter() *gin.Engine { |
| 86 | // Disable Console Color | 81 | // Disable Console Color |
| 87 | // gin.DisableConsoleColor() | 82 | // gin.DisableConsoleColor() |
| @@ -100,16 +95,31 @@ func setupRouter() *gin.Engine { | |||
| 100 | return | 95 | return |
| 101 | } | 96 | } |
| 102 | 97 | ||
| 103 | user, exists := users[username] | 98 | db := establishDBConnection() |
| 99 | defer db.Close() | ||
| 100 | |||
| 101 | var user models.User | ||
| 102 | var preference models.Preference | ||
| 103 | var size models.Size | ||
| 104 | |||
| 105 | row := db.QueryRow("SELECT name, uuid, password, color, size, unit FROM Users u INNER JOIN Preferences p ON p.user_id = u.id INNER JOIN Sizes s ON p.size_id = s.id WHERE u.name = ?", username) | ||
| 106 | if err := row.Scan(&user.Name, &user.UUID, &user.Password, &preference.Color, &size.Size, &size.Unit); err != nil { | ||
| 107 | if err == sql.ErrNoRows { | ||
| 108 | c.AbortWithStatus(http.StatusUnauthorized) | ||
| 109 | return | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { | ||
| 114 | c.AbortWithStatus(http.StatusUnauthorized) | ||
| 115 | return | ||
| 116 | } | ||
| 104 | 117 | ||
| 105 | if !exists || user.Password != password { | 118 | preference.Size = size |
| 106 | c.AbortWithStatus(http.StatusUnauthorized) | ||
| 107 | return | ||
| 108 | } | ||
| 109 | 119 | ||
| 110 | // Generate a simple API token | 120 | // Generate a simple API token |
| 111 | apiToken := generateToken() | 121 | apiToken := generateToken() |
| 112 | c.JSON(http.StatusOK, gin.H{"token": apiToken}) | 122 | c.JSON(http.StatusOK, gin.H{"token": apiToken, "user": user, "preferences": preference}) |
| 113 | }) | 123 | }) |
| 114 | 124 | ||
| 115 | stats := api.Group("stats") | 125 | stats := api.Group("stats") |
| @@ -119,7 +129,7 @@ func setupRouter() *gin.Engine { | |||
| 119 | db := establishDBConnection() | 129 | db := establishDBConnection() |
| 120 | defer db.Close() | 130 | defer db.Close() |
| 121 | 131 | ||
| 122 | rows, err := db.Query("SELECT * FROM statistics"); | 132 | rows, err := db.Query("SELECT s.date, s.quantity, u.uuid, u.name FROM Statistics s INNER JOIN Users u ON u.id = s.user_id"); |
| 123 | if err != nil { | 133 | if err != nil { |
| 124 | c.JSON(500, gin.H{"error": err.Error()}) | 134 | c.JSON(500, gin.H{"error": err.Error()}) |
| 125 | return | 135 | return |
| @@ -129,10 +139,12 @@ func setupRouter() *gin.Engine { | |||
| 129 | var data []models.Statistic | 139 | var data []models.Statistic |
| 130 | for rows.Next() { | 140 | for rows.Next() { |
| 131 | var stat models.Statistic | 141 | var stat models.Statistic |
| 132 | if err := rows.Scan(&stat.ID, &stat.Date, &stat.UserID, &stat.Quantity); err != nil { | 142 | var user models.User |
| 143 | if err := rows.Scan(&stat.Date, &stat.Quantity, &user.UUID, &user.Name); err != nil { | ||
| 133 | c.JSON(500, gin.H{"error": err.Error()}) | 144 | c.JSON(500, gin.H{"error": err.Error()}) |
| 134 | return | 145 | return |
| 135 | } | 146 | } |
| 147 | stat.User = user | ||
| 136 | data = append(data, stat) | 148 | data = append(data, stat) |
| 137 | } | 149 | } |
| 138 | 150 | ||
| @@ -150,7 +162,7 @@ func setupRouter() *gin.Engine { | |||
| 150 | db := establishDBConnection() | 162 | db := establishDBConnection() |
| 151 | defer db.Close() | 163 | defer db.Close() |
| 152 | 164 | ||
| 153 | result, err := db.Exec("INSERT INTO statistics (date, user_id, quantity) values (?, ?, ?)", stat.Date, stat.UserID, stat.Quantity) | 165 | result, err := db.Exec("INSERT INTO statistics (date, user_id, quantity) values (?, ?, ?)", stat.Date, 1, stat.Quantity) |
| 154 | 166 | ||
| 155 | if err != nil { | 167 | if err != nil { |
| 156 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | 168 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
