diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..0f580ed --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,2 @@ +*.db3 +*.db3-* diff --git a/backend/api_test.go b/backend/api_test.go index 0deb722..0eca0cc 100644 --- a/backend/api_test.go +++ b/backend/api_test.go @@ -385,3 +385,22 @@ func TestPutTaskInvalidTaskId(t *testing.T) { } e.PUT("/task/999").WithJSON(requestBody).Expect().Status(404) } + +func TestPostAllowance(t *testing.T) { + e := startServer(t) + + e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect().Status(200) + e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 20}).Expect().Status(200) + e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: -10}).Expect().Status(200) + + response := e.GET("/user/1").Expect().Status(200).JSON().Object() + response.Value("allowance").Number().IsEqual(100 + 20 - 10) +} + +func TestPostAllowanceInvalidUserId(t *testing.T) { + e := startServer(t) + + e.POST("/user/999/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect(). + Status(404) + +} diff --git a/backend/db.go b/backend/db.go index b707dce..6ea0ea2 100644 --- a/backend/db.go +++ b/backend/db.go @@ -3,6 +3,7 @@ package main import ( "errors" "log" + "time" "gitea.seeseepuff.be/seeseemelk/mysqlite" ) @@ -45,11 +46,11 @@ func (db *Db) GetUsers() ([]User, error) { return users, nil } -func (db *Db) GetUser(id int) (*User, error) { - user := &User{} +func (db *Db) GetUser(id int) (*UserWithAllowance, error) { + user := &UserWithAllowance{} - err := db.db.Query("select id, name from users where id = ?"). - Bind(id).ScanSingle(&user.ID, &user.Name) + err := db.db.Query("select u.id, u.name, sum(h.amount) from users u join history h on h.user_id = u.id where u.id = ?"). + Bind(id).ScanSingle(&user.ID, &user.Name, &user.Allowance) if errors.Is(err, mysqlite.ErrNoRows) { return nil, nil } @@ -237,3 +238,19 @@ func (db *Db) UpdateTask(id int, task *CreateTaskRequest) error { } return tx.Commit() } + +func (db *Db) AddAllowance(userId int, allowance *PostAllowance) error { + tx, err := db.db.Begin() + if err != nil { + return err + } + defer tx.MustRollback() + + err = tx.Query("insert into history (user_id, date, amount) values (?, ?, ?)"). + Bind(userId, time.Now().Unix(), allowance.Allowance). + Exec() + if err != nil { + return err + } + return tx.Commit() +} diff --git a/backend/dto.go b/backend/dto.go index 756df6e..8c0acfd 100644 --- a/backend/dto.go +++ b/backend/dto.go @@ -5,11 +5,21 @@ type User struct { Name string `json:"name"` } +type UserWithAllowance struct { + ID int `json:"id"` + Name string `json:"name"` + Allowance int `json:"allowance"` +} + type Allowance struct { Allowance int `json:"allowance"` Goals []Goal `json:"goals"` } +type PostAllowance struct { + Allowance int `json:"allowance"` +} + // Task represents a task in the system. type Task struct { ID int `json:"id"` diff --git a/backend/main.go b/backend/main.go index f9b6059..c7c137c 100644 --- a/backend/main.go +++ b/backend/main.go @@ -289,6 +289,31 @@ func putTask(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "Task updated successfully"}) } +func postAllowance(c *gin.Context) { + userIdStr := c.Param("userId") + userId, err := strconv.Atoi(userIdStr) + if err != nil { + log.Printf("Invalid user ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"}) + return + } + + var allowanceRequest PostAllowance + if err := c.ShouldBindJSON(&allowanceRequest); err != nil { + log.Printf("Error parsing request body: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) + return + } + + err = db.AddAllowance(userId, &allowanceRequest) + if err != nil { + log.Printf("Error updating allowance: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "Allowance updated successfully"}) +} + /* * Initialises the database, and then starts the server. @@ -308,6 +333,7 @@ func start(ctx context.Context, config *ServerConfig) { router.GET("/api/tasks", getTasks) router.GET("/api/task/:taskId", getTask) router.PUT("/api/task/:taskId", putTask) + router.POST("/api/user/:userId/allowance", postAllowance) srv := &http.Server{ Addr: config.Addr, diff --git a/common/api.yaml b/common/api.yaml index 7c30975..ed5871a 100644 --- a/common/api.yaml +++ b/common/api.yaml @@ -53,6 +53,9 @@ paths: name: type: string description: The user name + allowance: + type: integer + description: The total amount of allowance the user has 404: description: The users could not be found.