diff --git a/database/database.go b/database/database.go index 41fb32e..364e1ae 100644 --- a/database/database.go +++ b/database/database.go @@ -148,7 +148,15 @@ func NewAccount(database *sql.DB, account Account) error { } func UpdateAccount(database *sql.DB, account Account) error { - _, err := database.Exec("UPDATE accounts SET name = $1, kind = $2 WHERE id = $3", account.Name, account.Kind, account.ID) + exists, err := existAccount(database, int(account.ID)) + if err != nil { + return err + } + if !exists { + return errors.New("account does not exist") + } + + _, err = database.Exec("UPDATE accounts SET name = $1, kind = $2 WHERE id = $3", account.Name, account.Kind, account.ID) if err != nil { return err } @@ -157,7 +165,15 @@ func UpdateAccount(database *sql.DB, account Account) error { } func DeleteAccount(database *sql.DB, id int) error { - _, err := database.Exec("DELETE FROM accounts WHERE id = $1", id) + exists, err := existAccount(database, id) + if err != nil { + return err + } + if !exists { + return errors.New("account does not exist") + } + + _, err = database.Exec("DELETE FROM accounts WHERE id = $1", id) if err != nil { return err } @@ -175,6 +191,18 @@ func GetAccount(database *sql.DB, id int) (Account, error) { } +func existTransaction(database *sql.DB, id int) (bool, error) { + err := database.QueryRow("SELECT id FROM transactions WHERE id = $1", id).Scan(&id) + if err != nil { + if err != sql.ErrNoRows { + return false, err + } + return false, nil + } + return true, nil + +} + func NewTransaction(database *sql.DB, transaction Transaction) error { _, err := database.Exec("INSERT INTO transactions (amount, debit, offset_account, account, time, description) VALUES ($1, $2, $3, $4, $5, $6)", transaction.Amount, transaction.Debit, transaction.OffsetAccount, transaction.Account, transaction.Date, transaction.Description) if err != nil { @@ -185,7 +213,15 @@ func NewTransaction(database *sql.DB, transaction Transaction) error { } func UpdateTransaction(database *sql.DB, transaction Transaction) error { - _, err := database.Exec("UPDATE transactions SET amount = $1, debit = $2, offset_account = $3, account = $4, time = $5, description = $6 WHERE id = $7", transaction.Amount, transaction.Debit, transaction.OffsetAccount, transaction.Account, transaction.Date, transaction.Description, transaction.ID) + exists, err := existTransaction(database, int(transaction.ID)) + if err != nil { + return err + } + + if !exists { + return errors.New("transaction already exists") + } + _, err = database.Exec("UPDATE transactions SET amount = $1, debit = $2, offset_account = $3, account = $4, time = $5, description = $6 WHERE id = $7", transaction.Amount, transaction.Debit, transaction.OffsetAccount, transaction.Account, transaction.Date, transaction.Description, transaction.ID) if err != nil { return err } @@ -194,7 +230,15 @@ func UpdateTransaction(database *sql.DB, transaction Transaction) error { } func DeleteTransaction(database *sql.DB, id int) error { - _, err := database.Exec("DELETE FROM transactions WHERE id = $1", id) + exists, err := existTransaction(database, id) + if err != nil { + return err + } + + if !exists { + return errors.New("transaction already exists") + } + _, err = database.Exec("DELETE FROM transactions WHERE id = $1", id) if err != nil { return err } diff --git a/server/account.go b/server/account.go index c71d8ce..73c472c 100644 --- a/server/account.go +++ b/server/account.go @@ -1,31 +1,143 @@ package server import ( + "encoding/json" "net/http" + "strconv" + "github.com/LeRoid-hub/Bookholder-API/database" "github.com/gin-gonic/gin" ) func getAccount(c *gin.Context) { + id := c.Param("AccountID") + + idInt, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be an integer", + }) + return + } + + if idInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be greater than 0", + }) + return + } + + acc, err := database.GetAccount(Database, idInt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + + if acc.ID == 0 { + c.JSON(http.StatusNotFound, gin.H{ + "message": "account not found", + }) + return + } + + jsondata, err := json.Marshal(acc) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "getAccount", + "account": jsondata, }) } func newAccount(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "newAccount", + var acc database.Account + err := c.BindJSON(&acc) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid json", + }) + return + } + + err = database.NewAccount(Database, acc) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + + c.JSON(http.StatusCreated, gin.H{ + "message": "account created", }) } func updateAccount(c *gin.Context) { + var acc database.Account + err := c.BindJSON(&acc) + + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid json", + }) + return + } + + acc.ID = uint(acc.ID) + + if acc.ID < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be greater than 0", + }) + return + } + + err = database.UpdateAccount(Database, acc) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "updateAccount", + "message": "account updated", }) } func deleteAccount(c *gin.Context) { + id := c.Param("AccountID") + + idInt, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be an integer", + }) + return + } + + if idInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be greater than 0", + }) + return + } + + err = database.DeleteAccount(Database, idInt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "deleteAccount", + "message": "account deleted", }) } diff --git a/server/server.go b/server/server.go index ce387f0..1fc9d09 100644 --- a/server/server.go +++ b/server/server.go @@ -41,6 +41,7 @@ func Run(env map[string]string, db *database.DB) { r := gin.Default() + // Index r.GET("/", welcome) v1 := r.Group("/v1") @@ -51,7 +52,7 @@ func Run(env map[string]string, db *database.DB) { //Account v1.GET("/Account/:AccountID", checkAuth, getAccount) v1.POST("/NewAccount", checkAuth, newAccount) - v1.PUT("/UpdateAccount/:AccountID", checkAuth, updateAccount) + v1.PUT("/UpdateAccount", checkAuth, updateAccount) v1.DELETE("/DeleteAccount/:AccountID", checkAuth, deleteAccount) //Transaction diff --git a/server/transaction.go b/server/transaction.go index b8eaa3b..fad7511 100644 --- a/server/transaction.go +++ b/server/transaction.go @@ -1,14 +1,57 @@ package server import ( + "encoding/json" "net/http" + "strconv" + "github.com/LeRoid-hub/Bookholder-API/database" "github.com/gin-gonic/gin" ) func getTransaction(c *gin.Context) { + id := c.Param("TransactionID") + + idInt, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be an integer", + }) + return + } + + if idInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be greater than 0", + }) + return + } + + transaction, err := database.GetTransaction(Database, idInt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + + if transaction.ID == 0 { + c.JSON(http.StatusNotFound, gin.H{ + "message": "transaction not found", + }) + return + } + + jasondata, err := json.Marshal(transaction) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "getTransaction", + "transaction": jasondata, }) } @@ -16,26 +59,160 @@ func getTransactions(c *gin.Context) { year := c.Param("year") month := c.Param("month") - message := "getTransactions " + year + " " + month + yearInt, err := strconv.Atoi(year) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid year; must be an integer", + }) + return + } + + if yearInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid year; must be greater than 0", + }) + return + } + + monthInt, err := strconv.Atoi(month) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid month; must be an integer", + }) + return + } + + if monthInt < 1 || monthInt > 12 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid month; must be between 1 and 12", + }) + return + } + + account := c.Param("AccountID") + accountInt, err := strconv.Atoi(account) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid account; must be an integer", + }) + return + } + + if accountInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid account; must be greater than 0", + }) + return + } + + transactions, err := database.GetTransactions(Database, accountInt, yearInt, monthInt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + + jasondata, err := json.Marshal(transactions) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": message, + "transactions": jasondata, }) } func newTransaction(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "newTransaction", + var transaction database.Transaction + err := c.BindJSON(&transaction) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid json", + }) + return + } + + if transaction.OffsetAccount == transaction.Account { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid offset account; must be different from account", + }) + return + } + + err = database.NewTransaction(Database, transaction) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error: " + err.Error(), + }) + return + } + + c.JSON(http.StatusCreated, gin.H{ + "message": "transaction created", }) } func updateTransaction(c *gin.Context) { + var transaction database.Transaction + err := c.BindJSON(&transaction) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid json", + }) + return + } + + if transaction.OffsetAccount == transaction.Account { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid offset account; must be different from account", + }) + return + } + + err = database.UpdateTransaction(Database, transaction) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "updateTransaction", + "message": "transaction updated", }) } func deleteTransaction(c *gin.Context) { + id := c.Param("TransactionID") + + idInt, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be an integer", + }) + return + } + + if idInt < 1 { + c.JSON(http.StatusBadRequest, gin.H{ + "message": "invalid id; must be greater than 0", + }) + return + } + + err = database.DeleteTransaction(Database, idInt) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "message": "internal server error", + }) + return + } + c.JSON(http.StatusOK, gin.H{ - "message": "deleteTransaction", + "message": "transaction deleted", }) }