diff --git a/.gitignore b/.gitignore index a922cea..f478d13 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ tests/env *.swo *.swp +.idea/ diff --git a/action.go b/action.go index cbf0575..2a8526b 100644 --- a/action.go +++ b/action.go @@ -20,9 +20,9 @@ type Action struct { client *Client Id string `json:"id"` IdMemberCreator string `json:"idMemberCreator"` - Data struct { + Data struct { DateLastEdited string `json:"dateLastEdited"` - ListBefore struct { + ListBefore struct { Id string `json:"id"` Name string `json:"name"` } `json:"listBefore"` @@ -59,8 +59,8 @@ type Action struct { } `json:"card"` Text string `json:"text"` } `json:"data"` - Type string `json:"type"` - Date string `json:"date"` + Type ActionType `json:"type"` + Date string `json:"date"` MemberCreator struct { Id string `json:"id"` AvatarHash string `json:"avatarHash"` @@ -69,3 +69,75 @@ type Action struct { Username string `json:"username"` } `json:"memberCreator"` } + +type ActionType string + +const ( + AddAdminToBoard ActionType = "addAdminToBoard" + AddAdminToOrganization ActionType = "addAdminToOrganization" + AddAttachmentToCard ActionType = "addAttachmentToCard" + AddBoardsPinnedToMember ActionType = "addBoardsPinnedToMember" + AddChecklistToCard ActionType = "addChecklistToCard" + AddLabelToCard ActionType = "addLabelToCard" + AddMemberToBoard ActionType = "addMemberToBoard" + AddMemberToCard ActionType = "addMemberToCard" + AddMemberToOrganization ActionType = "addMemberToOrganization" + AddToOrganizationBoard ActionType = "addToOrganizationBoard" + CommentCard ActionType = "commentCard" + ConvertToCardFromCheckItem ActionType = "convertToCardFromCheckItem" + CopyBoard ActionType = "copyBoard" + CopyCard ActionType = "copyCard" + CopyChecklist ActionType = "copyChecklist" + CreateLabel ActionType = "createLabel" + CopyCommentCard ActionType = "copyCommentCard" + CreateBoard ActionType = "createBoard" + CreateBoardInvitation ActionType = "createBoardInvitation" + CreateBoardPreference ActionType = "createBoardPreference" + CreateCard ActionType = "createCard" + CreateChecklist ActionType = "createChecklist" + CreateList ActionType = "createList" + CreateOrganization ActionType = "createOrganization" + CreateOrganizationInvitation ActionType = "createOrganizationInvitation" + DeleteAttachmentFromCard ActionType = "deleteAttachmentFromCard" + DeleteBoardInvitation ActionType = "deleteBoardInvitation" + DeleteCard ActionType = "deleteCard" + DeleteCheckItem ActionType = "deleteCheckItem" + DeleteLabel ActionType = "deleteLabel" + DeleteOrganizationInvitation ActionType = "deleteOrganizationInvitation" + DisablePlugin ActionType = "disablePlugin" + DisablePowerUp ActionType = "disablePowerUp" + EmailCard ActionType = "emailCard" + EnablePlugin ActionType = "enablePlugin" + EnablePowerUp ActionType = "enablePowerUp" + MakeAdminOfBoard ActionType = "makeAdminOfBoard" + MakeAdminOfOrganization ActionType = "makeAdminOfOrganization" + MakeNormalMemberOfBoard ActionType = "makeNormalMemberOfBoard" + MakeNormalMemberOfOrganization ActionType = "makeNormalMemberOfOrganization" + MakeObserverOfBoard ActionType = "makeObserverOfBoard" + MemberJoinedTrello ActionType = "memberJoinedTrello" + MoveCardFromBoard ActionType = "moveCardFromBoard" + MoveCardToBoard ActionType = "moveCardToBoard" + MoveListFromBoard ActionType = "moveListFromBoard" + MoveListToBoard ActionType = "moveListToBoard" + RemoveAdminFromBoard ActionType = "removeAdminFromBoard" + RemoveAdminFromOrganization ActionType = "removeAdminFromOrganization" + RemoveBoardsPinnedFromMember ActionType = "removeBoardsPinnedFromMember" + RemoveChecklistFromCard ActionType = "removeChecklistFromCard" + RemoveFromOrganizationBoard ActionType = "removeFromOrganizationBoard" + RemoveLabelFromCard ActionType = "removeLabelFromCard" + RemoveMemberFromBoard ActionType = "removeMemberFromBoard" + RemoveMemberFromCard ActionType = "removeMemberFromCard" + RemoveMemberFromOrganization ActionType = "removeMemberFromOrganization" + UnconfirmedBoardInvitation ActionType = "unconfirmedBoardInvitation" + UnconfirmedOrganizationInvitation ActionType = "unconfirmedOrganizationInvitation" + UpdateBoard ActionType = "updateBoard" + UpdateCard ActionType = "updateCard" + UpdateCheckItem ActionType = "updateCheckItem" + UpdateCheckItemStateOnCard ActionType = "updateCheckItemStateOnCard" + UpdateChecklist ActionType = "updateChecklist" + UpdateLabel ActionType = "updateLabel" + UpdateList ActionType = "updateList" + UpdateMember ActionType = "updateMember" + UpdateOrganization ActionType = "updateOrganization" + VoteOnCard ActionType = "voteOnCard" +) diff --git a/board.go b/board.go index 9f7d7cc..c2b2baf 100644 --- a/board.go +++ b/board.go @@ -16,7 +16,11 @@ limitations under the License. package trello -import "encoding/json" +import ( + "encoding/json" + "net/url" + "strconv" +) type Board struct { client *Client @@ -184,3 +188,58 @@ func (b *Board) Actions(arg ...*Argument) (actions []Action, err error) { } return } + +func (b *Board) AddList(opts List) (*List, error) { + opts.IdBoard = b.Id + + payload := url.Values{} + payload.Set("name", opts.Name) + payload.Set("idBoard", opts.IdBoard) + payload.Set("pos", strconv.FormatFloat(float64(opts.Pos), 'g', -1, 32)) + + body, err := b.client.Post("/lists", payload) + if err != nil { + return nil, err + } + + var list List + if err = json.Unmarshal(body, &list); err != nil { + return nil, err + } + + list.client = b.client + return &list, nil +} + +func (b *Board) Labels() ([]Label, error) { + body, err := b.client.Get("/boards/" + b.Id + "/labels") + if err != nil { + return nil, err + } + + var labels []Label + if err = json.Unmarshal(body, &labels); err != nil { + return nil, err + } + return labels, nil +} + +//Color can be an empty string +func (b *Board) AddLabel(name, color string) (*Label, error) { + payload := url.Values{} + payload.Set("name", name) + payload.Set("color", color) + + body, err := b.client.Post("/boards/" + b.Id + "/labels", payload) + if err != nil { + return nil, err + } + + var label Label + if err = json.Unmarshal(body, &label); err != nil { + return nil, err + } + + label.client = b.client + return &label, nil +} diff --git a/card.go b/card.go index 7facf81..6311475 100644 --- a/card.go +++ b/card.go @@ -19,6 +19,7 @@ package trello import ( "encoding/json" "net/url" + "strconv" ) type Card struct { @@ -62,10 +63,7 @@ type Card struct { Description bool `json:"description"` Due string `json:"due"` } `json:"badges"` - Labels []struct { - Color string `json:"color"` - Name string `json:"name"` - } `json:"labels"` + Labels []Label `json:"labels"` } func (c *Client) Card(CardId string) (card *Card, err error) { @@ -111,6 +109,49 @@ func (c *Card) Members() (members []Member, err error) { return } +// Add a member to a card +// The AddMember function requires a member (pointer) to add +// It returns the resulting member-list +// https://developers.trello.com/v1.0/reference#cardsididmembers +func (c *Card) AddMember(member *Member) (members []Member, err error) { + payload := url.Values{} + payload.Set("value", member.Id) + body, err := c.client.Post("/cards/"+c.Id+"/idMembers", payload) + if err != nil { + return nil, err + } + if err = json.Unmarshal(body, &members); err != nil { + return nil, err + } + + // To enable our members to execute operations using our client, we need to pass each our client object + for i := range members { + members[i].client = c.client + } + return members, nil +} + +// Remove a member from a card +// The RemoveMember function requires a member (pointer) to delete +// It returns the resulting member-list +func (c *Card) RemoveMember(member *Member) (members []Member, err error) { + body, err := c.client.Delete("/cards/" + c.Id + "/idMembers/" + member.Id) + if err != nil { + return nil, err + } + + err = json.Unmarshal(body, &members) + if err != nil { + return nil, err + } + + // To enable our members to execute operations using our client, we need to pass each our client object + for i := range members { + members[i].client = c.client + } + return members, nil +} + func (c *Card) Attachments() (attachments []Attachment, err error) { body, err := c.client.Get("/cards/" + c.Id + "/attachments") if err != nil { @@ -188,3 +229,123 @@ func (c *Card) AddComment(text string) (*Action, error) { newAction.client = c.client return newAction, nil } + +func (c *Card) MoveToList(dstList List) (*Card, error) { + payload := url.Values{} + payload.Set("value", dstList.Id) + + body, err := c.client.Put("/cards/"+c.Id+"/idList", payload) + if err != nil { + return nil, err + } + + var card Card + if err = json.Unmarshal(body, &card); err != nil { + return nil, err + } + card.client = c.client + return &card, nil +} + +//pos can be "bottom", "top" or a positive number +func (c *Card) Move(pos string) (*Card, error) { + payload := url.Values{} + payload.Set("value", pos) + + body, err := c.client.Put("/cards/"+c.Id+"/pos", payload) + if err != nil { + return nil, err + } + + var card Card + if err = json.Unmarshal(body, &card); err != nil { + return nil, err + } + card.client = c.client + return &card, nil +} + +func (c *Card) Delete() error { + _, err := c.client.Delete("/cards/" + c.Id) + return err +} + +//If mode is true, card is archived, otherwise it's unarchived (returns to the board) +func (c *Card) Archive(mode bool) error { + payload := url.Values{} + payload.Set("value", strconv.FormatBool(mode)) + + _, err := c.client.Put("/cards/"+c.Id+"/closed", payload) + return err +} + +func (c *Card) SetName(name string) (*Card, error) { + payload := url.Values{} + payload.Set("value", name) + + body, err := c.client.Put("/cards/"+c.Id+"/name", payload) + if err != nil { + return nil, err + } + + var card Card + if err = json.Unmarshal(body, &card); err != nil { + return nil, err + } + card.client = c.client + return &card, nil +} + +func (c *Card) SetDescription(desc string) (*Card, error) { + payload := url.Values{} + payload.Set("value", desc) + + body, err := c.client.Put("/cards/"+c.Id+"/desc", payload) + if err != nil { + return nil, err + } + + var card Card + if err = json.Unmarshal(body, &card); err != nil { + return nil, err + } + card.client = c.client + return &card, nil +} + +//Returns an array of cards labels ids +func (c *Card) AddLabel(id string) ([]string, error) { + payload := url.Values{} + payload.Set("value", id) + + body, err := c.client.Post("/cards/"+c.Id+"/idLabels", payload) + if err != nil { + return nil, err + } + + var ids []string + if err = json.Unmarshal(body, &ids); err != nil { + return nil, err + } + + return ids, nil +} + +func (c *Card) AddNewLabel(name, color string) (*Label, error) { + payload := url.Values{} + payload.Set("name", name) + payload.Set("color", color) + + body, err := c.client.Post("/cards/"+c.Id+"/labels", payload) + if err != nil { + return nil, err + } + + var label Label + if err = json.Unmarshal(body, &label); err != nil { + return nil, err + } + + label.client = c.client + return &label, nil +} diff --git a/label.go b/label.go new file mode 100644 index 0000000..8505169 --- /dev/null +++ b/label.go @@ -0,0 +1,44 @@ +package trello + +import ( + "net/url" + "encoding/json" +) + +type Label struct { + client *Client + + Id string `json:"id"` + IdBoard string `json:"idBoard"` + Name string `json:"name"` + Color string `json:"color"` + Uses int `json:"uses"` +} + +func (l *Label) UpdateName(name string) (err error) { + payload := url.Values{} + payload.Set("value", name) + + body, err := l.client.Put("/labels/" + l.Id + "/name", payload) + if err != nil { + return + } + return json.Unmarshal(body, l) +} + +//Color can be null +func (l *Label) UpdateColor(color string) (err error) { + payload := url.Values{} + payload.Set("value", color) + + body, err := l.client.Put("/labels/" + l.Id + "/color", payload) + if err != nil { + return + } + return json.Unmarshal(body, l) +} + +func (l *Label) DeleteLabel() error { + _, err := l.client.Delete("/labels/" + l.Id) + return err +} diff --git a/list.go b/list.go index 06bacb7..35be87c 100644 --- a/list.go +++ b/list.go @@ -30,6 +30,7 @@ type List struct { Closed bool `json:"closed"` IdBoard string `json:"idBoard"` Pos float32 `json:"pos"` + cards []Card } func (c *Client) List(listId string) (list *List, err error) { @@ -44,6 +45,9 @@ func (c *Client) List(listId string) (list *List, err error) { } func (l *List) Cards() (cards []Card, err error) { + if l.cards != nil { + return l.cards, nil + } body, err := l.client.Get("/lists/" + l.Id + "/cards") if err != nil { return @@ -52,10 +56,19 @@ func (l *List) Cards() (cards []Card, err error) { err = json.Unmarshal(body, &cards) for i := range cards { cards[i].client = l.client + for j := range cards[i].Labels { + cards[i].Labels[j].client = l.client + } } + l.cards = cards return } +func (l *List) FreshCards() (cards []Card, err error) { + l.cards = nil + return l.Cards() +} + func (l *List) Actions() (actions []Action, err error) { body, err := l.client.Get("/lists/" + l.Id + "/actions") if err != nil { @@ -94,3 +107,30 @@ func (l *List) AddCard(opts Card) (*Card, error) { card.client = l.client return &card, nil } + +//If mode is true, list is archived, otherwise it's unarchived (returns to the board) +func (l *List) Archive(mode bool) error { + payload := url.Values{} + payload.Set("value", strconv.FormatBool(mode)) + + _, err := l.client.Put("/lists/"+l.Id+"/closed", payload) + return err +} + +//pos can be "bottom", "top" or a positive number +func (l *List) Move(pos string) (*List, error) { + payload := url.Values{} + payload.Set("value", pos) + + body, err := l.client.Put("/lists/"+l.Id+"/pos", payload) + if err != nil { + return nil, err + } + + var list List + if err = json.Unmarshal(body, &list); err != nil { + return nil, err + } + list.client = l.client + return &list, nil +} diff --git a/webhook.go b/webhook.go new file mode 100644 index 0000000..82b2208 --- /dev/null +++ b/webhook.go @@ -0,0 +1,62 @@ +package trello + +import ( + "encoding/json" + "fmt" + "net/url" +) + +type Webhook struct { + ID string `json:"id"` + Description string `json:"description"` + IDModel string `json:"idModel"` + CallbackURL string `json:"callbackURL"` + Active bool `json:"active"` +} + +func (c *Client) Webhooks(token string) (webhooks []Webhook, err error) { + + body, err := c.Get(webhookURL(token)) + if err != nil { + return []Webhook{}, err + } + err = json.Unmarshal(body, &webhooks) + return +} + +func (c *Client) CreateWebhook(hook Webhook) (webhook Webhook, err error) { + + payload := url.Values{} + payload.Set("description", hook.Description) + payload.Set("callbackURL", hook.CallbackURL) + payload.Set("idModel", hook.IDModel) + body, err := c.Post("/webhooks/", payload) + if err != nil { + return Webhook{}, err + } + err = json.Unmarshal(body, &webhook) + return +} + +func (c *Client) Webhook(webhookID string) (webhook Webhook, err error) { + + url := fmt.Sprintf("/webhooks/%s/", webhookID) + body, err := c.Get(url) + if err != nil { + return + } + err = json.Unmarshal(body, &webhook) + return +} + +func (c *Client) DeleteWebhook(webhookID string) (err error) { + + url := fmt.Sprintf("/webhooks/%s/", webhookID) + _, err = c.Delete(url) + return +} + +func webhookURL(token string) (url string) { + + return fmt.Sprintf("/tokens/%s/webhooks/", token) +}