diff --git a/backend/api_test.go b/backend/api_test.go index 22466f1..2192e0e 100644 --- a/backend/api_test.go +++ b/backend/api_test.go @@ -990,7 +990,7 @@ func TestTransferInsufficientFunds(t *testing.T) { transfer := map[string]interface{}{"from": 1, "to": 2, "amount": 10} resp := e.POST("/transfer").WithJSON(transfer).Expect().Status(400).JSON().Object() // Error text should mention insufficient funds - resp.Value("error").String().Contains("insufficient") + resp.Value("error").String().ContainsFold("insufficient") } func TestTransferNotFound(t *testing.T) { diff --git a/backend/db.go b/backend/db.go index 9f6ef40..6de6d01 100644 --- a/backend/db.go +++ b/backend/db.go @@ -666,7 +666,7 @@ func (db *Db) TransferAllowance(fromId int, toId int, amount float64) error { // Ensure same owner if fromUserId != toUserId { - return fmt.Errorf("allowances do not belong to the same user") + return fmt.Errorf(ErrDifferentUsers) } // Calculate how much the 'to' goal still needs @@ -684,7 +684,7 @@ func (db *Db) TransferAllowance(fromId int, toId int, amount float64) error { // Ensure 'from' has enough balance if fromBalance < transfer { - return fmt.Errorf("insufficient funds in source allowance") + return fmt.Errorf(ErrInsufficientFunds) } // Perform updates diff --git a/backend/main.go b/backend/main.go index c6baed3..5d1dd38 100644 --- a/backend/main.go +++ b/backend/main.go @@ -25,6 +25,8 @@ const ( ErrInvalidUserID = "Invalid user ID" ErrUserNotFound = "User not found" ErrCheckingUserExist = "Error checking user existence: %v" + ErrInsufficientFunds = "Insufficient funds in source allowance" + ErrDifferentUsers = "Allowances do not belong to the same user" ) // ServerConfig holds configuration for the server. @@ -644,6 +646,32 @@ func getHistory(c *gin.Context) { c.IndentedJSON(http.StatusOK, history) } +func transfer(c *gin.Context) { + var transferRequest TransferRequest + if err := c.ShouldBindJSON(&transferRequest); err != nil { + log.Printf("Error parsing request body: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) + return + } + + err := db.TransferAllowance(transferRequest.From, transferRequest.To, transferRequest.Amount) + if err != nil { + if errors.Is(err, mysqlite.ErrNoRows) { + c.JSON(http.StatusNotFound, gin.H{"error": "Allowance not found"}) + return + } + if err.Error() == ErrInsufficientFunds || err.Error() == ErrDifferentUsers { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + log.Printf("Error transferring allowance: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "Transfer successful"}) +} + /* Initialises the database, and then starts the server. If the context gets cancelled, the server is shutdown and the database is closed. @@ -679,6 +707,7 @@ func start(ctx context.Context, config *ServerConfig) { router.PUT("/api/task/:taskId", putTask) router.DELETE("/api/task/:taskId", deleteTask) router.POST("/api/task/:taskId/complete", completeTask) + router.POST("/api/transfer", transfer) srv := &http.Server{ Addr: config.Addr,