Add endpoint to get a single task (#106)
continuous-integration/drone/push Build is passing Details

This commit is contained in:
konrad 2019-11-02 20:33:18 +00:00
parent ed4c17892e
commit 9be5ab248c
8 changed files with 136 additions and 191 deletions

View File

@ -330,9 +330,18 @@ type LabelTaskBulk struct {
// @Failure 500 {object} models.Message "Internal error"
// @Router /tasks/{taskID}/labels/bulk [post]
func (ltb *LabelTaskBulk) Create(a web.Auth) (err error) {
task, err := GetTaskByID(ltb.TaskID)
task, err := GetTaskByIDSimple(ltb.TaskID)
if err != nil {
return
}
labels, _, _, err := getLabelsByTaskIDs(&LabelByTaskIDsOptions{
TaskIDs: []int64{ltb.TaskID},
})
if err != nil {
return err
}
for _, l := range labels {
task.Labels = append(task.Labels, &l.Label)
}
return task.updateTaskLabels(a, ltb.Labels)
}

View File

@ -284,9 +284,17 @@ type BulkAssignees struct {
// @Failure 500 {object} models.Message "Internal error"
// @Router /tasks/{taskID}/assignees/bulk [post]
func (ba *BulkAssignees) Create(a web.Auth) (err error) {
task, err := GetTaskByID(ba.TaskID) // We need to use the full method here because we need all current assignees.
task, err := GetTaskByIDSimple(ba.TaskID)
if err != nil {
return
}
assignees, err := getRawTaskAssigneesForTasks([]int64{task.ID})
if err != nil {
return err
}
for _, a := range assignees {
task.Assignees = append(task.Assignees, &a.User)
}
return task.updateTaskAssignees(ba.Assignees)
}

View File

@ -339,44 +339,6 @@ func GetTaskSimple(t *Task) (task Task, err error) {
return
}
// GetTaskByID returns all tasks a list has
func GetTaskByID(listTaskID int64) (listTask Task, err error) {
listTask, err = GetTaskByIDSimple(listTaskID)
if err != nil {
return
}
u, err := GetUserByID(listTask.CreatedByID)
if err != nil {
return
}
listTask.CreatedBy = u
// Get assignees
taskAssignees, err := getRawTaskAssigneesForTasks([]int64{listTaskID})
if err != nil {
return
}
for _, u := range taskAssignees {
if u != nil {
listTask.Assignees = append(listTask.Assignees, &u.User)
}
}
// Get task labels
taskLabels, _, _, err := getLabelsByTaskIDs(&LabelByTaskIDsOptions{
TaskIDs: []int64{listTaskID},
})
if err != nil {
return
}
for _, label := range taskLabels {
listTask.Labels = append(listTask.Labels, &label.Label)
}
return
}
// GetTasksByIDs returns all tasks for a list of ids
func (bt *BulkTask) GetTasksByIDs() (err error) {
for _, id := range bt.IDs {
@ -636,7 +598,7 @@ func (t *Task) Create(a web.Auth) (err error) {
// @Router /tasks/{id} [post]
func (t *Task) Update() (err error) {
// Check if the task exists
ot, err := GetTaskByID(t.ID)
ot, err := GetTaskByIDSimple(t.ID)
if err != nil {
return
}
@ -854,12 +816,6 @@ func (t *Task) updateReminders(reminders []int64) (err error) {
// @Router /tasks/{id} [delete]
func (t *Task) Delete() (err error) {
// Check if it exists
_, err = GetTaskByID(t.ID)
if err != nil {
return
}
if _, err = x.ID(t.ID).Delete(Task{}); err != nil {
return err
}
@ -874,3 +830,38 @@ func (t *Task) Delete() (err error) {
err = updateListLastUpdated(&List{ID: t.ListID})
return
}
// ReadOne gets one task by its ID
// @Summary Get one task
// @Description Returns one task by its ID
// @tags task
// @Accept json
// @Produce json
// @Param ID path int true "The task ID"
// @Security JWTKeyAuth
// @Success 200 {object} models.Task "The task"
// @Failure 404 {object} models.Message "Task not found"
// @Failure 500 {object} models.Message "Internal error"
// @Router /tasks/all [get]
func (t *Task) ReadOne() (err error) {
taskMap := make(map[int64]*Task, 1)
taskMap[t.ID] = &Task{}
*taskMap[t.ID], err = GetTaskByIDSimple(t.ID)
if err != nil {
return
}
tasks, err := addMoreInfoToTasks(taskMap)
if err != nil {
return
}
if len(tasks) == 0 {
return ErrTaskDoesNotExist{t.ID}
}
*t = *tasks[0]
return
}

View File

@ -24,6 +24,8 @@ import (
func TestTask_Create(t *testing.T) {
//assert.NoError(t, LoadFixtures())
// TODO: This test needs refactoring
// Fake list task
listtask := Task{
Text: "Lorem",
@ -48,11 +50,6 @@ func TestTask_Create(t *testing.T) {
err = listtask.Update()
assert.NoError(t, err)
// Check if it was updated
li, err := GetTaskByID(listtask.ID)
assert.NoError(t, err)
assert.Equal(t, li.Text, "Test34")
// Delete the task
allowed, _ = listtask.CanDelete(doer)
assert.True(t, allowed)
@ -61,7 +58,7 @@ func TestTask_Create(t *testing.T) {
// Delete a nonexistant task
listtask.ID = 0
err = listtask.Delete()
_, err = listtask.CanDelete(doer) // The check if the task exists happens in CanDelete
assert.Error(t, err)
assert.True(t, IsErrTaskDoesNotExist(err))
@ -106,3 +103,18 @@ func TestUpdateDone(t *testing.T) {
assert.Equal(t, int64(0), oldTask.DoneAtUnix)
})
}
func TestTask_ReadOne(t *testing.T) {
t.Run("default", func(t *testing.T) {
task := &Task{ID: 1}
err := task.ReadOne()
assert.NoError(t, err)
assert.Equal(t, "task #1", task.Text)
})
t.Run("nonexisting", func(t *testing.T) {
task := &Task{ID: 99999}
err := task.ReadOne()
assert.Error(t, err)
assert.True(t, IsErrTaskDoesNotExist(err))
})
}

View File

@ -221,6 +221,7 @@ func registerAPIRoutes(a *echo.Group) {
},
}
a.PUT("/lists/:list", taskHandler.CreateWeb)
a.GET("/tasks/:listtask", taskHandler.ReadOneWeb)
a.GET("/tasks/all", taskHandler.ReadAllWeb)
a.DELETE("/tasks/:listtask", taskHandler.DeleteWeb)
a.POST("/tasks/:listtask", taskHandler.UpdateWeb)

View File

@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-10-23 23:00:23.451871583 +0200 CEST m=+0.120322599
// 2019-11-02 21:06:44.848486087 +0100 CET m=+0.175638002
package swagger
@ -407,7 +407,7 @@ var doc = `{
"JWTKeyAuth": []
}
],
"description": "Returns a list by its ID.",
"description": "Returns a team by its ID.",
"consumes": [
"application/json"
],
@ -415,13 +415,13 @@ var doc = `{
"application/json"
],
"tags": [
"list"
"team"
],
"summary": "Gets one list",
"summary": "Gets one team",
"parameters": [
{
"type": "integer",
"description": "List ID",
"description": "Team ID",
"name": "id",
"in": "path",
"required": true
@ -429,13 +429,13 @@ var doc = `{
],
"responses": {
"200": {
"description": "The list",
"description": "The team",
"schema": {
"$ref": "#/definitions/models.List"
"$ref": "#/definitions/models.Team"
}
},
"403": {
"description": "The user does not have access to the list",
"description": "The user does not have access to the team",
"schema": {
"$ref": "#/definitions/code.vikunja.io.web.HTTPError"
}
@ -2561,7 +2561,7 @@ var doc = `{
"JWTKeyAuth": []
}
],
"description": "Returns all tasks on any list the user has access to.",
"description": "Returns one task by its ID",
"consumes": [
"application/json"
],
@ -2571,53 +2571,27 @@ var doc = `{
"tags": [
"task"
],
"summary": "Get tasks",
"summary": "Get one task",
"parameters": [
{
"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"
"description": "The task ID",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "The tasks",
"description": "The task",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Task"
}
"$ref": "#/definitions/models.Task"
}
},
"404": {
"description": "Task not found",
"schema": {
"$ref": "#/definitions/models.Message"
}
},
"500": {

View File

@ -389,7 +389,7 @@
"JWTKeyAuth": []
}
],
"description": "Returns a list by its ID.",
"description": "Returns a team by its ID.",
"consumes": [
"application/json"
],
@ -397,13 +397,13 @@
"application/json"
],
"tags": [
"list"
"team"
],
"summary": "Gets one list",
"summary": "Gets one team",
"parameters": [
{
"type": "integer",
"description": "List ID",
"description": "Team ID",
"name": "id",
"in": "path",
"required": true
@ -411,13 +411,13 @@
],
"responses": {
"200": {
"description": "The list",
"description": "The team",
"schema": {
"$ref": "#/definitions/models.List"
"$ref": "#/definitions/models.Team"
}
},
"403": {
"description": "The user does not have access to the list",
"description": "The user does not have access to the team",
"schema": {
"$ref": "#/definitions/code.vikunja.io/web.HTTPError"
}
@ -2543,7 +2543,7 @@
"JWTKeyAuth": []
}
],
"description": "Returns all tasks on any list the user has access to.",
"description": "Returns one task by its ID",
"consumes": [
"application/json"
],
@ -2553,53 +2553,27 @@
"tags": [
"task"
],
"summary": "Get tasks",
"summary": "Get one task",
"parameters": [
{
"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"
"description": "The task ID",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "The tasks",
"description": "The task",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Task"
}
"$ref": "#/definitions/models.Task"
}
},
"404": {
"description": "Task not found",
"schema": {
"$ref": "#/definitions/models.Message"
}
},
"500": {

View File

@ -1138,9 +1138,9 @@ paths:
get:
consumes:
- application/json
description: Returns a list by its ID.
description: Returns a team by its ID.
parameters:
- description: List ID
- description: Team ID
in: path
name: id
required: true
@ -1149,11 +1149,11 @@ paths:
- application/json
responses:
"200":
description: The list
description: The team
schema:
$ref: '#/definitions/models.List'
$ref: '#/definitions/models.Team'
"403":
description: The user does not have access to the list
description: The user does not have access to the team
schema:
$ref: '#/definitions/code.vikunja.io/web.HTTPError'
"500":
@ -1162,9 +1162,9 @@ paths:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Gets one list
summary: Gets one team
tags:
- list
- team
post:
consumes:
- application/json
@ -3177,55 +3177,31 @@ paths:
get:
consumes:
- application/json
description: Returns all tasks on any list the user has access to.
description: Returns one task by its ID
parameters:
- 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
- description: The task ID
in: path
name: ID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: The tasks
description: The task
schema:
items:
$ref: '#/definitions/models.Task'
type: array
$ref: '#/definitions/models.Task'
"404":
description: Task not found
schema:
$ref: '#/definitions/models.Message'
"500":
description: Internal error
schema:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Get tasks
summary: Get one task
tags:
- task
/tasks/bulk: