From 31a4a1dd0076995da253287142f07925dfa5a168 Mon Sep 17 00:00:00 2001 From: konrad Date: Fri, 2 Nov 2018 16:59:49 +0000 Subject: [PATCH] Added a route to get all tasks sorted desc by their due dates (#14) --- .gitignore | 1 + REST-Tests/auth.http | 2 +- REST-Tests/lists.http | 6 +++ pkg/models/list.go | 92 ++++++++++++++++++++++++-------- pkg/routes/api/v1/swaggerdocs.go | 15 ++++++ pkg/routes/routes.go | 7 +++ 6 files changed, 99 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index e5b39f05e..878441d99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ +.idea/* .idea/*/* config.yml config.yaml diff --git a/REST-Tests/auth.http b/REST-Tests/auth.http index 7da9d12d3..acba01457 100644 --- a/REST-Tests/auth.http +++ b/REST-Tests/auth.http @@ -4,7 +4,7 @@ Content-Type: application/json { "username": "user", - "password": "1234" + "password": "12345" } > {% client.global.set("auth_token", response.body.token); %} diff --git a/REST-Tests/lists.http b/REST-Tests/lists.http index 2c121aadc..5718b803e 100644 --- a/REST-Tests/lists.http +++ b/REST-Tests/lists.http @@ -98,4 +98,10 @@ Content-Type: application/json DELETE http://localhost:8080/api/v1/lists/28/users/3 Authorization: Bearer {{auth_token}} +### + +# Get all pending tasks +GET http://localhost:8080/api/v1/tasks +Authorization: Bearer {{auth_token}} + ### \ No newline at end of file diff --git a/pkg/models/list.go b/pkg/models/list.go index d353e34d2..1785577b3 100644 --- a/pkg/models/list.go +++ b/pkg/models/list.go @@ -1,5 +1,7 @@ package models +import "sort" + // List represents a list of tasks type List struct { ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"list"` @@ -26,32 +28,11 @@ func GetListsByNamespaceID(nID int64) (lists []*List, err error) { // ReadAll gets all lists a user has access to func (l *List) ReadAll(u *User) (interface{}, error) { - lists := []*List{} - fullUser, err := GetUserByID(u.ID) + lists, err := getRawListsForUser(u) if err != nil { - return lists, err + return nil, err } - // Gets all Lists where the user is either owner or in a team which has access to the list - // Or in a team which has namespace read access - err = x.Select("l.*"). - Table("list"). - Alias("l"). - Join("INNER", []string{"namespaces", "n"}, "l.namespace_id = n.id"). - Join("LEFT", []string{"team_namespaces", "tn"}, "tn.namespace_id = n.id"). - Join("LEFT", []string{"team_members", "tm"}, "tm.team_id = tn.team_id"). - Join("LEFT", []string{"team_list", "tl"}, "l.id = tl.list_id"). - Join("LEFT", []string{"team_members", "tm2"}, "tm2.team_id = tl.team_id"). - Join("LEFT", []string{"users_list", "ul"}, "ul.list_id = l.id"). - Join("LEFT", []string{"users_namespace", "un"}, "un.namespace_id = l.namespace_id"). - Where("tm.user_id = ?", fullUser.ID). - Or("tm2.user_id = ?", fullUser.ID). - Or("l.owner_id = ?", fullUser.ID). - Or("ul.user_id = ?", fullUser.ID). - Or("un.user_id = ?", fullUser.ID). - GroupBy("l.id"). - Find(&lists) - // Add more list details AddListDetails(lists) @@ -98,6 +79,36 @@ func (l *List) GetSimpleByID() (err error) { return } +// Gets the lists only, without any tasks or so +func getRawListsForUser(u *User) (lists []*List, err error) { + fullUser, err := GetUserByID(u.ID) + if err != nil { + return lists, err + } + + // Gets all Lists where the user is either owner or in a team which has access to the list + // Or in a team which has namespace read access + err = x.Select("l.*"). + Table("list"). + Alias("l"). + Join("INNER", []string{"namespaces", "n"}, "l.namespace_id = n.id"). + Join("LEFT", []string{"team_namespaces", "tn"}, "tn.namespace_id = n.id"). + Join("LEFT", []string{"team_members", "tm"}, "tm.team_id = tn.team_id"). + Join("LEFT", []string{"team_list", "tl"}, "l.id = tl.list_id"). + Join("LEFT", []string{"team_members", "tm2"}, "tm2.team_id = tl.team_id"). + Join("LEFT", []string{"users_list", "ul"}, "ul.list_id = l.id"). + Join("LEFT", []string{"users_namespace", "un"}, "un.namespace_id = l.namespace_id"). + Where("tm.user_id = ?", fullUser.ID). + Or("tm2.user_id = ?", fullUser.ID). + Or("l.owner_id = ?", fullUser.ID). + Or("ul.user_id = ?", fullUser.ID). + Or("un.user_id = ?", fullUser.ID). + GroupBy("l.id"). + Find(&lists) + + return lists, err +} + // AddListDetails adds owner user objects and list tasks to all lists in the slice func AddListDetails(lists []*List) (err error) { var listIDs []int64 @@ -141,3 +152,38 @@ func AddListDetails(lists []*List) (err error) { return } + +// ListTasksDummy is a dummy we use to be able to use the crud handler +type ListTasksDummy struct { + CRUDable + Rights +} + +// ReadAll gets all tasks for a user +func (lt *ListTasksDummy) ReadAll(u *User) (interface{}, error) { + + // Get all lists + lists, err := getRawListsForUser(u) + if err != nil { + return nil, err + } + + // Get all list IDs and get the tasks + var listIDs []int64 + for _, l := range lists { + listIDs = append(listIDs, l.ID) + } + + // Then return all tasks for that lists + var tasks []*ListTask + if err := x.In("list_id", listIDs).Find(&tasks); err != nil { + return nil, err + } + + // Sort it by due date + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].DueDateUnix > tasks[j].DueDateUnix + }) + + return tasks, err +} diff --git a/pkg/routes/api/v1/swaggerdocs.go b/pkg/routes/api/v1/swaggerdocs.go index 31914c08e..2a981badd 100644 --- a/pkg/routes/api/v1/swaggerdocs.go +++ b/pkg/routes/api/v1/swaggerdocs.go @@ -913,3 +913,18 @@ package v1 // "$ref": "#/responses/Message" // "500": // "$ref": "#/responses/Message" + +// swagger:operation GET /tasks lists getPendingTasks +// --- +// summary: gets all tasks for the currently authenticated user +// consumes: +// - application/json +// produces: +// - application/json +// responses: +// "200": +// "$ref": "#/responses/ListTask" +// "400": +// "$ref": "#/responses/Message" +// "500": +// "$ref": "#/responses/Message" diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 54affded8..1c222054a 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -99,6 +99,13 @@ func RegisterRoutes(e *echo.Echo) { a.DELETE("/tasks/:listtask", taskHandler.DeleteWeb) a.POST("/tasks/:listtask", taskHandler.UpdateWeb) + listTaskHandler := &crud.WebHandler{ + EmptyStruct: func() crud.CObject { + return &models.ListTasksDummy{} + }, + } + a.GET("/tasks", listTaskHandler.ReadAllWeb) + listTeamHandler := &crud.WebHandler{ EmptyStruct: func() crud.CObject { return &models.TeamList{}