From abea1a86bb9355021a46b8872262a231b33ca9b2 Mon Sep 17 00:00:00 2001 From: bedrockdude10 Date: Wed, 31 Jan 2024 19:08:22 -0500 Subject: [PATCH 1/8] Added mock data --- backend/db/migrations/init.sql | 68 +++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/backend/db/migrations/init.sql b/backend/db/migrations/init.sql index e5c0512..7dc3a13 100644 --- a/backend/db/migrations/init.sql +++ b/backend/db/migrations/init.sql @@ -8,7 +8,6 @@ DROP TABLE IF EXISTS label; DROP TABLE IF EXISTS task_labels; DROP TABLE IF EXISTS files; - CREATE TYPE role AS ENUM ('PATIENT', 'PRIMARY', 'SECONDARY'); CREATE TYPE task_assignment_status AS ENUM ('ACCEPTED', 'DECLINED', 'NOTIFIED'); CREATE TYPE task_status AS ENUM ('INCOMPLETE', 'COMPLETE', 'PARTIAL'); @@ -113,6 +112,7 @@ CREATE TABLE IF NOT EXISTS files ( FOREIGN KEY (task_id) REFERENCES task (task_id) ); +----------------- SAMPLE DATA :) ----------------------- -- Insert sample data into "medication" table INSERT INTO medication (medication_id, medication_name) @@ -122,3 +122,69 @@ VALUES (3, 'Medication C'), (4, 'Medication D'), (5, 'Medication E') + +INSERT INTO care_group (group_name, date_created) +VALUES + ('Smith Family', NOW()), + ('Johnson Support Network', NOW()), + ('Williams Care Team', NOW()), + ('Brown Medical Group', NOW()) +; + +INSERT INTO users (user_id, first_name, last_name, email, phone, address) +VALUES + ('user1', 'John', 'Smith', 'john.smith@example.com', '123-456-7890', '123 Main St'), + ('user2', 'Jane', 'Doe', 'jane.doe@example.com', '987-654-3210', '456 Elm St'), + ('user3', 'Bob', 'Johnson', 'bob.johnson@example.com', NULL, NULL), + ('user4', 'Emily', 'Garcia', 'emily.garcia@example.com', '555-1212', '789 Oak Ave') +; + +INSERT INTO group_roles (group_id, user_id, role) +VALUES + (1, 'user1', 'PATIENT'), + (1, 'user2', 'PRIMARY'), + (2, 'user3', 'PRIMARY'), + (2, 'user4', 'SECONDARY'), + (3, 'user4', 'PATIENT'), + (4, 'user1', 'SECONDARY'), + (4, 'user3', 'SECONDARY') +; + +INSERT INTO task (group_id, created_by, created_date, start_date, end_date, notes, task_status, task_type) +VALUES + (1, 'user2', NOW(), '2024-02-05 10:00:00', '2024-02-05 11:00:00', 'Pick up medication from pharmacy', 'INCOMPLETE', 'med_mgmt'), + (2, 'user3', NOW(), '2024-02-10 14:30:00', NULL, 'Schedule doctor appointment', 'INCOMPLETE', 'dr_appt'), + (3, 'user4', NOW(), NULL, '2024-02-20 23:59:59', 'Submit insurance claim', 'PARTIAL', 'financial'), + (4, 'user1', NOW(), NULL, NULL, 'Refill water pitcher', 'COMPLETE', 'other') +; + +INSERT INTO task_assignees (task_id, user_id, assignment_status, assigned_by, assigned_date) +VALUES + (1, 'user1', 'ACCEPTED', 'user2', NOW()), + (2, 'user3', 'NOTIFIED', 'user3', NOW()), + (3, 'user4', 'DECLINED', 'user4', NOW()), + (4, 'user2', 'COMPLETE', 'user1', NOW()) +; + +INSERT INTO label (group_id, label_name, label_color) +VALUES + (1, 'Medication', 'blue'), + (2, 'Appointments', 'green'), + (3, 'Financial', 'orange'), + (4, 'Household', 'purple') +; + +INSERT INTO task_labels (task_id, group_id, label_name) +VALUES + (1, 1, 'Medication'), + (2, 2, 'Appointments'), + (3, 3, 'Financial'), + (4, 4, 'Household') +; + +INSERT INTO files (file_id, file_name, group_id, upload_by, upload_date, file_size, task_id) +VALUES + (1, 'Medication list.pdf', 1, 'user2', NOW(), 123456, 1), + (2, 'Insurance form.docx', 3, 'user4', NOW(), 456789, 3), + (3, 'Water pitcher instructions.txt', 4, 'user1', NOW(), 1234, 4) +; From ba204fa7439da2080e7142cd0f2c80d34c5be533 Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Thu, 1 Feb 2024 16:12:50 -0500 Subject: [PATCH 2/8] feat: get tasks by gid/uid/status/type/date --- backend/db/migrations/init.sql | 11 +- backend/docs/docs.go | 165 +++++++++++++++++++++ backend/docs/swagger.json | 165 +++++++++++++++++++++ backend/docs/swagger.yaml | 108 ++++++++++++++ backend/models/task.go | 21 +++ backend/schema/tasks/routes.go | 129 +++++++++++++++++ backend/schema/tasks/task_test.go | 207 +++++++++++++++++++++++++++ backend/schema/tasks/transactions.go | 189 ++++++++++++++++++++++++ 8 files changed, 990 insertions(+), 5 deletions(-) create mode 100644 backend/models/task.go create mode 100644 backend/schema/tasks/routes.go create mode 100644 backend/schema/tasks/task_test.go create mode 100644 backend/schema/tasks/transactions.go diff --git a/backend/db/migrations/init.sql b/backend/db/migrations/init.sql index 7dc3a13..c380755 100644 --- a/backend/db/migrations/init.sql +++ b/backend/db/migrations/init.sql @@ -122,6 +122,7 @@ VALUES (3, 'Medication C'), (4, 'Medication D'), (5, 'Medication E') +; INSERT INTO care_group (group_name, date_created) VALUES @@ -152,10 +153,10 @@ VALUES INSERT INTO task (group_id, created_by, created_date, start_date, end_date, notes, task_status, task_type) VALUES - (1, 'user2', NOW(), '2024-02-05 10:00:00', '2024-02-05 11:00:00', 'Pick up medication from pharmacy', 'INCOMPLETE', 'med_mgmt'), - (2, 'user3', NOW(), '2024-02-10 14:30:00', NULL, 'Schedule doctor appointment', 'INCOMPLETE', 'dr_appt'), - (3, 'user4', NOW(), NULL, '2024-02-20 23:59:59', 'Submit insurance claim', 'PARTIAL', 'financial'), - (4, 'user1', NOW(), NULL, NULL, 'Refill water pitcher', 'COMPLETE', 'other') + (1, 'user2', '2024-02-03 10:45:00', '2024-02-05 10:00:00', '2024-02-05 11:00:00', 'Pick up medication from pharmacy', 'INCOMPLETE', 'med_mgmt'), + (2, 'user3', '2024-02-20 23:59:59', '2024-02-10 14:30:00', NULL, 'Schedule doctor appointment', 'INCOMPLETE', 'dr_appt'), + (3, 'user4', '2020-02-05 11:00:00', NULL, '2024-02-20 23:59:59', 'Submit insurance claim', 'PARTIAL', 'financial'), + (4, 'user1', '2006-01-02 15:04:05', NULL, NULL, 'Refill water pitcher', 'COMPLETE', 'other') ; INSERT INTO task_assignees (task_id, user_id, assignment_status, assigned_by, assigned_date) @@ -163,7 +164,7 @@ VALUES (1, 'user1', 'ACCEPTED', 'user2', NOW()), (2, 'user3', 'NOTIFIED', 'user3', NOW()), (3, 'user4', 'DECLINED', 'user4', NOW()), - (4, 'user2', 'COMPLETE', 'user1', NOW()) + (4, 'user2', 'DECLINED', 'user1', NOW()) ; INSERT INTO label (group_id, label_name, label_color) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 1c29687..63057d2 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -48,6 +48,126 @@ const docTemplate = `{ } } } + }, + "/tasks/{endDate}": { + "get": { + "description": "get all tasks by end date", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By End Date", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{gid}": { + "get": { + "description": "get all tasks by group id", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Group ID", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{startDate}": { + "get": { + "description": "get all tasks by start date", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Start Date", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{status}": { + "get": { + "description": "get all tasks by status", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Status", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{type}": { + "get": { + "description": "get all tasks by type", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Type", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{uid}": { + "get": { + "description": "get all tasks by user id", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By User ID", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } } }, "definitions": { @@ -61,6 +181,51 @@ const docTemplate = `{ "type": "string" } } + }, + "models.Task": { + "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_id": { + "type": "integer" + }, + "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 1ac678d..212af82 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -41,6 +41,126 @@ } } } + }, + "/tasks/{endDate}": { + "get": { + "description": "get all tasks by end date", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By End Date", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{gid}": { + "get": { + "description": "get all tasks by group id", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Group ID", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{startDate}": { + "get": { + "description": "get all tasks by start date", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Start Date", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{status}": { + "get": { + "description": "get all tasks by status", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Status", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{type}": { + "get": { + "description": "get all tasks by type", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By Type", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } + }, + "/tasks/{uid}": { + "get": { + "description": "get all tasks by user id", + "tags": [ + "tasks" + ], + "summary": "Get All Tasks By User ID", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Task" + } + } + } + } + } } }, "definitions": { @@ -54,6 +174,51 @@ "type": "string" } } + }, + "models.Task": { + "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_id": { + "type": "integer" + }, + "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 0f4976b..053172c 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -7,6 +7,36 @@ definitions: medication_name: type: string type: object + models.Task: + 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_id: + type: integer + 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. @@ -35,4 +65,82 @@ paths: summary: Get All Meds tags: - medications + /tasks/{endDate}: + get: + description: get all tasks by end date + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By End Date + tags: + - tasks + /tasks/{gid}: + get: + description: get all tasks by group id + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By Group ID + tags: + - tasks + /tasks/{startDate}: + get: + description: get all tasks by start date + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By Start Date + tags: + - tasks + /tasks/{status}: + get: + description: get all tasks by status + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By Status + tags: + - tasks + /tasks/{type}: + get: + description: get all tasks by type + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By Type + tags: + - tasks + /tasks/{uid}: + get: + description: get all tasks by user id + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Task' + type: array + summary: Get All Tasks By User ID + tags: + - tasks swagger: "2.0" diff --git a/backend/models/task.go b/backend/models/task.go new file mode 100644 index 0000000..7dd5193 --- /dev/null +++ b/backend/models/task.go @@ -0,0 +1,21 @@ +package models + +import ( + "time" +) + +type Task struct { + TaskID int `json:"task_id"` + 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"` +} \ No newline at end of file diff --git a/backend/schema/tasks/routes.go b/backend/schema/tasks/routes.go new file mode 100644 index 0000000..00b6615 --- /dev/null +++ b/backend/schema/tasks/routes.go @@ -0,0 +1,129 @@ +package tasks + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/jackc/pgx" +) + +type PgModel struct { + Conn *pgx.Conn +} + +func TaskGroup(v1 *gin.RouterGroup, c *PgModel) *gin.RouterGroup { + + tasks := v1.Group("tasks") + { + tasks.GET("/group/:gid", c.GetTasksByGroupId) + tasks.GET("/created_by/:uid", c.GetTasksByCreatedBy) + tasks.GET("/status/:status", c.GetTasksByStatus) + tasks.GET("/type/:type", c.GetTasksByType) + tasks.GET("/start/:startDate", c.GetTasksByStartDate) + tasks.GET("/end/:endDate", c.GetTasksByEndDate) + } + + return tasks +} + +// GetTasksByGroupId godoc +// +// @summary Get All Tasks By Group ID +// @description get all tasks by group id +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{gid} [get] +func (pg *PgModel) GetTasksByGroupId(c *gin.Context) { + tasks, err := GetTasksByGroupIdFromDB(pg.Conn, c.Param("gid")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} + +// GetTasksByCreatedBy godoc +// +// @summary Get All Tasks By Created By +// @description get all tasks by created by +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{uid} [get] +func (pg *PgModel) GetTasksByCreatedBy(c *gin.Context) { + tasks, err := GetTasksByCreatedByFromDB(pg.Conn, c.Param("uid")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} + +// GetTasksByStatus godoc +// +// @summary Get All Tasks By Status +// @description get all tasks by status +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{status} [get] +func (pg *PgModel) GetTasksByStatus(c *gin.Context) { + tasks, err := GetTasksByStatusFromDB(pg.Conn, c.Param("status")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} + +// GetTasksByType godoc +// +// @summary Get All Tasks By Type +// @description get all tasks by type +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{type} [get] +func (pg *PgModel) GetTasksByType(c *gin.Context) { + tasks, err := GetTasksByTypeFromDB(pg.Conn, c.Param("type")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} + +// GetTasksByStartDate godoc +// +// @summary Get All Tasks By Start Date +// @description get all tasks by start date +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{startDate} [get] +func (pg *PgModel) GetTasksByStartDate(c *gin.Context) { + tasks, err := GetTasksByStartDateFromDB(pg.Conn, c.Param("startDate")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} + +// GetTasksByEndDate godoc +// +// @summary Get All Tasks By End Date +// @description get all tasks by end date +// @tags tasks +// @success 200 {array} models.Task +// @router /tasks/{endDate} [get] +func (pg *PgModel) GetTasksByEndDate(c *gin.Context) { + tasks, err := GetTasksByEndDateFromDB(pg.Conn, c.Param("endDate")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, tasks) +} \ No newline at end of file diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go new file mode 100644 index 0000000..03a1bf9 --- /dev/null +++ b/backend/schema/tasks/task_test.go @@ -0,0 +1,207 @@ +package tasks + +import ( + "carewallet/configuration" + "carewallet/db" + "carewallet/models" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "reflect" + "testing" + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func TestGetTasks(t *testing.T) { + config, err := configuration.GetConfiguration() + + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to retreive configuration file: %v\n", err) + os.Exit(1) + } + + conn := db.ConnectPosgresDatabase(config) + defer conn.Close() + + controller := PgModel{Conn: conn} + router := gin.Default() + router.Use(cors.Default()) + + v1 := router.Group("/") + { + TaskGroup(v1, &controller) + } + + t.Run("TestGetTasksByGroupId", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/group/4", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by group id.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2006-01-02 15:04:05") + expectedTasks := []models.Task{ + { + TaskID: 4, + GroupID: 4, + CreatedBy: "user1", + CreatedDate: createdDate, + TaskStatus: "COMPLETE", + TaskType: "other", + }, + } + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + + t.Run("TestGetTasksByCreatedBy", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/created_by/user2", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by user id.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + expectedTasks := []models.Task{ + { + TaskID: 1, + GroupID: 1, + CreatedBy: "user2", + CreatedDate: createdDate, + TaskStatus: "INCOMPLETE", + TaskType: "med_mgmt", + }, + } + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + + t.Run("TestGetTasksByStatus", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/status/COMPLETE", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by status.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2006-01-02 15:04:05") + expectedTasks := []models.Task{ + { + TaskID: 4, + GroupID: 4, + CreatedBy: "user1", + CreatedDate: createdDate, + TaskStatus: "COMPLETE", + TaskType: "other", + }, + } + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + + t.Run("TestGetTasksByStartDate", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/start/2024-02-05 10:00:00", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by start date.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + expectedTasks := []models.Task{ + { + TaskID: 1, + GroupID: 1, + CreatedBy: "user2", + CreatedDate: createdDate, + TaskStatus: "INCOMPLETE", + TaskType: "med_mgmt", + }, + } + + fmt.Println("Expected:", expectedTasks) + fmt.Println("Response: ", responseTasks) + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + + t.Run("TestGetTasksByEndDate", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/end/2024-02-05 11:00:00", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by end date.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + expectedTasks := []models.Task{ + { + TaskID: 1, + GroupID: 1, + CreatedBy: "user2", + CreatedDate: createdDate, + TaskStatus: "INCOMPLETE", + TaskType: "med_mgmt", + }, + } + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) +} \ No newline at end of file diff --git a/backend/schema/tasks/transactions.go b/backend/schema/tasks/transactions.go new file mode 100644 index 0000000..ee0ded4 --- /dev/null +++ b/backend/schema/tasks/transactions.go @@ -0,0 +1,189 @@ +package tasks + +import ( + "carewallet/models" + "strconv" + "strings" + + "github.com/jackc/pgx" +) + +func GetTasksByGroupIdFromDB(pool *pgx.Conn, groupId string) ([]models.Task, error) { + groupID, err := strconv.Atoi(groupId) + if err != nil { + return nil, err + } + + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type FROM task WHERE group_id = $1;", groupID) + + if err != nil { + print(err, "error selecting tasks by group id") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by group id") + + return nil, err + } + results = append(results, task) + } + + return results, nil +} + +func GetTasksByCreatedByFromDB(pool *pgx.Conn, createdBy string) ([]models.Task, error) { + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type FROM task WHERE created_by = $1;", createdBy) + + if err != nil { + print(err, "error selecting tasks by user id") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by user id") + + return nil, err + } + + results = append(results, task) + } + + return results, nil +} + +func GetTasksByStatusFromDB(pool *pgx.Conn, status string) ([]models.Task, error) { + task_status := strings.ToUpper(status) + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type from task WHERE task_status = $1;", task_status) + + if err != nil { + print(err, "error selecting tasks by status") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by status") + + return nil, err + } + + results = append(results, task) + } + + return results, nil +} + +func GetTasksByTypeFromDB(pool *pgx.Conn, taskType string) ([]models.Task, error) { + task_type := strings.ToLower(taskType) + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type FROM task WHERE task_type = $1;", task_type) + + if err != nil { + print(err, "error selecting tasks by type") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by type") + + return nil, err + } + + results = append(results, task) + } + + return results, nil +} + +func GetTasksByStartDateFromDB(pool *pgx.Conn, startDate string) ([]models.Task, error) { + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type FROM task WHERE start_date = $1;", startDate) + + if err != nil { + print(err, "error selecting tasks by start date") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by start date") + + return nil, err + } + + results = append(results, task) + } + + return results, nil +} + +func GetTasksByEndDateFromDB(pool *pgx.Conn, endDate string) ([]models.Task, error) { + rows, err := pool.Query("SELECT task_id, group_id, created_by, created_date, task_status, task_type FROM task WHERE end_date = $1;", endDate) + + if err != nil { + print(err, "error selecting tasks by end date") + + return nil, err + } + + defer rows.Close() + + var results []models.Task + + for rows.Next() { + task := models.Task{} + err := rows.Scan(&task.TaskID, &task.GroupID, &task.CreatedBy, &task.CreatedDate, &task.TaskStatus, &task.TaskType) + + if err != nil { + print(err, "error scanning tasks by end date") + + return nil, err + } + + results = append(results, task) + } + + return results, nil +} \ No newline at end of file From dc4e66b1d9525e92c3a9fc6344172a0b5c9243f2 Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Thu, 1 Feb 2024 16:16:51 -0500 Subject: [PATCH 3/8] style: formatting --- backend/models/task.go | 2 +- backend/schema/tasks/routes.go | 2 +- backend/schema/tasks/task_test.go | 2 +- backend/schema/tasks/transactions.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/models/task.go b/backend/models/task.go index 7dd5193..5bd4e1c 100644 --- a/backend/models/task.go +++ b/backend/models/task.go @@ -18,4 +18,4 @@ type Task struct { TaskStatus string `json:"task_status"` TaskType string `json:"task_type"` TaskInfo *string `json:"task_info"` -} \ No newline at end of file +} diff --git a/backend/schema/tasks/routes.go b/backend/schema/tasks/routes.go index 00b6615..a890a0b 100644 --- a/backend/schema/tasks/routes.go +++ b/backend/schema/tasks/routes.go @@ -126,4 +126,4 @@ func (pg *PgModel) GetTasksByEndDate(c *gin.Context) { } c.JSON(http.StatusOK, tasks) -} \ No newline at end of file +} diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index 03a1bf9..16487d8 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -204,4 +204,4 @@ func TestGetTasks(t *testing.T) { t.Error("Result was not correct") } }) -} \ No newline at end of file +} diff --git a/backend/schema/tasks/transactions.go b/backend/schema/tasks/transactions.go index ee0ded4..1bd5e42 100644 --- a/backend/schema/tasks/transactions.go +++ b/backend/schema/tasks/transactions.go @@ -186,4 +186,4 @@ func GetTasksByEndDateFromDB(pool *pgx.Conn, endDate string) ([]models.Task, err } return results, nil -} \ No newline at end of file +} From 51bd4b544a02138654086b70c176ea0a7647dc8a Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Thu, 1 Feb 2024 16:24:46 -0500 Subject: [PATCH 4/8] fix: Remove commitizen branch --- .pre-commit-config.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ded1a6f..2323431 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,5 +20,3 @@ repos: rev: v3.13.0 hooks: - id: commitizen - - id: commitizen-branch - stages: [push] From 8e40ed242a4303b4b37104843613abcfc918c3ff Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Thu, 1 Feb 2024 16:49:45 -0500 Subject: [PATCH 5/8] test: fix task tests --- backend/db/migrations/init.sql | 2 +- backend/docs/docs.go | 4 +-- backend/docs/swagger.json | 4 +-- backend/docs/swagger.yaml | 4 +-- backend/schema/tasks/task_test.go | 60 +++++++++++++++++++++++++++---- 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/backend/db/migrations/init.sql b/backend/db/migrations/init.sql index c380755..132f1b8 100644 --- a/backend/db/migrations/init.sql +++ b/backend/db/migrations/init.sql @@ -154,7 +154,7 @@ VALUES INSERT INTO task (group_id, created_by, created_date, start_date, end_date, notes, task_status, task_type) VALUES (1, 'user2', '2024-02-03 10:45:00', '2024-02-05 10:00:00', '2024-02-05 11:00:00', 'Pick up medication from pharmacy', 'INCOMPLETE', 'med_mgmt'), - (2, 'user3', '2024-02-20 23:59:59', '2024-02-10 14:30:00', NULL, 'Schedule doctor appointment', 'INCOMPLETE', 'dr_appt'), + (2, 'user3', '2024-02-20 23:59:59', '2024-02-10 14:30:00', NULL, 'Schedule doctor appointment', 'INCOMPLETE', 'other'), (3, 'user4', '2020-02-05 11:00:00', NULL, '2024-02-20 23:59:59', 'Submit insurance claim', 'PARTIAL', 'financial'), (4, 'user1', '2006-01-02 15:04:05', NULL, NULL, 'Refill water pitcher', 'COMPLETE', 'other') ; diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 63057d2..b271426 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -151,11 +151,11 @@ const docTemplate = `{ }, "/tasks/{uid}": { "get": { - "description": "get all tasks by user id", + "description": "get all tasks by created by", "tags": [ "tasks" ], - "summary": "Get All Tasks By User ID", + "summary": "Get All Tasks By Created By", "responses": { "200": { "description": "OK", diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 212af82..4f772a9 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -144,11 +144,11 @@ }, "/tasks/{uid}": { "get": { - "description": "get all tasks by user id", + "description": "get all tasks by created by", "tags": [ "tasks" ], - "summary": "Get All Tasks By User ID", + "summary": "Get All Tasks By Created By", "responses": { "200": { "description": "OK", diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 053172c..54db19c 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -132,7 +132,7 @@ paths: - tasks /tasks/{uid}: get: - description: get all tasks by user id + description: get all tasks by created by responses: "200": description: OK @@ -140,7 +140,7 @@ paths: items: $ref: '#/definitions/models.Task' type: array - summary: Get All Tasks By User ID + summary: Get All Tasks By Created By tags: - tasks swagger: "2.0" diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index 16487d8..8143691 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -86,7 +86,7 @@ func TestGetTasks(t *testing.T) { t.Error("Failed to unmarshal json") } - createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-03 10:45:00") expectedTasks := []models.Task{ { TaskID: 1, @@ -136,6 +136,57 @@ func TestGetTasks(t *testing.T) { } }) + t.Run("TestGetTasksByType", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/tasks/type/other", nil) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to retrieve tasks by start date.") + } + + var responseTasks []models.Task + err := json.Unmarshal(w.Body.Bytes(), &responseTasks) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + createdDate1, _ := time.Parse("2006-01-02 15:04:05", "2024-02-20 23:59:59") + createdDate2, _ := time.Parse("2006-01-02 15:04:05", "2006-01-02 15:04:05") + expectedTasks := []models.Task{ + { + TaskID: 2, + GroupID: 2, + CreatedBy: "user3", + CreatedDate: createdDate1, + TaskStatus: "INCOMPLETE", + TaskType: "other", + }, + { + TaskID: 4, + GroupID: 4, + CreatedBy: "user1", + CreatedDate: createdDate2, + TaskStatus: "COMPLETE", + TaskType: "other", + }, + } + + fmt.Println( + "responseTasks: ", responseTasks, + ) + fmt.Println( + "expectedTasks: ", expectedTasks, + ) + + if !reflect.DeepEqual(expectedTasks, responseTasks) { + t.Error("Result was not correct") + } + }) + + + t.Run("TestGetTasksByStartDate", func(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/tasks/start/2024-02-05 10:00:00", nil) @@ -152,7 +203,7 @@ func TestGetTasks(t *testing.T) { t.Error("Failed to unmarshal json") } - createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-03 10:45:00") expectedTasks := []models.Task{ { TaskID: 1, @@ -164,9 +215,6 @@ func TestGetTasks(t *testing.T) { }, } - fmt.Println("Expected:", expectedTasks) - fmt.Println("Response: ", responseTasks) - if !reflect.DeepEqual(expectedTasks, responseTasks) { t.Error("Result was not correct") } @@ -188,7 +236,7 @@ func TestGetTasks(t *testing.T) { t.Error("Failed to unmarshal json") } - createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-01 20:14:26.126136") + createdDate, _ := time.Parse("2006-01-02 15:04:05", "2024-02-03 10:45:00") expectedTasks := []models.Task{ { TaskID: 1, From ccd9ce1312b44fe1eefba1c4236f918bf3258040 Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Thu, 1 Feb 2024 16:53:12 -0500 Subject: [PATCH 6/8] style: quick reformat --- backend/models/task.go | 26 +++++++++++++------------- backend/schema/tasks/task_test.go | 2 -- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/backend/models/task.go b/backend/models/task.go index 5bd4e1c..4f700c2 100644 --- a/backend/models/task.go +++ b/backend/models/task.go @@ -5,17 +5,17 @@ import ( ) type Task struct { - TaskID int `json:"task_id"` - 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"` + TaskID int `json:"task_id"` + 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"` } diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index 8143691..bff88d5 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -185,8 +185,6 @@ func TestGetTasks(t *testing.T) { } }) - - t.Run("TestGetTasksByStartDate", func(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/tasks/start/2024-02-05 10:00:00", nil) From ac31075287e62af34d183e362599a20e3b925c88 Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Fri, 2 Feb 2024 10:37:33 -0500 Subject: [PATCH 7/8] feat: assign user(s) to a task CRUD and test --- backend/docs/docs.go | 31 +++++++++++++++ backend/docs/swagger.json | 31 +++++++++++++++ backend/docs/swagger.yaml | 20 ++++++++++ backend/models/task_user.go | 6 +++ backend/schema/tasks/routes.go | 30 +++++++++++++++ backend/schema/tasks/task_test.go | 56 +++++++++++++++++++++++++++- backend/schema/tasks/transactions.go | 28 ++++++++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 backend/models/task_user.go diff --git a/backend/docs/docs.go b/backend/docs/docs.go index b271426..896014d 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -129,6 +129,26 @@ const docTemplate = `{ } } }, + "/tasks/{tid}/assignees": { + "post": { + "description": "assign users to task", + "tags": [ + "tasks" + ], + "summary": "Assign Users To Task", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.TaskUser" + } + } + } + } + } + }, "/tasks/{type}": { "get": { "description": "get all tasks by type", @@ -226,6 +246,17 @@ const docTemplate = `{ "type": "string" } } + }, + "models.TaskUser": { + "type": "object", + "properties": { + "taskID": { + "type": "integer" + }, + "userID": { + "type": "string" + } + } } } }` diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 4f772a9..b5feab8 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -122,6 +122,26 @@ } } }, + "/tasks/{tid}/assignees": { + "post": { + "description": "assign users to task", + "tags": [ + "tasks" + ], + "summary": "Assign Users To Task", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.TaskUser" + } + } + } + } + } + }, "/tasks/{type}": { "get": { "description": "get all tasks by type", @@ -219,6 +239,17 @@ "type": "string" } } + }, + "models.TaskUser": { + "type": "object", + "properties": { + "taskID": { + "type": "integer" + }, + "userID": { + "type": "string" + } + } } } } \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 54db19c..85ff88e 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -37,6 +37,13 @@ definitions: task_type: type: string type: object + models.TaskUser: + properties: + taskID: + type: integer + userID: + type: string + type: object info: contact: {} description: This is an API for the Care-Wallet App. @@ -117,6 +124,19 @@ paths: summary: Get All Tasks By Status tags: - tasks + /tasks/{tid}/assignees: + post: + description: assign users to task + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.TaskUser' + type: array + summary: Assign Users To Task + tags: + - tasks /tasks/{type}: get: description: get all tasks by type diff --git a/backend/models/task_user.go b/backend/models/task_user.go new file mode 100644 index 0000000..105a996 --- /dev/null +++ b/backend/models/task_user.go @@ -0,0 +1,6 @@ +package models + +type TaskUser struct { + TaskID int + UserID string +} diff --git a/backend/schema/tasks/routes.go b/backend/schema/tasks/routes.go index a890a0b..ea5050b 100644 --- a/backend/schema/tasks/routes.go +++ b/backend/schema/tasks/routes.go @@ -1,6 +1,7 @@ package tasks import ( + "fmt" "net/http" "github.com/gin-gonic/gin" @@ -21,6 +22,7 @@ func TaskGroup(v1 *gin.RouterGroup, c *PgModel) *gin.RouterGroup { tasks.GET("/type/:type", c.GetTasksByType) tasks.GET("/start/:startDate", c.GetTasksByStartDate) tasks.GET("/end/:endDate", c.GetTasksByEndDate) + tasks.POST("/:tid/assignees", c.AssignUsersToTask) } return tasks @@ -127,3 +129,31 @@ func (pg *PgModel) GetTasksByEndDate(c *gin.Context) { c.JSON(http.StatusOK, tasks) } + +// AssignUsersToTask godoc +// +// @summary Assign Users To Task +// @description assign users to task +// @tags tasks +// @success 200 {array} models.TaskUser +// @router /tasks/{tid}/assignees [post] +func (pg *PgModel) AssignUsersToTask(c *gin.Context) { + var requestBody struct { + UserIDs []string `json:"userIDs"` + Assigner string `json:"assigner"` + } + + if err := c.BindJSON(&requestBody); err != nil { + fmt.Println("error binding to request body: ", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + taskUser, err := AssignUsersToTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid"), requestBody.Assigner) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, taskUser) +} diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index bff88d5..370b1fe 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -1,6 +1,7 @@ package tasks import ( + "bytes" "carewallet/configuration" "carewallet/db" "carewallet/models" @@ -17,7 +18,7 @@ import ( "github.com/gin-gonic/gin" ) -func TestGetTasks(t *testing.T) { +func TestTaskGroup(t *testing.T) { config, err := configuration.GetConfiguration() if err != nil { @@ -250,4 +251,57 @@ func TestGetTasks(t *testing.T) { t.Error("Result was not correct") } }) + + t.Run("TestAssignUsersToTask", func(t *testing.T) { + type AssignRequest struct { + UserIDs []string `json:"userIDs"` + Assigner string `json:"assigner"` + } + + assignRequest := AssignRequest{ + UserIDs: []string{"user3", "user4"}, + Assigner: "user3", + } + + userIdsJSON, err := json.Marshal(assignRequest) + if err != nil { + t.Error("Failed to marshal userIds to JSON") + } + + fmt.Println("userIdsJSON: ", string(userIdsJSON)) + + // Create a request with the userIds JSON + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/tasks/1/assignees", bytes.NewBuffer(userIdsJSON)) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to assign users to task.") + } + + var responseTaskUsers []models.TaskUser + err = json.Unmarshal(w.Body.Bytes(), &responseTaskUsers) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + expectedTaskUsers := []models.TaskUser{ + { + TaskID: 1, + UserID: "user3", + }, + { + TaskID: 1, + UserID: "user4", + }, + } + + fmt.Println("responseTaskUsers: ", responseTaskUsers) + fmt.Println("expectedTaskUsers: ", expectedTaskUsers) + + if !reflect.DeepEqual(expectedTaskUsers, responseTaskUsers) { + t.Error("Result was not correct") + } + }) } diff --git a/backend/schema/tasks/transactions.go b/backend/schema/tasks/transactions.go index 1bd5e42..5a1de66 100644 --- a/backend/schema/tasks/transactions.go +++ b/backend/schema/tasks/transactions.go @@ -2,8 +2,10 @@ package tasks import ( "carewallet/models" + "fmt" "strconv" "strings" + "time" "github.com/jackc/pgx" ) @@ -187,3 +189,29 @@ func GetTasksByEndDateFromDB(pool *pgx.Conn, endDate string) ([]models.Task, err return results, nil } + +func AssignUsersToTaskInDB(pool *pgx.Conn, users []string, taskID string, assigner string) ([]models.TaskUser, error) { + task_id, err := strconv.Atoi(taskID) + if err != nil { + print(err, "error converting task ID to int") + return nil, err + } + + var taskUsers []models.TaskUser + + for _, user := range users { + print(task_id, " ", user) + _, err := pool.Exec("INSERT INTO task_assignees (task_id, user_id, assignment_status, assigned_by, assigned_date) VALUES ($1, $2, $3, $4, $5);", task_id, user, "NOTIFIED", assigner, time.Now()) + + if err != nil { + print(err, "error inserting users into task_user") + + return nil, err + } + + taskUsers = append(taskUsers, models.TaskUser{TaskID: task_id, UserID: user}) + fmt.Println(taskUsers) + } + + return taskUsers, nil +} From cc20bd35715950ea10db5f4bf04c672f0308efdf Mon Sep 17 00:00:00 2001 From: Olivia Sedarski Date: Fri, 2 Feb 2024 11:20:31 -0500 Subject: [PATCH 8/8] style: quick style --- backend/docs/docs.go | 20 +++++++++ backend/docs/swagger.json | 20 +++++++++ backend/docs/swagger.yaml | 13 ++++++ backend/schema/tasks/routes.go | 34 ++++++++++++++-- backend/schema/tasks/task_test.go | 61 ++++++++++++++++++++-------- backend/schema/tasks/transactions.go | 44 +++++++++++++++++--- 6 files changed, 168 insertions(+), 24 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 896014d..46ce572 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -149,6 +149,26 @@ const docTemplate = `{ } } }, + "/tasks/{tid}/remove": { + "delete": { + "description": "remove users from task", + "tags": [ + "tasks" + ], + "summary": "Remove Users From Task", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.TaskUser" + } + } + } + } + } + }, "/tasks/{type}": { "get": { "description": "get all tasks by type", diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index b5feab8..f4f9312 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -142,6 +142,26 @@ } } }, + "/tasks/{tid}/remove": { + "delete": { + "description": "remove users from task", + "tags": [ + "tasks" + ], + "summary": "Remove Users From Task", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.TaskUser" + } + } + } + } + } + }, "/tasks/{type}": { "get": { "description": "get all tasks by type", diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 85ff88e..23dc752 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -137,6 +137,19 @@ paths: summary: Assign Users To Task tags: - tasks + /tasks/{tid}/remove: + delete: + description: remove users from task + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.TaskUser' + type: array + summary: Remove Users From Task + tags: + - tasks /tasks/{type}: get: description: get all tasks by type diff --git a/backend/schema/tasks/routes.go b/backend/schema/tasks/routes.go index ea5050b..c6c2af6 100644 --- a/backend/schema/tasks/routes.go +++ b/backend/schema/tasks/routes.go @@ -22,7 +22,8 @@ func TaskGroup(v1 *gin.RouterGroup, c *PgModel) *gin.RouterGroup { tasks.GET("/type/:type", c.GetTasksByType) tasks.GET("/start/:startDate", c.GetTasksByStartDate) tasks.GET("/end/:endDate", c.GetTasksByEndDate) - tasks.POST("/:tid/assignees", c.AssignUsersToTask) + tasks.POST("/:tid/assign", c.AssignUsersToTask) + tasks.DELETE("/:tid/remove", c.RemoveUsersFromTask) } return tasks @@ -149,11 +150,38 @@ func (pg *PgModel) AssignUsersToTask(c *gin.Context) { return } - taskUser, err := AssignUsersToTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid"), requestBody.Assigner) + assignedUsers, err := AssignUsersToTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid"), requestBody.Assigner) if err != nil { panic(err) } - c.JSON(http.StatusOK, taskUser) + c.JSON(http.StatusOK, assignedUsers) +} + +// RemoveUsersFromTask godoc +// +// @summary Remove Users From Task +// @description remove users from task +// @tags tasks +// @success 200 {array} models.TaskUser +// @router /tasks/{tid}/remove [delete] +func (pg *PgModel) RemoveUsersFromTask(c *gin.Context) { + var requestBody struct { + UserIDs []string `json:"userIDs"` + } + + if err := c.BindJSON(&requestBody); err != nil { + fmt.Println("error binding to request body: ", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + removedUsers, err := RemoveUsersFromTaskInDB(pg.Conn, requestBody.UserIDs, c.Param("tid")) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, removedUsers) } diff --git a/backend/schema/tasks/task_test.go b/backend/schema/tasks/task_test.go index 370b1fe..0af417b 100644 --- a/backend/schema/tasks/task_test.go +++ b/backend/schema/tasks/task_test.go @@ -174,13 +174,6 @@ func TestTaskGroup(t *testing.T) { }, } - fmt.Println( - "responseTasks: ", responseTasks, - ) - fmt.Println( - "expectedTasks: ", expectedTasks, - ) - if !reflect.DeepEqual(expectedTasks, responseTasks) { t.Error("Result was not correct") } @@ -259,7 +252,7 @@ func TestTaskGroup(t *testing.T) { } assignRequest := AssignRequest{ - UserIDs: []string{"user3", "user4"}, + UserIDs: []string{"user3"}, Assigner: "user3", } @@ -268,11 +261,9 @@ func TestTaskGroup(t *testing.T) { t.Error("Failed to marshal userIds to JSON") } - fmt.Println("userIdsJSON: ", string(userIdsJSON)) - // Create a request with the userIds JSON w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/tasks/1/assignees", bytes.NewBuffer(userIdsJSON)) + req, _ := http.NewRequest("POST", "/tasks/4/assign", bytes.NewBuffer(userIdsJSON)) router.ServeHTTP(w, req) if http.StatusOK != w.Code { @@ -288,13 +279,9 @@ func TestTaskGroup(t *testing.T) { expectedTaskUsers := []models.TaskUser{ { - TaskID: 1, + TaskID: 4, UserID: "user3", }, - { - TaskID: 1, - UserID: "user4", - }, } fmt.Println("responseTaskUsers: ", responseTaskUsers) @@ -304,4 +291,46 @@ func TestTaskGroup(t *testing.T) { t.Error("Result was not correct") } }) + + t.Run("TestRemoveUsersFromTask", func(t *testing.T) { + type RemoveRequest struct { + UserIDs []string `json:"userIDs"` + } + + removeRequest := RemoveRequest{ + UserIDs: []string{"user2"}, + } + + userIdsJSON, err := json.Marshal(removeRequest) + if err != nil { + t.Error("Failed to marshal userIds to JSON") + } + + // Create a request with the userIds JSON + w := httptest.NewRecorder() + req, _ := http.NewRequest("DELETE", "/tasks/4/remove", bytes.NewBuffer(userIdsJSON)) + router.ServeHTTP(w, req) + + if http.StatusOK != w.Code { + t.Error("Failed to remove users from task.") + } + + var responseTaskUsers []models.TaskUser + err = json.Unmarshal(w.Body.Bytes(), &responseTaskUsers) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + expectedTaskUsers := []models.TaskUser{ + { + TaskID: 4, + UserID: "user2", + }, + } + + if !reflect.DeepEqual(expectedTaskUsers, responseTaskUsers) { + t.Error("Result was not correct") + } + }) } diff --git a/backend/schema/tasks/transactions.go b/backend/schema/tasks/transactions.go index 5a1de66..498bdc3 100644 --- a/backend/schema/tasks/transactions.go +++ b/backend/schema/tasks/transactions.go @@ -197,21 +197,55 @@ func AssignUsersToTaskInDB(pool *pgx.Conn, users []string, taskID string, assign return nil, err } - var taskUsers []models.TaskUser + var assignedUsers []models.TaskUser for _, user := range users { print(task_id, " ", user) _, err := pool.Exec("INSERT INTO task_assignees (task_id, user_id, assignment_status, assigned_by, assigned_date) VALUES ($1, $2, $3, $4, $5);", task_id, user, "NOTIFIED", assigner, time.Now()) if err != nil { - print(err, "error inserting users into task_user") + print(err, "error inserting users into task_assignees") return nil, err } - taskUsers = append(taskUsers, models.TaskUser{TaskID: task_id, UserID: user}) - fmt.Println(taskUsers) + assignedUsers = append(assignedUsers, models.TaskUser{TaskID: task_id, UserID: user}) + fmt.Println(assignedUsers) } - return taskUsers, nil + return assignedUsers, nil +} + +func RemoveUsersFromTaskInDB(pool *pgx.Conn, users []string, taskID string) ([]models.TaskUser, error) { + task_id, err := strconv.Atoi(taskID) + if err != nil { + print(err, "error converting task ID to int") + return nil, err + } + + var removedUsers []models.TaskUser + + for _, user := range users { + // Check if the user ID and task ID exist in the table + var exists int + err := pool.QueryRow("SELECT 1 FROM task_assignees WHERE task_id = $1 AND user_id = $2 LIMIT 1;", task_id, user).Scan(&exists) + if err != nil { + if err == pgx.ErrNoRows { + // User ID or task ID does not exist, return an error + return nil, fmt.Errorf("user not assigned to task") + } + print(err, "error checking if user and task exist in task_assignees") + return nil, err + } + + _, err = pool.Exec("DELETE FROM task_assignees WHERE task_id = $1 AND user_id = $2;", task_id, user) + if err != nil { + print(err, "error deleting users from task_assignees") + return nil, err + } + + removedUsers = append(removedUsers, models.TaskUser{TaskID: task_id, UserID: user}) + } + + return removedUsers, nil }