update
This commit is contained in:
parent
be11f5b013
commit
b1b367ca33
45 changed files with 24 additions and 1976 deletions
|
@ -118,7 +118,6 @@ func TestGetAccountStatuses(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -151,7 +150,6 @@ func TestGetAccountFollowers(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -187,7 +185,6 @@ func TestGetAccountFollowing(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -225,7 +222,6 @@ func TestGetBlocks(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -261,7 +257,6 @@ func TestAccountFollow(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"following":true}`)
|
fmt.Fprintln(w, `{"id":1234567,"following":true}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -271,11 +266,11 @@ func TestAccountFollow(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
rel, err := client.AccountFollow(context.Background(), "123")
|
_, err := client.AccountFollow(context.Background(), "123")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
rel, err = client.AccountFollow(context.Background(), "1234567")
|
rel, err := client.AccountFollow(context.Background(), "1234567")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +289,6 @@ func TestAccountUnfollow(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"following":false}`)
|
fmt.Fprintln(w, `{"id":1234567,"following":false}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -304,11 +298,11 @@ func TestAccountUnfollow(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
rel, err := client.AccountUnfollow(context.Background(), "123")
|
_, err := client.AccountUnfollow(context.Background(), "123")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
rel, err = client.AccountUnfollow(context.Background(), "1234567")
|
rel, err := client.AccountUnfollow(context.Background(), "1234567")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -327,7 +321,6 @@ func TestAccountBlock(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"blocking":true}`)
|
fmt.Fprintln(w, `{"id":1234567,"blocking":true}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -360,7 +353,6 @@ func TestAccountUnblock(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"blocking":false}`)
|
fmt.Fprintln(w, `{"id":1234567,"blocking":false}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -393,7 +385,6 @@ func TestAccountMute(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"muting":true}`)
|
fmt.Fprintln(w, `{"id":1234567,"muting":true}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -426,7 +417,6 @@ func TestAccountUnmute(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id":1234567,"muting":false}`)
|
fmt.Fprintln(w, `{"id":1234567,"muting":false}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -492,7 +482,6 @@ func TestAccountsSearch(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foobar"}, {"username": "barfoo"}]`)
|
fmt.Fprintln(w, `[{"username": "foobar"}, {"username": "barfoo"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -528,7 +517,6 @@ func TestFollowRemoteUser(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"username": "zzz"}`)
|
fmt.Fprintln(w, `{"username": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -560,7 +548,6 @@ func TestGetFollowRequests(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -646,7 +633,6 @@ func TestGetMutes(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ func TestRegisterApp(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": 123, "client_id": "foo", "client_secret": "bar"}`)
|
fmt.Fprintln(w, `{"id": 123, "client_id": "foo", "client_secret": "bar"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -79,7 +78,6 @@ func TestRegisterAppWithCancel(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
fmt.Fprintln(w, `{"client_id": "foo", "client_secret": "bar"}`)
|
fmt.Fprintln(w, `{"client_id": "foo", "client_secret": "bar"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
# mstdn
|
|
||||||
|
|
||||||
command line tool for mstdn.jp
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```
|
|
||||||
NAME:
|
|
||||||
mstdn - mastodon client
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
mstdn [global options] command [command options] [arguments...]
|
|
||||||
|
|
||||||
VERSION:
|
|
||||||
0.0.1
|
|
||||||
|
|
||||||
COMMANDS:
|
|
||||||
toot post toot
|
|
||||||
stream stream statuses
|
|
||||||
timeline show timeline
|
|
||||||
notification show notification
|
|
||||||
instance show instance information
|
|
||||||
account show account information
|
|
||||||
search search content
|
|
||||||
follow follow account
|
|
||||||
followers show followers
|
|
||||||
upload upload file
|
|
||||||
delete delete status
|
|
||||||
init initialize profile
|
|
||||||
mikami search mikami
|
|
||||||
xsearch cross search
|
|
||||||
help, h Shows a list of commands or help for one command
|
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
|
||||||
--profile value profile name
|
|
||||||
--help, -h show help
|
|
||||||
--version, -v print the version
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go get github.com/mattn/go-mastodon/cmd/mstdn
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
Yasuhiro Matsumoto (a.k.a. mattn)
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdAccount(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
account, err := client.GetAccountCurrentUser(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(c.App.Writer, "URI : %v\n", account.Acct)
|
|
||||||
fmt.Fprintf(c.App.Writer, "ID : %v\n", account.ID)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Username : %v\n", account.Username)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Acct : %v\n", account.Acct)
|
|
||||||
fmt.Fprintf(c.App.Writer, "DisplayName : %v\n", account.DisplayName)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Locked : %v\n", account.Locked)
|
|
||||||
fmt.Fprintf(c.App.Writer, "CreatedAt : %v\n", account.CreatedAt.Local())
|
|
||||||
fmt.Fprintf(c.App.Writer, "FollowersCount: %v\n", account.FollowersCount)
|
|
||||||
fmt.Fprintf(c.App.Writer, "FollowingCount: %v\n", account.FollowingCount)
|
|
||||||
fmt.Fprintf(c.App.Writer, "StatusesCount : %v\n", account.StatusesCount)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Note : %v\n", textContent(account.Note))
|
|
||||||
fmt.Fprintf(c.App.Writer, "URL : %v\n", account.URL)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdAccount(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/accounts/verify_credentials":
|
|
||||||
fmt.Fprintln(w, `{"username": "zzz"}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "account"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !strings.Contains(out, "zzz") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "zzz", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdDelete(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
if !c.Args().Present() {
|
|
||||||
return errors.New("arguments required")
|
|
||||||
}
|
|
||||||
for i := 0; i < c.NArg(); i++ {
|
|
||||||
err := client.DeleteStatus(context.Background(), mastodon.ID(c.Args().Get(i)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdDelete(t *testing.T) {
|
|
||||||
ok := false
|
|
||||||
f := func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/statuses/123":
|
|
||||||
fmt.Fprintln(w, `{}`)
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
testWithServer(
|
|
||||||
f, func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "delete", "122"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if ok {
|
|
||||||
t.Fatal("something wrong to sequence to follow account")
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = false
|
|
||||||
testWithServer(
|
|
||||||
f, func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "delete", "123"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("something wrong to sequence to follow account")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdFollow(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
if !c.Args().Present() {
|
|
||||||
return errors.New("arguments required")
|
|
||||||
}
|
|
||||||
for i := 0; i < c.NArg(); i++ {
|
|
||||||
account, err := client.AccountsSearch(context.Background(), c.Args().Get(i), 1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(account) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, err = client.AccountFollow(context.Background(), account[0].ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdFollow(t *testing.T) {
|
|
||||||
ok := false
|
|
||||||
testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/accounts/search":
|
|
||||||
q := r.URL.Query().Get("q")
|
|
||||||
if q == "mattn" {
|
|
||||||
fmt.Fprintln(w, `[{"id": 123}]`)
|
|
||||||
return
|
|
||||||
} else if q == "different_id" {
|
|
||||||
fmt.Fprintln(w, `[{"id": 1234567}]`)
|
|
||||||
return
|
|
||||||
} else if q == "empty" {
|
|
||||||
fmt.Fprintln(w, `[]`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "/api/v1/accounts/123/follow":
|
|
||||||
fmt.Fprintln(w, `{"id": 123}`)
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "follow", "mattn"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "follow"})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("should be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "follow", "fail"})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("should be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "follow", "empty"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "follow", "different_id"})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("should be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("something wrong to sequence to follow account")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdFollowers(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
|
|
||||||
account, err := client.GetAccountCurrentUser(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var followers []*mastodon.Account
|
|
||||||
var pg mastodon.Pagination
|
|
||||||
for {
|
|
||||||
fs, err := client.GetAccountFollowers(context.Background(), account.ID, &pg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
followers = append(followers, fs...)
|
|
||||||
if pg.MaxID == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pg.SinceID = ""
|
|
||||||
pg.MinID = ""
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
for _, follower := range followers {
|
|
||||||
fmt.Fprintf(c.App.Writer, "%v,%v\n", follower.ID, s.acct(follower.Acct))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdFollowers(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/accounts/verify_credentials":
|
|
||||||
fmt.Fprintln(w, `{"id": 123}`)
|
|
||||||
return
|
|
||||||
case "/api/v1/accounts/123/followers":
|
|
||||||
w.Header().Set("Link", `<http://example.com?since_id=890>; rel="prev"`)
|
|
||||||
fmt.Fprintln(w, `[{"id": 234, "username": "ZZZ", "acct": "zzz"}]`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "followers"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !strings.Contains(out, "zzz") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "zzz", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdInstance(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
instance, err := client.GetInstance(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(c.App.Writer, "URI : %s\n", instance.URI)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Title : %s\n", instance.Title)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Description: %s\n", instance.Description)
|
|
||||||
fmt.Fprintf(c.App.Writer, "EMail : %s\n", instance.EMail)
|
|
||||||
if instance.Version != "" {
|
|
||||||
fmt.Fprintf(c.App.Writer, "Version : %s\n", instance.Version)
|
|
||||||
}
|
|
||||||
if instance.Thumbnail != "" {
|
|
||||||
fmt.Fprintf(c.App.Writer, "Thumbnail : %s\n", instance.Thumbnail)
|
|
||||||
}
|
|
||||||
if instance.URLs != nil {
|
|
||||||
var keys []string
|
|
||||||
for _, k := range instance.URLs {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
fmt.Fprintf(c.App.Writer, "%s: %s\n", k, instance.URLs[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if instance.Stats != nil {
|
|
||||||
fmt.Fprintf(c.App.Writer, "User Count : %v\n", instance.Stats.UserCount)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Status Count : %v\n", instance.Stats.StatusCount)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Domain Count : %v\n", instance.Stats.DomainCount)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdInstanceActivity(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
activities, err := client.GetInstanceActivity(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, activity := range activities {
|
|
||||||
fmt.Fprintf(c.App.Writer, "Logins : %v\n", activity.Logins)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Registrations : %v\n", activity.Registrations)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Statuses : %v\n", activity.Statuses)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Week : %v\n", activity.Week)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdInstancePeers(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
peers, err := client.GetInstancePeers(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, peer := range peers {
|
|
||||||
fmt.Fprintln(c.App.Writer, peer)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdInstance(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/instance":
|
|
||||||
fmt.Fprintln(w, `{"title": "zzz"}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "instance"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !strings.Contains(out, "zzz") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "zzz", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdMikami(c *cli.Context) error {
|
|
||||||
return xSearch(c.App.Metadata["xsearch_url"].(string), "三上", c.App.Writer)
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdMikami(t *testing.T) {
|
|
||||||
ok := false
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.Query().Get("q") == "三上" {
|
|
||||||
ok = true
|
|
||||||
fmt.Fprintln(w, `<div class="post"><div class="mst_content"><a href="http://example.com/@test/1"><p>三上</p></a></div></div>`)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Writer = buf
|
|
||||||
err := app.Run([]string{"mstdn", "mikami"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("should be search Mikami")
|
|
||||||
}
|
|
||||||
result := buf.String()
|
|
||||||
if !strings.Contains(result, "http://example.com/@test/1") {
|
|
||||||
t.Fatalf("%q should be contained in output of search: %s", "http://example.com/@test/1", result)
|
|
||||||
}
|
|
||||||
if !strings.Contains(result, "三上") {
|
|
||||||
t.Fatalf("%q should be contained in output of search: %s", "三上", result)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdNotification(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
notifications, err := client.GetNotifications(context.Background(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, n := range notifications {
|
|
||||||
if n.Status != nil {
|
|
||||||
color.Set(color.FgHiRed)
|
|
||||||
fmt.Fprint(c.App.Writer, n.Account.Acct)
|
|
||||||
color.Set(color.Reset)
|
|
||||||
fmt.Fprintln(c.App.Writer, " "+n.Type)
|
|
||||||
s := n.Status
|
|
||||||
fmt.Fprintln(c.App.Writer, textContent(s.Content))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdNotification(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/notifications":
|
|
||||||
fmt.Fprintln(w, `[{"type": "rebloged", "status": {"content": "foo"}}]`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "notification"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !strings.Contains(out, "rebloged") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "rebloged", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdSearch(c *cli.Context) error {
|
|
||||||
if !c.Args().Present() {
|
|
||||||
return errors.New("arguments required")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
|
|
||||||
results, err := client.Search(context.Background(), argstr(c), false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
if len(results.Accounts) > 0 {
|
|
||||||
fmt.Fprintln(c.App.Writer, "===ACCOUNT===")
|
|
||||||
for _, result := range results.Accounts {
|
|
||||||
fmt.Fprintf(c.App.Writer, "%v,%v\n", result.ID, s.acct(result.Acct))
|
|
||||||
}
|
|
||||||
fmt.Fprintln(c.App.Writer)
|
|
||||||
}
|
|
||||||
if len(results.Statuses) > 0 {
|
|
||||||
fmt.Fprintln(c.App.Writer, "===STATUS===")
|
|
||||||
for _, result := range results.Statuses {
|
|
||||||
s.displayStatus(c.App.Writer, result)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(c.App.Writer)
|
|
||||||
}
|
|
||||||
if len(results.Hashtags) > 0 {
|
|
||||||
fmt.Fprintln(c.App.Writer, "===HASHTAG===")
|
|
||||||
for _, result := range results.Hashtags {
|
|
||||||
fmt.Fprintf(c.App.Writer, "#%v\n", result)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(c.App.Writer)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdSearch(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v2/search":
|
|
||||||
fmt.Fprintln(w, `{"accounts": [{"id": 234, "acct": "zzz"}], "statuses":[{"id": 345, "content": "yyy"}], "hashtags": [{"name": "www"}, {"name": "わろす"}]}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "search", "zzz"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
for _, s := range []string{"zzz", "yyy", "www", "わろす"} {
|
|
||||||
if !strings.Contains(out, s) {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", s, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SimpleJSON is a struct for output JSON for data to be simple used
|
|
||||||
type SimpleJSON struct {
|
|
||||||
ID mastodon.ID `json:"id"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Acct string `json:"acct"`
|
|
||||||
Avatar string `json:"avatar"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkFlag(f ...bool) bool {
|
|
||||||
n := 0
|
|
||||||
for _, on := range f {
|
|
||||||
if on {
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdStream(c *cli.Context) error {
|
|
||||||
asJSON := c.Bool("json")
|
|
||||||
asSimpleJSON := c.Bool("simplejson")
|
|
||||||
asFormat := c.String("template")
|
|
||||||
|
|
||||||
if checkFlag(asJSON, asSimpleJSON, asFormat != "") {
|
|
||||||
return errors.New("cannot speicify two or three options in --json/--simplejson/--template")
|
|
||||||
}
|
|
||||||
tx, err := template.New("mstdn").Funcs(template.FuncMap{
|
|
||||||
"nl": func(s string) string {
|
|
||||||
return s + "\n"
|
|
||||||
},
|
|
||||||
"text": textContent,
|
|
||||||
}).Parse(asFormat)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
sc := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sc, os.Interrupt)
|
|
||||||
|
|
||||||
var q chan mastodon.Event
|
|
||||||
|
|
||||||
t := c.String("type")
|
|
||||||
if t == "public" {
|
|
||||||
q, err = client.StreamingPublic(ctx, false)
|
|
||||||
} else if t == "" || t == "public/local" {
|
|
||||||
q, err = client.StreamingPublic(ctx, true)
|
|
||||||
} else if strings.HasPrefix(t, "user:") {
|
|
||||||
q, err = client.StreamingUser(ctx)
|
|
||||||
} else if strings.HasPrefix(t, "hashtag:") {
|
|
||||||
q, err = client.StreamingHashtag(ctx, t[8:], false)
|
|
||||||
} else {
|
|
||||||
return errors.New("invalid type")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
<-sc
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
|
|
||||||
c.App.Metadata["signal"] = sc
|
|
||||||
|
|
||||||
s := newScreen(config)
|
|
||||||
for e := range q {
|
|
||||||
if asJSON {
|
|
||||||
json.NewEncoder(c.App.Writer).Encode(e)
|
|
||||||
} else if asSimpleJSON {
|
|
||||||
if t, ok := e.(*mastodon.UpdateEvent); ok {
|
|
||||||
json.NewEncoder(c.App.Writer).Encode(&SimpleJSON{
|
|
||||||
ID: t.Status.ID,
|
|
||||||
Username: t.Status.Account.Username,
|
|
||||||
Acct: t.Status.Account.Acct,
|
|
||||||
Avatar: t.Status.Account.AvatarStatic,
|
|
||||||
Content: textContent(t.Status.Content),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if asFormat != "" {
|
|
||||||
tx.ExecuteTemplate(c.App.Writer, "mstdn", e)
|
|
||||||
} else {
|
|
||||||
switch t := e.(type) {
|
|
||||||
case *mastodon.UpdateEvent:
|
|
||||||
s.displayStatus(c.App.Writer, t.Status)
|
|
||||||
case *mastodon.NotificationEvent:
|
|
||||||
// TODO s.displayStatus(c.App.Writer, t.Notification.Status)
|
|
||||||
case *mastodon.ErrorEvent:
|
|
||||||
s.displayError(c.App.Writer, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdStream(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.Path != "/api/v1/streaming/public/local" {
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f, _ := w.(http.Flusher)
|
|
||||||
fmt.Fprintln(w, `
|
|
||||||
event: update
|
|
||||||
data: {"content": "foo", "account":{"acct":"FOO"}}
|
|
||||||
`)
|
|
||||||
f.Flush()
|
|
||||||
|
|
||||||
fmt.Fprintln(w, `
|
|
||||||
event: update
|
|
||||||
data: {"content": "bar", "account":{"acct":"BAR"}}
|
|
||||||
`)
|
|
||||||
f.Flush()
|
|
||||||
return
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
config := &mastodon.Config{
|
|
||||||
Server: ts.URL,
|
|
||||||
ClientID: "foo",
|
|
||||||
ClientSecret: "bar",
|
|
||||||
AccessToken: "zoo",
|
|
||||||
}
|
|
||||||
client := mastodon.NewClient(config)
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
app := makeApp()
|
|
||||||
app.Writer = &buf
|
|
||||||
app.Metadata = map[string]interface{}{
|
|
||||||
"client": client,
|
|
||||||
"config": config,
|
|
||||||
}
|
|
||||||
|
|
||||||
stop := func() {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
if sig, ok := app.Metadata["signal"]; ok {
|
|
||||||
sig.(chan os.Signal) <- os.Interrupt
|
|
||||||
return
|
|
||||||
}
|
|
||||||
panic("timeout")
|
|
||||||
}
|
|
||||||
|
|
||||||
var out string
|
|
||||||
|
|
||||||
go stop()
|
|
||||||
app.Run([]string{"mstdn", "stream"})
|
|
||||||
out = buf.String()
|
|
||||||
if !strings.Contains(out, "FOO@") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "FOO@", out)
|
|
||||||
}
|
|
||||||
if !strings.Contains(out, "foo") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "foo", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
go stop()
|
|
||||||
app.Run([]string{"mstdn", "stream", "--simplejson"})
|
|
||||||
out = buf.String()
|
|
||||||
if !strings.Contains(out, "FOO@") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "FOO@", out)
|
|
||||||
}
|
|
||||||
if !strings.Contains(out, "foo") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "foo", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testWithServer(h http.HandlerFunc, testFuncs ...func(*cli.App)) string {
|
|
||||||
ts := httptest.NewServer(h)
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
cli.OsExiter = func(n int) {}
|
|
||||||
|
|
||||||
client := mastodon.NewClient(&mastodon.Config{
|
|
||||||
Server: ts.URL,
|
|
||||||
ClientID: "foo",
|
|
||||||
ClientSecret: "bar",
|
|
||||||
AccessToken: "zoo",
|
|
||||||
})
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
app := makeApp()
|
|
||||||
app.Writer = &buf
|
|
||||||
app.Metadata = map[string]interface{}{
|
|
||||||
"client": client,
|
|
||||||
"config": &mastodon.Config{
|
|
||||||
Server: "https://example.com",
|
|
||||||
},
|
|
||||||
"xsearch_url": ts.URL,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range testFuncs {
|
|
||||||
f(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdTimeline(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
timeline, err := client.GetTimelineHome(context.Background(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
for i := len(timeline) - 1; i >= 0; i-- {
|
|
||||||
s.displayStatus(c.App.Writer, timeline[i])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTimelineHome(c *cli.Context) error {
|
|
||||||
return cmdTimeline(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTimelinePublic(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
timeline, err := client.GetTimelinePublic(context.Background(), false, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
for i := len(timeline) - 1; i >= 0; i-- {
|
|
||||||
s.displayStatus(c.App.Writer, timeline[i])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTimelineLocal(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
timeline, err := client.GetTimelinePublic(context.Background(), true, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
for i := len(timeline) - 1; i >= 0; i-- {
|
|
||||||
s.displayStatus(c.App.Writer, timeline[i])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTimelineDirect(c *cli.Context) error {
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
config := c.App.Metadata["config"].(*mastodon.Config)
|
|
||||||
timeline, err := client.GetTimelineDirect(context.Background(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := newScreen(config)
|
|
||||||
for i := len(timeline) - 1; i >= 0; i-- {
|
|
||||||
s.displayStatus(c.App.Writer, timeline[i])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdTimeline(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/timelines/home":
|
|
||||||
fmt.Fprintln(w, `[{"content": "home"}]`)
|
|
||||||
return
|
|
||||||
case "/api/v1/timelines/public":
|
|
||||||
fmt.Fprintln(w, `[{"content": "public"}]`)
|
|
||||||
return
|
|
||||||
case "/api/v1/conversations":
|
|
||||||
fmt.Fprintln(w, `[{"id": "4", "unread":false, "last_status" : {"content": "direct"}}]`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "timeline"})
|
|
||||||
app.Run([]string{"mstdn", "timeline-home"})
|
|
||||||
app.Run([]string{"mstdn", "timeline-public"})
|
|
||||||
app.Run([]string{"mstdn", "timeline-local"})
|
|
||||||
app.Run([]string{"mstdn", "timeline-direct"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
want := strings.Join([]string{
|
|
||||||
"@example.com",
|
|
||||||
"home",
|
|
||||||
"@example.com",
|
|
||||||
"home",
|
|
||||||
"@example.com",
|
|
||||||
"public",
|
|
||||||
"@example.com",
|
|
||||||
"public",
|
|
||||||
"@example.com",
|
|
||||||
"direct",
|
|
||||||
}, "\n") + "\n"
|
|
||||||
if !strings.Contains(out, want) {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", want, out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdToot(c *cli.Context) error {
|
|
||||||
var toot string
|
|
||||||
ff := c.String("ff")
|
|
||||||
if ff != "" {
|
|
||||||
text, err := readFile(ff)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
toot = string(text)
|
|
||||||
} else {
|
|
||||||
if !c.Args().Present() {
|
|
||||||
return errors.New("arguments required")
|
|
||||||
}
|
|
||||||
toot = argstr(c)
|
|
||||||
}
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
_, err := client.PostStatus(context.Background(), &mastodon.Toot{
|
|
||||||
Status: toot,
|
|
||||||
InReplyToID: mastodon.ID(fmt.Sprint(c.String("i"))),
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdToot(t *testing.T) {
|
|
||||||
toot := ""
|
|
||||||
testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/statuses":
|
|
||||||
toot = r.FormValue("status")
|
|
||||||
fmt.Fprintln(w, `{"id": 2345}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "toot", "foo"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if toot != "foo" {
|
|
||||||
t.Fatalf("want %q, got %q", "foo", toot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmdTootFileNotFound(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/statuses":
|
|
||||||
fmt.Fprintln(w, `{"id": 2345}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err = app.Run([]string{"mstdn", "toot", "-ff", "not-found"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("should be fail")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdUpload(c *cli.Context) error {
|
|
||||||
if !c.Args().Present() {
|
|
||||||
return errors.New("arguments required")
|
|
||||||
}
|
|
||||||
client := c.App.Metadata["client"].(*mastodon.Client)
|
|
||||||
for i := 0; i < c.NArg(); i++ {
|
|
||||||
attachment, err := client.UploadMedia(context.Background(), c.Args().Get(i))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if i > 0 {
|
|
||||||
fmt.Fprintln(c.App.Writer)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(c.App.Writer, "ID : %v\n", attachment.ID)
|
|
||||||
fmt.Fprintf(c.App.Writer, "Type : %v\n", attachment.Type)
|
|
||||||
fmt.Fprintf(c.App.Writer, "URL : %v\n", attachment.URL)
|
|
||||||
fmt.Fprintf(c.App.Writer, "RemoteURL : %v\n", attachment.RemoteURL)
|
|
||||||
fmt.Fprintf(c.App.Writer, "PreviewURL: %v\n", attachment.PreviewURL)
|
|
||||||
fmt.Fprintf(c.App.Writer, "TextURL : %v\n", attachment.TextURL)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdUpload(t *testing.T) {
|
|
||||||
out := testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v1/media":
|
|
||||||
fmt.Fprintln(w, `{"id": 123}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
app.Run([]string{"mstdn", "upload", "../../testdata/logo.png"})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if !strings.Contains(out, "123") {
|
|
||||||
t.Fatalf("%q should be contained in output of command: %v", "123", out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cmdXSearch(c *cli.Context) error {
|
|
||||||
return xSearch(c.App.Metadata["xsearch_url"].(string), c.Args().First(), c.App.Writer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func xSearch(xsearchRawurl, query string, w io.Writer) error {
|
|
||||||
u, err := url.Parse(xsearchRawurl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
params := url.Values{}
|
|
||||||
params.Set("q", query)
|
|
||||||
u.RawQuery = params.Encode()
|
|
||||||
doc, err := goquery.NewDocument(u.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
doc.Find(".post").Each(func(n int, elem *goquery.Selection) {
|
|
||||||
href, ok := elem.Find(".mst_content a").Attr("href")
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text := elem.Find(".mst_content p").Text()
|
|
||||||
fmt.Fprintf(w, "%s\n", href)
|
|
||||||
fmt.Fprintf(w, "%s\n\n", text)
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCmdXSearch(t *testing.T) {
|
|
||||||
testWithServer(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, `<div class="post"><div class="mst_content"><a href="http://example.com/@test/1"><p>test status</p></a></div></div>`)
|
|
||||||
},
|
|
||||||
func(app *cli.App) {
|
|
||||||
err := app.Run([]string{"mstdn", "xsearch", "test"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestXSearch(t *testing.T) {
|
|
||||||
canErr := true
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if canErr {
|
|
||||||
canErr = false
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), 9999)
|
|
||||||
return
|
|
||||||
} else if r.URL.Query().Get("q") == "empty" {
|
|
||||||
fmt.Fprintln(w, `<div class="post"><div class="mst_content"><a><p>test status</p></a></div></div>`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintln(w, `<div class="post"><div class="mst_content"><a href="http://example.com/@test/1"><p>test status</p></a></div></div>`)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
err := xSearch(":", "", nil)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("should be fail: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = xSearch(ts.URL, "", nil)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("should be fail: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
err = xSearch(ts.URL, "empty", buf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
result := buf.String()
|
|
||||||
if result != "" {
|
|
||||||
t.Fatalf("the search result should be empty: %s", result)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = bytes.NewBuffer(nil)
|
|
||||||
err = xSearch(ts.URL, "test", buf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
result = buf.String()
|
|
||||||
if !strings.Contains(result, "http://example.com/@test/1") {
|
|
||||||
t.Fatalf("%q should be contained in output of search: %s", "http://example.com/@test/1", result)
|
|
||||||
}
|
|
||||||
if !strings.Contains(result, "test status") {
|
|
||||||
t.Fatalf("%q should be contained in output of search: %s", "test status", result)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,411 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/mattn/go-tty"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
"golang.org/x/net/html"
|
|
||||||
)
|
|
||||||
|
|
||||||
func readFile(filename string) ([]byte, error) {
|
|
||||||
if filename == "-" {
|
|
||||||
return ioutil.ReadAll(os.Stdin)
|
|
||||||
}
|
|
||||||
return ioutil.ReadFile(filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func textContent(s string) string {
|
|
||||||
doc, err := html.Parse(strings.NewReader(s))
|
|
||||||
if err != nil {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
var extractText func(node *html.Node, w *bytes.Buffer)
|
|
||||||
extractText = func(node *html.Node, w *bytes.Buffer) {
|
|
||||||
if node.Type == html.TextNode {
|
|
||||||
data := strings.Trim(node.Data, "\r\n")
|
|
||||||
if data != "" {
|
|
||||||
w.WriteString(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
|
||||||
extractText(c, w)
|
|
||||||
}
|
|
||||||
if node.Type == html.ElementNode {
|
|
||||||
name := strings.ToLower(node.Data)
|
|
||||||
if name == "br" {
|
|
||||||
w.WriteString("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extractText(doc, &buf)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
readUsername = func() (string, error) {
|
|
||||||
b, _, err := bufio.NewReader(os.Stdin).ReadLine()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(b), nil
|
|
||||||
}
|
|
||||||
readPassword func() (string, error)
|
|
||||||
)
|
|
||||||
|
|
||||||
func prompt() (string, string, error) {
|
|
||||||
fmt.Print("E-Mail: ")
|
|
||||||
email, err := readUsername()
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Print("Password: ")
|
|
||||||
var password string
|
|
||||||
if readPassword == nil {
|
|
||||||
var t *tty.TTY
|
|
||||||
t, err = tty.Open()
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
defer t.Close()
|
|
||||||
password, err = t.ReadPassword()
|
|
||||||
} else {
|
|
||||||
password, err = readPassword()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
return email, password, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configFile(c *cli.Context) (string, error) {
|
|
||||||
dir := os.Getenv("HOME")
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
dir = os.Getenv("APPDATA")
|
|
||||||
if dir == "" {
|
|
||||||
dir = filepath.Join(os.Getenv("USERPROFILE"), "Application Data", "mstdn")
|
|
||||||
}
|
|
||||||
dir = filepath.Join(dir, "mstdn")
|
|
||||||
} else {
|
|
||||||
dir = filepath.Join(dir, ".config", "mstdn")
|
|
||||||
}
|
|
||||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
var file string
|
|
||||||
profile := c.String("profile")
|
|
||||||
if profile != "" {
|
|
||||||
file = filepath.Join(dir, "settings-"+profile+".json")
|
|
||||||
} else {
|
|
||||||
file = filepath.Join(dir, "settings.json")
|
|
||||||
}
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConfig(c *cli.Context) (string, *mastodon.Config, error) {
|
|
||||||
file, err := configFile(c)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadFile(file)
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
config := &mastodon.Config{
|
|
||||||
Server: "https://mstdn.jp",
|
|
||||||
ClientID: "1e463436008428a60ed14ff1f7bc0b4d923e14fc4a6827fa99560b0c0222612f",
|
|
||||||
ClientSecret: "72b63de5bc11111a5aa1a7b690672d78ad6a207ce32e16ea26115048ec5d234d",
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(b, &config)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("could not unmarshal %v: %v", file, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return file, config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func authenticate(client *mastodon.Client, config *mastodon.Config, file string) error {
|
|
||||||
email, password, err := prompt()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = client.Authenticate(context.Background(), email, password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b, err := json.MarshalIndent(config, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to store file: %v", err)
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(file, b, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to store file: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func argstr(c *cli.Context) string {
|
|
||||||
a := []string{}
|
|
||||||
for i := 0; i < c.NArg(); i++ {
|
|
||||||
a = append(a, c.Args().Get(i))
|
|
||||||
}
|
|
||||||
return strings.Join(a, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func fatalIf(err error) {
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "%s: %v\n", os.Args[0], err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeApp() *cli.App {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Name = "mstdn"
|
|
||||||
app.Usage = "mastodon client"
|
|
||||||
app.Version = "0.0.1"
|
|
||||||
app.Flags = []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "profile",
|
|
||||||
Usage: "profile name",
|
|
||||||
Value: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
app.Commands = []cli.Command{
|
|
||||||
{
|
|
||||||
Name: "toot",
|
|
||||||
Usage: "post toot",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "ff",
|
|
||||||
Usage: "post utf-8 string from a file(\"-\" means STDIN)",
|
|
||||||
Value: "",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "i",
|
|
||||||
Usage: "in-reply-to",
|
|
||||||
Value: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: cmdToot,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "stream",
|
|
||||||
Usage: "stream statuses",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "type",
|
|
||||||
Usage: "stream type (public,public/local,user:NAME,hashtag:TAG)",
|
|
||||||
},
|
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "json",
|
|
||||||
Usage: "output JSON",
|
|
||||||
},
|
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "simplejson",
|
|
||||||
Usage: "output simple JSON",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "template",
|
|
||||||
Usage: "output with tamplate format",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: cmdStream,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "timeline",
|
|
||||||
Usage: "show timeline",
|
|
||||||
Action: cmdTimeline,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "timeline-home",
|
|
||||||
Usage: "show timeline home",
|
|
||||||
Action: cmdTimelineHome,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "timeline-local",
|
|
||||||
Usage: "show timeline local",
|
|
||||||
Action: cmdTimelineLocal,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "timeline-public",
|
|
||||||
Usage: "show timeline public",
|
|
||||||
Action: cmdTimelinePublic,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "timeline-direct",
|
|
||||||
Usage: "show timeline direct",
|
|
||||||
Action: cmdTimelineDirect,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "notification",
|
|
||||||
Usage: "show notification",
|
|
||||||
Action: cmdNotification,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "instance",
|
|
||||||
Usage: "show instance information",
|
|
||||||
Action: cmdInstance,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "instance_activity",
|
|
||||||
Usage: "show instance activity information",
|
|
||||||
Action: cmdInstanceActivity,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "instance_peers",
|
|
||||||
Usage: "show instance peers information",
|
|
||||||
Action: cmdInstancePeers,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "account",
|
|
||||||
Usage: "show account information",
|
|
||||||
Action: cmdAccount,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "search",
|
|
||||||
Usage: "search content",
|
|
||||||
Action: cmdSearch,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "follow",
|
|
||||||
Usage: "follow account",
|
|
||||||
Action: cmdFollow,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "followers",
|
|
||||||
Usage: "show followers",
|
|
||||||
Action: cmdFollowers,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "upload",
|
|
||||||
Usage: "upload file",
|
|
||||||
Action: cmdUpload,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "delete",
|
|
||||||
Usage: "delete status",
|
|
||||||
Action: cmdDelete,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "init",
|
|
||||||
Usage: "initialize profile",
|
|
||||||
Action: func(c *cli.Context) error { return nil },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "mikami",
|
|
||||||
Usage: "search mikami",
|
|
||||||
Action: cmdMikami,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "xsearch",
|
|
||||||
Usage: "cross search",
|
|
||||||
Action: cmdXSearch,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
app.Setup()
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
type screen struct {
|
|
||||||
host string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newScreen(config *mastodon.Config) *screen {
|
|
||||||
var host string
|
|
||||||
u, err := url.Parse(config.Server)
|
|
||||||
if err == nil {
|
|
||||||
host = u.Host
|
|
||||||
}
|
|
||||||
return &screen{host}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *screen) acct(a string) string {
|
|
||||||
if !strings.Contains(a, "@") {
|
|
||||||
a += "@" + s.host
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *screen) displayError(w io.Writer, e error) {
|
|
||||||
color.Set(color.FgYellow)
|
|
||||||
fmt.Fprintln(w, e.Error())
|
|
||||||
color.Set(color.Reset)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *screen) displayStatus(w io.Writer, t *mastodon.Status) {
|
|
||||||
if t == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if t.Reblog != nil {
|
|
||||||
color.Set(color.FgHiRed)
|
|
||||||
fmt.Fprint(w, s.acct(t.Account.Acct))
|
|
||||||
color.Set(color.Reset)
|
|
||||||
fmt.Fprint(w, " reblogged ")
|
|
||||||
color.Set(color.FgHiBlue)
|
|
||||||
fmt.Fprintln(w, s.acct(t.Reblog.Account.Acct))
|
|
||||||
fmt.Fprintln(w, textContent(t.Reblog.Content))
|
|
||||||
color.Set(color.Reset)
|
|
||||||
} else {
|
|
||||||
color.Set(color.FgHiRed)
|
|
||||||
fmt.Fprintln(w, s.acct(t.Account.Acct))
|
|
||||||
color.Set(color.Reset)
|
|
||||||
fmt.Fprintln(w, textContent(t.Content))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() int {
|
|
||||||
app := makeApp()
|
|
||||||
|
|
||||||
app.Before = func(c *cli.Context) error {
|
|
||||||
if c.Args().Get(0) == "init" {
|
|
||||||
file, err := configFile(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
os.Remove(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, config, err := getConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := mastodon.NewClient(config)
|
|
||||||
client.UserAgent = "mstdn"
|
|
||||||
app.Metadata = map[string]interface{}{
|
|
||||||
"client": client,
|
|
||||||
"config": config,
|
|
||||||
"xsearch_url": "http://mastodonsearch.jp/cross/",
|
|
||||||
}
|
|
||||||
if config.AccessToken == "" {
|
|
||||||
return authenticate(client, config, file)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fatalIf(app.Run(os.Args))
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
os.Exit(run())
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReadFileFile(t *testing.T) {
|
|
||||||
b, err := readFile("main.go")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(b) == 0 {
|
|
||||||
t.Fatalf("should read something: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReadFileStdin(t *testing.T) {
|
|
||||||
f, err := os.Open("main.go")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
stdin := os.Stdin
|
|
||||||
os.Stdin = f
|
|
||||||
defer func() {
|
|
||||||
os.Stdin = stdin
|
|
||||||
}()
|
|
||||||
|
|
||||||
b, err := readFile("-")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(b) == 0 {
|
|
||||||
t.Fatalf("should read something: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTextContent(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{input: "", want: ""},
|
|
||||||
{input: "<p>foo</p>", want: "foo"},
|
|
||||||
{input: "<p>foo<span>\nbar\n</span>baz</p>", want: "foobarbaz"},
|
|
||||||
{input: "<p>foo<span>\nbar<br></span>baz</p>", want: "foobar\nbaz"},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
got := textContent(test.input)
|
|
||||||
if got != test.want {
|
|
||||||
t.Fatalf("want %q but %q", test.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetConfig(t *testing.T) {
|
|
||||||
tmpdir, err := ioutil.TempDir("", "mstdn")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
home := os.Getenv("HOME")
|
|
||||||
appdata := os.Getenv("APPDATA")
|
|
||||||
os.Setenv("HOME", tmpdir)
|
|
||||||
os.Setenv("APPDATA", tmpdir)
|
|
||||||
defer func() {
|
|
||||||
os.RemoveAll(tmpdir)
|
|
||||||
os.Setenv("HOME", home)
|
|
||||||
os.Setenv("APPDATA", appdata)
|
|
||||||
}()
|
|
||||||
|
|
||||||
app := makeApp()
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
set.Parse([]string{"mstdn", "-profile", ""})
|
|
||||||
c := cli.NewContext(app, set, nil)
|
|
||||||
file, config, err := getConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
t.Fatal("should not exists")
|
|
||||||
}
|
|
||||||
if config.AccessToken != "" {
|
|
||||||
t.Fatalf("should be empty: %v", config.AccessToken)
|
|
||||||
}
|
|
||||||
if config.ClientID == "" {
|
|
||||||
t.Fatalf("should not be empty")
|
|
||||||
}
|
|
||||||
if config.ClientSecret == "" {
|
|
||||||
t.Fatalf("should not be empty")
|
|
||||||
}
|
|
||||||
config.AccessToken = "foo"
|
|
||||||
b, err := json.MarshalIndent(config, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(file, b, 0700)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
file, config, err = getConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
|
||||||
t.Fatalf("should exists: %v", err)
|
|
||||||
}
|
|
||||||
if got := config.AccessToken; got != "foo" {
|
|
||||||
t.Fatalf("want %q but %q", "foo", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrompt(t *testing.T) {
|
|
||||||
readUsername = func() (string, error) {
|
|
||||||
return "foo", nil
|
|
||||||
}
|
|
||||||
readPassword = func() (string, error) {
|
|
||||||
return "bar", nil
|
|
||||||
}
|
|
||||||
username, password, err := prompt()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if username != "foo" {
|
|
||||||
t.Fatalf("want %q but %q", "foo", username)
|
|
||||||
}
|
|
||||||
if password != "bar" {
|
|
||||||
t.Fatalf("want %q but %q", "bar", password)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/RasmusLindroth/go-mastodon"
|
"github.com/RasmusLindroth/tut3/mastodon"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleRegisterApp() {
|
func ExampleRegisterApp() {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
func TestGetFilters(t *testing.T) {
|
func TestGetFilters(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, `[{"id": "6191", "phrase": "rust", "context": ["home"], "whole_word": true, "expires_at": "2019-05-21T13:47:31.333Z", "irreversible": false}, {"id": "5580", "phrase": "@twitter.com", "context": ["home", "notifications", "public", "thread"], "whole_word": false, "expires_at": null, "irreversible": true}]`)
|
fmt.Fprintln(w, `[{"id": "6191", "phrase": "rust", "context": ["home"], "whole_word": true, "expires_at": "2019-05-21T13:47:31.333Z", "irreversible": false}, {"id": "5580", "phrase": "@twitter.com", "context": ["home", "notifications", "public", "thread"], "whole_word": false, "expires_at": null, "irreversible": true}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -85,7 +84,6 @@ func TestGetFilter(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": "1", "phrase": "rust", "context": ["home"], "whole_word": true, "expires_at": "2019-05-21T13:47:31.333Z", "irreversible": false}`)
|
fmt.Fprintln(w, `{"id": "1", "phrase": "rust", "context": ["home"], "whole_word": true, "expires_at": "2019-05-21T13:47:31.333Z", "irreversible": false}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -328,7 +326,6 @@ func TestDeleteFilter(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
16
go.mod
16
go.mod
|
@ -1,16 +0,0 @@
|
||||||
module github.com/RasmusLindroth/go-mastodon
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/PuerkitoBio/goquery v1.8.0
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
|
||||||
github.com/fatih/color v1.13.0
|
|
||||||
github.com/gorilla/websocket v1.5.0
|
|
||||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
|
||||||
github.com/mattn/go-tty v0.0.3
|
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
|
||||||
github.com/urfave/cli v1.22.5
|
|
||||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3
|
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
|
|
||||||
)
|
|
53
go.sum
53
go.sum
|
@ -1,53 +0,0 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
|
||||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
|
||||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
|
||||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
|
|
||||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
|
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
|
||||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
|
||||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
|
||||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU=
|
|
||||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
|
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
|
@ -15,7 +15,6 @@ func TestGetLists(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
|
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -47,7 +46,6 @@ func TestGetAccountLists(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
|
fmt.Fprintln(w, `[{"id": "1", "title": "foo"}, {"id": "2", "title": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -83,7 +81,6 @@ func TestGetListAccounts(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -119,7 +116,6 @@ func TestGetList(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
|
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -129,11 +125,11 @@ func TestGetList(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
list, err := client.GetList(context.Background(), "2")
|
_, err := client.GetList(context.Background(), "2")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
list, err = client.GetList(context.Background(), "1")
|
list, err := client.GetList(context.Background(), "1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +145,6 @@ func TestCreateList(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
|
fmt.Fprintln(w, `{"id": "1", "title": "foo"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -159,11 +154,11 @@ func TestCreateList(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
list, err := client.CreateList(context.Background(), "")
|
_, err := client.CreateList(context.Background(), "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
list, err = client.CreateList(context.Background(), "foo")
|
list, err := client.CreateList(context.Background(), "foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -183,7 +178,6 @@ func TestRenameList(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": "1", "title": "bar"}`)
|
fmt.Fprintln(w, `{"id": "1", "title": "bar"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -193,11 +187,11 @@ func TestRenameList(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
list, err := client.RenameList(context.Background(), "2", "bar")
|
_, err := client.RenameList(context.Background(), "2", "bar")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
list, err = client.RenameList(context.Background(), "1", "bar")
|
list, err := client.RenameList(context.Background(), "1", "bar")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +210,6 @@ func TestDeleteList(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -246,7 +239,6 @@ func TestAddToList(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -272,7 +264,6 @@ func TestRemoveFromList(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,6 @@ func TestAuthenticate(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"access_token": "zoo"}`)
|
fmt.Fprintln(w, `{"access_token": "zoo"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -124,7 +123,6 @@ func TestAuthenticate(t *testing.T) {
|
||||||
func TestAuthenticateWithCancel(t *testing.T) {
|
func TestAuthenticateWithCancel(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -151,7 +149,6 @@ func TestPostStatus(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"access_token": "zoo"}`)
|
fmt.Fprintln(w, `{"access_token": "zoo"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -184,7 +181,6 @@ func TestPostStatus(t *testing.T) {
|
||||||
func TestPostStatusWithCancel(t *testing.T) {
|
func TestPostStatusWithCancel(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -319,7 +315,6 @@ func TestPostStatusParams(t *testing.T) {
|
||||||
func TestGetTimelineHome(t *testing.T) {
|
func TestGetTimelineHome(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -359,7 +354,6 @@ func TestGetTimelineHome(t *testing.T) {
|
||||||
func TestGetTimelineHomeWithCancel(t *testing.T) {
|
func TestGetTimelineHomeWithCancel(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ func TestGetNotifications(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -76,7 +75,6 @@ func TestPushSubscription(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ func TestGetReports(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"id": 122, "action_taken": false}, {"id": 123, "action_taken": true}]`)
|
fmt.Fprintln(w, `[{"id": 122, "action_taken": false}, {"id": 123, "action_taken": true}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -55,7 +54,6 @@ func TestReport(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(w, `{"id": 1234, "action_taken": true}`)
|
fmt.Fprintln(w, `{"id": 1234, "action_taken": true}`)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -65,11 +63,11 @@ func TestReport(t *testing.T) {
|
||||||
ClientSecret: "bar",
|
ClientSecret: "bar",
|
||||||
AccessToken: "zoo",
|
AccessToken: "zoo",
|
||||||
})
|
})
|
||||||
rp, err := client.Report(context.Background(), "121", nil, "")
|
_, err := client.Report(context.Background(), "121", nil, "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should be fail: %v", err)
|
t.Fatalf("should be fail: %v", err)
|
||||||
}
|
}
|
||||||
rp, err = client.Report(context.Background(), "122", nil, "")
|
rp, err := client.Report(context.Background(), "122", nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not be fail: %v", err)
|
t.Fatalf("should not be fail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
10
status.go
10
status.go
|
@ -28,10 +28,10 @@ type Status struct {
|
||||||
RepliesCount int64 `json:"replies_count"`
|
RepliesCount int64 `json:"replies_count"`
|
||||||
ReblogsCount int64 `json:"reblogs_count"`
|
ReblogsCount int64 `json:"reblogs_count"`
|
||||||
FavouritesCount int64 `json:"favourites_count"`
|
FavouritesCount int64 `json:"favourites_count"`
|
||||||
Reblogged interface{} `json:"reblogged"`
|
Reblogged bool `json:"reblogged"`
|
||||||
Favourited interface{} `json:"favourited"`
|
Favourited bool `json:"favourited"`
|
||||||
Bookmarked interface{} `json:"bookmarked"`
|
Bookmarked bool `json:"bookmarked"`
|
||||||
Muted interface{} `json:"muted"`
|
Muted bool `json:"muted"`
|
||||||
Sensitive bool `json:"sensitive"`
|
Sensitive bool `json:"sensitive"`
|
||||||
SpoilerText string `json:"spoiler_text"`
|
SpoilerText string `json:"spoiler_text"`
|
||||||
Visibility string `json:"visibility"`
|
Visibility string `json:"visibility"`
|
||||||
|
@ -42,7 +42,7 @@ type Status struct {
|
||||||
Poll *Poll `json:"poll"`
|
Poll *Poll `json:"poll"`
|
||||||
Application Application `json:"application"`
|
Application Application `json:"application"`
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
Pinned interface{} `json:"pinned"`
|
Pinned bool `json:"pinned"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context hold information for mastodon context.
|
// Context hold information for mastodon context.
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
func TestGetFavourites(t *testing.T) {
|
func TestGetFavourites(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -40,7 +39,6 @@ func TestGetFavourites(t *testing.T) {
|
||||||
func TestGetBookmarks(t *testing.T) {
|
func TestGetBookmarks(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -72,7 +70,6 @@ func TestGetStatus(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz", "emojis":[{"shortcode":"💩", "url":"http://example.com", "static_url": "http://example.com/static"}]}`)
|
fmt.Fprintln(w, `{"content": "zzz", "emojis":[{"shortcode":"💩", "url":"http://example.com", "static_url": "http://example.com/static"}]}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -114,7 +111,6 @@ func TestGetStatusCard(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"title": "zzz"}`)
|
fmt.Fprintln(w, `{"title": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -144,7 +140,6 @@ func TestGetStatusContext(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"ancestors": [{"content": "zzz"},{"content": "bbb"}]}`)
|
fmt.Fprintln(w, `{"ancestors": [{"content": "zzz"},{"content": "bbb"}]}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -183,7 +178,6 @@ func TestGetRebloggedBy(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -219,7 +213,6 @@ func TestGetFavouritedBy(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
fmt.Fprintln(w, `[{"username": "foo"}, {"username": "bar"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -255,7 +248,6 @@ func TestReblog(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -285,7 +277,6 @@ func TestUnreblog(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -315,7 +306,6 @@ func TestFavourite(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -345,7 +335,6 @@ func TestUnfavourite(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -375,7 +364,6 @@ func TestBookmark(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -405,7 +393,6 @@ func TestUnbookmark(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"content": "zzz"}`)
|
fmt.Fprintln(w, `{"content": "zzz"}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -487,7 +474,6 @@ func TestGetTimelineHashtag(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -523,7 +509,6 @@ func TestGetTimelineList(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -559,7 +544,6 @@ func TestGetTimelineMedia(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
fmt.Fprintln(w, `[{"content": "zzz"},{"content": "yyy"}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -598,7 +582,6 @@ func TestDeleteStatus(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -634,7 +617,6 @@ func TestSearch(t *testing.T) {
|
||||||
"statuses":[{"content": "aaa"}],
|
"statuses":[{"content": "aaa"}],
|
||||||
"hashtags":[{"name": "tag"},{"name": "tag2"},{"name": "tag3"}]
|
"hashtags":[{"name": "tag"},{"name": "tag2"},{"name": "tag3"}]
|
||||||
}`)
|
}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -679,7 +661,6 @@ func TestUploadMedia(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `{"id": 123}`)
|
fmt.Fprintln(w, `{"id": 123}`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -716,7 +697,6 @@ func TestGetConversations(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, `[{"id": "4", "unread":false, "last_status" : {"content": "zzz"}}, {"id": "3", "unread":true, "last_status" : {"content": "bar"}}]`)
|
fmt.Fprintln(w, `[{"id": "4", "unread":false, "last_status" : {"content": "zzz"}}, {"id": "3", "unread":true, "last_status" : {"content": "bar"}}]`)
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -754,7 +734,6 @@ func TestDeleteConversation(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
@ -780,7 +759,6 @@ func TestMarkConversationsAsRead(t *testing.T) {
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,11 @@ event: delete
|
||||||
data: 1234567
|
data: 1234567
|
||||||
:thump
|
:thump
|
||||||
`)
|
`)
|
||||||
|
errs := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(q)
|
defer close(q)
|
||||||
err := handleReader(q, r)
|
err := handleReader(q, r)
|
||||||
if err != nil {
|
errs <- err
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
var passUpdate, passNotification, passDelete, passError bool
|
var passUpdate, passNotification, passDelete, passError bool
|
||||||
for e := range q {
|
for e := range q {
|
||||||
|
@ -60,6 +59,10 @@ data: 1234567
|
||||||
"update %t, notification %t, delete %t, error %t",
|
"update %t, notification %t, delete %t, error %t",
|
||||||
passUpdate, passNotification, passDelete, passError)
|
passUpdate, passNotification, passDelete, passError)
|
||||||
}
|
}
|
||||||
|
err := <-errs
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not be fail: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStreaming(t *testing.T) {
|
func TestStreaming(t *testing.T) {
|
||||||
|
@ -142,9 +145,6 @@ func TestDoStreaming(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer close(q)
|
defer close(q)
|
||||||
c.doStreaming(req, q)
|
c.doStreaming(req, q)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not be fail: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
var passError bool
|
var passError bool
|
||||||
for e := range q {
|
for e := range q {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue