diff options
Diffstat (limited to 'api')
-rwxr-xr-x | api/bin/water | bin | 0 -> 15831520 bytes | |||
-rw-r--r-- | api/internal/controllers/auth.go | 21 | ||||
-rw-r--r-- | api/internal/controllers/preferences.go | 13 | ||||
-rw-r--r-- | api/internal/controllers/stats.go | 27 | ||||
-rw-r--r-- | api/internal/controllers/user.go | 14 | ||||
-rw-r--r-- | api/internal/database/database.go | 18 | ||||
-rwxr-xr-x | api/main | bin | 0 -> 17796784 bytes | |||
-rw-r--r-- | api/water-api.nginx.conf | 8 | ||||
-rw-r--r-- | api/water.service | 14 |
9 files changed, 89 insertions, 26 deletions
diff --git a/api/bin/water b/api/bin/water new file mode 100755 index 0000000..b311c73 --- /dev/null +++ b/api/bin/water | |||
Binary files differ | |||
diff --git a/api/internal/controllers/auth.go b/api/internal/controllers/auth.go index ab2fbbb..b06c6ef 100644 --- a/api/internal/controllers/auth.go +++ b/api/internal/controllers/auth.go | |||
@@ -5,21 +5,21 @@ import ( | |||
5 | "database/sql" | 5 | "database/sql" |
6 | "encoding/base64" | 6 | "encoding/base64" |
7 | "errors" | 7 | "errors" |
8 | "github.com/gin-gonic/gin" | ||
9 | "net/http" | 8 | "net/http" |
10 | "water/api/internal/models" | 9 | "water/api/internal/models" |
11 | 10 | ||
11 | "github.com/gin-gonic/gin" | ||
12 | |||
13 | "water/api/internal/database" | ||
14 | |||
12 | _ "github.com/mattn/go-sqlite3" | 15 | _ "github.com/mattn/go-sqlite3" |
13 | "golang.org/x/crypto/bcrypt" | 16 | "golang.org/x/crypto/bcrypt" |
14 | "water/api/internal/database" | ||
15 | ) | 17 | ) |
16 | 18 | ||
17 | |||
18 | |||
19 | // AuthHandler is a function that handles users' authentication. It checks if the request | 19 | // AuthHandler is a function that handles users' authentication. It checks if the request |
20 | // has valid credentials, authenticates the user and sets the user's session. | 20 | // has valid credentials, authenticates the user and sets the user's session. |
21 | // If the authentication is successful, it will allow the user to access protected routes. | 21 | // If the authentication is successful, it will allow the user to access protected routes. |
22 | func AuthHandler (c *gin.Context) { | 22 | func AuthHandler(c *gin.Context) { |
23 | username, password, ok := c.Request.BasicAuth() | 23 | username, password, ok := c.Request.BasicAuth() |
24 | if !ok { | 24 | if !ok { |
25 | c.Header("WWW-Authenticate", `Basic realm="Please enter your username and password."`) | 25 | c.Header("WWW-Authenticate", `Basic realm="Please enter your username and password."`) |
@@ -27,7 +27,11 @@ func AuthHandler (c *gin.Context) { | |||
27 | return | 27 | return |
28 | } | 28 | } |
29 | 29 | ||
30 | db := database.EstablishDBConnection() | 30 | db, err := database.EstablishDBConnection() |
31 | if err != nil { | ||
32 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
33 | return | ||
34 | } | ||
31 | defer func(db *sql.DB) { | 35 | defer func(db *sql.DB) { |
32 | err := db.Close() | 36 | err := db.Close() |
33 | if err != nil { | 37 | if err != nil { |
@@ -44,6 +48,8 @@ func AuthHandler (c *gin.Context) { | |||
44 | if errors.Is(err, sql.ErrNoRows) { | 48 | if errors.Is(err, sql.ErrNoRows) { |
45 | c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) | 49 | c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) |
46 | return | 50 | return |
51 | } else { | ||
52 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
47 | } | 53 | } |
48 | } | 54 | } |
49 | 55 | ||
@@ -64,7 +70,6 @@ func AuthHandler (c *gin.Context) { | |||
64 | c.JSON(http.StatusOK, gin.H{"token": apiToken, "user": user, "preferences": preference}) | 70 | c.JSON(http.StatusOK, gin.H{"token": apiToken, "user": user, "preferences": preference}) |
65 | } | 71 | } |
66 | 72 | ||
67 | |||
68 | // generateToken is a helper function used in the AuthHandler. It generates a random token for API authentication. | 73 | // generateToken is a helper function used in the AuthHandler. It generates a random token for API authentication. |
69 | // This function creates an empty byte slice of length 32 and fills it with cryptographic random data using the rand.Read function. | 74 | // This function creates an empty byte slice of length 32 and fills it with cryptographic random data using the rand.Read function. |
70 | // If an error occurs during the generation, it will return an empty string. | 75 | // If an error occurs during the generation, it will return an empty string. |
@@ -76,4 +81,4 @@ func generateToken() string { | |||
76 | return "" | 81 | return "" |
77 | } | 82 | } |
78 | return base64.StdEncoding.EncodeToString(token) | 83 | return base64.StdEncoding.EncodeToString(token) |
79 | } \ No newline at end of file | 84 | } |
diff --git a/api/internal/controllers/preferences.go b/api/internal/controllers/preferences.go index a1bcf4f..da52e74 100644 --- a/api/internal/controllers/preferences.go +++ b/api/internal/controllers/preferences.go | |||
@@ -1,22 +1,27 @@ | |||
1 | package controllers | 1 | package controllers |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "github.com/gin-gonic/gin" | ||
5 | "net/http" | ||
6 | "database/sql" | 4 | "database/sql" |
5 | "net/http" | ||
7 | "water/api/internal/database" | 6 | "water/api/internal/database" |
8 | "water/api/internal/models" | 7 | "water/api/internal/models" |
8 | |||
9 | "github.com/gin-gonic/gin" | ||
9 | ) | 10 | ) |
10 | 11 | ||
11 | func GetSizes(c *gin.Context) { | 12 | func GetSizes(c *gin.Context) { |
12 | db := database.EstablishDBConnection() | 13 | db, err := database.EstablishDBConnection() |
14 | if err != nil { | ||
15 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
16 | return | ||
17 | } | ||
13 | defer func(db *sql.DB) { | 18 | defer func(db *sql.DB) { |
14 | err := db.Close() | 19 | err := db.Close() |
15 | if err != nil { | 20 | if err != nil { |
16 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | 21 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
17 | } | 22 | } |
18 | }(db) | 23 | }(db) |
19 | 24 | ||
20 | rows, err := db.Query("SELECT id, size, unit FROM Sizes") | 25 | rows, err := db.Query("SELECT id, size, unit FROM Sizes") |
21 | if err != nil { | 26 | if err != nil { |
22 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | 27 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
diff --git a/api/internal/controllers/stats.go b/api/internal/controllers/stats.go index 2234787..889b923 100644 --- a/api/internal/controllers/stats.go +++ b/api/internal/controllers/stats.go | |||
@@ -2,10 +2,11 @@ package controllers | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "database/sql" | 4 | "database/sql" |
5 | "github.com/gin-gonic/gin" | ||
6 | "net/http" | 5 | "net/http" |
7 | "water/api/internal/database" | 6 | "water/api/internal/database" |
8 | "water/api/internal/models" | 7 | "water/api/internal/models" |
8 | |||
9 | "github.com/gin-gonic/gin" | ||
9 | ) | 10 | ) |
10 | 11 | ||
11 | // TODO: add comments to all exported members of package. | 12 | // TODO: add comments to all exported members of package. |
@@ -13,7 +14,11 @@ import ( | |||
13 | // GetAllStatistics connects to the database and queries for all statistics in the database. | 14 | // GetAllStatistics connects to the database and queries for all statistics in the database. |
14 | // If none have been found it will return an error, otherwise a 200 code is sent along with the list of statistics. | 15 | // If none have been found it will return an error, otherwise a 200 code is sent along with the list of statistics. |
15 | func GetAllStatistics(c *gin.Context) { | 16 | func GetAllStatistics(c *gin.Context) { |
16 | db := database.EstablishDBConnection() | 17 | db, err := database.EstablishDBConnection() |
18 | if err != nil { | ||
19 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
20 | return | ||
21 | } | ||
17 | defer func(db *sql.DB) { | 22 | defer func(db *sql.DB) { |
18 | err := db.Close() | 23 | err := db.Close() |
19 | if err != nil { | 24 | if err != nil { |
@@ -59,7 +64,11 @@ func PostNewStatistic(c *gin.Context) { | |||
59 | return | 64 | return |
60 | } | 65 | } |
61 | 66 | ||
62 | db := database.EstablishDBConnection() | 67 | db, err := database.EstablishDBConnection() |
68 | if err != nil { | ||
69 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
70 | return | ||
71 | } | ||
63 | defer func(db *sql.DB) { | 72 | defer func(db *sql.DB) { |
64 | err := db.Close() | 73 | err := db.Close() |
65 | if err != nil { | 74 | if err != nil { |
@@ -83,7 +92,11 @@ func PostNewStatistic(c *gin.Context) { | |||
83 | } | 92 | } |
84 | 93 | ||
85 | func GetWeeklyStatistics(c *gin.Context) { | 94 | func GetWeeklyStatistics(c *gin.Context) { |
86 | db := database.EstablishDBConnection() | 95 | db, err := database.EstablishDBConnection() |
96 | if err != nil { | ||
97 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
98 | return | ||
99 | } | ||
87 | defer func(db *sql.DB) { | 100 | defer func(db *sql.DB) { |
88 | err := db.Close() | 101 | err := db.Close() |
89 | if err != nil { | 102 | if err != nil { |
@@ -118,7 +131,11 @@ func GetWeeklyStatistics(c *gin.Context) { | |||
118 | } | 131 | } |
119 | 132 | ||
120 | func GetDailyUserStatistics(c *gin.Context) { | 133 | func GetDailyUserStatistics(c *gin.Context) { |
121 | db := database.EstablishDBConnection() | 134 | db, err := database.EstablishDBConnection() |
135 | if err != nil { | ||
136 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
137 | return | ||
138 | } | ||
122 | defer func(db *sql.DB) { | 139 | defer func(db *sql.DB) { |
123 | err := db.Close() | 140 | err := db.Close() |
124 | if err != nil { | 141 | if err != nil { |
diff --git a/api/internal/controllers/user.go b/api/internal/controllers/user.go index dbb09cf..fa9617a 100644 --- a/api/internal/controllers/user.go +++ b/api/internal/controllers/user.go | |||
@@ -15,7 +15,11 @@ func GetUser(c *gin.Context) { | |||
15 | c.JSON(http.StatusOK, gin.H{"message": "User found"}) | 15 | c.JSON(http.StatusOK, gin.H{"message": "User found"}) |
16 | } | 16 | } |
17 | func GetUserPreferences(c *gin.Context) { | 17 | func GetUserPreferences(c *gin.Context) { |
18 | db := database.EstablishDBConnection() | 18 | db, err := database.EstablishDBConnection() |
19 | if err != nil { | ||
20 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
21 | return | ||
22 | } | ||
19 | defer func(db *sql.DB) { | 23 | defer func(db *sql.DB) { |
20 | err := db.Close() | 24 | err := db.Close() |
21 | if err != nil { | 25 | if err != nil { |
@@ -41,7 +45,11 @@ func GetUserPreferences(c *gin.Context) { | |||
41 | } | 45 | } |
42 | 46 | ||
43 | func UpdateUserPreferences(c *gin.Context) { | 47 | func UpdateUserPreferences(c *gin.Context) { |
44 | db := database.EstablishDBConnection() | 48 | db, err := database.EstablishDBConnection() |
49 | if err != nil { | ||
50 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | ||
51 | return | ||
52 | } | ||
45 | defer func(db *sql.DB) { | 53 | defer func(db *sql.DB) { |
46 | err := db.Close() | 54 | err := db.Close() |
47 | if err != nil { | 55 | if err != nil { |
@@ -58,7 +66,7 @@ func UpdateUserPreferences(c *gin.Context) { | |||
58 | 66 | ||
59 | log.Printf("newPreferences: %v", newPreferences) | 67 | log.Printf("newPreferences: %v", newPreferences) |
60 | 68 | ||
61 | _, err := db.Exec("UPDATE Preferences SET color = ?, size_id = ? WHERE id = ?", newPreferences.Color, newPreferences.SizeID, newPreferences.ID) | 69 | _, err = db.Exec("UPDATE Preferences SET color = ?, size_id = ? WHERE id = ?", newPreferences.Color, newPreferences.SizeID, newPreferences.ID) |
62 | if err != nil { | 70 | if err != nil { |
63 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) | 71 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
64 | return | 72 | return |
diff --git a/api/internal/database/database.go b/api/internal/database/database.go index 1866655..1a55127 100644 --- a/api/internal/database/database.go +++ b/api/internal/database/database.go | |||
@@ -2,23 +2,29 @@ package database | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "database/sql" | 4 | "database/sql" |
5 | _ "github.com/mattn/go-sqlite3" | 5 | "fmt" |
6 | "log" | 6 | "log" |
7 | "path/filepath" | 7 | "path/filepath" |
8 | "water/api/internal/config" | 8 | "water/api/internal/config" |
9 | |||
10 | _ "github.com/mattn/go-sqlite3" | ||
9 | ) | 11 | ) |
10 | 12 | ||
11 | func EstablishDBConnection() *sql.DB { | 13 | func EstablishDBConnection() (*sql.DB, error) { |
12 | c, err := config.Load() | 14 | c, err := config.Load() |
15 | if err != nil { | ||
16 | return nil, fmt.Errorf("error while reading config file: %w", err) | ||
17 | } | ||
13 | 18 | ||
14 | driver := c.GetString("DB_DRIVER") | 19 | driver := c.GetString("DB_DRIVER") |
15 | path, err := filepath.Abs(c.GetString("DB_PATH")) | 20 | path, err := filepath.Abs(c.GetString("DB_PATH")) |
21 | log.Println("my db path: ", path) | ||
16 | if err != nil { | 22 | if err != nil { |
17 | log.Fatal("There was and error getting the absolute path of the database.") | 23 | return nil, fmt.Errorf("failed to get absolute path of the database: %w", err) |
18 | } | 24 | } |
19 | db, err := sql.Open(driver, path) | 25 | db, err := sql.Open(driver, path) |
20 | if err != nil { | 26 | if err != nil { |
21 | panic(err) | 27 | return nil, fmt.Errorf("error while opening the database: %w", err) |
22 | } | 28 | } |
23 | return db | 29 | return db, nil |
24 | } \ No newline at end of file | 30 | } |
diff --git a/api/main b/api/main new file mode 100755 index 0000000..1eeaf51 --- /dev/null +++ b/api/main | |||
Binary files differ | |||
diff --git a/api/water-api.nginx.conf b/api/water-api.nginx.conf new file mode 100644 index 0000000..73b0d7c --- /dev/null +++ b/api/water-api.nginx.conf | |||
@@ -0,0 +1,8 @@ | |||
1 | server { | ||
2 | listen 443 ssl; | ||
3 | listen [::]:443 ssl; | ||
4 | server_name water-api.example.com; | ||
5 | location / { | ||
6 | proxy_pass http://localhost:8888; | ||
7 | } | ||
8 | } | ||
diff --git a/api/water.service b/api/water.service new file mode 100644 index 0000000..eb8a779 --- /dev/null +++ b/api/water.service | |||
@@ -0,0 +1,14 @@ | |||
1 | [Unit] | ||
2 | Description=Water is a backend for tracking water consumption | ||
3 | StartLimitIntervalSec=600 | ||
4 | StartLimitBurst=2 | ||
5 | |||
6 | [Service] | ||
7 | WorkingDirectory=/path/to/water/binary | ||
8 | User=water | ||
9 | Restart=on-failure | ||
10 | RestartSec=30 | ||
11 | PermissionsStartOnly=true | ||
12 | |||
13 | [Install] | ||
14 | WantedBy=multi-user.target | ||