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.

305 rivejä
7.1 KiB

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