diff --git a/backend/api_test.go b/backend/api_test.go index c74919f..542820e 100644 --- a/backend/api_test.go +++ b/backend/api_test.go @@ -9,7 +9,7 @@ import ( ) const ( - TestGoalName = "Test Goal" + TestAllowanceName = "Test History" ) func startServer(t *testing.T) *httpexpect.Expect { @@ -49,56 +49,56 @@ func TestGetUserBadId(t *testing.T) { e.GET("/user/bad-id").Expect().Status(400) } -func TestGetUserGoalsWhenNoGoalsPresent(t *testing.T) { +func TestGetUserAllowanceWhenNoAllowancePresent(t *testing.T) { e := startServer(t) - result := e.GET("/user/1/goals").Expect().Status(200).JSON().Array() + result := e.GET("/user/1/allowance").Expect().Status(200).JSON().Array() result.Length().IsEqual(0) } -func TestGetUserGoals(t *testing.T) { +func TestGetUserAllowance(t *testing.T) { e := startServer(t) - // Create a new goal + // Create a new allowance requestBody := map[string]interface{}{ - "name": TestGoalName, + "name": TestAllowanceName, "target": 5000, "weight": 10, } - e.POST("/user/1/goals").WithJSON(requestBody).Expect().Status(201) + e.POST("/user/1/allowance").WithJSON(requestBody).Expect().Status(201) - // Validate goal - result := e.GET("/user/1/goals").Expect().Status(200).JSON().Array() + // Validate allowance + result := e.GET("/user/1/allowance").Expect().Status(200).JSON().Array() result.Length().IsEqual(1) item := result.Value(0).Object() item.Value("id").IsEqual(1) - item.Value("name").IsEqual(TestGoalName) + item.Value("name").IsEqual(TestAllowanceName) item.Value("target").IsEqual(5000) item.Value("weight").IsEqual(10) item.Value("progress").IsEqual(0) item.NotContainsKey("user_id") } -func TestGetUserGoalsNoUser(t *testing.T) { +func TestGetUserAllowanceNoUser(t *testing.T) { e := startServer(t) - e.GET("/user/999/goals").Expect().Status(404) + e.GET("/user/999/allowance").Expect().Status(404) } -func TestGetUserGoalsBadId(t *testing.T) { +func TestGetUserAllowanceBadId(t *testing.T) { e := startServer(t) - e.GET("/user/bad-id/goals").Expect().Status(400) + e.GET("/user/bad-id/allowance").Expect().Status(400) } -func TestCreateUserGoal(t *testing.T) { +func TestCreateUserAllowance(t *testing.T) { e := startServer(t) - // Create a new goal + // Create a new allowance requestBody := map[string]interface{}{ - "name": TestGoalName, + "name": TestAllowanceName, "target": 5000, "weight": 10, } - response := e.POST("/user/1/goals"). + response := e.POST("/user/1/allowance"). WithJSON(requestBody). Expect(). Status(201). @@ -106,40 +106,40 @@ func TestCreateUserGoal(t *testing.T) { // Verify the response has an ID response.ContainsKey("id") - goalId := response.Value("id").Number().Raw() + allowanceId := response.Value("id").Number().Raw() - // Verify the goal exists in the list of goals - goals := e.GET("/user/1/goals"). + // Verify the allowance exists in the list of allowances + allowances := e.GET("/user/1/allowance"). Expect(). Status(200). JSON().Array() - goals.Length().IsEqual(1) + allowances.Length().IsEqual(1) - goal := goals.Value(0).Object() - goal.Value("id").IsEqual(goalId) - goal.Value("name").IsEqual(TestGoalName) - goal.Value("target").IsEqual(5000) - goal.Value("weight").IsEqual(10) - goal.Value("progress").IsEqual(0) + allowance := allowances.Value(0).Object() + allowance.Value("id").IsEqual(allowanceId) + allowance.Value("name").IsEqual(TestAllowanceName) + allowance.Value("target").IsEqual(5000) + allowance.Value("weight").IsEqual(10) + allowance.Value("progress").IsEqual(0) } -func TestCreateUserGoalNoUser(t *testing.T) { +func TestCreateUserAllowanceNoUser(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ - "name": TestGoalName, + "name": TestAllowanceName, "target": 5000, "weight": 10, } - e.POST("/user/999/goals"). + e.POST("/user/999/allowance"). WithJSON(requestBody). Expect(). Status(404) } -func TestCreateUserGoalInvalidInput(t *testing.T) { +func TestCreateUserAllowanceInvalidInput(t *testing.T) { e := startServer(t) // Test with empty name @@ -149,7 +149,7 @@ func TestCreateUserGoalInvalidInput(t *testing.T) { "weight": 10, } - e.POST("/user/1/goals"). + e.POST("/user/1/allowance"). WithJSON(requestBody). Expect(). Status(400) @@ -159,76 +159,76 @@ func TestCreateUserGoalInvalidInput(t *testing.T) { "target": 5000, } - e.POST("/user/1/goals"). + e.POST("/user/1/allowance"). WithJSON(invalidRequest). Expect(). Status(400) } -func TestCreateUserGoalBadId(t *testing.T) { +func TestCreateUserAllowanceBadId(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ - "name": TestGoalName, + "name": TestAllowanceName, "target": 5000, "weight": 10, } - e.POST("/user/bad-id/goals"). + e.POST("/user/bad-id/allowance"). WithJSON(requestBody). Expect(). Status(400) } -func TestDeleteUserGoal(t *testing.T) { +func TestDeleteUserAllowance(t *testing.T) { e := startServer(t) - // Create a new goal to delete + // Create a new allowance to delete createRequest := map[string]interface{}{ - "name": TestGoalName, + "name": TestAllowanceName, "target": 1000, "weight": 5, } - response := e.POST("/user/1/goals"). + response := e.POST("/user/1/allowance"). WithJSON(createRequest). Expect(). Status(201). JSON().Object() - goalId := response.Value("id").Number().Raw() + allowanceId := response.Value("id").Number().Raw() - // Delete the goal - e.DELETE("/user/1/goal/" + strconv.Itoa(int(goalId))). + // Delete the allowance + e.DELETE("/user/1/allowance/" + strconv.Itoa(int(allowanceId))). Expect(). Status(200). - JSON().Object().Value("message").IsEqual("Goal deleted successfully") + JSON().Object().Value("message").IsEqual("History deleted successfully") - // Verify the goal no longer exists - goals := e.GET("/user/1/goals"). + // Verify the allowance no longer exists + allowances := e.GET("/user/1/allowance"). Expect(). Status(200). JSON().Array() - goals.Length().IsEqual(0) + allowances.Length().IsEqual(0) } -func TestDeleteUserGoalNotFound(t *testing.T) { +func TestDeleteUserAllowanceNotFound(t *testing.T) { e := startServer(t) - // Attempt to delete a non-existent goal - e.DELETE("/user/1/goal/999"). + // Attempt to delete a non-existent allowance + e.DELETE("/user/1/allowance/999"). Expect(). Status(404). - JSON().Object().Value("error").IsEqual("Goal not found") + JSON().Object().Value("error").IsEqual("History not found") } -func TestDeleteUserGoalInvalidId(t *testing.T) { +func TestDeleteUserAllowanceInvalidId(t *testing.T) { e := startServer(t) - // Attempt to delete a goal with an invalid ID - e.DELETE("/user/1/goal/invalid-id"). + // Attempt to delete an allowance with an invalid ID + e.DELETE("/user/1/allowance/invalid-id"). Expect(). Status(400). - JSON().Object().Value("error").IsEqual("Invalid goal ID") + JSON().Object().Value("error").IsEqual("Invalid allowance ID") } func TestCreateTask(t *testing.T) { @@ -323,7 +323,7 @@ func createTestTask(e *httpexpect.Expect) { e.POST("/tasks").WithJSON(requestBody).Expect().Status(201) } -func TestGetTaskSWhenTasks(t *testing.T) { +func TestGetTasksWhenTasks(t *testing.T) { e := startServer(t) createTestTask(e) @@ -391,9 +391,9 @@ func TestPutTaskInvalidTaskId(t *testing.T) { 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) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: 100}).Expect().Status(200) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: 20}).Expect().Status(200) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: -10}).Expect().Status(200) response := e.GET("/user/1").Expect().Status(200).JSON().Object() response.Value("allowance").Number().IsEqual(100 + 20 - 10) @@ -402,16 +402,16 @@ func TestPostAllowance(t *testing.T) { func TestPostAllowanceInvalidUserId(t *testing.T) { e := startServer(t) - e.POST("/user/999/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect(). + e.POST("/user/999/history").WithJSON(PostHistory{Allowance: 100}).Expect(). Status(404) } func TestGetHistory(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) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: 100}).Expect().Status(200) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: 20}).Expect().Status(200) + e.POST("/user/1/history").WithJSON(PostHistory{Allowance: -10}).Expect().Status(200) response := e.GET("/user/1/history").Expect().Status(200).JSON().Array() response.Length().IsEqual(3) diff --git a/backend/db.go b/backend/db.go index 120143b..bf5c003 100644 --- a/backend/db.go +++ b/backend/db.go @@ -67,27 +67,27 @@ func (db *Db) UserExists(userId int) (bool, error) { return count > 0, nil } -func (db *Db) GetUserGoals(userId int) ([]Goal, error) { - goals := make([]Goal, 0) +func (db *Db) GetUserAllowances(userId int) ([]Allowance, error) { + allowances := make([]Allowance, 0) var err error - for row := range db.db.Query("select id, name, target, progress, weight from goals where user_id = ?"). + for row := range db.db.Query("select id, name, target, progress, weight from allowances where user_id = ?"). Bind(userId).Range(&err) { - goal := Goal{} - err = row.Scan(&goal.ID, &goal.Name, &goal.Target, &goal.Progress, &goal.Weight) + allowance := Allowance{} + err = row.Scan(&allowance.ID, &allowance.Name, &allowance.Target, &allowance.Progress, &allowance.Weight) if err != nil { return nil, err } - goals = append(goals, goal) + allowances = append(allowances, allowance) } if err != nil { return nil, err } - return goals, nil + return allowances, nil } -func (db *Db) CreateGoal(userId int, goal *CreateGoalRequest) (int, error) { - // Check if user exists before attempting to create a goal +func (db *Db) CreateAllowance(userId int, allowance *CreateAllowanceRequest) (int, error) { + // Check if user exists before attempting to create an allowance exists, err := db.UserExists(userId) if err != nil { return 0, err @@ -102,9 +102,9 @@ func (db *Db) CreateGoal(userId int, goal *CreateGoalRequest) (int, error) { } defer tx.MustRollback() - // Insert the new goal - err = tx.Query("insert into goals (user_id, name, target, progress, weight) values (?, ?, ?, 0, ?)"). - Bind(userId, goal.Name, goal.Target, goal.Weight). + // Insert the new allowance + err = tx.Query("insert into allowances (user_id, name, target, progress, weight) values (?, ?, ?, 0, ?)"). + Bind(userId, allowance.Name, allowance.Target, allowance.Weight). Exec() if err != nil { @@ -127,21 +127,21 @@ func (db *Db) CreateGoal(userId int, goal *CreateGoalRequest) (int, error) { return lastId, nil } -func (db *Db) DeleteGoal(userId int, goalId int) error { - // Check if the goal exists for the user +func (db *Db) DeleteAllowance(userId int, allowanceId int) error { + // Check if the allowance exists for the user count := 0 - err := db.db.Query("select count(*) from goals where id = ? and user_id = ?"). - Bind(goalId, userId).ScanSingle(&count) + err := db.db.Query("select count(*) from allowances where id = ? and user_id = ?"). + Bind(allowanceId, userId).ScanSingle(&count) if err != nil { return err } if count == 0 { - return errors.New("goal not found") + return errors.New("allowance not found") } - // Delete the goal - err = db.db.Query("delete from goals where id = ? and user_id = ?"). - Bind(goalId, userId).Exec() + // Delete the allowance + err = db.db.Query("delete from allowances where id = ? and user_id = ?"). + Bind(allowanceId, userId).Exec() if err != nil { return err } @@ -236,7 +236,7 @@ func (db *Db) UpdateTask(id int, task *CreateTaskRequest) error { return tx.Commit() } -func (db *Db) AddAllowance(userId int, allowance *PostAllowance) error { +func (db *Db) AddHistory(userId int, allowance *PostHistory) error { tx, err := db.db.Begin() if err != nil { return err @@ -252,13 +252,13 @@ func (db *Db) AddAllowance(userId int, allowance *PostAllowance) error { return tx.Commit() } -func (db *Db) GetHistory(userId int) ([]Allowance, error) { - history := make([]Allowance, 0) +func (db *Db) GetHistory(userId int) ([]History, error) { + history := make([]History, 0) var err error for row := range db.db.Query("select amount, `timestamp` from history where user_id = ? order by `timestamp` desc"). Bind(userId).Range(&err) { - allowance := Allowance{} + allowance := History{} var timestamp int64 err = row.Scan(&allowance.Allowance, ×tamp) if err != nil { diff --git a/backend/dto.go b/backend/dto.go index 225e28d..e305014 100644 --- a/backend/dto.go +++ b/backend/dto.go @@ -13,12 +13,12 @@ type UserWithAllowance struct { Allowance int `json:"allowance"` } -type Allowance struct { +type History struct { Allowance int `json:"allowance"` Timestamp time.Time `json:"timestamp"` } -type PostAllowance struct { +type PostHistory struct { Allowance int `json:"allowance"` } @@ -30,7 +30,7 @@ type Task struct { Assigned *int `json:"assigned"` // Pointer to allow null } -type Goal struct { +type Allowance struct { ID int `json:"id"` Name string `json:"name"` Target int `json:"target"` @@ -38,7 +38,7 @@ type Goal struct { Weight int `json:"weight"` } -type CreateGoalRequest struct { +type CreateAllowanceRequest struct { Name string `json:"name"` Target int `json:"target"` Weight int `json:"weight"` diff --git a/backend/main.go b/backend/main.go index 25ea271..ba28005 100644 --- a/backend/main.go +++ b/backend/main.go @@ -76,7 +76,7 @@ func getUser(c *gin.Context) { c.IndentedJSON(http.StatusOK, user) } -func getUserGoals(c *gin.Context) { +func getUserAllowance(c *gin.Context) { userIdStr := c.Param("userId") userId, err := strconv.Atoi(userIdStr) if err != nil { @@ -97,16 +97,16 @@ func getUserGoals(c *gin.Context) { return } - goals, err := db.GetUserGoals(userId) + allowances, err := db.GetUserAllowances(userId) if err != nil { - log.Printf("Error getting user goals: %v", err) + log.Printf("Error getting user allowance: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) return } - c.IndentedJSON(http.StatusOK, goals) + c.IndentedJSON(http.StatusOK, allowances) } -func createUserGoal(c *gin.Context) { +func createUserAllowance(c *gin.Context) { userIdStr := c.Param("userId") userId, err := strconv.Atoi(userIdStr) if err != nil { @@ -116,7 +116,7 @@ func createUserGoal(c *gin.Context) { } // Parse request body - var goalRequest CreateGoalRequest + var goalRequest CreateAllowanceRequest if err := c.ShouldBindJSON(&goalRequest); err != nil { log.Printf("Error parsing request body: %v", err) c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) @@ -125,12 +125,12 @@ func createUserGoal(c *gin.Context) { // Validate request if goalRequest.Name == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Goal name cannot be empty"}) + c.JSON(http.StatusBadRequest, gin.H{"error": "Allowance name cannot be empty"}) return } // Create goal in database - goalId, err := db.CreateGoal(userId, &goalRequest) + goalId, err := db.CreateAllowance(userId, &goalRequest) if err != nil { log.Printf("Error creating goal: %v", err) if err.Error() == "user does not exist" { @@ -146,9 +146,9 @@ func createUserGoal(c *gin.Context) { c.IndentedJSON(http.StatusCreated, response) } -func deleteUserGoal(c *gin.Context) { +func deleteUserAllowance(c *gin.Context) { userIdStr := c.Param("userId") - goalIdStr := c.Param("goalId") + allowanceIdStr := c.Param("allowanceId") userId, err := strconv.Atoi(userIdStr) if err != nil { @@ -157,10 +157,10 @@ func deleteUserGoal(c *gin.Context) { return } - goalId, err := strconv.Atoi(goalIdStr) + allowanceId, err := strconv.Atoi(allowanceIdStr) if err != nil { - log.Printf("Invalid goal ID: %v", err) - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"}) + log.Printf("Invalid allowance ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid allowance ID"}) return } @@ -175,18 +175,18 @@ func deleteUserGoal(c *gin.Context) { return } - err = db.DeleteGoal(userId, goalId) + err = db.DeleteAllowance(userId, allowanceId) if err != nil { - if err.Error() == "goal not found" { - c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"}) + if err.Error() == "allowance not found" { + c.JSON(http.StatusNotFound, gin.H{"error": "History not found"}) } else { - log.Printf("Error deleting goal: %v", err) + log.Printf("Error deleting allowance: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) } return } - c.IndentedJSON(http.StatusOK, gin.H{"message": "Goal deleted successfully"}) + c.IndentedJSON(http.StatusOK, gin.H{"message": "History deleted successfully"}) } func createTask(c *gin.Context) { @@ -290,7 +290,7 @@ func putTask(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "Task updated successfully"}) } -func postAllowance(c *gin.Context) { +func postHistory(c *gin.Context) { userIdStr := c.Param("userId") userId, err := strconv.Atoi(userIdStr) if err != nil { @@ -299,8 +299,8 @@ func postAllowance(c *gin.Context) { return } - var allowanceRequest PostAllowance - if err := c.ShouldBindJSON(&allowanceRequest); err != nil { + var historyRequest PostHistory + if err := c.ShouldBindJSON(&historyRequest); err != nil { log.Printf("Error parsing request body: %v", err) c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return @@ -317,13 +317,13 @@ func postAllowance(c *gin.Context) { return } - err = db.AddAllowance(userId, &allowanceRequest) + err = db.AddHistory(userId, &historyRequest) if err != nil { - log.Printf("Error updating allowance: %v", err) + log.Printf("Error updating history: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) return } - c.JSON(http.StatusOK, gin.H{"message": "Allowance updated successfully"}) + c.JSON(http.StatusOK, gin.H{"message": "History updated successfully"}) } func getHistory(c *gin.Context) { @@ -359,11 +359,11 @@ func start(ctx context.Context, config *ServerConfig) { })) router.GET("/api/users", getUsers) router.GET("/api/user/:userId", getUser) - router.POST("/api/user/:userId/allowance", postAllowance) + router.POST("/api/user/:userId/history", postHistory) router.GET("/api/user/:userId/history", getHistory) - router.GET("/api/user/:userId/goals", getUserGoals) - router.POST("/api/user/:userId/goals", createUserGoal) - router.DELETE("/api/user/:userId/goal/:goalId", deleteUserGoal) + router.GET("/api/user/:userId/allowance", getUserAllowance) + router.POST("/api/user/:userId/allowance", createUserAllowance) + router.DELETE("/api/user/:userId/allowance/:allowanceId", deleteUserAllowance) router.POST("/api/tasks", createTask) router.GET("/api/tasks", getTasks) router.GET("/api/task/:taskId", getTask) diff --git a/backend/migrations/1_initial.sql b/backend/migrations/1_initial.sql index 9c3500e..cb7a4ce 100644 --- a/backend/migrations/1_initial.sql +++ b/backend/migrations/1_initial.sql @@ -12,7 +12,7 @@ create table history amount integer not null ); -create table goals +create table allowances ( id integer primary key, user_id integer not null, diff --git a/common/api.yaml b/common/api.yaml index 240255a..e2fddd9 100644 --- a/common/api.yaml +++ b/common/api.yaml @@ -59,7 +59,7 @@ paths: 404: description: The users could not be found. - /user/{userId}/allowance: + /user/{userId}/history: get: summary: Gets the allowance history of a user parameters: @@ -114,7 +114,7 @@ paths: 400: description: The allowance could not be updated. - /user/{userId}/goals: + /user/{userId}/allowance: get: summary: Gets all goals parameters: @@ -201,7 +201,7 @@ paths: 404: description: The goals could not be found. - /user/{userId}/goal/{goalId}: + /user/{userId}/allowance/{goalId}: get: summary: Gets information about a goal parameters: @@ -284,7 +284,7 @@ paths: 404: description: The goal could not be found. - /user/{userId}/goal/{goalId}/complete: + /user/{userId}/allowance/{goalId}/complete: post: summary: Completes a goal. description: Completes a goal. This will subtract this goal's value from the user's allowance and then remove the goal.