From e2fd429909e1034aa42f88de337a4f54a9b7adfe Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 28 Dec 2018 07:06:30 -0800 Subject: [PATCH] collection: Support collecting posts This adds support for moving posts to a collection. This change relies on #13 so that we can create and delete collections during tests. Couple notes: - CollectPosts accepts a single struct rather than an alias and a list of structs. This makes it easy to add new optional parameters in the future. - We're passing `[]*CollectPost` around rather than `*[]CollectPost` which is done in some of the existing APIs. The reasoning for this is: - Idiomatically, slices are passed by-value (`[]foo`) rather than by-pointer (`*[]foo`) because slices are already reference types. Plus they're really cheap to copy since they're just a triple: pointer, length, and capacity ([related blog post][1]). We need pointers to slices only when we're trying to modify the original slice reference and don't have the ability to return a slice, like with `json.Unmarshal` (see also [this post][2]). - If we're trying to reduce copying, `[]*foo` is better than `[]foo` because otherwise `foo` will be copied when manipulating or accessing entries in the slice (like ranging over it). Existing APIs were left as-is to avoid breaking them. I can switch to `*[]CollectPost` if you'd prefer that but `[]*CollectPost` is more idiomatic. [1]: https://blog.golang.org/go-slices-usage-and-internals#TOC_4. [2]: https://blog.golang.org/slices#TOC_5. Resolves #4. --- collection.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ collection_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/collection.go b/collection.go index 9d16e48..f928ccc 100644 --- a/collection.go +++ b/collection.go @@ -35,6 +35,35 @@ type ( DeleteCollectionParams struct { Alias string `json:"-"` } + + // CollectPostParams holds the parameters for moving posts to a collection. + CollectPostParams struct { + // Alias of the collection. + Alias string `json:"-"` + + // Posts to move to this collection. + Posts []*CollectPost + } + + // CollectPost is a post being moved to a collection. + CollectPost struct { + // ID of the post. + ID string `json:"id,omitempty"` + + // The post's modify token. + // + // This is required if the post does not belong to the user making + // this request. + Token string `json:"token,omitempty"` + } + + // CollectPostResult holds the result of moving a single post to a + // collection. + CollectPostResult struct { + Code int `json:"code,omitempty"` + ErrorMessage string `json:"error_msg,omitempty"` + Post *Post `json:"post,omitempty"` + } ) // CreateCollection creates a new collection, returning a user-friendly error @@ -165,3 +194,28 @@ func (c *Client) DeleteCollection(p *DeleteCollectionParams) error { return fmt.Errorf("Problem deleting collection: %d. %s\n", status, env.ErrorMessage) } } + +// CollectPosts adds a group of posts to a collection. +// +// See https://developers.write.as/docs/api/#move-a-post-to-a-collection. +func (c *Client) CollectPosts(sp *CollectPostParams) ([]*CollectPostResult, error) { + endpoint := "/collections/" + sp.Alias + "/collect" + + var p []*CollectPostResult + env, err := c.post(endpoint, sp.Posts, &p) + if err != nil { + return nil, err + } + + status := env.Code + switch { + case status == http.StatusOK: + return p, nil + case c.isNotLoggedIn(status): + return nil, fmt.Errorf("Not authenticated.") + case status == http.StatusBadRequest: + return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage) + default: + return nil, fmt.Errorf("Problem claiming post: %d. %s\n", status, env.ErrorMessage) + } +} diff --git a/collection_test.go b/collection_test.go index 905290e..77a32cb 100644 --- a/collection_test.go +++ b/collection_test.go @@ -2,6 +2,7 @@ package writeas import ( "fmt" + "net/http" "strings" "testing" "time" @@ -103,3 +104,59 @@ func ExampleClient_GetCollection() { fmt.Printf("%s", coll.Title) // Output: write.as } + +func TestCollectPostsAnonymous(t *testing.T) { + // Create a post anonymously. + wac := NewDevClient() + p, err := wac.CreatePost(&PostParams{ + Title: "Title!", + Content: "This is a post.", + Font: "sans", + }) + if err != nil { + t.Errorf("Post create failed: %v", err) + return + } + t.Logf("Post created: %+v", p) + + // Log in. + if _, err := wac.LogIn("demo", "demo"); err != nil { + t.Fatalf("Unable to log in: %v", err) + } + defer wac.LogOut() + + now := time.Now().Unix() + alias := fmt.Sprintf("test-collection-%v", now) + + // Create a collection. + _, err = wac.CreateCollection(&CollectionParams{ + Alias: alias, + Title: fmt.Sprintf("Test Collection %v", now), + }) + if err != nil { + t.Fatalf("Unable to create collection %q: %v", alias, err) + } + defer wac.DeleteCollection(&DeleteCollectionParams{Alias: alias}) + + // Move the anonymous post to this collection. + res, err := wac.CollectPosts(&CollectPostParams{ + Alias: alias, + Posts: []*CollectPost{ + { + ID: p.ID, + Token: p.Token, + }, + }, + }) + if err != nil { + t.Fatalf("Could not collect post %q: %v", p.ID, err) + } + + for _, cr := range res { + if cr.Code != http.StatusOK { + t.Errorf("Failed to move post: %v", cr.ErrorMessage) + } else { + t.Logf("Moved post %q", cr.Post.ID) + } + } +}