The Kanboard API returns only true/false for many operations without explaining why they failed. Added OperationFailedError type that includes operation details and hints about possible causes. Updated MoveTaskPosition and MoveTaskToProject to use this new error type, providing users with actionable debugging information instead of generic "failed to move task" messages. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
130 lines
3.9 KiB
Go
130 lines
3.9 KiB
Go
package kanboard
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// Network errors
|
|
var (
|
|
// ErrConnectionFailed indicates a connection to the Kanboard server failed.
|
|
ErrConnectionFailed = errors.New("connection to Kanboard server failed")
|
|
|
|
// ErrTimeout indicates a request timed out.
|
|
ErrTimeout = errors.New("request timed out")
|
|
|
|
// ErrTooManyRedirects indicates the server returned too many redirects.
|
|
ErrTooManyRedirects = errors.New("too many redirects")
|
|
)
|
|
|
|
// Authentication errors
|
|
var (
|
|
// ErrUnauthorized indicates authentication failed.
|
|
ErrUnauthorized = errors.New("authentication failed: invalid credentials")
|
|
|
|
// ErrForbidden indicates insufficient permissions.
|
|
ErrForbidden = errors.New("access forbidden: insufficient permissions")
|
|
)
|
|
|
|
// Resource errors
|
|
var (
|
|
// ErrNotFound indicates a resource was not found.
|
|
ErrNotFound = errors.New("resource not found")
|
|
|
|
// ErrProjectNotFound indicates the specified project was not found.
|
|
ErrProjectNotFound = errors.New("project not found")
|
|
|
|
// ErrTaskNotFound indicates the specified task was not found.
|
|
ErrTaskNotFound = errors.New("task not found")
|
|
|
|
// ErrColumnNotFound indicates the specified column was not found.
|
|
ErrColumnNotFound = errors.New("column not found")
|
|
|
|
// ErrCommentNotFound indicates the specified comment was not found.
|
|
ErrCommentNotFound = errors.New("comment not found")
|
|
|
|
// ErrCategoryNotFound indicates the specified category was not found.
|
|
ErrCategoryNotFound = errors.New("category not found")
|
|
)
|
|
|
|
// Logic errors
|
|
var (
|
|
// ErrAlreadyInLastColumn indicates a task is already in the last column.
|
|
ErrAlreadyInLastColumn = errors.New("task is already in the last column")
|
|
|
|
// ErrAlreadyInFirstColumn indicates a task is already in the first column.
|
|
ErrAlreadyInFirstColumn = errors.New("task is already in the first column")
|
|
|
|
// ErrTaskClosed indicates a task is already closed.
|
|
ErrTaskClosed = errors.New("task is already closed")
|
|
|
|
// ErrTaskOpen indicates a task is already open.
|
|
ErrTaskOpen = errors.New("task is already open")
|
|
)
|
|
|
|
// Validation errors
|
|
var (
|
|
// ErrEmptyTitle indicates a task title cannot be empty.
|
|
ErrEmptyTitle = errors.New("task title cannot be empty")
|
|
|
|
// ErrInvalidProjectID indicates an invalid project ID was provided.
|
|
ErrInvalidProjectID = errors.New("invalid project ID")
|
|
)
|
|
|
|
// APIError represents an error returned by the Kanboard API.
|
|
type APIError struct {
|
|
Code int
|
|
Message string
|
|
}
|
|
|
|
// Error implements the error interface.
|
|
func (e *APIError) Error() string {
|
|
return fmt.Sprintf("Kanboard API error (code %d): %s", e.Code, e.Message)
|
|
}
|
|
|
|
// OperationFailedError represents an API operation that returned false without details.
|
|
// The Kanboard API often returns only true/false without explaining why an operation failed.
|
|
type OperationFailedError struct {
|
|
Operation string
|
|
Hints []string
|
|
}
|
|
|
|
// Error implements the error interface.
|
|
func (e *OperationFailedError) Error() string {
|
|
msg := fmt.Sprintf("%s: operation failed", e.Operation)
|
|
if len(e.Hints) > 0 {
|
|
msg += " (possible causes: " + e.Hints[0]
|
|
for _, hint := range e.Hints[1:] {
|
|
msg += ", " + hint
|
|
}
|
|
msg += ")"
|
|
}
|
|
return msg
|
|
}
|
|
|
|
// IsNotFound returns true if the error indicates a resource was not found.
|
|
func IsNotFound(err error) bool {
|
|
return errors.Is(err, ErrNotFound) ||
|
|
errors.Is(err, ErrProjectNotFound) ||
|
|
errors.Is(err, ErrTaskNotFound) ||
|
|
errors.Is(err, ErrColumnNotFound) ||
|
|
errors.Is(err, ErrCommentNotFound) ||
|
|
errors.Is(err, ErrCategoryNotFound)
|
|
}
|
|
|
|
// IsUnauthorized returns true if the error indicates an authentication failure.
|
|
func IsUnauthorized(err error) bool {
|
|
return errors.Is(err, ErrUnauthorized)
|
|
}
|
|
|
|
// IsAPIError returns true if the error is an APIError from the Kanboard API.
|
|
func IsAPIError(err error) bool {
|
|
var apiErr *APIError
|
|
return errors.As(err, &apiErr)
|
|
}
|
|
|
|
// IsOperationFailed returns true if the error is an OperationFailedError.
|
|
func IsOperationFailed(err error) bool {
|
|
var opErr *OperationFailedError
|
|
return errors.As(err, &opErr)
|
|
}
|