Command line client for Write.as https://write.as/apps/cli
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.

256 lines
5.9 KiB

  1. package api
  2. import (
  3. "fmt"
  4. "path/filepath"
  5. "github.com/atotto/clipboard"
  6. writeas "github.com/writeas/go-writeas/v2"
  7. "github.com/writeas/web-core/posts"
  8. "github.com/writeas/writeas-cli/config"
  9. "github.com/writeas/writeas-cli/fileutils"
  10. "github.com/writeas/writeas-cli/log"
  11. cli "gopkg.in/urfave/cli.v1"
  12. )
  13. func newClient(c *cli.Context, authRequired bool) (*writeas.Client, error) {
  14. var client *writeas.Client
  15. if config.IsTor(c) {
  16. client = writeas.NewTorClient(config.TorPort(c))
  17. } else {
  18. if config.IsDev() {
  19. client = writeas.NewDevClient()
  20. } else {
  21. client = writeas.NewClient()
  22. }
  23. }
  24. client.UserAgent = config.UserAgent(c)
  25. // TODO: load user into var shared across the app
  26. u, _ := config.LoadUser(config.UserDataDir(c.App.ExtraInfo()["configDir"]))
  27. if u != nil {
  28. client.SetToken(u.AccessToken)
  29. } else if authRequired {
  30. return nil, fmt.Errorf("Not currently logged in. Authenticate with: writeas auth <username>")
  31. }
  32. return client, nil
  33. }
  34. // DoFetch retrieves the Write.as post with the given friendlyID,
  35. // optionally via the Tor hidden service.
  36. func DoFetch(c *cli.Context, friendlyID string) error {
  37. cl, err := newClient(c, false)
  38. if err != nil {
  39. return err
  40. }
  41. p, err := cl.GetPost(friendlyID)
  42. if err != nil {
  43. return err
  44. }
  45. if p.Title != "" {
  46. fmt.Printf("# %s\n\n", string(p.Title))
  47. }
  48. fmt.Printf("%s\n", string(p.Content))
  49. return nil
  50. }
  51. // DoFetchPosts retrieves all remote posts for the
  52. // authenticated user
  53. func DoFetchPosts(c *cli.Context) ([]writeas.Post, error) {
  54. cl, err := newClient(c, true)
  55. if err != nil {
  56. return nil, fmt.Errorf("Unable to create client: %v", err)
  57. }
  58. posts, err := cl.GetUserPosts()
  59. if err != nil {
  60. return nil, err
  61. }
  62. return *posts, nil
  63. }
  64. // DoPost creates a Write.as post, returning an error if it was
  65. // unsuccessful.
  66. func DoPost(c *cli.Context, post []byte, font string, encrypt, code bool) (*writeas.Post, error) {
  67. cl, err := newClient(c, false)
  68. if err != nil {
  69. return nil, fmt.Errorf("Unable to create client: %v", err)
  70. }
  71. pp := &writeas.PostParams{
  72. Font: config.GetFont(code, font),
  73. Collection: config.Collection(c),
  74. }
  75. pp.Title, pp.Content = posts.ExtractTitle(string(post))
  76. if lang := config.Language(c, true); lang != "" {
  77. pp.Language = &lang
  78. }
  79. p, err := cl.CreatePost(pp)
  80. if err != nil {
  81. return nil, fmt.Errorf("Unable to post: %v", err)
  82. }
  83. var url string
  84. if p.Collection != nil {
  85. url = p.Collection.URL + p.Slug
  86. } else {
  87. if config.IsTor(c) {
  88. url = config.TorBaseURL
  89. } else if config.IsDev() {
  90. url = config.DevBaseURL
  91. } else {
  92. url = config.WriteasBaseURL
  93. }
  94. url += "/" + p.ID
  95. // Output URL in requested format
  96. if c.Bool("md") {
  97. url += ".md"
  98. }
  99. }
  100. if cl.Token() == "" {
  101. // Store post locally, since we're not authenticated
  102. AddPost(c, p.ID, p.Token)
  103. }
  104. // Copy URL to clipboard
  105. err = clipboard.WriteAll(string(url))
  106. if err != nil {
  107. log.Errorln("writeas: Didn't copy to clipboard: %s", err)
  108. } else {
  109. log.Info(c, "Copied to clipboard.")
  110. }
  111. // Output URL
  112. fmt.Printf("%s\n", url)
  113. return p, nil
  114. }
  115. // DoFetchCollections retrieves a list of the currently logged in users
  116. // collections.
  117. func DoFetchCollections(c *cli.Context) ([]RemoteColl, error) {
  118. cl, err := newClient(c, true)
  119. if err != nil {
  120. if config.Debug() {
  121. log.ErrorlnQuit("could not create client: %v", err)
  122. }
  123. return nil, fmt.Errorf("Couldn't create new client")
  124. }
  125. colls, err := cl.GetUserCollections()
  126. if err != nil {
  127. if config.Debug() {
  128. log.ErrorlnQuit("failed fetching user collections: %v", err)
  129. }
  130. return nil, fmt.Errorf("Couldn't get user blogs")
  131. }
  132. out := make([]RemoteColl, len(*colls))
  133. for i, c := range *colls {
  134. coll := RemoteColl{
  135. Alias: c.Alias,
  136. Title: c.Title,
  137. URL: c.URL,
  138. }
  139. out[i] = coll
  140. }
  141. return out, nil
  142. }
  143. // DoUpdate updates the given post on Write.as.
  144. func DoUpdate(c *cli.Context, post []byte, friendlyID, token, font string, code bool) error {
  145. cl, err := newClient(c, false)
  146. if err != nil {
  147. return fmt.Errorf("Unable to create client: %v", err)
  148. }
  149. params := writeas.PostParams{}
  150. params.Title, params.Content = posts.ExtractTitle(string(post))
  151. if lang := config.Language(c, false); lang != "" {
  152. params.Language = &lang
  153. }
  154. if code || font != "" {
  155. params.Font = config.GetFont(code, font)
  156. }
  157. _, err = cl.UpdatePost(friendlyID, token, &params)
  158. if err != nil {
  159. if config.Debug() {
  160. log.ErrorlnQuit("Problem updating: %v", err)
  161. }
  162. return fmt.Errorf("Post doesn't exist, or bad edit token given.")
  163. }
  164. return nil
  165. }
  166. // DoDelete deletes the given post on Write.as, and removes any local references
  167. func DoDelete(c *cli.Context, friendlyID, token string) error {
  168. cl, err := newClient(c, false)
  169. if err != nil {
  170. return fmt.Errorf("Unable to create client: %v", err)
  171. }
  172. err = cl.DeletePost(friendlyID, token)
  173. if err != nil {
  174. if config.Debug() {
  175. log.ErrorlnQuit("Problem deleting: %v", err)
  176. }
  177. return fmt.Errorf("Post doesn't exist, or bad edit token given.")
  178. }
  179. RemovePost(c.App.ExtraInfo()["configDir"], friendlyID)
  180. return nil
  181. }
  182. func DoLogIn(c *cli.Context, username, password string) error {
  183. cl, err := newClient(c, false)
  184. if err != nil {
  185. return fmt.Errorf("Unable to create client: %v", err)
  186. }
  187. u, err := cl.LogIn(username, password)
  188. if err != nil {
  189. if config.Debug() {
  190. log.ErrorlnQuit("Problem logging in: %v", err)
  191. }
  192. return err
  193. }
  194. err = config.SaveUser(config.UserDataDir(c.App.ExtraInfo()["configDir"]), u)
  195. if err != nil {
  196. return err
  197. }
  198. log.Info(c, "Logged in as %s.\n", u.User.Username)
  199. return nil
  200. }
  201. func DoLogOut(c *cli.Context) error {
  202. cl, err := newClient(c, true)
  203. if err != nil {
  204. return fmt.Errorf("Unable to create client: %v", err)
  205. }
  206. err = cl.LogOut()
  207. if err != nil {
  208. if config.Debug() {
  209. log.ErrorlnQuit("Problem logging out: %v", err)
  210. }
  211. return err
  212. }
  213. // Delete local user data
  214. err = fileutils.DeleteFile(filepath.Join(config.UserDataDir(c.App.ExtraInfo()["configDir"]), config.UserFile))
  215. if err != nil {
  216. return err
  217. }
  218. return nil
  219. }