Go client for the Write.as API https://developers.write.as
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
6.1 KiB

  1. package writeas
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. )
  7. type (
  8. // Post represents a published Write.as post, whether anonymous, owned by a
  9. // user, or part of a collection.
  10. Post struct {
  11. ID string `json:"id"`
  12. Slug string `json:"slug"`
  13. Token string `json:"token"`
  14. Font string `json:"appearance"`
  15. Language *string `json:"language"`
  16. RTL *bool `json:"rtl"`
  17. Listed bool `json:"listed"`
  18. Created time.Time `json:"created"`
  19. Updated time.Time `json:"updated"`
  20. Title string `json:"title"`
  21. Content string `json:"body"`
  22. Views int64 `json:"views"`
  23. Tags []string `json:"tags"`
  24. Images []string `json:"images"`
  25. OwnerName string `json:"owner,omitempty"`
  26. Collection *Collection `json:"collection,omitempty"`
  27. }
  28. // OwnedPostParams are, together, fields only the original post author knows.
  29. OwnedPostParams struct {
  30. ID string `json:"-"`
  31. Token string `json:"token,omitempty"`
  32. }
  33. // PostParams holds values for creating or updating a post.
  34. PostParams struct {
  35. // Parameters only for updating
  36. ID string `json:"-"`
  37. Token string `json:"token,omitempty"`
  38. // Parameters for creating or updating
  39. Title string `json:"title,omitempty"`
  40. Content string `json:"body,omitempty"`
  41. Font string `json:"font,omitempty"`
  42. IsRTL *bool `json:"rtl,omitempty"`
  43. Language *string `json:"lang,omitempty"`
  44. // Parameters only for creating
  45. Crosspost []map[string]string `json:"crosspost,omitempty"`
  46. // Parameters for collection posts
  47. Collection string `json:"-"`
  48. }
  49. // ClaimPostResult contains the post-specific result for a request to
  50. // associate a post to an account.
  51. ClaimPostResult struct {
  52. ID string `json:"id,omitempty"`
  53. Code int `json:"code,omitempty"`
  54. ErrorMessage string `json:"error_msg,omitempty"`
  55. Post *Post `json:"post,omitempty"`
  56. }
  57. )
  58. // GetPost retrieves a published post, returning the Post and any error (in
  59. // user-friendly form) that occurs. See
  60. // https://developer.write.as/docs/api/#retrieve-a-post.
  61. func (c *Client) GetPost(id string) (*Post, error) {
  62. p := &Post{}
  63. env, err := c.get(fmt.Sprintf("/posts/%s", id), p)
  64. if err != nil {
  65. return nil, err
  66. }
  67. var ok bool
  68. if p, ok = env.Data.(*Post); !ok {
  69. return nil, fmt.Errorf("Wrong data returned from API.")
  70. }
  71. status := env.Code
  72. if status == http.StatusOK {
  73. return p, nil
  74. } else if status == http.StatusNotFound {
  75. return nil, fmt.Errorf("Post not found.")
  76. } else if status == http.StatusGone {
  77. return nil, fmt.Errorf("Post unpublished.")
  78. }
  79. return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
  80. }
  81. // CreatePost publishes a new post, returning a user-friendly error if one comes
  82. // up. See https://developer.write.as/docs/api/#publish-a-post.
  83. func (c *Client) CreatePost(sp *PostParams) (*Post, error) {
  84. p := &Post{}
  85. endPre := ""
  86. if sp.Collection != "" {
  87. endPre = "/collections/" + sp.Collection
  88. }
  89. env, err := c.post(endPre+"/posts", sp, p)
  90. if err != nil {
  91. return nil, err
  92. }
  93. var ok bool
  94. if p, ok = env.Data.(*Post); !ok {
  95. return nil, fmt.Errorf("Wrong data returned from API.")
  96. }
  97. status := env.Code
  98. if status == http.StatusCreated {
  99. return p, nil
  100. } else if status == http.StatusBadRequest {
  101. return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
  102. } else {
  103. return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
  104. }
  105. }
  106. // UpdatePost updates a published post with the given PostParams. See
  107. // https://developer.write.as/docs/api/#update-a-post.
  108. func (c *Client) UpdatePost(sp *PostParams) (*Post, error) {
  109. p := &Post{}
  110. env, err := c.put(fmt.Sprintf("/posts/%s", sp.ID), sp, p)
  111. if err != nil {
  112. return nil, err
  113. }
  114. var ok bool
  115. if p, ok = env.Data.(*Post); !ok {
  116. return nil, fmt.Errorf("Wrong data returned from API.")
  117. }
  118. status := env.Code
  119. if status == http.StatusOK {
  120. return p, nil
  121. } else if c.isNotLoggedIn(status) {
  122. return nil, fmt.Errorf("Not authenticated.")
  123. } else if status == http.StatusBadRequest {
  124. return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
  125. }
  126. return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
  127. }
  128. // DeletePost permanently deletes a published post. See
  129. // https://developer.write.as/docs/api/#delete-a-post.
  130. func (c *Client) DeletePost(sp *PostParams) error {
  131. env, err := c.delete(fmt.Sprintf("/posts/%s", sp.ID), map[string]string{
  132. "token": sp.Token,
  133. })
  134. if err != nil {
  135. return err
  136. }
  137. status := env.Code
  138. if status == http.StatusNoContent {
  139. return nil
  140. } else if c.isNotLoggedIn(status) {
  141. return fmt.Errorf("Not authenticated.")
  142. } else if status == http.StatusBadRequest {
  143. return fmt.Errorf("Bad request: %s", env.ErrorMessage)
  144. }
  145. return fmt.Errorf("Problem getting post: %d. %v\n", status, err)
  146. }
  147. // ClaimPosts associates anonymous posts with a user / account.
  148. // https://developer.write.as/docs/api/#claim-posts.
  149. func (c *Client) ClaimPosts(sp *[]OwnedPostParams) (*[]ClaimPostResult, error) {
  150. p := &[]ClaimPostResult{}
  151. env, err := c.put("/posts/claim", sp, p)
  152. if err != nil {
  153. return nil, err
  154. }
  155. var ok bool
  156. if p, ok = env.Data.(*[]ClaimPostResult); !ok {
  157. return nil, fmt.Errorf("Wrong data returned from API.")
  158. }
  159. status := env.Code
  160. if status == http.StatusOK {
  161. return p, nil
  162. } else if c.isNotLoggedIn(status) {
  163. return nil, fmt.Errorf("Not authenticated.")
  164. } else if status == http.StatusBadRequest {
  165. return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
  166. } else {
  167. return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
  168. }
  169. // TODO: does this also happen with moving posts?
  170. }
  171. // GetUserPosts retrieves the authenticated user's posts.
  172. // See https://developers.write.as/docs/api/#retrieve-user-39-s-posts
  173. func (c *Client) GetUserPosts() (*[]Post, error) {
  174. p := &[]Post{}
  175. env, err := c.get("/me/posts", p)
  176. if err != nil {
  177. return nil, err
  178. }
  179. var ok bool
  180. if p, ok = env.Data.(*[]Post); !ok {
  181. return nil, fmt.Errorf("Wrong data returned from API.")
  182. }
  183. status := env.Code
  184. if status != http.StatusOK {
  185. if c.isNotLoggedIn(status) {
  186. return nil, fmt.Errorf("Not authenticated.")
  187. }
  188. return nil, fmt.Errorf("Problem getting posts: %d. %v\n", status, err)
  189. }
  190. return p, nil
  191. }