Add IntOrFalse type to handle polymorphic API responses
Kanboard API returns int (ID) on success and false (bool) on failure for create operations. Add IntOrFalse type that handles both cases and update CreateTask, CreateComment, CreateTag, CreateTaskFile, and CreateTaskLink to use it.
This commit is contained in:
parent
59252a3f63
commit
a34a40cb12
7 changed files with 63 additions and 10 deletions
|
|
@ -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.
|
||||
|
|
|
|||
4
files.go
4
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.
|
||||
|
|
|
|||
4
links.go
4
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.
|
||||
|
|
|
|||
4
tags.go
4
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.
|
||||
|
|
|
|||
4
tasks.go
4
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.
|
||||
|
|
|
|||
28
types.go
28
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"`
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue