Skip to content
This repository has been archived by the owner on Feb 9, 2018. It is now read-only.

Commit

Permalink
Added AddCard method
Browse files Browse the repository at this point in the history
  • Loading branch information
Luzifer committed Feb 25, 2016
1 parent 938d1a8 commit bf56605
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 4 deletions.
81 changes: 80 additions & 1 deletion board.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ limitations under the License.

package trello

import "encoding/json"
import (
"encoding/json"
"errors"
"net/url"
"strings"
"time"
)

type Board struct {
client *Client
Expand Down Expand Up @@ -179,3 +185,76 @@ func (b *Board) Actions() (actions []Action, err error) {
}
return
}

type AddCardOpts struct {
Name string
Description string
Position string
Due *time.Time
ListID string
Labels []string
Members []string
}

func (a AddCardOpts) validate() (bool, error) {
if len(a.Name) < 1 || len(a.Name) > 16384 {
return false, errors.New("Name must be a string of length from 1 to 16384")
}

if len(a.Description) > 16384 {
return false, errors.New("Description may not be longer than 16384 characters")
}

if a.Position != "" && (a.Position != "bottom" && a.Position != "top") {
return false, errors.New("If position is present it has to be 'bottom' or 'top'")
}

//TODO: Maybe it's not a good idea to hardcode the number 24 even if the documentation is explicit about it
if len(a.ListID) != 24 {
return false, errors.New("ListID is required and must be a valid 24-char hex string")
}

return true, nil
}

func (b *Board) AddCard(opts AddCardOpts) (*Card, error) {
if ok, err := opts.validate(); !ok {
return nil, err
}

params := url.Values{
"name": []string{opts.Name},
"idList": []string{opts.ListID},
"urlSource": []string{"null"}, // Not yet implemented
}

if len(opts.Description) > 0 {
params.Set("desc", opts.Description)
}

if len(opts.Position) > 0 {
params.Set("pos", opts.Position)
}

if len(opts.Labels) > 0 {
params.Set("idLabels", strings.Join(opts.Labels, ","))
}

if len(opts.Members) > 0 {
params.Set("idMembers", strings.Join(opts.Members, ","))
}

if opts.Due == nil {
params.Set("due", "null")
} else {
params.Set("due", opts.Due.Format("2006-01-02T15:04:05-07:00"))
}

resp, err := b.client.Post("/cards", params)
if err != nil {
return nil, err
}

c := &Card{client: b.client}
return c, json.Unmarshal(resp, c)
}
4 changes: 1 addition & 3 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ limitations under the License.

package trello

import (
"encoding/json"
)
import "encoding/json"

type List struct {
client *Client
Expand Down

5 comments on commit bf56605

@fiatjaf
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you think this will make the code base unnecessarily huge? I mean, if we are going to write a new struct and validation method for AddCard we are easily going to write custom structs and validation methods for almost all Trello API calls. Wouldn't this be a mess?

@fiatjaf
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is a stupid idea, but I can't stop thinking we should just accept a map[string]interface{} everywhere, serialize it to JSON and make the request with it. Wouldn't it be an easy solution?

(Instead of VojtechVitek#24, for example)

@Luzifer
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd strongly object against using map[string]interface{} as you then need to to type conversions all the time and need to handle the types yourself. You're loosing the advantage of a strongly typed language like Go.

Having input-structs for functions requiring a lot of parameters which are then passed to the API is a standard I see all over Go libraries (for example libraries by Amazon, Google and other widely used libraries) so I tend to follow their example when implementing this. You know what to pass in and what type to pass in when you're building your application around the library instead of passing a generic map not telling you which parameters are there, which are required and what type they are…

@fiatjaf
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I understand the point. map[string]interface{} wasn't a real well-thought suggestion, it was there just to compose the argument of the my first comment.

I understand that having proper well-defined types makes the library better and is the standard -- and it really should be! --, but perhaps considering that this is not much of a library, but more of a thin wrapper around the Trello API, and considering that people using this will surely need to know about the Trello API (for example, the documentation for the methos of this library don't explain anything, it just shows links to Trello API documentation), perhaps we don't need all this (again, considering the amount of work and hugeness of the code base that well-defined types will require), perhaps, then map[string]string (you'll object to this also, I think, but hey, we don't even need to check the existence of keys or anything like it, just serialize to JSON)?

Converting a map[string]string to JSON is worse than converting a struct, I know, but I'm talking about a trade-off here. Does that make sense? Am I totally wrong in thinking this way?

@Luzifer
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why serializing to JSON? The API does not accept JSON but only application/x-www-form-urlencoded… I don't see any advantage of a map against a well written library / wrapper… Sure, you might spare some minutes not writing a struct with defined parameters but imho that's only technical dept… You will need to keep the documentation open all the time you're using the library looking up which parameters you can pass in. With a well defined interface you have the property names to see what you can pass in and what type the value has. (Sure with changing types like float32 and string for position that's hard too but thats the implementation of the API which we can't change)

Please sign in to comment.