diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 6da6f32..f958fba 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -432,6 +432,34 @@ const docTemplate = `{ } } }, + "/tasks": { + "post": { + "description": "Create a new task", + "tags": [ + "tasks" + ], + "summary": "Create a New Task", + "parameters": [ + { + "description": "Create Task Request", + "name": "request_body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tasks.TaskBody" + } + } + ], + "responses": { + "201": { + "description": "Created Task", + "schema": { + "$ref": "#/definitions/models.Task" + } + } + } + } + }, "/tasks/assigned": { "get": { "description": "get tasks assigned to given users", @@ -532,6 +560,92 @@ const docTemplate = `{ } } }, + "/tasks/{tid}": { + "get": { + "description": "get a task given its id", + "tags": [ + "tasks" + ], + "summary": "get task by id", + "parameters": [ + { + "type": "integer", + "description": "the id of the task", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Task" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + } + } + }, + "put": { + "description": "Update the task_info field of a task by ID", + "tags": [ + "tasks" + ], + "summary": "Update Task Info", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + }, + { + "description": "Update Task Info Request", + "name": "request_body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tasks.TaskBody" + } + } + ], + "responses": { + "200": { + "description": "Updated Task", + "schema": { + "$ref": "#/definitions/models.Task" + } + } + } + }, + "delete": { + "description": "Delete a task by ID", + "tags": [ + "tasks" + ], + "summary": "Delete a Task", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/tasks/{tid}/assign": { "post": { "description": "assign users to task", @@ -576,6 +690,41 @@ const docTemplate = `{ } } }, + "/tasks/{tid}/assigned": { + "get": { + "description": "Get list of users assigned to a task by task ID", + "tags": [ + "tasks" + ], + "summary": "Get list of users assigned to a task", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "List of user IDs assigned to the task", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + } + } + } + }, "/tasks/{tid}/labels": { "get": { "description": "get a tasks labels given the task id", @@ -954,6 +1103,48 @@ const docTemplate = `{ } } } + }, + "tasks.TaskBody": { + "type": "object", + "properties": { + "created_by": { + "description": "User ID", + "type": "string" + }, + "created_date": { + "type": "string" + }, + "end_date": { + "type": "string" + }, + "group_id": { + "type": "integer" + }, + "notes": { + "type": "string" + }, + "repeating": { + "type": "boolean" + }, + "repeating_end_date": { + "type": "string" + }, + "repeating_interval": { + "type": "string" + }, + "start_date": { + "type": "string" + }, + "task_info": { + "type": "string" + }, + "task_status": { + "type": "string" + }, + "task_type": { + "type": "string" + } + } } } }` diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 40f2229..05ec608 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -425,6 +425,34 @@ } } }, + "/tasks": { + "post": { + "description": "Create a new task", + "tags": [ + "tasks" + ], + "summary": "Create a New Task", + "parameters": [ + { + "description": "Create Task Request", + "name": "request_body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tasks.TaskBody" + } + } + ], + "responses": { + "201": { + "description": "Created Task", + "schema": { + "$ref": "#/definitions/models.Task" + } + } + } + } + }, "/tasks/assigned": { "get": { "description": "get tasks assigned to given users", @@ -525,6 +553,92 @@ } } }, + "/tasks/{tid}": { + "get": { + "description": "get a task given its id", + "tags": [ + "tasks" + ], + "summary": "get task by id", + "parameters": [ + { + "type": "integer", + "description": "the id of the task", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Task" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + } + } + }, + "put": { + "description": "Update the task_info field of a task by ID", + "tags": [ + "tasks" + ], + "summary": "Update Task Info", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + }, + { + "description": "Update Task Info Request", + "name": "request_body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tasks.TaskBody" + } + } + ], + "responses": { + "200": { + "description": "Updated Task", + "schema": { + "$ref": "#/definitions/models.Task" + } + } + } + }, + "delete": { + "description": "Delete a task by ID", + "tags": [ + "tasks" + ], + "summary": "Delete a Task", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/tasks/{tid}/assign": { "post": { "description": "assign users to task", @@ -569,6 +683,41 @@ } } }, + "/tasks/{tid}/assigned": { + "get": { + "description": "Get list of users assigned to a task by task ID", + "tags": [ + "tasks" + ], + "summary": "Get list of users assigned to a task", + "parameters": [ + { + "type": "integer", + "description": "Task ID", + "name": "tid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "List of user IDs assigned to the task", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + } + } + } + }, "/tasks/{tid}/labels": { "get": { "description": "get a tasks labels given the task id", @@ -947,6 +1096,48 @@ } } } + }, + "tasks.TaskBody": { + "type": "object", + "properties": { + "created_by": { + "description": "User ID", + "type": "string" + }, + "created_date": { + "type": "string" + }, + "end_date": { + "type": "string" + }, + "group_id": { + "type": "integer" + }, + "notes": { + "type": "string" + }, + "repeating": { + "type": "boolean" + }, + "repeating_end_date": { + "type": "string" + }, + "repeating_interval": { + "type": "string" + }, + "start_date": { + "type": "string" + }, + "task_info": { + "type": "string" + }, + "task_status": { + "type": "string" + }, + "task_type": { + "type": "string" + } + } } } } \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 2617a4b..f6b619e 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -144,6 +144,34 @@ definitions: type: string type: array type: object + tasks.TaskBody: + properties: + created_by: + description: User ID + type: string + created_date: + type: string + end_date: + type: string + group_id: + type: integer + notes: + type: string + repeating: + type: boolean + repeating_end_date: + type: string + repeating_interval: + type: string + start_date: + type: string + task_info: + type: string + task_status: + type: string + task_type: + type: string + type: object info: contact: {} description: This is an API for the Care-Wallet App. @@ -426,6 +454,81 @@ paths: summary: add a medication tags: - medications + /tasks: + post: + description: Create a new task + parameters: + - description: Create Task Request + in: body + name: request_body + required: true + schema: + $ref: '#/definitions/tasks.TaskBody' + responses: + "201": + description: Created Task + schema: + $ref: '#/definitions/models.Task' + summary: Create a New Task + tags: + - tasks + /tasks/{tid}: + delete: + description: Delete a task by ID + parameters: + - description: Task ID + in: path + name: tid + required: true + type: integer + responses: + "204": + description: No Content + summary: Delete a Task + tags: + - tasks + get: + description: get a task given its id + parameters: + - description: the id of the task + in: path + name: tid + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Task' + "400": + description: Bad Request + schema: + type: string + summary: get task by id + tags: + - tasks + put: + description: Update the task_info field of a task by ID + parameters: + - description: Task ID + in: path + name: tid + required: true + type: integer + - description: Update Task Info Request + in: body + name: request_body + required: true + schema: + $ref: '#/definitions/tasks.TaskBody' + responses: + "200": + description: Updated Task + schema: + $ref: '#/definitions/models.Task' + summary: Update Task Info + tags: + - tasks /tasks/{tid}/assign: post: description: assign users to task @@ -455,6 +558,29 @@ paths: summary: Assign Users To Task tags: - tasks + /tasks/{tid}/assigned: + get: + description: Get list of users assigned to a task by task ID + parameters: + - description: Task ID + in: path + name: tid + required: true + type: integer + responses: + "200": + description: List of user IDs assigned to the task + schema: + items: + type: string + type: array + "400": + description: Bad Request + schema: + type: string + summary: Get list of users assigned to a task + tags: + - tasks /tasks/{tid}/labels: delete: description: remove a label from a task given the task id, group id, and label diff --git a/backend/schema/tasks/routes.go b/backend/schema/tasks/routes.go index 6fef37a..9452a46 100644 --- a/backend/schema/tasks/routes.go +++ b/backend/schema/tasks/routes.go @@ -1,8 +1,13 @@ package tasks import ( + "carewallet/models" + "encoding/json" + "fmt" "net/http" + "strconv" "strings" + "time" "github.com/gin-gonic/gin" "github.com/jackc/pgx" @@ -13,18 +18,50 @@ type PgModel struct { } func TaskGroup(v1 *gin.RouterGroup, c *PgModel) *gin.RouterGroup { - tasks := v1.Group("") { tasks.GET("/filtered", c.GetFilteredTasks) - tasks.POST("/:tid/assign", c.AssignUsersToTask) - tasks.DELETE("/:tid/remove", c.RemoveUsersFromTask) tasks.GET("/assigned", c.GetTasksByAssignedUsers) - } + tasks.POST("", c.CreateTask) + byId := tasks.Group("/:tid") + { + byId.GET("", c.GetTaskByID) + byId.DELETE("", c.DeleteTask) + byId.PUT("", c.UpdateTaskInfo) + byId.GET("/assigned", c.GetUsersAssignedToTask) + byId.POST("/assign", c.AssignUsersToTask) + byId.DELETE("/remove", c.RemoveUsersFromTask) + } + } return tasks } +// GetTaskByID godoc +// +// @summary get task by id +// @description get a task given its id +// @tags tasks +// +// @param tid path int true "the id of the task" +// +// @success 200 {object} models.Task +// @failure 400 {object} string +// @router /tasks/{tid} [GET] +func (pg *PgModel) GetTaskByID(c *gin.Context) { + taskID, err := strconv.Atoi(c.Param("tid")) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + task, err := GetTaskByID(pg.Conn, taskID) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + c.JSON(http.StatusOK, task) +} + type TaskQuery struct { TaskID string `form:"taskID"` GroupID string `form:"groupID"` @@ -52,14 +89,11 @@ func (pg *PgModel) GetFilteredTasks(c *gin.Context) { c.JSON(http.StatusBadRequest, err.Error()) return } - tasks, err := GetTasksByQueryFromDB(pg.Conn, filterQuery) - if err != nil { c.JSON(http.StatusBadRequest, err.Error()) return } - c.JSON(http.StatusOK, tasks) } @@ -82,19 +116,15 @@ type Assignment struct { // @router /tasks/{tid}/assign [post] func (pg *PgModel) AssignUsersToTask(c *gin.Context) { var requestBody Assignment - if err := c.BindJSON(&requestBody); err != nil { c.JSON(http.StatusBadRequest, err.Error()) return } - assignedUsers, err := AssignUsersToTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid"), requestBody.Assigner) - if err != nil { c.JSON(http.StatusBadRequest, err.Error()) return } - c.JSON(http.StatusOK, assignedUsers) } @@ -116,19 +146,15 @@ type Removal struct { // @router /tasks/{tid}/remove [delete] func (pg *PgModel) RemoveUsersFromTask(c *gin.Context) { var requestBody Removal - if err := c.BindJSON(&requestBody); err != nil { c.JSON(http.StatusBadRequest, err.Error()) return } - removedUsers, err := RemoveUsersFromTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid")) - if err != nil { c.JSON(http.StatusBadRequest, err.Error()) return } - c.JSON(http.StatusOK, removedUsers) } @@ -152,13 +178,180 @@ func (pg *PgModel) GetTasksByAssignedUsers(c *gin.Context) { assignedQuery := AssignedQuery{ UserIDs: strings.Split(userIDs, ","), } - tasks, err := GetTasksByAssignedFromDB(pg.Conn, assignedQuery.UserIDs) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + c.JSON(http.StatusOK, tasks) +} +type TaskBody struct { + GroupID int `json:"group_id"` + CreatedBy string `json:"created_by"` // User ID + CreatedDate time.Time `json:"created_date"` + StartDate *time.Time `json:"start_date"` + EndDate *time.Time `json:"end_date"` + Notes *string `json:"notes"` + Repeating bool `json:"repeating"` + RepeatingInterval *string `json:"repeating_interval"` + RepeatingEndDate *time.Time `json:"repeating_end_date"` + TaskStatus string `json:"task_status"` + TaskType string `json:"task_type"` + TaskInfo *string `json:"task_info"` +} + +// CreateTask godoc +// +// @summary Create a New Task +// @description Create a new task +// @tags tasks +// +// @param request_body body TaskBody true "Create Task Request" +// +// @success 201 {object} models.Task "Created Task" +// @router /tasks [post] +func (pg *PgModel) CreateTask(c *gin.Context) { + // Bind the request body to the CreateTaskRequest struct + var requestBody models.Task + if err := c.BindJSON(&requestBody); err != nil { + fmt.Println("error binding to request body: ", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Create the new task in the database + newTaskID, err := CreateTaskInDB(pg.Conn, requestBody) if err != nil { + fmt.Println("error creating task in the database:", err) c.JSON(http.StatusBadRequest, err.Error()) return } - c.JSON(http.StatusOK, tasks) + // Fetch the created task from the database + createdTask, err := GetTaskByID(pg.Conn, newTaskID) + if err != nil { + fmt.Println("error fetching created task from the database:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + c.JSON(http.StatusCreated, createdTask) +} + +// DeleteTask godoc +// +// @summary Delete a Task +// @description Delete a task by ID +// @tags tasks +// @param tid path int true "Task ID" +// @success 204 "No Content" +// @router /tasks/{tid} [delete] +func (pg *PgModel) DeleteTask(c *gin.Context) { + // Extract task ID from the path parameter + taskID, err := strconv.Atoi(c.Param("tid")) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Check if the task exists before attempting to delete + if _, err := GetTaskByID(pg.Conn, taskID); err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Delete the task from the database + if err := DeleteTaskInDB(pg.Conn, taskID); err != nil { + fmt.Println("error deleting task from the database:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + c.Status(http.StatusNoContent) +} + +// UpdateTaskInfo godoc +// +// @summary Update Task Info +// @description Update the task_info field of a task by ID +// @tags tasks +// @param tid path int true "Task ID" +// @param request_body body TaskBody true "Update Task Info Request" +// @success 200 {object} models.Task "Updated Task" +// @router /tasks/{tid} [put] +func (pg *PgModel) UpdateTaskInfo(c *gin.Context) { + // Extract task ID from the path parameter + taskID, err := strconv.Atoi(c.Param("tid")) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Bind the request body to the UpdateTaskInfoRequest struct + var requestBody models.Task + + if err := c.BindJSON(&requestBody); err != nil { + fmt.Println("error binding to request body: ", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Convert TaskInfo to json.RawMessage + taskInfoRaw, err := json.Marshal(requestBody.TaskInfo) + if err != nil { + fmt.Println("error converting TaskInfo to json.RawMessage:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Update the task_info field in the database + if err := UpdateTaskInfoInDB(pg.Conn, taskID, taskInfoRaw); err != nil { + fmt.Println("error updating task info in the database:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Fetch the updated task from the database + updatedTask, err := GetTaskByID(pg.Conn, taskID) + if err != nil { + fmt.Println("error fetching updated task from the database:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + c.JSON(http.StatusOK, updatedTask) +} + +// TaskUser represents the user assigned to a task. +type TaskUser struct { + UserID string `json:"userID"` +} + +// GetUsersAssignedToTask godoc +// +// @summary Get list of users assigned to a task +// @description Get list of users assigned to a task by task ID +// @tags tasks +// @param tid path int true "Task ID" +// @success 200 {array} string "List of user IDs assigned to the task" +// @failure 400 {object} string +// @router /tasks/{tid}/assigned [get] +func (pg *PgModel) GetUsersAssignedToTask(c *gin.Context) { + // Extract task ID from the path parameter + taskIDStr := c.Param("tid") + taskID, err := strconv.Atoi(taskIDStr) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Get list of users assigned to the task + userIDs, err := GetUsersAssignedToTaskFromDB(pg.Conn, taskID) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + c.JSON(http.StatusOK, userIDs) } diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index c8785fe..12847d8 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -12,6 +12,7 @@ import ( "net/url" "os" "reflect" + "strconv" "testing" "time" @@ -51,12 +52,12 @@ func TestTaskGroup(t *testing.T) { w := httptest.NewRecorder() query := url.Values{} - query.Add("groupID", getRequest.GroupID) - query.Add("createdBy", getRequest.CreatedBy) - query.Add("taskStatus", getRequest.TaskStatus) - query.Add("taskType", getRequest.TaskType) - query.Add("startDate", getRequest.StartDate) - query.Add("endDate", getRequest.EndDate) + query.Set("groupID", getRequest.GroupID) + query.Set("createdBy", getRequest.CreatedBy) + query.Set("taskStatus", getRequest.TaskStatus) + query.Set("taskType", getRequest.TaskType) + query.Set("startDate", getRequest.StartDate) + query.Set("endDate", getRequest.EndDate) req, _ := http.NewRequest("GET", "/tasks/filtered?"+query.Encode(), nil) router.ServeHTTP(w, req) @@ -172,6 +173,40 @@ func TestTaskGroup(t *testing.T) { } }) + t.Run("TestGetTasksByAssigned", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/assigned?userIDs=user2", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by assigned user.") + } + + var responseTasks []models.Task + err = json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + note := "Refill water pitcher" + expectedTasks := []models.Task{ + { + TaskID: 4, + GroupID: 4, + CreatedBy: "user1", + CreatedDate: time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), + Notes: ¬e, + TaskStatus: "COMPLETE", + TaskType: "other", + }, + } + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + t.Run("TestGetTasksByAssigned", func(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/tasks/assigned?userIDs=user2", nil) @@ -207,4 +242,208 @@ func TestTaskGroup(t *testing.T) { t.Error("Result was not correct") } }) + + t.Run("TestCreateTask_Success", func(t *testing.T) { + // Creating a Task instance + startDate := time.Now().UTC() + endDate := time.Now().Add(24 * time.Hour).UTC() + notes := "This is a sample task" + repeating := true + repeatingInterval := "Weekly" + repeatingEndDate := time.Now().Add(7 * 24 * time.Hour).UTC() + taskInfo := `{"info": "Additional information about the task"}` + + taskData := models.Task{ + TaskID: 1, + GroupID: 1, + CreatedBy: "user1", + CreatedDate: time.Now().UTC(), + StartDate: &startDate, + EndDate: &endDate, + Notes: ¬es, + Repeating: repeating, + RepeatingInterval: &repeatingInterval, + RepeatingEndDate: &repeatingEndDate, + TaskStatus: "INCOMPLETE", + TaskType: "med_mgmt", + TaskInfo: &taskInfo, + } + + taskJSON, err := json.Marshal(taskData) + if err != nil { + t.Error("Failed to marshal task data to JSON:", err) + } + + // Create a new request with the task data + req, err := http.NewRequest("POST", "/tasks", bytes.NewBuffer(taskJSON)) + if err != nil { + t.Error("Failed to create HTTP request:", err) + } + + // Create a recorder to capture the response + w := httptest.NewRecorder() + + // Serve the request using the router + router.ServeHTTP(w, req) + + // Assertions + if http.StatusCreated != w.Code { + t.Error("Expected status 201, got", w.Code) + } + + // Validate the response body + var createdTask models.Task + err = json.Unmarshal(w.Body.Bytes(), &createdTask) + if err != nil { + t.Error("Failed to unmarshal JSON:", err) + } + + // Add more specific assertions based on the expected response + if createdTask.TaskID == -1 { + t.Error("Expected task ID to be present") + } + if createdTask.CreatedBy != "user1" { + t.Error("Unexpected created_by value") + } + // Add more assertions as needed + }) + + t.Run("TestDeleteTask", func(t *testing.T) { + getTaskByIDFunc := func(taskID int) (models.Task, error) { + return models.Task{ + TaskID: taskID, + // Add other necessary fields + }, nil + } + + // Mock the successful deletion of the task in the database + deleteTaskInDBFunc := func(taskID int) error { + return nil + } + + // Create a new Gin router + router := gin.Default() + + // Attach the DeleteTask route to the router + router.DELETE("/tasks/:tid", func(c *gin.Context) { + // Extract task ID from the path parameter + taskID, err := strconv.Atoi(c.Param("tid")) + if err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Check if the task exists before attempting to delete + if _, err := getTaskByIDFunc(taskID); err != nil { + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + // Delete the task from the database + if err := deleteTaskInDBFunc(taskID); err != nil { + fmt.Println("error deleting task from the database:", err) + c.JSON(http.StatusBadRequest, err.Error()) + return + } + + c.Status(http.StatusNoContent) + }) + + // Perform a DELETE request to the /tasks/:tid endpoint + req, err := http.NewRequest("DELETE", "/tasks/1", nil) + if err != nil { + t.Fatal("Failed to create HTTP request:", err) + } + + w := httptest.NewRecorder() + router.ServeHTTP(w, req) + + // Assertions + if http.StatusNoContent != w.Code { + t.Fatal("Expected status 204, got", w.Code) + } + + if body := w.Body.String(); body != "" { + t.Fatal("Expected empty response body, got", body) + } + }) + + t.Run("TestUpdateTaskInfo", func(t *testing.T) { + // Creating a Task instance + startDate := time.Now().UTC() + endDate := time.Now().Add(24 * time.Hour).UTC() + notes := "This is a sample task" + repeating := true + repeatingInterval := "Weekly" + repeatingEndDate := time.Now().Add(7 * 24 * time.Hour).UTC() + taskInfo := `{"info": "Additional information about the task"}` + + taskData := models.Task{ + TaskID: 1, + GroupID: 1, + CreatedBy: "user1", + CreatedDate: time.Now().UTC(), + StartDate: &startDate, + EndDate: &endDate, + Notes: ¬es, + Repeating: repeating, + RepeatingInterval: &repeatingInterval, + RepeatingEndDate: &repeatingEndDate, + TaskStatus: "INCOMPLETE", + TaskType: "med_mgmt", + TaskInfo: &taskInfo, + } + requestBodyJSON, err := json.Marshal(taskData) + if err != nil { + t.Fatal("Failed to marshal task data to JSON:", err) + return + } + + // Perform a PUT request to the /tasks/:tid/info endpoint + req, err := http.NewRequest("PUT", "/tasks/1", bytes.NewBuffer(requestBodyJSON)) + if err != nil { + t.Fatal("Failed to create HTTP request:", err) + return + } + + // Create a recorder to capture the response + w := httptest.NewRecorder() + + // Serve the request using the router + router.ServeHTTP(w, req) + + // Assertions + if http.StatusOK != w.Code { + t.Fatal("Expected status 200, got", w.Code) + return + } + }) + + t.Run("TestGetUsersAssignedToTask", func(t *testing.T) { + // Create a new recorder and request + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/2/assigned", nil) + + // Serve the request using the router + router.ServeHTTP(w, req) + + // Print the response body for debugging + fmt.Println("Response Body:", w.Body.String()) + + // Assertions + if http.StatusOK != w.Code { + t.Error("Failed to retrieve users assigned to task.") + } + + var responseUsers []string + err := json.Unmarshal(w.Body.Bytes(), &responseUsers) + if err != nil { + t.Error("Failed to unmarshal JSON") + } + + expectedUsers := []string{"user3", "user4"} + if !reflect.DeepEqual(expectedUsers, responseUsers) { + t.Error("Result was not correct") + } + }) } diff --git a/backend/schema/tasks/transactions.go b/backend/schema/tasks/transactions.go index 77f87b2..31895b5 100644 --- a/backend/schema/tasks/transactions.go +++ b/backend/schema/tasks/transactions.go @@ -2,6 +2,7 @@ package tasks import ( "carewallet/models" + "encoding/json" "fmt" "strconv" "time" @@ -154,3 +155,97 @@ func GetTasksByAssignedFromDB(pool *pgx.Conn, userIDs []string) ([]models.Task, return tasks, nil } + +// CreateTaskInDB creates a new task in the database and returns its ID +func CreateTaskInDB(pool *pgx.Conn, newTask models.Task) (int, error) { + query := ` + INSERT INTO task (group_id, created_by, created_date, start_date, end_date, notes, repeating, repeating_interval, repeating_end_date, task_status, task_type, task_info) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING task_id` + + var newTaskID int + err := pool.QueryRow( + query, + newTask.GroupID, + newTask.CreatedBy, + time.Now(), // Assuming created_date should be the current timestamp + newTask.StartDate, + newTask.EndDate, + newTask.Notes, + newTask.Repeating, + newTask.RepeatingInterval, + newTask.RepeatingEndDate, + newTask.TaskStatus, + newTask.TaskType, + newTask.TaskInfo, + ).Scan(&newTaskID) + + return newTaskID, err +} + +// DeleteTaskInDB deletes a task from the database by ID +func DeleteTaskInDB(pool *pgx.Conn, taskID int) error { + // Assuming "task" table structure, adjust the query based on your schema + query := "DELETE FROM task WHERE task_id = $1" + + _, err := pool.Exec(query, taskID) + return err +} + +// UpdateTaskInfoInDB updates the task_info field in the database +func UpdateTaskInfoInDB(pool *pgx.Conn, taskID int, taskInfo json.RawMessage) error { + // Assuming "task" table structure, adjust the query based on your schema + query := "UPDATE task SET task_info = $1 WHERE task_id = $2" + + _, err := pool.Exec(query, taskInfo, taskID) + return err +} + +// GetTaskByID fetches a task from the database by its ID +func GetTaskByID(pool *pgx.Conn, taskID int) (models.Task, error) { + query := ` + SELECT task_id, group_id, created_by, created_date, start_date, end_date, notes, repeating, repeating_interval, repeating_end_date, task_status, task_type, task_info FROM task WHERE task_id = $1` + + var task models.Task + err := pool.QueryRow(query, taskID).Scan( + &task.TaskID, + &task.GroupID, + &task.CreatedBy, + &task.CreatedDate, + &task.StartDate, + &task.EndDate, + &task.Notes, + &task.Repeating, + &task.RepeatingInterval, + &task.RepeatingEndDate, + &task.TaskStatus, + &task.TaskType, + &task.TaskInfo, + ) + return task, err +} + +func GetUsersAssignedToTaskFromDB(pool *pgx.Conn, taskID int) ([]string, error) { + var userIDs []string + + // Get all user IDs assigned to the task + rows, err := pool.Query("SELECT user_id FROM task_assignees WHERE task_id = $1;", taskID) + if err != nil { + fmt.Println(err, "error selecting user assignees") + return nil, err + } + defer rows.Close() + + for rows.Next() { + var userID string + + err := rows.Scan(&userID) + if err != nil { + fmt.Println(err, "error scanning user ID") + return nil, err + } + + fmt.Println(userID) + userIDs = append(userIDs, userID) + } + + return userIDs, nil +}