diff --git a/pkg/integrations/task_collection_test.go b/pkg/integrations/task_collection_test.go
new file mode 100644
index 000000000..06eebd493
--- /dev/null
+++ b/pkg/integrations/task_collection_test.go
@@ -0,0 +1,182 @@
+// Copyright 2019 Vikunja and contriubtors. All rights reserved.
+//
+// This file is part of Vikunja.
+//
+// Vikunja is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Vikunja is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Vikunja. If not, see .
+
+package integrations
+
+import (
+ "code.vikunja.io/api/pkg/models"
+ "code.vikunja.io/web/handler"
+ "github.com/stretchr/testify/assert"
+ "net/url"
+ "testing"
+)
+
+func TestTaskCollection(t *testing.T) {
+ testHandler := webHandlerTest{
+ user: &testuser1,
+ strFunc: func() handler.CObject {
+ return &models.TaskCollection{}
+ },
+ t: t,
+ }
+ // Only run specific nested tests:
+ // ^TestTask$/^Update$/^Update_task_items$/^Removing_Assignees_null$
+ t.Run("ReadAll", func(t *testing.T) {
+ t.Run("Normal", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(nil, map[string]string{"list": "1"})
+ assert.NoError(t, err)
+ // Not using assert.Equal to avoid having the tests break every time we add new fixtures
+ assert.Contains(t, rec.Body.String(), `task #1`)
+ assert.Contains(t, rec.Body.String(), `task #2`)
+ assert.Contains(t, rec.Body.String(), `task #3`)
+ assert.Contains(t, rec.Body.String(), `task #4`)
+ assert.Contains(t, rec.Body.String(), `task #5`)
+ assert.Contains(t, rec.Body.String(), `task #6`)
+ assert.Contains(t, rec.Body.String(), `task #7`)
+ assert.Contains(t, rec.Body.String(), `task #8`)
+ assert.Contains(t, rec.Body.String(), `task #9`)
+ assert.Contains(t, rec.Body.String(), `task #10`)
+ assert.Contains(t, rec.Body.String(), `task #11`)
+ assert.Contains(t, rec.Body.String(), `task #12`)
+ assert.NotContains(t, rec.Body.String(), `task #13`)
+ assert.NotContains(t, rec.Body.String(), `task #14`)
+ assert.NotContains(t, rec.Body.String(), `task #15`) // Shared via team readonly
+ assert.NotContains(t, rec.Body.String(), `task #16`) // Shared via team write
+ assert.NotContains(t, rec.Body.String(), `task #17`) // Shared via team admin
+ assert.NotContains(t, rec.Body.String(), `task #18`) // Shared via user readonly
+ assert.NotContains(t, rec.Body.String(), `task #19`) // Shared via user write
+ assert.NotContains(t, rec.Body.String(), `task #20`) // Shared via user admin
+ assert.NotContains(t, rec.Body.String(), `task #21`) // Shared via namespace team readonly
+ assert.NotContains(t, rec.Body.String(), `task #22`) // Shared via namespace team write
+ assert.NotContains(t, rec.Body.String(), `task #23`) // Shared via namespace team admin
+ assert.NotContains(t, rec.Body.String(), `task #24`) // Shared via namespace user readonly
+ assert.NotContains(t, rec.Body.String(), `task #25`) // Shared via namespace user write
+ assert.NotContains(t, rec.Body.String(), `task #26`) // Shared via namespace user admin
+ assert.Contains(t, rec.Body.String(), `task #27`)
+ assert.Contains(t, rec.Body.String(), `task #28`)
+ assert.NotContains(t, rec.Body.String(), `task #32`)
+ })
+ t.Run("Search", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"task #6"}}, nil)
+ assert.NoError(t, err)
+ assert.NotContains(t, rec.Body.String(), `task #1`)
+ assert.NotContains(t, rec.Body.String(), `task #2`)
+ assert.NotContains(t, rec.Body.String(), `task #3`)
+ assert.NotContains(t, rec.Body.String(), `task #4`)
+ assert.NotContains(t, rec.Body.String(), `task #5`)
+ assert.Contains(t, rec.Body.String(), `task #6`)
+ assert.NotContains(t, rec.Body.String(), `task #7`)
+ assert.NotContains(t, rec.Body.String(), `task #8`)
+ assert.NotContains(t, rec.Body.String(), `task #9`)
+ assert.NotContains(t, rec.Body.String(), `task #10`)
+ assert.NotContains(t, rec.Body.String(), `task #11`)
+ assert.NotContains(t, rec.Body.String(), `task #12`)
+ assert.NotContains(t, rec.Body.String(), `task #13`)
+ assert.NotContains(t, rec.Body.String(), `task #14`)
+ })
+ t.Run("Sort Order", func(t *testing.T) {
+ // should equal priority desc
+ t.Run("by priority", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priority"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
+ })
+ t.Run("by priority desc", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"prioritydesc"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
+ })
+ t.Run("by priority asc", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priorityasc"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0.5,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
+ })
+ // should equal duedate desc
+ t.Run("by duedate", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedate"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
+ })
+ t.Run("by duedate desc", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedatedesc"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
+ })
+ t.Run("by duedate asc", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedateasc"}}, nil)
+ assert.NoError(t, err)
+ assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
+ })
+ t.Run("invalid parameter", func(t *testing.T) {
+ // Invalid parameter should not sort at all
+ rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"loremipsum"}}, nil)
+ assert.NoError(t, err)
+ assert.NotContains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"dueDate":0,"reminderDates":null,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"dueDate":0,"reminderDates":null,"repeatAfter":0,"priority":1`)
+ assert.NotContains(t, rec.Body.String(), `{"id":4,"text":"task #4 low prio","description":"","done":false,"dueDate":0,"reminderDates":null,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"dueDate":0,"reminderDates":null,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}}]`)
+ assert.NotContains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"dueDate":1543636724,"reminderDates":null,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
+ assert.NotContains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"dueDate":1543616724,"reminderDates":null,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"dueDate":1543636724,"reminderDates":null,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","email":"","created":0,"updated":0}}]`)
+ })
+ })
+ t.Run("Date range", func(t *testing.T) {
+ t.Run("start and end date", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"startdate": []string{"1540000000"}, "enddate": []string{"1544700001"}}, nil)
+ assert.NoError(t, err)
+ assert.NotContains(t, rec.Body.String(), `task #1`)
+ assert.NotContains(t, rec.Body.String(), `task #2`)
+ assert.NotContains(t, rec.Body.String(), `task #3`)
+ assert.NotContains(t, rec.Body.String(), `task #4`)
+ assert.Contains(t, rec.Body.String(), `task #5`)
+ assert.Contains(t, rec.Body.String(), `task #6`)
+ assert.Contains(t, rec.Body.String(), `task #7`)
+ assert.Contains(t, rec.Body.String(), `task #8`)
+ assert.Contains(t, rec.Body.String(), `task #9`)
+ assert.NotContains(t, rec.Body.String(), `task #10`)
+ assert.NotContains(t, rec.Body.String(), `task #11`)
+ assert.NotContains(t, rec.Body.String(), `task #12`)
+ assert.NotContains(t, rec.Body.String(), `task #13`)
+ assert.NotContains(t, rec.Body.String(), `task #14`)
+ })
+ t.Run("start date only", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"startdate": []string{"1540000000"}}, nil)
+ assert.NoError(t, err)
+ assert.NotContains(t, rec.Body.String(), `task #1`)
+ assert.NotContains(t, rec.Body.String(), `task #2`)
+ assert.NotContains(t, rec.Body.String(), `task #3`)
+ assert.NotContains(t, rec.Body.String(), `task #4`)
+ assert.Contains(t, rec.Body.String(), `task #5`)
+ assert.Contains(t, rec.Body.String(), `task #6`)
+ assert.Contains(t, rec.Body.String(), `task #7`)
+ assert.Contains(t, rec.Body.String(), `task #8`)
+ assert.Contains(t, rec.Body.String(), `task #9`)
+ assert.NotContains(t, rec.Body.String(), `task #10`)
+ assert.NotContains(t, rec.Body.String(), `task #11`)
+ assert.NotContains(t, rec.Body.String(), `task #12`)
+ assert.NotContains(t, rec.Body.String(), `task #13`)
+ assert.NotContains(t, rec.Body.String(), `task #14`)
+ })
+ t.Run("end date only", func(t *testing.T) {
+ rec, err := testHandler.testReadAllWithUser(url.Values{"enddate": []string{"1544700001"}}, nil)
+ assert.NoError(t, err)
+ // If no start date but an end date is specified, this should be null
+ // since we don't have any tasks in the fixtures with an end date >
+ // the current date.
+ assert.Equal(t, "null\n", rec.Body.String())
+ })
+ })
+ })
+
+}
diff --git a/pkg/integrations/task_test.go b/pkg/integrations/task_test.go
index 5b2b1f1f2..b7ccb8a34 100644
--- a/pkg/integrations/task_test.go
+++ b/pkg/integrations/task_test.go
@@ -54,8 +54,21 @@ func TestTask(t *testing.T) {
assert.Contains(t, rec.Body.String(), `task #12`)
assert.NotContains(t, rec.Body.String(), `task #13`)
assert.NotContains(t, rec.Body.String(), `task #14`)
- // TODO: add more tasks, since the whole point of this is to get all tasks in all lists where the user
- // has at least read access
+ assert.NotContains(t, rec.Body.String(), `task #13`)
+ assert.NotContains(t, rec.Body.String(), `task #14`)
+ assert.Contains(t, rec.Body.String(), `task #15`) // Shared via team readonly
+ assert.Contains(t, rec.Body.String(), `task #16`) // Shared via team write
+ assert.Contains(t, rec.Body.String(), `task #17`) // Shared via team admin
+ assert.Contains(t, rec.Body.String(), `task #18`) // Shared via user readonly
+ assert.Contains(t, rec.Body.String(), `task #19`) // Shared via user write
+ assert.Contains(t, rec.Body.String(), `task #20`) // Shared via user admin
+ assert.Contains(t, rec.Body.String(), `task #21`) // Shared via namespace team readonly
+ assert.Contains(t, rec.Body.String(), `task #22`) // Shared via namespace team write
+ assert.Contains(t, rec.Body.String(), `task #23`) // Shared via namespace team admin
+ assert.Contains(t, rec.Body.String(), `task #24`) // Shared via namespace user readonly
+ assert.Contains(t, rec.Body.String(), `task #25`) // Shared via namespace user write
+ assert.Contains(t, rec.Body.String(), `task #26`) // Shared via namespace user admin
+ // TODO: Add some cases where the user has access to the list, somhow shared
})
t.Run("Search", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"task #6"}}, nil)
diff --git a/pkg/models/task_collection.go b/pkg/models/task_collection.go
new file mode 100644
index 000000000..db79f953a
--- /dev/null
+++ b/pkg/models/task_collection.go
@@ -0,0 +1,113 @@
+// Copyright 2019 Vikunja and contriubtors. All rights reserved.
+//
+// This file is part of Vikunja.
+//
+// Vikunja is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Vikunja is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Vikunja. If not, see .
+
+package models
+
+import (
+ "code.vikunja.io/web"
+ "time"
+)
+
+// TaskCollection is a struct used to hold filter details and not clutter the Task struct with information not related to actual tasks.
+type TaskCollection struct {
+ ListID int64 `param:"list"`
+ Sorting string `query:"sort"` // Parameter to sort by
+ StartDateSortUnix int64 `query:"startdate"`
+ EndDateSortUnix int64 `query:"enddate"`
+ Lists []*List
+
+ web.CRUDable `xorm:"-" json:"-"`
+ web.Rights `xorm:"-" json:"-"`
+}
+
+// ReadAll gets all tasks for a collection
+// @Summary Get tasks on a list
+// @Description Returns all tasks for the current list.
+// @tags task
+// @Accept json
+// @Produce json
+// @Param listID path int true "The list ID."
+// @Param page query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
+// @Param per_page query int false "The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page."
+// @Param s query string false "Search tasks by task text."
+// @Param sort query string false "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc."
+// @Param startdate query int false "The start date parameter to filter by. Expects a unix timestamp. If no end date, but a start date is specified, the end date is set to the current time."
+// @Param enddate query int false "The end date parameter to filter by. Expects a unix timestamp. If no start date, but an end date is specified, the start date is set to the current time."
+// @Security JWTKeyAuth
+// @Success 200 {array} models.Task "The tasks"
+// @Failure 500 {object} models.Message "Internal error"
+// @Router /lists/{listID}/tasks [get]
+func (tf *TaskCollection) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
+ var sortby SortBy
+ switch tf.Sorting {
+ case "priority":
+ sortby = SortTasksByPriorityDesc
+ case "prioritydesc":
+ sortby = SortTasksByPriorityDesc
+ case "priorityasc":
+ sortby = SortTasksByPriorityAsc
+ case "duedate":
+ sortby = SortTasksByDueDateDesc
+ case "duedatedesc":
+ sortby = SortTasksByDueDateDesc
+ case "duedateasc":
+ sortby = SortTasksByDueDateAsc
+ default:
+ sortby = SortTasksByUnsorted
+ }
+
+ taskopts := &taskOptions{
+ search: search,
+ sortby: sortby,
+ startDate: time.Unix(tf.StartDateSortUnix, 0),
+ endDate: time.Unix(tf.EndDateSortUnix, 0),
+ page: page,
+ perPage: perPage,
+ }
+
+ shareAuth, is := a.(*LinkSharing)
+ if is {
+ list := &List{ID: shareAuth.ListID}
+ err := list.GetSimpleByID()
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ return getTasksForLists([]*List{list}, taskopts)
+ }
+
+ // If the list ID is not set, we get all tasks for the user.
+ // This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
+ if tf.ListID == 0 {
+ tf.Lists, _, _, err = getRawListsForUser("", &User{ID: a.GetID()}, -1, 0)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ } else {
+ // Check the list exists and the user has acess on it
+ list := &List{ID: tf.ListID}
+ canRead, err := list.CanRead(a)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ if !canRead {
+ return nil, 0, 0, ErrUserDoesNotHaveAccessToList{ListID: tf.ListID}
+ }
+ tf.Lists = []*List{{ID: tf.ListID}}
+ }
+
+ return getTasksForLists(tf.Lists, taskopts)
+}
diff --git a/pkg/models/tasks.go b/pkg/models/tasks.go
index b6e021adb..2dc6ee0ff 100644
--- a/pkg/models/tasks.go
+++ b/pkg/models/tasks.go
@@ -134,50 +134,12 @@ const (
// @Failure 500 {object} models.Message "Internal error"
// @Router /tasks/all [get]
func (t *Task) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
- var sortby SortBy
- switch t.Sorting {
- case "priority":
- sortby = SortTasksByPriorityDesc
- case "prioritydesc":
- sortby = SortTasksByPriorityDesc
- case "priorityasc":
- sortby = SortTasksByPriorityAsc
- case "duedate":
- sortby = SortTasksByDueDateDesc
- case "duedatedesc":
- sortby = SortTasksByDueDateDesc
- case "duedateasc":
- sortby = SortTasksByDueDateAsc
- default:
- sortby = SortTasksByUnsorted
+ tc := &TaskCollection{
+ Sorting: t.Sorting,
+ StartDateSortUnix: t.StartDateSortUnix,
+ EndDateSortUnix: t.EndDateSortUnix,
}
-
- taskopts := &taskOptions{
- search: search,
- sortby: sortby,
- startDate: time.Unix(t.StartDateSortUnix, 0),
- endDate: time.Unix(t.EndDateSortUnix, 0),
- page: page,
- perPage: perPage,
- }
-
- shareAuth, is := a.(*LinkSharing)
- if is {
- list := &List{ID: shareAuth.ListID}
- err := list.GetSimpleByID()
- if err != nil {
- return nil, 0, 0, err
- }
- return getTasksForLists([]*List{list}, taskopts)
- }
-
- // Get all lists for the user
- lists, _, _, err := getRawListsForUser("", &User{ID: a.GetID()}, -1, 0)
- if err != nil {
- return nil, 0, 0, err
- }
-
- return getTasksForLists(lists, taskopts)
+ return tc.ReadAll(a, search, page, perPage)
}
type taskOptions struct {
diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go
index a01970a58..2cef8f2ee 100644
--- a/pkg/routes/routes.go
+++ b/pkg/routes/routes.go
@@ -226,6 +226,13 @@ func registerAPIRoutes(a *echo.Group) {
a.DELETE("/tasks/:listtask", taskHandler.DeleteWeb)
a.POST("/tasks/:listtask", taskHandler.UpdateWeb)
+ taskCollectionHandler := &handler.WebHandler{
+ EmptyStruct: func() handler.CObject {
+ return &models.TaskCollection{}
+ },
+ }
+ a.GET("/lists/:list/tasks", taskCollectionHandler.ReadAllWeb)
+
bulkTaskHandler := &handler.WebHandler{
EmptyStruct: func() handler.CObject {
return &models.BulkTask{}
diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go
index 4dcd470f6..18734cac2 100644
--- a/pkg/swagger/docs.go
+++ b/pkg/swagger/docs.go
@@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
-// 2019-11-02 21:06:44.848486087 +0100 CET m=+0.175638002
+// 2019-11-29 18:11:53.766019702 +0100 CET m=+0.153156633
package swagger
@@ -967,6 +967,88 @@ var doc = `{
}
}
},
+ "/lists/{listID}/tasks": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Returns all tasks for the current list.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "task"
+ ],
+ "summary": "Get tasks on a list",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "The list ID.",
+ "name": "listID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "The page number. Used for pagination. If not provided, the first page of results is returned.",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page.",
+ "name": "per_page",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Search tasks by task text.",
+ "name": "s",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.",
+ "name": "sort",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The start date parameter to filter by. Expects a unix timestamp. If no end date, but a start date is specified, the end date is set to the current time.",
+ "name": "startdate",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The end date parameter to filter by. Expects a unix timestamp. If no start date, but an end date is specified, the start date is set to the current time.",
+ "name": "enddate",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "The tasks",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Task"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal error",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
"/lists/{listID}/teams/{teamID}": {
"post": {
"security": [
diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json
index 409218a25..e57397bb5 100644
--- a/pkg/swagger/swagger.json
+++ b/pkg/swagger/swagger.json
@@ -949,6 +949,88 @@
}
}
},
+ "/lists/{listID}/tasks": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Returns all tasks for the current list.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "task"
+ ],
+ "summary": "Get tasks on a list",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "The list ID.",
+ "name": "listID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "The page number. Used for pagination. If not provided, the first page of results is returned.",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page.",
+ "name": "per_page",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Search tasks by task text.",
+ "name": "s",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.",
+ "name": "sort",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The start date parameter to filter by. Expects a unix timestamp. If no end date, but a start date is specified, the end date is set to the current time.",
+ "name": "startdate",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "The end date parameter to filter by. Expects a unix timestamp. If no start date, but an end date is specified, the start date is set to the current time.",
+ "name": "enddate",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "The tasks",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Task"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal error",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
"/lists/{listID}/teams/{teamID}": {
"post": {
"security": [
diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml
index 73da65cf0..e41f64556 100644
--- a/pkg/swagger/swagger.yaml
+++ b/pkg/swagger/swagger.yaml
@@ -1642,6 +1642,66 @@ paths:
summary: Get one link shares for a list
tags:
- sharing
+ /lists/{listID}/tasks:
+ get:
+ consumes:
+ - application/json
+ description: Returns all tasks for the current list.
+ parameters:
+ - description: The list ID.
+ in: path
+ name: listID
+ required: true
+ type: integer
+ - description: The page number. Used for pagination. If not provided, the first
+ page of results is returned.
+ in: query
+ name: page
+ type: integer
+ - description: The maximum number of items per page. Note this parameter is
+ limited by the configured maximum of items per page.
+ in: query
+ name: per_page
+ type: integer
+ - description: Search tasks by task text.
+ in: query
+ name: s
+ type: string
+ - description: The sorting parameter. Possible values to sort by are priority,
+ prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.
+ in: query
+ name: sort
+ type: string
+ - description: The start date parameter to filter by. Expects a unix timestamp.
+ If no end date, but a start date is specified, the end date is set to the
+ current time.
+ in: query
+ name: startdate
+ type: integer
+ - description: The end date parameter to filter by. Expects a unix timestamp.
+ If no start date, but an end date is specified, the start date is set to
+ the current time.
+ in: query
+ name: enddate
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: The tasks
+ schema:
+ items:
+ $ref: '#/definitions/models.Task'
+ type: array
+ "500":
+ description: Internal error
+ schema:
+ $ref: '#/definitions/models.Message'
+ security:
+ - JWTKeyAuth: []
+ summary: Get tasks on a list
+ tags:
+ - task
/lists/{listID}/teams/{teamID}:
delete:
description: Delets a team from a list. The team won't have access to the list