Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
Expand Down Expand Up @@ -143,6 +145,7 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
Expand All @@ -158,10 +161,12 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
Expand Down
12 changes: 6 additions & 6 deletions go/pkg/basecamp/cards.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ func (s *CardColumnsService) Move(ctx context.Context, cardTableID int64, req *M
// SetColor sets the color of a column.
// Valid colors: white, red, orange, yellow, green, blue, aqua, purple, gray, pink, brown.
// Returns the updated column.
func (s *CardColumnsService) SetColor(ctx context.Context, columnID int64, color string) (result *CardColumn, err error) {
func (s *CardColumnsService) SetColor(ctx context.Context, bucketID, columnID int64, color string) (result *CardColumn, err error) {
op := OperationInfo{
Service: "CardColumns", Operation: "SetColor",
ResourceType: "card_column", IsMutation: true,
Expand All @@ -763,7 +763,7 @@ func (s *CardColumnsService) SetColor(ctx context.Context, columnID int64, color
Color: color,
}

resp, err := s.client.parent.gen.SetCardColumnColorWithResponse(ctx, s.client.accountID, columnID, body)
resp, err := s.client.parent.gen.SetCardColumnColorWithResponse(ctx, s.client.accountID, bucketID, columnID, body)
if err != nil {
return nil, err
}
Expand All @@ -781,7 +781,7 @@ func (s *CardColumnsService) SetColor(ctx context.Context, columnID int64, color

// EnableOnHold adds an on-hold section to a column.
// Returns the updated column.
func (s *CardColumnsService) EnableOnHold(ctx context.Context, columnID int64) (result *CardColumn, err error) {
func (s *CardColumnsService) EnableOnHold(ctx context.Context, bucketID, columnID int64) (result *CardColumn, err error) {
op := OperationInfo{
Service: "CardColumns", Operation: "EnableOnHold",
ResourceType: "card_column", IsMutation: true,
Expand All @@ -796,7 +796,7 @@ func (s *CardColumnsService) EnableOnHold(ctx context.Context, columnID int64) (
ctx = s.client.parent.hooks.OnOperationStart(ctx, op)
defer func() { s.client.parent.hooks.OnOperationEnd(ctx, op, err, time.Since(start)) }()

resp, err := s.client.parent.gen.EnableCardColumnOnHoldWithResponse(ctx, s.client.accountID, columnID)
resp, err := s.client.parent.gen.EnableCardColumnOnHoldWithResponse(ctx, s.client.accountID, bucketID, columnID)
if err != nil {
return nil, err
}
Expand All @@ -814,7 +814,7 @@ func (s *CardColumnsService) EnableOnHold(ctx context.Context, columnID int64) (

// DisableOnHold removes the on-hold section from a column.
// Returns the updated column.
func (s *CardColumnsService) DisableOnHold(ctx context.Context, columnID int64) (result *CardColumn, err error) {
func (s *CardColumnsService) DisableOnHold(ctx context.Context, bucketID, columnID int64) (result *CardColumn, err error) {
op := OperationInfo{
Service: "CardColumns", Operation: "DisableOnHold",
ResourceType: "card_column", IsMutation: true,
Expand All @@ -829,7 +829,7 @@ func (s *CardColumnsService) DisableOnHold(ctx context.Context, columnID int64)
ctx = s.client.parent.hooks.OnOperationStart(ctx, op)
defer func() { s.client.parent.hooks.OnOperationEnd(ctx, op, err, time.Since(start)) }()

resp, err := s.client.parent.gen.DisableCardColumnOnHoldWithResponse(ctx, s.client.accountID, columnID)
resp, err := s.client.parent.gen.DisableCardColumnOnHoldWithResponse(ctx, s.client.accountID, bucketID, columnID)
if err != nil {
return nil, err
}
Expand Down
101 changes: 101 additions & 0 deletions go/pkg/basecamp/cards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,3 +901,104 @@ func TestCardStepsService_UpdatePartial(t *testing.T) {
}
}
}

// testCardColumnsServer creates an httptest.Server and a CardColumnsService wired to it.
func testCardColumnsServer(t *testing.T, handler http.HandlerFunc) *CardColumnsService {
t.Helper()
server := httptest.NewServer(handler)
t.Cleanup(server.Close)

cfg := DefaultConfig()
cfg.BaseURL = server.URL
token := &StaticTokenProvider{Token: "test-token"}
client := NewClient(cfg, token)
account := client.ForAccount("99999")
return account.CardColumns()
}

// Distinct bucketID/columnID — a future swap of the (bucketID, columnID) argument
// order would build a path with the IDs in the wrong slots and fail the assertion.
const (
cardColumnsTestBucketID = int64(2085958499)
cardColumnsTestColumnID = int64(1069479347)
)

func TestCardColumnsService_SetColor(t *testing.T) {
fixture := loadCardsFixture(t, "column.json")
wantPath := "/99999/buckets/2085958499/card_tables/columns/1069479347/color.json"

var receivedBody map[string]any
svc := testCardColumnsServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {
t.Errorf("expected PUT, got %s", r.Method)
}
if r.URL.Path != wantPath {
t.Errorf("path = %q, want %q", r.URL.Path, wantPath)
}
receivedBody = decodeRequestBody(t, r)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
w.Write(fixture)
})

column, err := svc.SetColor(context.Background(), cardColumnsTestBucketID, cardColumnsTestColumnID, "blue")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if column == nil || column.ID != cardColumnsTestColumnID {
t.Fatalf("expected column ID %d, got %+v", cardColumnsTestColumnID, column)
}
if got := receivedBody["color"]; got != "blue" {
t.Errorf("body color = %v, want \"blue\"", got)
}
}

func TestCardColumnsService_EnableOnHold(t *testing.T) {
fixture := loadCardsFixture(t, "column.json")
wantPath := "/99999/buckets/2085958499/card_tables/columns/1069479347/on_hold.json"

svc := testCardColumnsServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != wantPath {
t.Errorf("path = %q, want %q", r.URL.Path, wantPath)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
w.Write(fixture)
})

column, err := svc.EnableOnHold(context.Background(), cardColumnsTestBucketID, cardColumnsTestColumnID)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if column == nil || column.ID != cardColumnsTestColumnID {
t.Fatalf("expected column ID %d, got %+v", cardColumnsTestColumnID, column)
}
}

func TestCardColumnsService_DisableOnHold(t *testing.T) {
fixture := loadCardsFixture(t, "column.json")
wantPath := "/99999/buckets/2085958499/card_tables/columns/1069479347/on_hold.json"

svc := testCardColumnsServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != "DELETE" {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != wantPath {
t.Errorf("path = %q, want %q", r.URL.Path, wantPath)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
w.Write(fixture)
})

column, err := svc.DisableOnHold(context.Background(), cardColumnsTestBucketID, cardColumnsTestColumnID)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if column == nil || column.ID != cardColumnsTestColumnID {
t.Fatalf("expected column ID %d, got %+v", cardColumnsTestColumnID, column)
}
}
68 changes: 38 additions & 30 deletions go/pkg/basecamp/url-routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,10 @@
}
},
{
"pattern": "/{accountId}/buckets/{bucketId}/webhooks",
"resource": "Automation",
"pattern": "/{accountId}/buckets/{bucketId}/card_tables/columns/{columnId}/color",
"resource": "Card Tables",
"operations": {
"GET": "ListWebhooks",
"POST": "CreateWebhook"
"PUT": "SetCardColumnColor"
},
"params": {
"accountId": {
Expand All @@ -89,66 +88,76 @@
"bucketId": {
"role": "parent",
"type": "int64"
},
"columnId": {
"role": "parent",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/cards/{cardId}",
"pattern": "/{accountId}/buckets/{bucketId}/card_tables/columns/{columnId}/on_hold",
"resource": "Card Tables",
"operations": {
"GET": "GetCard",
"PUT": "UpdateCard"
"DELETE": "DisableCardColumnOnHold",
"POST": "EnableCardColumnOnHold"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"cardId": {
"role": "recording",
"bucketId": {
"role": "parent",
"type": "int64"
},
"columnId": {
"role": "parent",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/cards/{cardId}/moves",
"resource": "Card Tables",
"pattern": "/{accountId}/buckets/{bucketId}/webhooks",
"resource": "Automation",
"operations": {
"POST": "MoveCard"
"GET": "ListWebhooks",
"POST": "CreateWebhook"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"cardId": {
"bucketId": {
"role": "parent",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/cards/{cardId}/positions",
"pattern": "/{accountId}/card_tables/cards/{cardId}",
"resource": "Card Tables",
"operations": {
"POST": "RepositionCardStep"
"GET": "GetCard",
"PUT": "UpdateCard"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"cardId": {
"role": "parent",
"role": "recording",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/cards/{cardId}/steps",
"pattern": "/{accountId}/card_tables/cards/{cardId}/moves",
"resource": "Card Tables",
"operations": {
"POST": "CreateCardStep"
"POST": "MoveCard"
},
"params": {
"accountId": {
Expand All @@ -162,54 +171,53 @@
}
},
{
"pattern": "/{accountId}/card_tables/columns/{columnId}",
"pattern": "/{accountId}/card_tables/cards/{cardId}/positions",
"resource": "Card Tables",
"operations": {
"GET": "GetCardColumn",
"PUT": "UpdateCardColumn"
"POST": "RepositionCardStep"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"columnId": {
"role": "recording",
"cardId": {
"role": "parent",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/columns/{columnId}/color",
"pattern": "/{accountId}/card_tables/cards/{cardId}/steps",
"resource": "Card Tables",
"operations": {
"PUT": "SetCardColumnColor"
"POST": "CreateCardStep"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"columnId": {
"cardId": {
"role": "parent",
"type": "int64"
}
}
},
{
"pattern": "/{accountId}/card_tables/columns/{columnId}/on_hold",
"pattern": "/{accountId}/card_tables/columns/{columnId}",
"resource": "Card Tables",
"operations": {
"DELETE": "DisableCardColumnOnHold",
"POST": "EnableCardColumnOnHold"
"GET": "GetCardColumn",
"PUT": "UpdateCardColumn"
},
"params": {
"accountId": {
"role": "account",
"type": "string"
},
"columnId": {
"role": "parent",
"role": "recording",
"type": "int64"
}
}
Expand Down
Loading
Loading