diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8bc1a8b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "console": "integratedTerminal" + }, + { + "name": "mstdn", + "type": "go", + "request": "launch", + "mode": "auto", + // "cwd": "${workspaceFolder}/cmd/mstdn", + "program": "${workspaceFolder}/cmd/mstdn", + "console": "integratedTerminal" + } + ] +} diff --git a/accounts.go b/accounts.go index 0b43e4c..2908261 100644 --- a/accounts.go +++ b/accounts.go @@ -2,6 +2,7 @@ package mastodon import ( "context" + "encoding/json" "fmt" "net/http" "net/url" @@ -32,6 +33,7 @@ type Account struct { Bot bool `json:"bot"` Discoverable bool `json:"discoverable"` Source *AccountSource `json:"source"` + FollowedTag []FollowedTag `json:"followed_tags"` } // Field is a Mastodon account profile field. @@ -50,6 +52,40 @@ type AccountSource struct { Fields *[]Field `json:"fields"` } +// UnixTimeString represents a time in a Unix Epoch string +type UnixTimeString struct { + time.Time +} + +func (u *UnixTimeString) UnmarshalJSON(b []byte) error { + var timestampSring string + err := json.Unmarshal(b, ×tampSring) + if err != nil { + return err + } + timestamp, err := strconv.ParseInt(timestampSring, 0, 0) + if err != nil { + return err + } + u.Time = time.Unix(timestamp, 0) + return nil +} + +// History is the history of a followed tag +type FollowedTagHistory struct { + Day UnixTimeString `json:"day,omitempty"` + Accounts int `json:"accounts,string,omitempty"` + Uses int `json:"uses,string,omitempty"` +} + +// FollowedTag is a Hash Tag followed by the user +type FollowedTag struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` + History []FollowedTagHistory `json:"history,omitempty"` + Following bool `json:"following,omitempty"` +} + // GetAccount return Account. func (c *Client) GetAccount(ctx context.Context, id ID) (*Account, error) { var account Account @@ -326,3 +362,13 @@ func (c *Client) GetMutes(ctx context.Context, pg *Pagination) ([]*Account, erro } return accounts, nil } + +// GetMutes returns the list of users muted by the current user. +func (c *Client) GetFollowedTags(ctx context.Context, pg *Pagination) ([]*FollowedTag, error) { + var followedTags []*FollowedTag + err := c.doAPI(ctx, http.MethodGet, "/api/v1/followed_tags", nil, &followedTags, pg) + if err != nil { + return nil, err + } + return followedTags, nil +} diff --git a/accounts_test.go b/accounts_test.go index 47e0310..9affd45 100644 --- a/accounts_test.go +++ b/accounts_test.go @@ -697,3 +697,92 @@ func TestGetMutes(t *testing.T) { t.Fatalf("want %q but %q", "bar", mutes[1].Username) } } +func TestGetFollowedTags(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), http.StatusInternalServerError) + return + } + fmt.Fprintln(w, `[ + { + "name": "Test1", + "url": "http://mastodon.example/tags/test1", + "history": [ + { + "day": "1668211200", + "accounts": "0", + "uses": "0" + }, + { + "day": "1668124800", + "accounts": "0", + "uses": "0" + }, + { + "day": "1668038400", + "accounts": "0", + "uses": "0" + } + ], + "following": true + }, + { + "name": "Test2", + "url": "http://mastodon.example/tags/test2", + "history": [ + { + "day": "1668211200", + "accounts": "0", + "uses": "0" + } + ], + "following": true + } +]`) + })) + defer ts.Close() + + client := NewClient(&Config{ + Server: ts.URL, + ClientID: "foo", + ClientSecret: "bar", + AccessToken: "zoo", + }) + _, err := client.GetFollowedTags(context.Background(), nil) + if err == nil { + t.Fatalf("should be fail: %v", err) + } + followedTags, err := client.GetFollowedTags(context.Background(), nil) + if err != nil { + t.Fatalf("should not be fail: %v", err) + } + if len(followedTags) != 2 { + t.Fatalf("result should be two: %d", len(followedTags)) + } + if followedTags[0].Name != "Test1" { + t.Fatalf("want %q but %q", "Test1", followedTags[0].Name) + } + if followedTags[0].URL != "http://mastodon.example/tags/test1" { + t.Fatalf("want %q but got %q", "http://mastodon.example/tags/test1", followedTags[0].URL) + } + if !followedTags[0].Following { + t.Fatalf("want following, but got false") + } + if 3 != len(followedTags[0].History){ + t.Fatalf("expecting first tag history length to be %d but got %d", 3, len(followedTags[0].History)) + } + if followedTags[1].Name != "Test2" { + t.Fatalf("want %q but %q", "Test2", followedTags[1].Name) + } + if followedTags[1].URL != "http://mastodon.example/tags/test2" { + t.Fatalf("want %q but got %q", "http://mastodon.example/tags/test2", followedTags[1].URL) + } + if !followedTags[1].Following { + t.Fatalf("want following, but got false") + } + if 1 != len(followedTags[1].History){ + t.Fatalf("expecting first tag history length to be %d but got %d", 1, len(followedTags[1].History)) + } +} diff --git a/cmd/mstdn/go.mod b/cmd/mstdn/go.mod index 19d310d..fe41f20 100644 --- a/cmd/mstdn/go.mod +++ b/cmd/mstdn/go.mod @@ -9,7 +9,6 @@ require ( github.com/fatih/color v1.13.0 github.com/mattn/go-mastodon v0.0.4 github.com/mattn/go-tty v0.0.4 - github.com/urfave/cli v1.13.0 - github.com/urfave/cli/v2 v2.23.5 // indirect + github.com/urfave/cli/v2 v2.23.5 golang.org/x/net v0.0.0-20220531201128-c960675eff93 ) diff --git a/cmd/mstdn/go.sum b/cmd/mstdn/go.sum index 65758c5..070c0a7 100644 --- a/cmd/mstdn/go.sum +++ b/cmd/mstdn/go.sum @@ -24,8 +24,6 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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.13.0 h1:kkpCmfxnnnWIie2rCljcvaVrNYmsFq1ynTJH5kn1Ip4= -github.com/urfave/cli v1.13.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw= github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= diff --git a/cmd/mstdn/main.go b/cmd/mstdn/main.go index a52cf10..05a151b 100644 --- a/cmd/mstdn/main.go +++ b/cmd/mstdn/main.go @@ -258,7 +258,7 @@ func makeApp() *cli.App { { Name: "timeline-tag", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "local", Usage: "local tags only", }, diff --git a/go.work b/go.work new file mode 100644 index 0000000..50be376 --- /dev/null +++ b/go.work @@ -0,0 +1,6 @@ +go 1.19 + +use ( + . + ./cmd/mstdn +)