diff --git a/action.go b/action.go index 9dc0940..39ff2aa 100644 --- a/action.go +++ b/action.go @@ -50,21 +50,24 @@ type ActionDataCard struct { } // GetActions make a GET call for a board's actions -func (b *Board) GetActions(args Arguments) (actions ActionCollection, err error) { +func (b *Board) GetActions(extraArgs ...Arguments) (actions ActionCollection, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/actions", b.ID) err = b.client.Get(path, args, &actions) return } // GetActions makes a GET call for a list's actions -func (l *List) GetActions(args Arguments) (actions ActionCollection, err error) { +func (l *List) GetActions(extraArgs ...Arguments) (actions ActionCollection, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s/actions", l.ID) err = l.client.Get(path, args, &actions) return } // GetActions makes a GET for a card's actions -func (c *Card) GetActions(args Arguments) (actions ActionCollection, err error) { +func (c *Card) GetActions(extraArgs ...Arguments) (actions ActionCollection, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s/actions", c.ID) err = c.client.Get(path, args, &actions) return diff --git a/arguments.go b/arguments.go index 5830759..02b7d3c 100644 --- a/arguments.go +++ b/arguments.go @@ -25,3 +25,21 @@ func (args Arguments) ToURLValues() url.Values { } return v } + +// flattenArguments will return a Arguments by merging a slice of Arguments, +// where each successive slice can override fields in the previous. +func flattenArguments(extraArgs []Arguments) (args Arguments) { + args = make(Arguments) + args.flatten(extraArgs) + return +} + +// flatten will merge a slice of Arguments into the current one +// where each successive slice can override fields in the previous. +func (args Arguments) flatten(extraArgs []Arguments) { + for _, extraArg := range extraArgs { + for key, val := range extraArg { + args[key] = val + } + } +} diff --git a/board.go b/board.go index a357d50..0e0a2d6 100644 --- a/board.go +++ b/board.go @@ -91,7 +91,7 @@ func (b *Board) CreatedAt() time.Time { // Attributes currently known to be unsupported: idBoardSource, keepFromSource. // // API Docs: https://developers.trello.com/reference/#boardsid -func (c *Client) CreateBoard(board *Board, extraArgs Arguments) error { +func (c *Client) CreateBoard(board *Board, extraArgs ...Arguments) error { path := "boards" args := Arguments{ "desc": board.Desc, @@ -120,14 +120,7 @@ func (c *Client) CreateBoard(board *Board, extraArgs Arguments) error { args["prefs_cardAging"] = board.Prefs.CardAging } - // Expects "true" or "false" - if defaultLists, ok := extraArgs["defaultLists"]; ok { - args["defaultLists"] = defaultLists - } - // Expects one of "all", "calendar", "cardAging", "recap", or "voting". - if powerUps, ok := extraArgs["powerUps"]; ok { - args["powerUps"] = powerUps - } + args.flatten(extraArgs) err := c.Post(path, args, &board) if err == nil { @@ -138,14 +131,16 @@ func (c *Client) CreateBoard(board *Board, extraArgs Arguments) error { // Update PUTs the supported board attributes remote and updates // the struct from the returned values. -func (b *Board) Update(extraArgs Arguments) error { - return b.client.PutBoard(b, extraArgs) +func (b *Board) Update(extraArgs ...Arguments) error { + args := flattenArguments(extraArgs) + return b.client.PutBoard(b, args) } // Delete makes a DELETE call for the receiver Board. -func (b *Board) Delete(extraArgs Arguments) error { +func (b *Board) Delete(extraArgs ...Arguments) error { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s", b.ID) - return b.client.Delete(path, Arguments{}, b) + return b.client.Delete(path, args, b) } // AddedMembersResponse represents a response after adding a new member. @@ -157,18 +152,12 @@ type AddedMembersResponse struct { // AddMember adds a new member to the board. // https://developers.trello.com/reference#boardsidlabelnamesmembers -func (b *Board) AddMember(member *Member, extraArgs Arguments) (response *AddedMembersResponse, err error) { +func (b *Board) AddMember(member *Member, extraArgs ...Arguments) (response *AddedMembersResponse, err error) { args := Arguments{ "email": member.Email, } - // "normal" is the default type, so we can omit it. - if memberType, ok := extraArgs["type"]; ok { - switch memberType { - case "admin", "observer": - args["type"] = memberType - } - } + args.flatten(extraArgs) path := fmt.Sprintf("boards/%s/members", b.ID) err = b.client.Put(path, args, &response) @@ -176,7 +165,8 @@ func (b *Board) AddMember(member *Member, extraArgs Arguments) (response *AddedM } // GetBoard retrieves a Trello board by its ID. -func (c *Client) GetBoard(boardID string, args Arguments) (board *Board, err error) { +func (c *Client) GetBoard(boardID string, extraArgs ...Arguments) (board *Board, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s", boardID) err = c.Get(path, args, &board) if board != nil { @@ -186,7 +176,8 @@ func (c *Client) GetBoard(boardID string, args Arguments) (board *Board, err err } // GetMyBoards returns a slice of all boards associated with the credentials set on the client. -func (c *Client) GetMyBoards(args Arguments) (boards []*Board, err error) { +func (c *Client) GetMyBoards(extraArgs ...Arguments) (boards []*Board, err error) { + args := flattenArguments(extraArgs) path := "members/me/boards" err = c.Get(path, args, &boards) for i := range boards { @@ -196,7 +187,8 @@ func (c *Client) GetMyBoards(args Arguments) (boards []*Board, err error) { } // GetBoards returns a slice of all public boards of the receiver Member. -func (m *Member) GetBoards(args Arguments) (boards []*Board, err error) { +func (m *Member) GetBoards(extraArgs ...Arguments) (boards []*Board, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("members/%s/boards", m.ID) err = m.client.Get(path, args, &boards) for i := range boards { @@ -212,7 +204,7 @@ func (m *Member) GetBoards(args Arguments) (boards []*Board, err error) { // PutBoard PUTs a board remote. Extra arguments are currently unsupported. // // API Docs: https://developers.trello.com/reference#idnext -func (c *Client) PutBoard(board *Board, extraArgs Arguments) error { +func (c *Client) PutBoard(board *Board, extraArgs ...Arguments) error { path := fmt.Sprintf("boards/%s", board.ID) args := Arguments{ "desc": board.Desc, @@ -241,6 +233,8 @@ func (c *Client) PutBoard(board *Board, extraArgs Arguments) error { args["prefs/cardAging"] = board.Prefs.CardAging } + args.flatten(extraArgs) + err := c.Put(path, args, &board) if err == nil { board.client = c diff --git a/card.go b/card.go index 682f935..a61b298 100644 --- a/card.go +++ b/card.go @@ -144,7 +144,8 @@ func (c *Card) CustomFields(boardCustomFields []*CustomField) map[string]interfa } // MoveToList moves a card to a list given by listID. -func (c *Card) MoveToList(listID string, args Arguments) error { +func (c *Card) MoveToList(listID string, extraArgs ...Arguments) error { + args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s", c.ID) args["idList"] = listID return c.client.Put(path, args, &c) @@ -196,7 +197,8 @@ func (c *Card) MoveToBottomOfList() error { } // Update UPDATEs the card's attributes. -func (c *Card) Update(args Arguments) error { +func (c *Card) Update(extraArgs ...Arguments) error { + args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s", c.ID) return c.client.Put(path, args, c) } @@ -218,7 +220,7 @@ func (c *Card) Delete() error { } // CreateCard takes a Card and Arguments and POSTs the card. -func (c *Client) CreateCard(card *Card, extraArgs Arguments) error { +func (c *Client) CreateCard(card *Card, extraArgs ...Arguments) error { path := "cards" args := Arguments{ "name": card.Name, @@ -231,10 +233,8 @@ func (c *Client) CreateCard(card *Card, extraArgs Arguments) error { if card.Due != nil { args["due"] = card.Due.Format(time.RFC3339) } - // Allow overriding the creation position with 'top' or 'botttom' - if pos, ok := extraArgs["pos"]; ok { - args["pos"] = pos - } + + args.flatten(extraArgs) err := c.Post(path, args, &card) if err == nil { card.client = c @@ -243,7 +243,7 @@ func (c *Client) CreateCard(card *Card, extraArgs Arguments) error { } // AddCard takes a Card and Arguments and adds the card to the receiver list. -func (l *List) AddCard(card *Card, extraArgs Arguments) error { +func (l *List) AddCard(card *Card, extraArgs ...Arguments) error { path := fmt.Sprintf("lists/%s/cards", l.ID) args := Arguments{ "name": card.Name, @@ -254,10 +254,9 @@ func (l *List) AddCard(card *Card, extraArgs Arguments) error { if card.Due != nil { args["due"] = card.Due.Format(time.RFC3339) } - // Allow overwriting the creation position with 'top' or 'bottom' - if pos, ok := extraArgs["pos"]; ok { - args["pos"] = pos - } + + args.flatten(extraArgs) + err := l.client.Post(path, args, &card) if err == nil { card.client = l.client @@ -273,11 +272,14 @@ func (l *List) AddCard(card *Card, extraArgs Arguments) error { // Arguments["keepFromSource"] = "all" // Arguments["keepFromSource"] = "none" // Arguments["keepFromSource"] = "attachments,checklists,comments" -func (c *Card) CopyToList(listID string, args Arguments) (*Card, error) { +func (c *Card) CopyToList(listID string, extraArgs ...Arguments) (*Card, error) { + args := Arguments{ + "idList": listID, + "idCardSource": c.ID, + } path := "cards" - args["idList"] = listID - args["idCardSource"] = c.ID newCard := Card{} + args.flatten(extraArgs) err := c.client.Post(path, args, &newCard) if err == nil { newCard.client = c.client @@ -288,9 +290,12 @@ func (c *Card) CopyToList(listID string, args Arguments) (*Card, error) { } // AddComment takes a comment string and Arguments and adds the comment to the card. -func (c *Card) AddComment(comment string, args Arguments) (*Action, error) { +func (c *Card) AddComment(comment string, extraArgs ...Arguments) (*Action, error) { + args := Arguments{ + "text": comment, + } + args.flatten(extraArgs) path := fmt.Sprintf("cards/%s/actions/comments", c.ID) - args["text"] = comment action := Action{} err := c.client.Post(path, args, &action) if err != nil { @@ -300,12 +305,13 @@ func (c *Card) AddComment(comment string, args Arguments) (*Action, error) { } // AddURLAttachment takes an Attachment and adds it to the card. -func (c *Card) AddURLAttachment(attachment *Attachment) error { +func (c *Card) AddURLAttachment(attachment *Attachment, extraArgs ...Arguments) error { path := fmt.Sprintf("cards/%s/attachments", c.ID) args := Arguments{ "url": attachment.URL, "name": attachment.Name, } + args.flatten(extraArgs) err := c.client.Post(path, args, &attachment) if err != nil { err = errors.Wrapf(err, "Error adding attachment to card %s", c.ID) @@ -318,8 +324,8 @@ func (c *Card) AddURLAttachment(attachment *Attachment) error { // from a copy of another Card. Returns an error only when a low-level failure occurred. // If this Card has no parent, a nil card and nil error are returned. In other words, the // non-existence of a parent is not treated as an error. -func (c *Card) GetParentCard(args Arguments) (*Card, error) { - +func (c *Card) GetParentCard(extraArgs ...Arguments) (*Card, error) { + args := flattenArguments(extraArgs) // Hopefully the card came pre-loaded with Actions including the card creation action := c.Actions.FirstCardCreateAction() @@ -343,8 +349,8 @@ func (c *Card) GetParentCard(args Arguments) (*Card, error) { } // GetAncestorCards takes Arguments, GETs the card's ancestors and returns them as a slice. -func (c *Card) GetAncestorCards(args Arguments) (ancestors []*Card, err error) { - +func (c *Card) GetAncestorCards(extraArgs ...Arguments) (ancestors []*Card, err error) { + args := flattenArguments(extraArgs) // Get the first parent parent, err := c.GetParentCard(args) if IsNotFound(err) || IsPermissionDenied(err) { @@ -367,7 +373,8 @@ func (c *Card) GetAncestorCards(args Arguments) (ancestors []*Card, err error) { } // GetOriginatingCard takes Arguments, GETs ancestors and returns most recent ancestor card of the Card. -func (c *Card) GetOriginatingCard(args Arguments) (*Card, error) { +func (c *Card) GetOriginatingCard(extraArgs ...Arguments) (*Card, error) { + args := flattenArguments(extraArgs) ancestors, err := c.GetAncestorCards(args) if err != nil { return c, err @@ -427,8 +434,11 @@ func (c *Card) CreatorMemberID() (string, error) { // ContainsCopyOfCard accepts a card id and Arguments and returns true // if the receiver Board contains a Card with the id. -func (b *Board) ContainsCopyOfCard(cardID string, args Arguments) (bool, error) { - args["filter"] = "copyCard" +func (b *Board) ContainsCopyOfCard(cardID string, extraArgs ...Arguments) (bool, error) { + args := Arguments{ + "filter": "copyCard", + } + args.flatten(extraArgs) actions, err := b.GetActions(args) if err != nil { err := errors.Wrapf(err, "GetCards() failed inside ContainsCopyOf() for board '%s' and card '%s'.", b.ID, cardID) @@ -445,7 +455,8 @@ func (b *Board) ContainsCopyOfCard(cardID string, args Arguments) (bool, error) // GetCard receives a card id and Arguments and returns the card if found // with the credentials given for the receiver Client. Returns an error // otherwise. -func (c *Client) GetCard(cardID string, args Arguments) (card *Card, err error) { +func (c *Client) GetCard(cardID string, extraArgs ...Arguments) (card *Card, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s", cardID) err = c.Get(path, args, &card) if card != nil { @@ -455,7 +466,8 @@ func (c *Client) GetCard(cardID string, args Arguments) (card *Card, err error) } // GetCards takes Arguments and retrieves all Cards on a Board as slice or returns error. -func (b *Board) GetCards(args Arguments) (cards []*Card, err error) { +func (b *Board) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/cards", b.ID) err = b.client.Get(path, args, &cards) @@ -484,7 +496,8 @@ func (b *Board) GetCards(args Arguments) (cards []*Card, err error) { } // GetCards retrieves all Cards in a List or an error if something goes wrong. -func (l *List) GetCards(args Arguments) (cards []*Card, err error) { +func (l *List) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s/cards", l.ID) err = l.client.Get(path, args, &cards) for i := range cards { diff --git a/checklist.go b/checklist.go index 7ef018a..1fbc0cc 100644 --- a/checklist.go +++ b/checklist.go @@ -5,6 +5,8 @@ package trello +import "fmt" + // Checklist represents Trello card's checklists. // A card can have one zero or more checklists. // https://developers.trello.com/reference/#checklist-object @@ -38,16 +40,14 @@ type CheckItemState struct { // Attributes currently known to be unsupported: idChecklistSource. // // API Docs: https://developers.trello.com/reference#cardsidchecklists-1 -func (c *Client) CreateChecklist(card *Card, name string, extraArgs Arguments) (checklist *Checklist, err error) { +func (c *Client) CreateChecklist(card *Card, name string, extraArgs ...Arguments) (checklist *Checklist, err error) { path := "cards/" + card.ID + "/checklists" args := Arguments{ "name": name, "pos": "bottom", } - if pos, ok := extraArgs["pos"]; ok { - args["pos"] = pos - } + args.flatten(extraArgs) checklist = &Checklist{} err = c.Post(path, args, &checklist) @@ -64,8 +64,9 @@ func (c *Client) CreateChecklist(card *Card, name string, extraArgs Arguments) ( // Attributes currently known to be unsupported: checked. // // API Docs: https://developers.trello.com/reference#checklistsidcheckitems -func (cl *Checklist) CreateCheckItem(name string, extraArgs Arguments) (item *CheckItem, err error) { - return cl.client.CreateCheckItem(cl, name, extraArgs) +func (cl *Checklist) CreateCheckItem(name string, extraArgs ...Arguments) (item *CheckItem, err error) { + args := flattenArguments(extraArgs) + return cl.client.CreateCheckItem(cl, name, args) } // CreateCheckItem creates a checkitem inside the given checklist. @@ -73,7 +74,7 @@ func (cl *Checklist) CreateCheckItem(name string, extraArgs Arguments) (item *Ch // Attributes currently known to be unsupported: checked. // // API Docs: https://developers.trello.com/reference#checklistsidcheckitems -func (c *Client) CreateCheckItem(checklist *Checklist, name string, extraArgs Arguments) (item *CheckItem, err error) { +func (c *Client) CreateCheckItem(checklist *Checklist, name string, extraArgs ...Arguments) (item *CheckItem, err error) { path := "checklists/" + checklist.ID + "/checkItems" args := Arguments{ "name": name, @@ -81,12 +82,7 @@ func (c *Client) CreateCheckItem(checklist *Checklist, name string, extraArgs Ar "checked": "false", } - if pos, ok := extraArgs["pos"]; ok { - args["pos"] = pos - } - if checked, ok := extraArgs["checked"]; ok { - args["checked"] = checked - } + args.flatten(extraArgs) item = &CheckItem{} err = c.Post(path, args, item) @@ -95,3 +91,15 @@ func (c *Client) CreateCheckItem(checklist *Checklist, name string, extraArgs Ar } return } + +// GetChecklist receives a checklist id and Arguments and returns the checklist if found +// with the credentials given for the receiver Client. Returns an error +// otherwise. +func (c *Client) GetChecklist(checklistID string, args Arguments) (checklist *Checklist, err error) { + path := fmt.Sprintf("checklists/%s", checklistID) + err = c.Get(path, args, &checklist) + if checklist != nil { + checklist.client = c + } + return checklist, err +} diff --git a/checklist_test.go b/checklist_test.go index 3777b15..160c5a0 100644 --- a/checklist_test.go +++ b/checklist_test.go @@ -91,3 +91,42 @@ func TestCreateCheckItem(t *testing.T) { t.Errorf("Expected checked to be set. Instead got '%s'.", item.State) } } + +func TestGetChecklist(t *testing.T) { + checklist := testChecklist(t) + if checklist.Name != "Example checklist" { + t.Errorf("Name incorrect. Got '%s'", checklist.Name) + } + + if checklist.Pos != 1 { + t.Errorf("Pos incorrect. Got '%0.2f'", checklist.Pos) + } + + if len(checklist.CheckItems) != 1 { + t.Errorf("len(checklist.CheckItems) incorrect. Got '%0.2f'", checklist.Pos) + } + + if checklist.CheckItems[0].Name != "Example checkItem" { + t.Errorf("CheckItem Name incorrect. Got '%s'", checklist.CheckItems[0].Name) + } + + if checklist.CheckItems[0].State != "complete" { + t.Errorf("CheckItem State incorrect. Got '%s'", checklist.CheckItems[0].State) + } + + if checklist.CheckItems[0].Pos != 2 { + t.Errorf("CheckItem Pos incorrect. Got '%0.2f'", checklist.CheckItems[0].Pos) + } +} + +// Utility function to get a simple response from Client.GetChecklist() +// +func testChecklist(t *testing.T) *Checklist { + c := testClient() + c.BaseURL = mockResponse("checklists", "checklist-api-example.json").URL + checklist, err := c.GetChecklist("4eea503", Defaults()) + if err != nil { + t.Fatal(err) + } + return checklist +} diff --git a/client.go b/client.go index 3129faa..02a8b9b 100644 --- a/client.go +++ b/client.go @@ -14,6 +14,7 @@ import ( "time" "github.com/pkg/errors" + "golang.org/x/time/rate" ) // DefaultBaseURL is the default API base url used by Client to send requests to Trello. @@ -27,7 +28,7 @@ type Client struct { BaseURL string Key string Token string - throttle <-chan time.Time + throttle *rate.Limiter testMode bool ctx context.Context } @@ -39,12 +40,14 @@ type logger interface { // NewClient is a constructor for the Client. It takes the key and token credentials // of a Trello member to authenticate and authorise requests with. func NewClient(key, token string) *Client { + limit := rate.Every(time.Second / 8) // Actually 10/second, but we're extra cautious + return &Client{ Client: http.DefaultClient, BaseURL: DefaultBaseURL, Key: key, Token: token, - throttle: time.Tick(time.Second / 8), // Actually 10/second, but we're extra cautious + throttle: rate.NewLimiter(limit, 1), testMode: false, ctx: context.Background(), } @@ -61,7 +64,7 @@ func (c *Client) WithContext(ctx context.Context) *Client { // Throttle starts receiving throttles from throttle channel each ticker period. func (c *Client) Throttle() { if !c.testMode { - <-c.throttle + c.throttle.Wait(c.ctx) } } diff --git a/custom-fields.go b/custom-fields.go index 05d19ec..b0852e7 100644 --- a/custom-fields.go +++ b/custom-fields.go @@ -144,14 +144,16 @@ type CustomFieldOption struct { } // GetCustomField takes a field id string and Arguments and returns the matching custom Field. -func (c *Client) GetCustomField(fieldID string, args Arguments) (customField *CustomField, err error) { +func (c *Client) GetCustomField(fieldID string, extraArgs ...Arguments) (customField *CustomField, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("customFields/%s", fieldID) err = c.Get(path, args, &customField) return } // GetCustomFields returns a slice of all receiver board's custom fields. -func (b *Board) GetCustomFields(args Arguments) (customFields []*CustomField, err error) { +func (b *Board) GetCustomFields(extraArgs ...Arguments) (customFields []*CustomField, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/customFields", b.ID) err = b.client.Get(path, args, &customFields) return diff --git a/go.mod b/go.mod index 2c4bb0a..a33a592 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/adlio/trello go 1.13 -require github.com/pkg/errors v0.8.1 +require ( + github.com/pkg/errors v0.8.1 + golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e +) diff --git a/go.sum b/go.sum index f29ab35..b3b14f0 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/label.go b/label.go index 4d3155f..d413ab8 100644 --- a/label.go +++ b/label.go @@ -20,14 +20,16 @@ type Label struct { // GetLabel takes a label id and Arguments and returns the matching label (per Trello member) // or an error. -func (c *Client) GetLabel(labelID string, args Arguments) (label *Label, err error) { +func (c *Client) GetLabel(labelID string, extraArgs ...Arguments) (label *Label, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("labels/%s", labelID) err = c.Get(path, args, &label) return } // GetLabels takes Arguments and returns a slice containing all labels of the receiver board or an error. -func (b *Board) GetLabels(args Arguments) (labels []*Label, err error) { +func (b *Board) GetLabels(extraArgs ...Arguments) (labels []*Label, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/labels", b.ID) err = b.client.Get(path, args, &labels) return diff --git a/list.go b/list.go index 3b28b7f..83aadc4 100644 --- a/list.go +++ b/list.go @@ -31,7 +31,8 @@ func (l *List) CreatedAt() time.Time { } // GetList takes a list's id and Arguments and returns the matching list. -func (c *Client) GetList(listID string, args Arguments) (list *List, err error) { +func (c *Client) GetList(listID string, extraArgs ...Arguments) (list *List, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s", listID) err = c.Get(path, args, &list) if list != nil { @@ -44,7 +45,8 @@ func (c *Client) GetList(listID string, args Arguments) (list *List, err error) } // GetLists takes Arguments and returns the lists of the receiver Board. -func (b *Board) GetLists(args Arguments) (lists []*List, err error) { +func (b *Board) GetLists(extraArgs ...Arguments) (lists []*List, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/lists", b.ID) err = b.client.Get(path, args, &lists) for i := range lists { @@ -61,7 +63,7 @@ func (b *Board) GetLists(args Arguments) (lists []*List, err error) { // Attributes currently known to be unsupported: idListSource. // // API Docs: https://developers.trello.com/reference/#lists-1 -func (c *Client) CreateList(onBoard *Board, name string, extraArgs Arguments) (list *List, err error) { +func (c *Client) CreateList(onBoard *Board, name string, extraArgs ...Arguments) (list *List, err error) { path := "lists" args := Arguments{ "name": name, @@ -69,9 +71,7 @@ func (c *Client) CreateList(onBoard *Board, name string, extraArgs Arguments) (l "idBoard": onBoard.ID, } - if pos, ok := extraArgs["pos"]; ok { - args["pos"] = pos - } + args.flatten(extraArgs) list = &List{} err = c.Post(path, args, &list) @@ -86,13 +86,15 @@ func (c *Client) CreateList(onBoard *Board, name string, extraArgs Arguments) (l // Attributes currently known to be unsupported: idListSource. // // API Docs: https://developers.trello.com/reference/#lists-1 -func (b *Board) CreateList(name string, extraArgs Arguments) (list *List, err error) { - return b.client.CreateList(b, name, extraArgs) +func (b *Board) CreateList(name string, extraArgs ...Arguments) (list *List, err error) { + args := flattenArguments(extraArgs) + return b.client.CreateList(b, name, args) } // Update UPDATEs the list's attributes. // API Docs: https://developers.trello.com/reference/#listsid-1 -func (l *List) Update(args Arguments) error { +func (l *List) Update(extraArgs ...Arguments) error { + args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s", l.ID) return l.client.Put(path, args, l) } diff --git a/member.go b/member.go index 40f2965..57e40ef 100644 --- a/member.go +++ b/member.go @@ -12,17 +12,20 @@ import ( // Member represents a Trello member. // https://developers.trello.com/reference/#member-object type Member struct { - client *Client - ID string `json:"id"` - Username string `json:"username"` - FullName string `json:"fullName"` - Initials string `json:"initials"` - AvatarHash string `json:"avatarHash"` - Email string `json:"email"` + client *Client + ID string `json:"id"` + Username string `json:"username"` + FullName string `json:"fullName"` + Initials string `json:"initials"` + AvatarHash string `json:"avatarHash"` + Email string `json:"email"` + IDBoards []string `json:"idBoards"` + IDOrganizations []string `json:"idOrganizations"` } // GetMember takes a member id and Arguments and returns a Member or an error. -func (c *Client) GetMember(memberID string, args Arguments) (member *Member, err error) { +func (c *Client) GetMember(memberID string, extraArgs ...Arguments) (member *Member, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("members/%s", memberID) err = c.Get(path, args, &member) if err == nil { @@ -31,8 +34,19 @@ func (c *Client) GetMember(memberID string, args Arguments) (member *Member, err return } +// GetMyMember returns Member for the user authenticating the API call +func (c *Client) GetMyMember(args Arguments) (member *Member, err error) { + path := fmt.Sprintf("members/me") + err = c.Get(path, args, &member) + if err == nil { + member.client = c + } + return +} + // GetMembers takes Arguments and returns a slice of all members of the organization or an error. -func (o *Organization) GetMembers(args Arguments) (members []*Member, err error) { +func (o *Organization) GetMembers(extraArgs ...Arguments) (members []*Member, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("organizations/%s/members", o.ID) err = o.client.Get(path, args, &members) for i := range members { @@ -42,7 +56,8 @@ func (o *Organization) GetMembers(args Arguments) (members []*Member, err error) } // GetMembers takes Arguments and returns a slice of all members of the Board or an error. -func (b *Board) GetMembers(args Arguments) (members []*Member, err error) { +func (b *Board) GetMembers(extraArgs ...Arguments) (members []*Member, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/members", b.ID) err = b.client.Get(path, args, &members) for i := range members { @@ -52,7 +67,8 @@ func (b *Board) GetMembers(args Arguments) (members []*Member, err error) { } // GetMembers takes Arguments and returns a slice of all members of the Card or an error. -func (c *Card) GetMembers(args Arguments) (members []*Member, err error) { +func (c *Card) GetMembers(extraArgs ...Arguments) (members []*Member, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s/members", c.ID) err = c.client.Get(path, args, &members) for i := range members { diff --git a/notification.go b/notification.go index d2ae4b2..641583d 100644 --- a/notification.go +++ b/notification.go @@ -43,7 +43,8 @@ type NotificationDataCard struct { } // GetMyNotifications returns the notifications of the authenticated user -func (c *Client) GetMyNotifications(args Arguments) (notifications []*Notification, err error) { +func (c *Client) GetMyNotifications(extraArgs ...Arguments) (notifications []*Notification, err error) { + args := flattenArguments(extraArgs) path := "members/me/notifications" err = c.Get(path, args, ¬ifications) for i := range notifications { diff --git a/organization.go b/organization.go index 3c46f77..12669a9 100644 --- a/organization.go +++ b/organization.go @@ -25,7 +25,8 @@ type Organization struct { // GetOrganization takes an organization id and Arguments and either // GETs returns an Organization, or an error. -func (c *Client) GetOrganization(orgID string, args Arguments) (organization *Organization, err error) { +func (c *Client) GetOrganization(orgID string, extraArgs ...Arguments) (organization *Organization, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("organizations/%s", orgID) err = c.Get(path, args, &organization) if organization != nil { diff --git a/search.go b/search.go index 386039b..bc98a03 100644 --- a/search.go +++ b/search.go @@ -35,9 +35,12 @@ type SearchTerm struct { } // SearchCards takes a query string and Arguments and returns a slice of Cards or an error. -func (c *Client) SearchCards(query string, args Arguments) (cards []*Card, err error) { - args["query"] = query - args["modelTypes"] = "cards" +func (c *Client) SearchCards(query string, extraArgs ...Arguments) (cards []*Card, err error) { + args := Arguments{ + "query": query, + "modelTypes": "cards", + } + args.flatten(extraArgs) res := SearchResult{} err = c.Get("search", args, &res) cards = res.Cards @@ -48,9 +51,12 @@ func (c *Client) SearchCards(query string, args Arguments) (cards []*Card, err e } // SearchBoards takes a query string and Arguments and returns a slice of Boards or an error. -func (c *Client) SearchBoards(query string, args Arguments) (boards []*Board, err error) { - args["query"] = query - args["modelTypes"] = "boards" +func (c *Client) SearchBoards(query string, extraArgs ...Arguments) (boards []*Board, err error) { + args := Arguments{ + "query": query, + "modelTypes": "boards", + } + args.flatten(extraArgs) res := SearchResult{} err = c.Get("search", args, &res) boards = res.Boards @@ -61,8 +67,11 @@ func (c *Client) SearchBoards(query string, args Arguments) (boards []*Board, er } // SearchMembers takes a query string and Arguments and returns a slice of Members or an error. -func (c *Client) SearchMembers(query string, args Arguments) (members []*Member, err error) { - args["query"] = query +func (c *Client) SearchMembers(query string, extraArgs ...Arguments) (members []*Member, err error) { + args := Arguments{ + "query": query, + } + args.flatten(extraArgs) err = c.Get("search/members", args, &members) return } diff --git a/testdata/checklists/checklist-api-example.json b/testdata/checklists/checklist-api-example.json new file mode 100644 index 0000000..fd0bdbf --- /dev/null +++ b/testdata/checklists/checklist-api-example.json @@ -0,0 +1,21 @@ +{ + "id": "333333333333333333333333", + "name": "Example checklist", + "idCard": "222222222222222222222222", + "pos": 1, + "idBoard": "111111111111111111111111", + "checkItems": [ + { + "idChecklist": "444444444444444444444444", + "state": "complete", + "idMember": null, + "id": "555555555555555555555555", + "name": "Example checkItem", + "nameData": { + "emoji": {} + }, + "pos": 2, + "due": null + } + ] +} \ No newline at end of file diff --git a/token.go b/token.go index af9ad4b..ea7e7c7 100644 --- a/token.go +++ b/token.go @@ -31,7 +31,8 @@ type Permission struct { } // GetToken takes a token id and Arguments and GETs and returns the Token or an error. -func (c *Client) GetToken(tokenID string, args Arguments) (token *Token, err error) { +func (c *Client) GetToken(tokenID string, extraArgs ...Arguments) (token *Token, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("tokens/%s", tokenID) err = c.Get(path, args, &token) if token != nil { diff --git a/webhook.go b/webhook.go index 2753cab..182a670 100644 --- a/webhook.go +++ b/webhook.go @@ -62,13 +62,14 @@ func (c *Client) CreateWebhook(webhook *Webhook) error { } // Delete takes a webhook and deletes it -func (w *Webhook) Delete(args Arguments) error { +func (w *Webhook) Delete(extraArgs ...Arguments) error { path := fmt.Sprintf("webhooks/%s", w.ID) return w.client.Delete(path, Arguments{}, w) } // GetWebhook takes a webhook id and Arguments, GETs the matching Webhook and returns it or an error. -func (c *Client) GetWebhook(webhookID string, args Arguments) (webhook *Webhook, err error) { +func (c *Client) GetWebhook(webhookID string, extraArgs ...Arguments) (webhook *Webhook, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("webhooks/%s", webhookID) err = c.Get(path, args, &webhook) if webhook != nil { @@ -78,7 +79,8 @@ func (c *Client) GetWebhook(webhookID string, args Arguments) (webhook *Webhook, } // GetWebhooks takes Arguments and returns a list of all Webhooks for the receiver Token or an error. -func (t *Token) GetWebhooks(args Arguments) (webhooks []*Webhook, err error) { +func (t *Token) GetWebhooks(extraArgs ...Arguments) (webhooks []*Webhook, err error) { + args := flattenArguments(extraArgs) path := fmt.Sprintf("tokens/%s/webhooks", t.client.Token) err = t.client.Get(path, args, &webhooks) if err == nil {