Page MenuHomeMusing Studio

No OneTemporary

diff --git a/cmd/writeas/commands.go b/cmd/writeas/commands.go
index 20e2b7c..ef8fbec 100644
--- a/cmd/writeas/commands.go
+++ b/cmd/writeas/commands.go
@@ -1,242 +1,269 @@
package main
import (
+ "bytes"
"fmt"
"github.com/howeyc/gopass"
"github.com/writeas/writeas-cli/fileutils"
"gopkg.in/urfave/cli.v1"
"io/ioutil"
"os"
"path/filepath"
)
func cmdPost(c *cli.Context) error {
_, err := handlePost(readStdIn(), c)
return err
}
func cmdNew(c *cli.Context) error {
fname, p := composeNewPost()
if p == nil {
// Assume composeNewPost already told us what the error was. Abort now.
os.Exit(1)
}
// Ensure we have something to post
if len(*p) == 0 {
// Clean up temporary post
if fname != "" {
os.Remove(fname)
}
InfolnQuit("Empty post. Bye!")
}
_, err := handlePost(*p, c)
if err != nil {
Errorln("Error posting: %s", err)
Errorln(messageRetryCompose(fname))
return cli.NewExitError("", 1)
}
// Clean up temporary post
if fname != "" {
os.Remove(fname)
}
return nil
}
func cmdPublish(c *cli.Context) error {
filename := c.Args().Get(0)
if filename == "" {
return cli.NewExitError("usage: writeas publish <filename>", 1)
}
content, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
p, err := handlePost(content, c)
if err != nil {
return err
}
// Save post to posts folder
cfg, err := loadConfig()
if cfg.Posts.Directory != "" {
err = WritePost(cfg.Posts.Directory, p)
if err != nil {
return err
}
}
return nil
}
func cmdDelete(c *cli.Context) error {
friendlyID := c.Args().Get(0)
token := c.Args().Get(1)
if friendlyID == "" {
return cli.NewExitError("usage: writeas delete <postId> [<token>]", 1)
}
u, _ := loadUser()
if token == "" {
// Search for the token locally
token = tokenFromID(friendlyID)
if token == "" && u == nil {
Errorln("Couldn't find an edit token locally. Did you create this post here?")
ErrorlnQuit("If you have an edit token, use: writeas delete %s <token>", friendlyID)
}
}
tor := isTor(c)
if c.Int("tor-port") != 0 {
torPort = c.Int("tor-port")
}
if tor {
Info(c, "Deleting via hidden service...")
} else {
Info(c, "Deleting...")
}
err := DoDelete(c, friendlyID, token, tor)
if err != nil {
return err
}
// Delete local file, if necessary
cfg, err := loadConfig()
if cfg.Posts.Directory != "" {
// TODO: handle deleting blog posts
err = fileutils.DeleteFile(filepath.Join(cfg.Posts.Directory, friendlyID+postFileExt))
if err != nil {
return err
}
}
return nil
}
func cmdUpdate(c *cli.Context) error {
friendlyID := c.Args().Get(0)
token := c.Args().Get(1)
if friendlyID == "" {
return cli.NewExitError("usage: writeas update <postId> [<token>]", 1)
}
u, _ := loadUser()
if token == "" {
// Search for the token locally
token = tokenFromID(friendlyID)
if token == "" && u == nil {
Errorln("Couldn't find an edit token locally. Did you create this post here?")
ErrorlnQuit("If you have an edit token, use: writeas update %s <token>", friendlyID)
}
}
// Read post body
fullPost := readStdIn()
tor := isTor(c)
if c.Int("tor-port") != 0 {
torPort = c.Int("tor-port")
}
if tor {
Info(c, "Updating via hidden service...")
} else {
Info(c, "Updating...")
}
return DoUpdate(c, fullPost, friendlyID, token, c.String("font"), tor, c.Bool("code"))
}
func cmdGet(c *cli.Context) error {
friendlyID := c.Args().Get(0)
if friendlyID == "" {
return cli.NewExitError("usage: writeas get <postId>", 1)
}
tor := isTor(c)
if c.Int("tor-port") != 0 {
torPort = c.Int("tor-port")
}
if tor {
Info(c, "Getting via hidden service...")
} else {
Info(c, "Getting...")
}
return DoFetch(friendlyID, userAgent(c), tor)
}
func cmdAdd(c *cli.Context) error {
friendlyID := c.Args().Get(0)
token := c.Args().Get(1)
if friendlyID == "" || token == "" {
return cli.NewExitError("usage: writeas add <postId> <token>", 1)
}
err := addPost(friendlyID, token)
return err
}
func cmdList(c *cli.Context) error {
urls := c.Bool("url")
ids := c.Bool("id")
- var p Post
- posts := getPosts()
- for i := range *posts {
- p = (*posts)[len(*posts)-1-i]
+ user, err := loadUser()
+ if err != nil {
+ return cli.NewExitError(fmt.Sprintf("couldn't load config: %v", err), 1)
+ }
+
+ var posts []Post
+ if user == nil {
+ posts = *getPosts()
+ } else {
+ var err error
+ posts, err = getUserPosts(c, user)
+ if err != nil {
+ return cli.NewExitError(fmt.Sprintf("couldn't load posts for %q: %v", user.User.Username, err), 1)
+ }
+ }
+
+ for i := len(posts) - 1; i >= 0; i-- {
+ p := posts[i]
if ids || !urls {
fmt.Printf("%s ", p.ID)
}
if urls {
- base := writeasBaseURL
+ var url bytes.Buffer
+
+ // Base URL
if isDev() {
- base = devBaseURL
+ url.WriteString(devBaseURL)
+ } else {
+ url.WriteString(writeasBaseURL)
}
- ext := ""
- // Output URL in requested format
+
+ // Path
+ if p.Collection != "" {
+ fmt.Fprintf(&url, "/%v/%v", p.Collection, p.Slug)
+ } else {
+ fmt.Fprintf(&url, "/%v", p.ID)
+ }
+
+ // Extension
if c.Bool("md") {
- ext = ".md"
+ url.WriteString(".md")
}
- fmt.Printf("%s/%s%s ", base, p.ID, ext)
+
+ fmt.Print(url.String())
}
fmt.Print("\n")
}
return nil
}
func cmdAuth(c *cli.Context) error {
// Check configuration
u, err := loadUser()
if err != nil {
return cli.NewExitError(fmt.Sprintf("couldn't load config: %v", err), 1)
}
if u != nil && u.AccessToken != "" {
return cli.NewExitError("You're already authenticated as "+u.User.Username+". Log out with: writeas logout", 1)
}
// Validate arguments and get password
username := c.Args().Get(0)
if username == "" {
return cli.NewExitError("usage: writeas auth <username>", 1)
}
fmt.Print("Password: ")
pass, err := gopass.GetPasswdMasked()
if err != nil {
return cli.NewExitError(fmt.Sprintf("error reading password: %v", err), 1)
}
// Validate password
if len(pass) == 0 {
return cli.NewExitError("Please enter your password.", 1)
}
return DoLogIn(c, username, string(pass))
}
func cmdLogOut(c *cli.Context) error {
return DoLogOut(c)
}
diff --git a/cmd/writeas/posts.go b/cmd/writeas/posts.go
index 175341a..ffbe8d1 100644
--- a/cmd/writeas/posts.go
+++ b/cmd/writeas/posts.go
@@ -1,165 +1,195 @@
package main
import (
"fmt"
"github.com/writeas/writeas-cli/fileutils"
"go.code.as/writeas.v2"
"io/ioutil"
"os"
"path/filepath"
"strings"
+ cli "gopkg.in/urfave/cli.v1"
)
const (
postsFile = "posts.psv"
separator = `|`
)
// Post holds the basic authentication information for a Write.as post.
type Post struct {
- ID string
- EditToken string
+ ID string
+ EditToken string
+ Title string
+ Slug string
+ Collection string
}
func userDataDir() string {
return filepath.Join(parentDataDir(), dataDirName)
}
func dataDirExists() bool {
return fileutils.Exists(userDataDir())
}
func createDataDir() {
err := os.Mkdir(userDataDir(), 0700)
if err != nil {
if debug {
panic(err)
} else {
Errorln("Error creating data directory: %s", err)
return
}
}
}
func addPost(id, token string) error {
f, err := os.OpenFile(filepath.Join(userDataDir(), postsFile), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return fmt.Errorf("Error creating local posts list: %s", err)
}
defer f.Close()
l := fmt.Sprintf("%s%s%s\n", id, separator, token)
if _, err = f.WriteString(l); err != nil {
return fmt.Errorf("Error writing to local posts list: %s", err)
}
return nil
}
func tokenFromID(id string) string {
post := fileutils.FindLine(filepath.Join(userDataDir(), postsFile), id)
if post == "" {
return ""
}
parts := strings.Split(post, separator)
if len(parts) < 2 {
return ""
}
return parts[1]
}
func removePost(id string) {
fileutils.RemoveLine(filepath.Join(userDataDir(), postsFile), id)
}
+func getUserPosts(c *cli.Context, u *writeas.AuthUser) ([]Post, error) {
+ client := client(userAgent(c), isTor(c))
+ client.SetToken(u.AccessToken)
+
+ apiPosts, err := client.GetUserPosts()
+ if err != nil {
+ return nil, err
+ }
+
+ posts := make([]Post, len(*apiPosts))
+ for i, p := range *apiPosts {
+ posts[i] = Post{
+ ID: p.ID,
+ EditToken: p.Token,
+ Title: p.Title,
+ Slug: p.Slug,
+ }
+
+ if p.Collection != nil {
+ posts[i].Collection = p.Collection.Alias
+ }
+ }
+
+ return posts, nil
+}
+
func getPosts() *[]Post {
lines := fileutils.ReadData(filepath.Join(userDataDir(), postsFile))
posts := []Post{}
if lines != nil && len(*lines) > 0 {
parts := make([]string, 2)
for _, l := range *lines {
parts = strings.Split(l, separator)
if len(parts) < 2 {
continue
}
posts = append(posts, Post{ID: parts[0], EditToken: parts[1]})
}
}
return &posts
}
func composeNewPost() (string, *[]byte) {
f, err := fileutils.TempFile(os.TempDir(), "WApost", "txt")
if err != nil {
if debug {
panic(err)
} else {
Errorln("Error creating temp file: %s", err)
return "", nil
}
}
f.Close()
cmd := editPostCmd(f.Name())
if cmd == nil {
os.Remove(f.Name())
fmt.Println(noEditorErr)
return "", nil
}
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
if err := cmd.Start(); err != nil {
os.Remove(f.Name())
if debug {
panic(err)
} else {
Errorln("Error starting editor: %s", err)
return "", nil
}
}
// If something fails past this point, the temporary post file won't be
// removed automatically. Calling function should handle this.
if err := cmd.Wait(); err != nil {
if debug {
panic(err)
} else {
Errorln("Editor finished with error: %s", err)
return "", nil
}
}
post, err := ioutil.ReadFile(f.Name())
if err != nil {
if debug {
panic(err)
} else {
Errorln("Error reading post: %s", err)
return "", nil
}
}
return f.Name(), &post
}
func WritePost(postsDir string, p *writeas.Post) error {
postFilename := p.ID
collDir := ""
if p.Collection != nil {
postFilename = p.Slug
collDir = p.Collection.Alias
}
postFilename += postFileExt
txtFile := p.Content
if p.Title != "" {
txtFile = "# " + p.Title + "\n\n" + txtFile
}
return ioutil.WriteFile(filepath.Join(postsDir, collDir, postFilename), []byte(txtFile), 0644)
}

File Metadata

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

Event Timeline