diff --git a/comments.go b/comments.go index 53a1a0f..72f3b3f 100644 --- a/comments.go +++ b/comments.go @@ -42,7 +42,7 @@ func (c *Client) CreateComment(ctx context.Context, taskID, userID int, content "content": content, } - var commentID int + var commentID IntOrFalse if err := c.call(ctx, "createComment", params, &commentID); err != nil { return nil, fmt.Errorf("createComment: %w", err) } @@ -52,7 +52,7 @@ func (c *Client) CreateComment(ctx context.Context, taskID, userID int, content } // Fetch the created comment to return full details - return c.GetComment(ctx, commentID) + return c.GetComment(ctx, int(commentID)) } // UpdateComment updates the content of a comment. diff --git a/files.go b/files.go index 929db4e..5ed3d8f 100644 --- a/files.go +++ b/files.go @@ -29,7 +29,7 @@ func (c *Client) CreateTaskFile(ctx context.Context, projectID, taskID int, file "blob": base64.StdEncoding.EncodeToString(content), } - var result int + var result IntOrFalse if err := c.call(ctx, "createTaskFile", params, &result); err != nil { return 0, fmt.Errorf("createTaskFile: %w", err) } @@ -38,7 +38,7 @@ func (c *Client) CreateTaskFile(ctx context.Context, projectID, taskID int, file return 0, fmt.Errorf("createTaskFile: failed to upload file") } - return result, nil + return int(result), nil } // DownloadTaskFile downloads a file's content by its ID. diff --git a/links.go b/links.go index 1d26007..dc1e65c 100644 --- a/links.go +++ b/links.go @@ -27,7 +27,7 @@ func (c *Client) CreateTaskLink(ctx context.Context, taskID, oppositeTaskID, lin "link_id": linkID, } - var result int + var result IntOrFalse if err := c.call(ctx, "createTaskLink", params, &result); err != nil { return 0, fmt.Errorf("createTaskLink: %w", err) } @@ -36,7 +36,7 @@ func (c *Client) CreateTaskLink(ctx context.Context, taskID, oppositeTaskID, lin return 0, fmt.Errorf("createTaskLink: failed to create link") } - return result, nil + return int(result), nil } // RemoveTaskLink deletes a task link. diff --git a/tags.go b/tags.go index 4f40b20..de5b21e 100644 --- a/tags.go +++ b/tags.go @@ -75,11 +75,11 @@ func (c *Client) CreateTag(ctx context.Context, projectID int, name, colorID str params["color_id"] = colorID } - var result int + var result IntOrFalse if err := c.call(ctx, "createTag", params, &result); err != nil { return 0, fmt.Errorf("createTag: %w", err) } - return result, nil + return int(result), nil } // UpdateTag updates an existing tag's name and/or color. diff --git a/tasks.go b/tasks.go index 4d8211c..866e444 100644 --- a/tasks.go +++ b/tasks.go @@ -41,7 +41,7 @@ func (c *Client) GetAllTasks(ctx context.Context, projectID int, status TaskStat // CreateTask creates a new task and returns the created task. func (c *Client) CreateTask(ctx context.Context, req CreateTaskRequest) (*Task, error) { - var taskID int + var taskID IntOrFalse if err := c.call(ctx, "createTask", req, &taskID); err != nil { return nil, fmt.Errorf("createTask: %w", err) } @@ -51,7 +51,7 @@ func (c *Client) CreateTask(ctx context.Context, req CreateTaskRequest) (*Task, } // Fetch the created task to return full details - return c.GetTask(ctx, taskID) + return c.GetTask(ctx, int(taskID)) } // UpdateTask updates an existing task. diff --git a/types.go b/types.go index 3e0160d..c729dae 100644 --- a/types.go +++ b/types.go @@ -2,6 +2,7 @@ package kanboard import ( "encoding/json" + "fmt" "strconv" ) @@ -105,6 +106,33 @@ func (i *StringInt64) UnmarshalJSON(data []byte) error { return nil } +// IntOrFalse is an int that can be unmarshaled from a JSON int or false. +// Kanboard API returns false on failure, int (ID) on success for create operations. +type IntOrFalse int + +// UnmarshalJSON implements json.Unmarshaler. +func (i *IntOrFalse) UnmarshalJSON(data []byte) error { + // Try as int first (success case) + var n int + if err := json.Unmarshal(data, &n); err == nil { + *i = IntOrFalse(n) + return nil + } + + // Try as bool (failure case: false) + var b bool + if err := json.Unmarshal(data, &b); err == nil { + if b { + *i = 1 // true shouldn't happen, but handle it + } else { + *i = 0 + } + return nil + } + + return fmt.Errorf("cannot unmarshal %s into IntOrFalse", data) +} + // Project represents a Kanboard project (board). type Project struct { ID StringInt `json:"id"` diff --git a/types_test.go b/types_test.go index 6b3e9e3..1bc1d73 100644 --- a/types_test.go +++ b/types_test.go @@ -97,6 +97,31 @@ func TestStringInt64_UnmarshalJSON(t *testing.T) { } } +func TestIntOrFalse_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input string + expected int + }{ + {"int value", `42`, 42}, + {"int zero", `0`, 0}, + {"false", `false`, 0}, + {"true", `true`, 1}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var i IntOrFalse + if err := json.Unmarshal([]byte(tt.input), &i); err != nil { + t.Fatalf("unmarshal error: %v", err) + } + if int(i) != tt.expected { + t.Errorf("expected %v, got %v", tt.expected, i) + } + }) + } +} + func TestProject_UnmarshalJSON(t *testing.T) { jsonData := `{ "id": "1",