Page MenuHomeMusing Studio

No OneTemporary

diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index f4684ce..9f9e72e 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,7 +1,7 @@
## Overview
## Implementation
-[API documentation](https://developer.write.as/docs/api/?go#TODO-ENTER-SECTION-HERE).
+[API documentation](https://developers.write.as/docs/api/?go#TODO-ENTER-SECTION-HERE).
diff --git a/README.md b/README.md
index 5288001..029e1ee 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,71 @@
# go-writeas
[![godoc](https://godoc.org/go.code.as/writeas.v2?status.svg)](https://godoc.org/go.code.as/writeas.v2)
Official Write.as Go client library.
## Installation
**Warning**: the `v2` branch is under heavy development and its API will change without notice.
For a stable API, use `go.code.as/writeas.v1` and upgrade to `v2` once everything is merged into `master`.
```bash
go get go.code.as/writeas.v2
```
## Documentation
-See all functionality and usages in the [API documentation](https://developer.write.as/docs/api/).
+See all functionality and usages in the [API documentation](https://developers.write.as/docs/api/).
### Example usage
```go
import "go.code.as/writeas.v2"
func main() {
// Create the client
c := writeas.NewClient()
// Publish a post
p, err := c.CreatePost(&writeas.PostParams{
Title: "Title!",
Content: "This is a post.",
Font: "sans",
})
if err != nil {
// Perhaps show err.Error()
}
// Save token for later, since it won't ever be returned again
token := p.Token
// Update a published post
p, err = c.UpdatePost(p.ID, token, &writeas.PostParams{
Content: "Now it's been updated!",
})
if err != nil {
// handle
}
// Get a published post
p, err = c.GetPost(p.ID)
if err != nil {
// handle
}
// Delete a post
err = c.DeletePost(p.ID, token)
}
```
## Contributing
The library covers our usage, but might not be comprehensive of the API. So we always welcome contributions and improvements from the community. Before sending pull requests, make sure you've done the following:
* Run `goimports` on all updated .go files.
* Document all exported structs and funcs.
## License
MIT
diff --git a/auth.go b/auth.go
index 3cf4249..26b5eb9 100644
--- a/auth.go
+++ b/auth.go
@@ -1,75 +1,75 @@
package writeas
import (
"fmt"
"net/http"
)
// LogIn authenticates a user with Write.as.
-// See https://developer.write.as/docs/api/#authenticate-a-user
+// See https://developers.write.as/docs/api/#authenticate-a-user
func (c *Client) LogIn(username, pass string) (*AuthUser, error) {
u := &AuthUser{}
up := struct {
Alias string `json:"alias"`
Pass string `json:"pass"`
}{
Alias: username,
Pass: pass,
}
env, err := c.post("/auth/login", up, u)
if err != nil {
return nil, err
}
var ok bool
if u, ok = env.Data.(*AuthUser); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusOK {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusUnauthorized {
return nil, fmt.Errorf("Incorrect password.")
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("User does not exist.")
} else if status == http.StatusTooManyRequests {
return nil, fmt.Errorf("Too many log in attempts in a short period of time.")
}
return nil, fmt.Errorf("Problem authenticating: %d. %v\n", status, err)
}
c.SetToken(u.AccessToken)
return u, nil
}
// LogOut logs the current user out, making the Client's current access token
// invalid.
func (c *Client) LogOut() error {
env, err := c.delete("/auth/me", nil)
if err != nil {
return err
}
status := env.Code
if status != http.StatusNoContent {
if status == http.StatusNotFound {
return fmt.Errorf("Access token is invalid or doesn't exist")
}
return fmt.Errorf("Unable to log out: %v", env.ErrorMessage)
}
// Logout successful, so update the Client
c.token = ""
return nil
}
func (c *Client) isNotLoggedIn(code int) bool {
if c.token == "" {
return false
}
return code == http.StatusUnauthorized
}
diff --git a/collection.go b/collection.go
index 9b4a925..da44638 100644
--- a/collection.go
+++ b/collection.go
@@ -1,186 +1,186 @@
package writeas
import (
"fmt"
"net/http"
)
type (
// Collection represents a collection of posts. Blogs are a type of collection
// on Write.as.
Collection struct {
Alias string `json:"alias"`
Title string `json:"title"`
Description string `json:"description"`
StyleSheet string `json:"style_sheet"`
Private bool `json:"private"`
Views int64 `json:"views"`
Domain string `json:"domain,omitempty"`
Email string `json:"email,omitempty"`
URL string `json:"url,omitempty"`
TotalPosts int `json:"total_posts"`
Posts *[]Post `json:"posts,omitempty"`
}
// CollectionParams holds values for creating a collection.
CollectionParams struct {
Alias string `json:"alias"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
}
)
// CreateCollection creates a new collection, returning a user-friendly error
// if one comes up. Requires a Write.as subscription. See
-// https://developer.write.as/docs/api/#create-a-collection
+// https://developers.write.as/docs/api/#create-a-collection
func (c *Client) CreateCollection(sp *CollectionParams) (*Collection, error) {
p := &Collection{}
env, err := c.post("/collections", sp, p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusCreated {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusForbidden {
return nil, fmt.Errorf("Casual or Pro user required.")
} else if status == http.StatusConflict {
return nil, fmt.Errorf("Collection name is already taken.")
} else if status == http.StatusPreconditionFailed {
return nil, fmt.Errorf("Reached max collection quota.")
}
return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
}
return p, nil
}
// GetCollection retrieves a collection, returning the Collection and any error
// (in user-friendly form) that occurs. See
-// https://developer.write.as/docs/api/#retrieve-a-collection
+// https://developers.write.as/docs/api/#retrieve-a-collection
func (c *Client) GetCollection(alias string) (*Collection, error) {
coll := &Collection{}
env, err := c.get(fmt.Sprintf("/collections/%s", alias), coll)
if err != nil {
return nil, err
}
var ok bool
if coll, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status == http.StatusOK {
return coll, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Collection not found.")
} else {
return nil, fmt.Errorf("Problem getting collection: %d. %v\n", status, err)
}
}
// GetCollectionPosts retrieves a collection's posts, returning the Posts
// and any error (in user-friendly form) that occurs. See
-// https://developer.write.as/docs/api/#retrieve-collection-posts
+// https://developers.write.as/docs/api/#retrieve-collection-posts
func (c *Client) GetCollectionPosts(alias string) (*[]Post, error) {
coll := &Collection{}
env, err := c.get(fmt.Sprintf("/collections/%s/posts", alias), coll)
if err != nil {
return nil, err
}
var ok bool
if coll, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status == http.StatusOK {
return coll.Posts, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Collection not found.")
} else {
return nil, fmt.Errorf("Problem getting collection: %d. %v\n", status, err)
}
}
// GetCollectionPost retrieves a post from a collection
// and any error (in user-friendly form) that occurs). See
// https://developers.write.as/docs/api/#retrieve-a-collection-post
func (c *Client) GetCollectionPost(alias, slug string) (*Post, error) {
post := Post{}
env, err := c.get(fmt.Sprintf("/collections/%s/posts/%s", alias, slug), &post)
if err != nil {
return nil, err
}
if _, ok := env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
if env.Code == http.StatusOK {
return &post, nil
} else if env.Code == http.StatusNotFound {
return nil, fmt.Errorf("Post %s not found in collection %s", slug, alias)
}
return nil, fmt.Errorf("Problem getting post %s from collection %s: %d. %v\n", slug, alias, env.Code, err)
}
// GetUserCollections retrieves the authenticated user's collections.
// See https://developers.write.as/docs/api/#retrieve-user-39-s-collections
func (c *Client) GetUserCollections() (*[]Collection, error) {
colls := &[]Collection{}
env, err := c.get("/me/collections", colls)
if err != nil {
return nil, err
}
var ok bool
if colls, ok = env.Data.(*[]Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
}
return nil, fmt.Errorf("Problem getting collections: %d. %v\n", status, err)
}
return colls, nil
}
// DeleteCollection permanently deletes a collection and makes any posts on it
// anonymous.
//
// See https://developers.write.as/docs/api/#delete-a-collection.
func (c *Client) DeleteCollection(alias string) error {
endpoint := "/collections/" + alias
env, err := c.delete(endpoint, nil /* data */)
if err != nil {
return err
}
status := env.Code
switch status {
case http.StatusNoContent:
return nil
case http.StatusUnauthorized:
return fmt.Errorf("Not authenticated.")
case http.StatusBadRequest:
return fmt.Errorf("Bad request: %s", env.ErrorMessage)
default:
return fmt.Errorf("Problem deleting collection: %d. %s\n", status, env.ErrorMessage)
}
}
diff --git a/post.go b/post.go
index 1f8a55b..33d650f 100644
--- a/post.go
+++ b/post.go
@@ -1,330 +1,330 @@
package writeas
import (
"fmt"
"net/http"
"time"
)
type (
// Post represents a published Write.as post, whether anonymous, owned by a
// user, or part of a collection.
Post struct {
ID string `json:"id"`
Slug string `json:"slug"`
Token string `json:"token"`
Font string `json:"appearance"`
Language *string `json:"language"`
RTL *bool `json:"rtl"`
Listed bool `json:"listed"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Title string `json:"title"`
Content string `json:"body"`
Views int64 `json:"views"`
Tags []string `json:"tags"`
Images []string `json:"images"`
OwnerName string `json:"owner,omitempty"`
Collection *Collection `json:"collection,omitempty"`
}
// OwnedPostParams are, together, fields only the original post author knows.
OwnedPostParams struct {
ID string `json:"id"`
Token string `json:"token,omitempty"`
}
// PostParams holds values for creating or updating a post.
PostParams struct {
// Parameters only for updating
ID string `json:"-"`
Token string `json:"token,omitempty"`
// Parameters for creating or updating
Slug string `json:"slug"`
Created *time.Time `json:"created,omitempty"`
Updated *time.Time `json:"updated,omitempty"`
Title string `json:"title,omitempty"`
Content string `json:"body,omitempty"`
Font string `json:"font,omitempty"`
IsRTL *bool `json:"rtl,omitempty"`
Language *string `json:"lang,omitempty"`
// Parameters only for creating
Crosspost []map[string]string `json:"crosspost,omitempty"`
// Parameters for collection posts
Collection string `json:"-"`
}
// PinnedPostParams holds values for pinning a post
PinnedPostParams struct {
ID string `json:"id"`
Position int `json:"position"`
}
// BatchPostResult contains the post-specific result as part of a larger
// batch operation.
BatchPostResult struct {
ID string `json:"id,omitempty"`
Code int `json:"code,omitempty"`
ErrorMessage string `json:"error_msg,omitempty"`
}
// ClaimPostResult contains the post-specific result for a request to
// associate a post to an account.
ClaimPostResult struct {
ID string `json:"id,omitempty"`
Code int `json:"code,omitempty"`
ErrorMessage string `json:"error_msg,omitempty"`
Post *Post `json:"post,omitempty"`
}
)
// GetPost retrieves a published post, returning the Post and any error (in
// user-friendly form) that occurs. See
-// https://developer.write.as/docs/api/#retrieve-a-post.
+// https://developers.write.as/docs/api/#retrieve-a-post.
func (c *Client) GetPost(id string) (*Post, error) {
p := &Post{}
env, err := c.get(fmt.Sprintf("/posts/%s", id), p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status == http.StatusOK {
return p, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Post not found.")
} else if status == http.StatusGone {
return nil, fmt.Errorf("Post unpublished.")
}
return nil, fmt.Errorf("Problem getting post: %d. %s\n", status, env.ErrorMessage)
}
// CreatePost publishes a new post, returning a user-friendly error if one comes
-// up. See https://developer.write.as/docs/api/#publish-a-post.
+// up. See https://developers.write.as/docs/api/#publish-a-post.
func (c *Client) CreatePost(sp *PostParams) (*Post, error) {
p := &Post{}
endPre := ""
if sp.Collection != "" {
endPre = "/collections/" + sp.Collection
}
env, err := c.post(endPre+"/posts", sp, p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusCreated {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return nil, fmt.Errorf("Problem creating post: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}
// UpdatePost updates a published post with the given PostParams. See
-// https://developer.write.as/docs/api/#update-a-post.
+// https://developers.write.as/docs/api/#update-a-post.
func (c *Client) UpdatePost(id, token string, sp *PostParams) (*Post, error) {
return c.updatePost("", id, token, sp)
}
func (c *Client) updatePost(collection, identifier, token string, sp *PostParams) (*Post, error) {
p := &Post{}
endpoint := "/posts/" + identifier
/*
if collection != "" {
endpoint = "/collections/" + collection + endpoint
} else {
sp.Token = token
}
*/
sp.Token = token
env, err := c.put(endpoint, sp, p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return nil, fmt.Errorf("Problem updating post: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}
// DeletePost permanently deletes a published post. See
-// https://developer.write.as/docs/api/#delete-a-post.
+// https://developers.write.as/docs/api/#delete-a-post.
func (c *Client) DeletePost(id, token string) error {
return c.deletePost("", id, token)
}
func (c *Client) deletePost(collection, identifier, token string) error {
p := map[string]string{}
endpoint := "/posts/" + identifier
/*
if collection != "" {
endpoint = "/collections/" + collection + endpoint
} else {
p["token"] = token
}
*/
p["token"] = token
env, err := c.delete(endpoint, p)
if err != nil {
return err
}
status := env.Code
if status == http.StatusNoContent {
return nil
} else if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return fmt.Errorf("Problem deleting post: %d. %s\n", status, env.ErrorMessage)
}
// ClaimPosts associates anonymous posts with a user / account.
-// https://developer.write.as/docs/api/#claim-posts.
+// https://developers.write.as/docs/api/#claim-posts.
func (c *Client) ClaimPosts(sp *[]OwnedPostParams) (*[]ClaimPostResult, error) {
p := &[]ClaimPostResult{}
env, err := c.post("/posts/claim", sp, p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*[]ClaimPostResult); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status == http.StatusOK {
return p, nil
} else if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else {
return nil, fmt.Errorf("Problem claiming post: %d. %s\n", status, env.ErrorMessage)
}
// TODO: does this also happen with moving posts?
}
// GetUserPosts retrieves the authenticated user's posts.
// See https://developers.write.as/docs/api/#retrieve-user-39-s-posts
func (c *Client) GetUserPosts() (*[]Post, error) {
p := &[]Post{}
env, err := c.get("/me/posts", p)
if err != nil {
return nil, err
}
var ok bool
if p, ok = env.Data.(*[]Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
}
return nil, fmt.Errorf("Problem getting user posts: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}
// PinPost pins a post in the given collection.
// See https://developers.write.as/docs/api/#pin-a-post-to-a-collection
func (c *Client) PinPost(alias string, pp *PinnedPostParams) error {
res := &[]BatchPostResult{}
env, err := c.post(fmt.Sprintf("/collections/%s/pin", alias), []*PinnedPostParams{pp}, res)
if err != nil {
return err
}
var ok bool
if res, ok = env.Data.(*[]BatchPostResult); !ok {
return fmt.Errorf("Wrong data returned from API.")
}
// Check for basic request errors on top level response
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
}
return fmt.Errorf("Problem pinning post: %d. %s\n", status, env.ErrorMessage)
}
// Check the individual post result
if len(*res) == 0 || len(*res) > 1 {
return fmt.Errorf("Wrong data returned from API.")
}
if (*res)[0].Code != http.StatusOK {
return fmt.Errorf("Problem pinning post: %d", (*res)[0].Code)
// TODO: return ErrorMessage (right now it'll be empty)
// return fmt.Errorf("Problem pinning post: %s", res[0].ErrorMessage)
}
return nil
}
// UnpinPost unpins a post from the given collection.
// See https://developers.write.as/docs/api/#unpin-a-post-from-a-collection
func (c *Client) UnpinPost(alias string, pp *PinnedPostParams) error {
res := &[]BatchPostResult{}
env, err := c.post(fmt.Sprintf("/collections/%s/unpin", alias), []*PinnedPostParams{pp}, res)
if err != nil {
return err
}
var ok bool
if res, ok = env.Data.(*[]BatchPostResult); !ok {
return fmt.Errorf("Wrong data returned from API.")
}
// Check for basic request errors on top level response
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
}
return fmt.Errorf("Problem unpinning post: %d. %s\n", status, env.ErrorMessage)
}
// Check the individual post result
if len(*res) == 0 || len(*res) > 1 {
return fmt.Errorf("Wrong data returned from API.")
}
if (*res)[0].Code != http.StatusOK {
return fmt.Errorf("Problem unpinning post: %d", (*res)[0].Code)
// TODO: return ErrorMessage (right now it'll be empty)
// return fmt.Errorf("Problem unpinning post: %s", res[0].ErrorMessage)
}
return nil
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 31, 9:46 AM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3612209

Event Timeline