From eb51bdbfef8c2aacf0fdfde279a40de7f74c8d86 Mon Sep 17 00:00:00 2001 From: Zach Berwaldt Date: Mon, 18 Mar 2024 21:27:24 -0400 Subject: clean up, add better error handling --- api/bin/water | Bin 0 -> 15831520 bytes api/internal/controllers/auth.go | 21 +++++++++++++-------- api/internal/controllers/preferences.go | 13 +++++++++---- api/internal/controllers/stats.go | 27 ++++++++++++++++++++++----- api/internal/controllers/user.go | 14 +++++++++++--- api/internal/database/database.go | 18 ++++++++++++------ api/main | Bin 0 -> 17796784 bytes api/water-api.nginx.conf | 8 ++++++++ api/water.service | 14 ++++++++++++++ db/README.md | 10 +++++++++- db/scripts/init.sh | 6 ++---- fe/index.html | 2 +- fe/src/utils.ts | 2 +- fe/water.nginx.conf | 12 ++++++++++++ 14 files changed, 114 insertions(+), 33 deletions(-) create mode 100755 api/bin/water create mode 100755 api/main create mode 100644 api/water-api.nginx.conf create mode 100644 api/water.service create mode 100644 fe/water.nginx.conf diff --git a/api/bin/water b/api/bin/water new file mode 100755 index 0000000..b311c73 Binary files /dev/null and b/api/bin/water 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 ( "database/sql" "encoding/base64" "errors" - "github.com/gin-gonic/gin" "net/http" "water/api/internal/models" + "github.com/gin-gonic/gin" + + "water/api/internal/database" + _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" - "water/api/internal/database" ) - - // AuthHandler is a function that handles users' authentication. It checks if the request // has valid credentials, authenticates the user and sets the user's session. // If the authentication is successful, it will allow the user to access protected routes. -func AuthHandler (c *gin.Context) { +func AuthHandler(c *gin.Context) { username, password, ok := c.Request.BasicAuth() if !ok { c.Header("WWW-Authenticate", `Basic realm="Please enter your username and password."`) @@ -27,7 +27,11 @@ func AuthHandler (c *gin.Context) { return } - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -44,6 +48,8 @@ func AuthHandler (c *gin.Context) { if errors.Is(err, sql.ErrNoRows) { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return + } else { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } } @@ -64,7 +70,6 @@ func AuthHandler (c *gin.Context) { c.JSON(http.StatusOK, gin.H{"token": apiToken, "user": user, "preferences": preference}) } - // generateToken is a helper function used in the AuthHandler. It generates a random token for API authentication. // This function creates an empty byte slice of length 32 and fills it with cryptographic random data using the rand.Read function. // If an error occurs during the generation, it will return an empty string. @@ -76,4 +81,4 @@ func generateToken() string { return "" } return base64.StdEncoding.EncodeToString(token) -} \ No newline at end of file +} 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 @@ package controllers import ( - "github.com/gin-gonic/gin" - "net/http" "database/sql" + "net/http" "water/api/internal/database" "water/api/internal/models" + + "github.com/gin-gonic/gin" ) func GetSizes(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } }(db) - + rows, err := db.Query("SELECT id, size, unit FROM Sizes") if err != nil { 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 import ( "database/sql" - "github.com/gin-gonic/gin" "net/http" "water/api/internal/database" "water/api/internal/models" + + "github.com/gin-gonic/gin" ) // TODO: add comments to all exported members of package. @@ -13,7 +14,11 @@ import ( // GetAllStatistics connects to the database and queries for all statistics in the database. // If none have been found it will return an error, otherwise a 200 code is sent along with the list of statistics. func GetAllStatistics(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -59,7 +64,11 @@ func PostNewStatistic(c *gin.Context) { return } - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -83,7 +92,11 @@ func PostNewStatistic(c *gin.Context) { } func GetWeeklyStatistics(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -118,7 +131,11 @@ func GetWeeklyStatistics(c *gin.Context) { } func GetDailyUserStatistics(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() 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) { c.JSON(http.StatusOK, gin.H{"message": "User found"}) } func GetUserPreferences(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -41,7 +45,11 @@ func GetUserPreferences(c *gin.Context) { } func UpdateUserPreferences(c *gin.Context) { - db := database.EstablishDBConnection() + db, err := database.EstablishDBConnection() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } defer func(db *sql.DB) { err := db.Close() if err != nil { @@ -58,7 +66,7 @@ func UpdateUserPreferences(c *gin.Context) { log.Printf("newPreferences: %v", newPreferences) - _, err := db.Exec("UPDATE Preferences SET color = ?, size_id = ? WHERE id = ?", newPreferences.Color, newPreferences.SizeID, newPreferences.ID) + _, err = db.Exec("UPDATE Preferences SET color = ?, size_id = ? WHERE id = ?", newPreferences.Color, newPreferences.SizeID, newPreferences.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) 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 import ( "database/sql" - _ "github.com/mattn/go-sqlite3" + "fmt" "log" "path/filepath" "water/api/internal/config" + + _ "github.com/mattn/go-sqlite3" ) -func EstablishDBConnection() *sql.DB { +func EstablishDBConnection() (*sql.DB, error) { c, err := config.Load() + if err != nil { + return nil, fmt.Errorf("error while reading config file: %w", err) + } driver := c.GetString("DB_DRIVER") path, err := filepath.Abs(c.GetString("DB_PATH")) + log.Println("my db path: ", path) if err != nil { - log.Fatal("There was and error getting the absolute path of the database.") + return nil, fmt.Errorf("failed to get absolute path of the database: %w", err) } db, err := sql.Open(driver, path) if err != nil { - panic(err) + return nil, fmt.Errorf("error while opening the database: %w", err) } - return db -} \ No newline at end of file + return db, nil +} diff --git a/api/main b/api/main new file mode 100755 index 0000000..1eeaf51 Binary files /dev/null and b/api/main 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 @@ +server { + listen 443 ssl; + listen [::]:443 ssl; + server_name water-api.example.com; + location / { + proxy_pass http://localhost:8888; + } +} 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 @@ +[Unit] +Description=Water is a backend for tracking water consumption +StartLimitIntervalSec=600 +StartLimitBurst=2 + +[Service] +WorkingDirectory=/path/to/water/binary +User=water +Restart=on-failure +RestartSec=30 +PermissionsStartOnly=true + +[Install] +WantedBy=multi-user.target diff --git a/db/README.md b/db/README.md index f36e555..1d5ad71 100644 --- a/db/README.md +++ b/db/README.md @@ -1,3 +1,11 @@ # The Database -This document describes how to set up the database for your instance of the water application. \ No newline at end of file +This document describes how to set up the database for your instance of the water application. + +## Setup + +The first step is to decide where you are going to keep your database. Once you have decided on where that is going to be add it to your environment: + +```sh +export DB_PATH="path/to/database" +``` \ No newline at end of file diff --git a/db/scripts/init.sh b/db/scripts/init.sh index 1a8bbde..3baec36 100644 --- a/db/scripts/init.sh +++ b/db/scripts/init.sh @@ -1,10 +1,8 @@ PROJECT_DIR=$(pwd) -DB_PATH="$PROJECT_DIR/db/test.sqlite3" - -SQL_DIR="$PROJECT_DIR/db/sql" - +DB_PATH="$PROJECT_DIR/test.sqlite3" +SQL_DIR="$PROJECT_DIR/sql" insert_user() { read -p "Enter a username: " username diff --git a/fe/index.html b/fe/index.html index b6c5f0a..3b39d6f 100644 --- a/fe/index.html +++ b/fe/index.html @@ -4,7 +4,7 @@ - Vite + Svelte + TS + Track Your Water
diff --git a/fe/src/utils.ts b/fe/src/utils.ts index 9fddf41..41c733d 100644 --- a/fe/src/utils.ts +++ b/fe/src/utils.ts @@ -10,5 +10,5 @@ export function processFormInput(form: HTMLFormElement) { export function apiURL (path: string): string { const baseUrl = import.meta.env?.VITE_API_BASE_URL ?? "http://localhost:8080/api/v1"; - return `${baseUrl}${path}` + return `${baseUrl}/${path}` } diff --git a/fe/water.nginx.conf b/fe/water.nginx.conf new file mode 100644 index 0000000..a715845 --- /dev/null +++ b/fe/water.nginx.conf @@ -0,0 +1,12 @@ +server { + root /srv/www/water; + index index.html index.htm; + + listen 443 ssl; + listen [::]:443 ssl; + server_name water.example.com; + + location / { + try_files $uri $uri/ =404; + } +} -- cgit v1.1