Add transfer allowance functionality with error handling

This commit is contained in:
Sebastiaan de Schaetzen 2025-10-08 19:59:10 +02:00
parent b93f71aaf7
commit 8e2e5e6f71
3 changed files with 32 additions and 3 deletions

View File

@ -1039,7 +1039,7 @@ func TestTransferInsufficientFunds(t *testing.T) {
transfer := map[string]interface{}{"from": 1, "to": 2, "amount": 10} transfer := map[string]interface{}{"from": 1, "to": 2, "amount": 10}
resp := e.POST("/transfer").WithJSON(transfer).Expect().Status(400).JSON().Object() resp := e.POST("/transfer").WithJSON(transfer).Expect().Status(400).JSON().Object()
// Error text should mention insufficient funds // Error text should mention insufficient funds
resp.Value("error").String().Contains("insufficient") resp.Value("error").String().ContainsFold("insufficient")
} }
func TestTransferNotFound(t *testing.T) { func TestTransferNotFound(t *testing.T) {

View File

@ -746,7 +746,7 @@ func (db *Db) TransferAllowance(fromId int, toId int, amount float64) error {
// Ensure same owner // Ensure same owner
if fromUserId != toUserId { 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 // Calculate how much the 'to' goal still needs
@ -764,7 +764,7 @@ func (db *Db) TransferAllowance(fromId int, toId int, amount float64) error {
// Ensure 'from' has enough balance // Ensure 'from' has enough balance
if fromBalance < transfer { if fromBalance < transfer {
return fmt.Errorf("insufficient funds in source allowance") return fmt.Errorf(ErrInsufficientFunds)
} }
// Perform updates // Perform updates

View File

@ -25,6 +25,8 @@ const (
ErrInvalidUserID = "Invalid user ID" ErrInvalidUserID = "Invalid user ID"
ErrUserNotFound = "User not found" ErrUserNotFound = "User not found"
ErrCheckingUserExist = "Error checking user existence: %v" 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. // ServerConfig holds configuration for the server.
@ -644,6 +646,32 @@ func getHistory(c *gin.Context) {
c.IndentedJSON(http.StatusOK, history) 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. Initialises the database, and then starts the server.
If the context gets cancelled, the server is shutdown and the database is closed. 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.PUT("/api/task/:taskId", putTask)
router.DELETE("/api/task/:taskId", deleteTask) router.DELETE("/api/task/:taskId", deleteTask)
router.POST("/api/task/:taskId/complete", completeTask) router.POST("/api/task/:taskId/complete", completeTask)
router.POST("/api/transfer", transfer)
srv := &http.Server{ srv := &http.Server{
Addr: config.Addr, Addr: config.Addr,