diff --git a/accounts.go b/accounts.go index a52cf9a..01390b8 100644 --- a/accounts.go +++ b/accounts.go @@ -30,7 +30,7 @@ type Account struct { // GetAccount return Account. func (c *Client) GetAccount(ctx context.Context, id int) (*Account, error) { var account Account - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account, nil) + _, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account, nil) if err != nil { return nil, err } @@ -40,7 +40,7 @@ func (c *Client) GetAccount(ctx context.Context, id int) (*Account, error) { // GetAccountCurrentUser return Account of current user. func (c *Client) GetAccountCurrentUser(ctx context.Context) (*Account, error) { var account Account - err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/verify_credentials", nil, &account, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/verify_credentials", nil, &account, nil) if err != nil { return nil, err } @@ -76,7 +76,7 @@ func (c *Client) AccountUpdate(ctx context.Context, profile *Profile) (*Account, } var account Account - err := c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil) + _, err := c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil) if err != nil { return nil, err } @@ -84,53 +84,43 @@ func (c *Client) AccountUpdate(ctx context.Context, profile *Profile) (*Account, } // GetAccountStatuses return statuses by specified accuont. -func (c *Client) GetAccountStatuses(ctx context.Context, id int64) ([]*Status, error) { +func (c *Client) GetAccountStatuses(ctx context.Context, id int64, pg *Pagination) ([]*Status, *Pagination, error) { var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/statuses", id), nil, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/statuses", id), nil, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // GetAccountFollowers return followers list. -func (c *Client) GetAccountFollowers(ctx context.Context, id int64) ([]*Account, error) { - params := url.Values{} - var total []*Account - for { - var accounts []*Account - var next bool - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/followers", id), params, &accounts, &next) - if err != nil { - return nil, err - } - total = append(total, accounts...) - if !next { - break - } - time.Sleep(c.interval) +func (c *Client) GetAccountFollowers(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) { + var accounts []*Account + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/followers", id), nil, &accounts, pg) + if err != nil { + return nil, nil, err } - return total, nil + return accounts, retPG, nil } // GetAccountFollowing return following list. -func (c *Client) GetAccountFollowing(ctx context.Context, id int64) ([]*Account, error) { +func (c *Client) GetAccountFollowing(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } // GetBlocks return block list. -func (c *Client) GetBlocks(ctx context.Context) ([]*Account, error) { +func (c *Client) GetBlocks(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, "/api/v1/blocks", nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/blocks", nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } // Relationship hold information for relation-ship to the account. @@ -146,7 +136,7 @@ type Relationship struct { // AccountFollow follow the account. func (c *Client) AccountFollow(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/follow", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/follow", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -156,7 +146,7 @@ func (c *Client) AccountFollow(ctx context.Context, id int64) (*Relationship, er // AccountUnfollow unfollow the account. func (c *Client) AccountUnfollow(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unfollow", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unfollow", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -166,7 +156,7 @@ func (c *Client) AccountUnfollow(ctx context.Context, id int64) (*Relationship, // AccountBlock block the account. func (c *Client) AccountBlock(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/block", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/block", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -176,7 +166,7 @@ func (c *Client) AccountBlock(ctx context.Context, id int64) (*Relationship, err // AccountUnblock unblock the account. func (c *Client) AccountUnblock(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unblock", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unblock", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -186,7 +176,7 @@ func (c *Client) AccountUnblock(ctx context.Context, id int64) (*Relationship, e // AccountMute mute the account. func (c *Client) AccountMute(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/mute", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/mute", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -196,7 +186,7 @@ func (c *Client) AccountMute(ctx context.Context, id int64) (*Relationship, erro // AccountUnmute unmute the account. func (c *Client) AccountUnmute(ctx context.Context, id int64) (*Relationship, error) { var relationship Relationship - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unmute", id), nil, &relationship, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unmute", id), nil, &relationship, nil) if err != nil { return nil, err } @@ -211,7 +201,7 @@ func (c *Client) GetAccountRelationships(ctx context.Context, ids []int64) ([]*R } var relationships []*Relationship - err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/relationships", params, &relationships, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/relationships", params, &relationships, nil) if err != nil { return nil, err } @@ -225,7 +215,7 @@ func (c *Client) AccountsSearch(ctx context.Context, q string, limit int64) ([]* params.Set("limit", fmt.Sprint(limit)) var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/search", params, &accounts, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/search", params, &accounts, nil) if err != nil { return nil, err } @@ -238,7 +228,7 @@ func (c *Client) FollowRemoteUser(ctx context.Context, uri string) (*Account, er params.Set("uri", uri) var account Account - err := c.doAPI(ctx, http.MethodPost, "/api/v1/follows", params, &account, nil) + _, err := c.doAPI(ctx, http.MethodPost, "/api/v1/follows", params, &account, nil) if err != nil { return nil, err } @@ -246,31 +236,33 @@ func (c *Client) FollowRemoteUser(ctx context.Context, uri string) (*Account, er } // GetFollowRequests return follow-requests. -func (c *Client) GetFollowRequests(ctx context.Context) ([]*Account, error) { +func (c *Client) GetFollowRequests(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, "/api/v1/follow_requests", nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/follow_requests", nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } // FollowRequestAuthorize is authorize the follow request of user with id. func (c *Client) FollowRequestAuthorize(ctx context.Context, id int64) error { - return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/authorize", id), nil, nil, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/authorize", id), nil, nil, nil) + return err } // FollowRequestReject is rejects the follow request of user with id. func (c *Client) FollowRequestReject(ctx context.Context, id int64) error { - return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/reject", id), nil, nil, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/reject", id), nil, nil, nil) + return err } // GetMutes returns the list of users muted by the current user. -func (c *Client) GetMutes(ctx context.Context) ([]*Account, error) { +func (c *Client) GetMutes(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, "/api/v1/mutes", nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/mutes", nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } diff --git a/accounts_test.go b/accounts_test.go index cc05d1b..f4dc8d6 100644 --- a/accounts_test.go +++ b/accounts_test.go @@ -25,11 +25,11 @@ func TestGetAccount(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - a, err := client.GetAccount(context.Background(), 1) + _, err := client.GetAccount(context.Background(), 1) if err == nil { t.Fatalf("should be fail: %v", err) } - a, err = client.GetAccount(context.Background(), 1234567) + a, err := client.GetAccount(context.Background(), 1234567) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -113,6 +113,7 @@ func TestGetAccountStatuses(t *testing.T) { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } + //w.Header().Set("Link", `; rel="next", ; rel="prev"`) fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`) return })) @@ -124,11 +125,11 @@ func TestGetAccountStatuses(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetAccountStatuses(context.Background(), 123) + _, _, err := client.GetAccountStatuses(context.Background(), 123, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - ss, err := client.GetAccountStatuses(context.Background(), 1234567) + ss, _, err := client.GetAccountStatuses(context.Background(), 1234567, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -157,11 +158,11 @@ func TestGetAccountFollowers(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetAccountFollowers(context.Background(), 123) + _, _, err := client.GetAccountFollowers(context.Background(), 123, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - fl, err := client.GetAccountFollowers(context.Background(), 1234567) + fl, _, err := client.GetAccountFollowers(context.Background(), 1234567, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -193,11 +194,11 @@ func TestGetAccountFollowing(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetAccountFollowing(context.Background(), 123) + _, _, err := client.GetAccountFollowing(context.Background(), 123, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - fl, err := client.GetAccountFollowing(context.Background(), 1234567) + fl, _, err := client.GetAccountFollowing(context.Background(), 1234567, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -231,11 +232,11 @@ func TestGetBlocks(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetBlocks(context.Background()) + _, _, err := client.GetBlocks(context.Background(), nil) if err == nil { t.Fatalf("should be fail: %v", err) } - bl, err := client.GetBlocks(context.Background()) + bl, _, err := client.GetBlocks(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -566,11 +567,11 @@ func TestGetFollowRequests(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetFollowRequests(context.Background()) + _, _, err := client.GetFollowRequests(context.Background(), nil) if err == nil { t.Fatalf("should be fail: %v", err) } - fReqs, err := client.GetFollowRequests(context.Background()) + fReqs, _, err := client.GetFollowRequests(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -652,11 +653,11 @@ func TestGetMutes(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetMutes(context.Background()) + _, _, err := client.GetMutes(context.Background(), nil) if err == nil { t.Fatalf("should be fail: %v", err) } - mutes, err := client.GetMutes(context.Background()) + mutes, _, err := client.GetMutes(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } diff --git a/example_test.go b/example_test.go index 307b6d5..1d85b25 100644 --- a/example_test.go +++ b/example_test.go @@ -32,7 +32,7 @@ func ExampleClient() { if err != nil { log.Fatal(err) } - timeline, err := c.GetTimelineHome(context.Background()) + timeline, _, err := c.GetTimelineHome(context.Background(), nil) if err != nil { log.Fatal(err) } diff --git a/helper.go b/helper.go index 05af20f..281f5a2 100644 --- a/helper.go +++ b/helper.go @@ -37,6 +37,9 @@ func Base64Encode(file *os.File) (string, error) { ";base64," + base64.StdEncoding.EncodeToString(d), nil } +// Int64 is a helper function to get the pointer value of a int64. +func Int64(v int64) *int64 { return &v } + // String is a helper function to get the pointer value of a string. func String(v string) *string { return &v } diff --git a/instance.go b/instance.go index 9b45c25..43c455c 100644 --- a/instance.go +++ b/instance.go @@ -16,7 +16,7 @@ type Instance struct { // GetInstance return Instance. func (c *Client) GetInstance(ctx context.Context) (*Instance, error) { var instance Instance - err := c.doAPI(ctx, http.MethodGet, "/api/v1/instance", nil, &instance, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/instance", nil, &instance, nil) if err != nil { return nil, err } diff --git a/mastodon.go b/mastodon.go index 16ccb08..b352e32 100644 --- a/mastodon.go +++ b/mastodon.go @@ -4,6 +4,8 @@ import ( "bytes" "context" "encoding/json" + "errors" + "fmt" "io" "mime/multipart" "net/http" @@ -11,8 +13,10 @@ import ( "os" "path" "path/filepath" + "strconv" "strings" - "time" + + "github.com/tomnomnom/linkheader" ) // Config is a setting for access mastodon APIs. @@ -26,64 +30,13 @@ type Config struct { // Client is a API client for mastodon. type Client struct { http.Client - config *Config - interval time.Duration + config *Config } -type page struct { - next string -} - -func linkHeader(h http.Header, rel string) []string { - var links []string - for _, v := range h["Link"] { - var p string - for len(v) > 0 { - i := strings.Index(v, ";") - if i < 0 { - break - } - e := i - i++ - for i < len(v) { - if v[i] != ' ' { - break - } - i++ - } - p = strings.TrimSpace(v[i:]) - if !strings.HasPrefix(p, "rel=") { - break - } - i += 4 - pos := strings.Index(p[4:], `,`) - if pos > 0 { - p = p[4 : 4+pos] - i += pos - } else { - p = p[4:] - i = len(v) - 1 - } - if k := strings.Trim(p, `"`); k == rel { - links = append(links, strings.Trim(v[:e], "<>")) - } - i++ - for i < len(v) { - if v[i] != ' ' { - break - } - i++ - } - v = v[i:] - } - } - return links -} - -func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, next *bool) error { +func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) (*Pagination, error) { u, err := url.Parse(c.config.Server) if err != nil { - return err + return nil, err } u.Path = path.Join(u.Path, uri) @@ -92,18 +45,18 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in if values, ok := params.(url.Values); ok { var body io.Reader if method == http.MethodGet { - u.RawQuery = values.Encode() + u.RawQuery = pg.setValues(values).Encode() } else { body = strings.NewReader(values.Encode()) } req, err = http.NewRequest(method, u.String(), body) if err != nil { - return err + return nil, err } } else if file, ok := params.(string); ok { f, err := os.Open(file) if err != nil { - return err + return nil, err } defer f.Close() @@ -111,25 +64,25 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in mw := multipart.NewWriter(&buf) part, err := mw.CreateFormFile("file", filepath.Base(file)) if err != nil { - return err + return nil, err } _, err = io.Copy(part, f) if err != nil { - return err + return nil, err } err = mw.Close() if err != nil { - return err + return nil, err } req, err = http.NewRequest(method, u.String(), &buf) if err != nil { - return err + return nil, err } ct = mw.FormDataContentType() } else { req, err = http.NewRequest(method, u.String(), nil) if err != nil { - return err + return nil, err } } req = req.WithContext(ctx) @@ -140,37 +93,32 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in resp, err := c.Do(req) if err != nil { - return err + return nil, err } defer resp.Body.Close() - if next != nil && params != nil { - nl := linkHeader(resp.Header, "next") - *next = false - if len(nl) > 0 { - u, err = url.Parse(nl[0]) - if err == nil { - for k, v := range u.Query() { - params.(url.Values)[k] = v - } - } - *next = true + lh := resp.Header.Get("Link") + var retPG *Pagination + if lh != "" { + retPG, err = newPagination(lh) + if err != nil { + return nil, err } } + if resp.StatusCode != http.StatusOK { - return parseAPIError("bad request", resp) + return nil, parseAPIError("bad request", resp) } else if res == nil { - return nil + return nil, nil } - return json.NewDecoder(resp.Body).Decode(&res) + return retPG, json.NewDecoder(resp.Body).Decode(&res) } // NewClient return new mastodon API client. func NewClient(config *Config) *Client { return &Client{ - Client: *http.DefaultClient, - config: config, - interval: 10 * time.Second, + Client: *http.DefaultClient, + config: config, } } @@ -257,3 +205,66 @@ type Results struct { Statuses []*Status `json:"statuses"` Hashtags []string `json:"hashtags"` } + +// Pagination is a struct for specifying the get range. +type Pagination struct { + MaxID *int64 + SinceID *int64 + Limit *int64 +} + +func newPagination(rawlink string) (*Pagination, error) { + if rawlink == "" { + return nil, errors.New("empty link header") + } + + p := &Pagination{} + for _, link := range linkheader.Parse(rawlink) { + switch link.Rel { + case "next": + maxID, err := getPaginationID(link.URL, "max_id") + if err != nil { + return nil, err + } + p.MaxID = &maxID + case "prev": + sinceID, err := getPaginationID(link.URL, "since_id") + if err != nil { + return nil, err + } + p.SinceID = &sinceID + } + } + + return p, nil +} + +func getPaginationID(rawurl, key string) (int64, error) { + u, err := url.Parse(rawurl) + if err != nil { + return 0, err + } + + id, err := strconv.ParseInt(u.Query().Get(key), 10, 64) + if err != nil { + return 0, err + } + + return id, nil +} + +func (p *Pagination) setValues(params url.Values) url.Values { + if p != nil { + if p.MaxID != nil { + params.Set("max_id", fmt.Sprint(p.MaxID)) + } + if p.SinceID != nil { + params.Set("since_id", fmt.Sprint(p.SinceID)) + } + if p.Limit != nil { + params.Set("limit", fmt.Sprint(p.Limit)) + } + } + + return params +} diff --git a/mastodon_test.go b/mastodon_test.go index e0bf960..0eb376a 100644 --- a/mastodon_test.go +++ b/mastodon_test.go @@ -6,7 +6,6 @@ import ( "io" "net/http" "net/http/httptest" - "reflect" "testing" "time" ) @@ -153,7 +152,7 @@ func TestGetTimelineHome(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - tl, err := client.GetTimelineHome(context.Background()) + tl, _, err := client.GetTimelineHome(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -183,7 +182,7 @@ func TestGetTimelineHomeWithCancel(t *testing.T) { }) ctx, cancel := context.WithCancel(context.Background()) cancel() - _, err := client.GetTimelineHome(ctx) + _, _, err := client.GetTimelineHome(ctx, nil) if err == nil { t.Fatalf("should be fail: %v", err) } @@ -199,48 +198,3 @@ func TestForTheCoverages(t *testing.T) { (*ErrorEvent)(nil).event() _ = (&ErrorEvent{io.EOF}).Error() } - -func TestLinkHeader(t *testing.T) { - tests := []struct { - header []string - rel string - want []string - }{ - { - header: []string{`; rel="foo"`}, - rel: "boo", - want: nil, - }, - { - header: []string{`; rel="foo"`}, - rel: "foo", - want: []string{"http://example.com/?max_id=3"}, - }, - { - header: []string{`; rel="foo1"`}, - rel: "foo", - want: nil, - }, - { - header: []string{`; rel="foo", ; rel="bar"`}, - rel: "foo", - want: []string{"http://example.com/?max_id=3"}, - }, - { - header: []string{`; rel="foo", ; rel="bar"`}, - rel: "bar", - want: []string{"http://example.com/?max_id=4"}, - }, - } - - for _, test := range tests { - h := make(http.Header) - for _, he := range test.header { - h.Add("Link", he) - } - got := linkHeader(h, test.rel) - if !reflect.DeepEqual(got, test.want) { - t.Fatalf("want %v but %v", test.want, got) - } - } -} diff --git a/notification.go b/notification.go index a25f3f0..5df3485 100644 --- a/notification.go +++ b/notification.go @@ -17,19 +17,19 @@ type Notification struct { } // GetNotifications return notifications. -func (c *Client) GetNotifications(ctx context.Context) ([]*Notification, error) { +func (c *Client) GetNotifications(ctx context.Context, pg *Pagination) ([]*Notification, *Pagination, error) { var notifications []*Notification - err := c.doAPI(ctx, http.MethodGet, "/api/v1/notifications", nil, ¬ifications, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/notifications", nil, ¬ifications, pg) if err != nil { - return nil, err + return nil, nil, err } - return notifications, nil + return notifications, retPG, nil } // GetNotification return notification. func (c *Client) GetNotification(ctx context.Context, id int64) (*Notification, error) { var notification Notification - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/notifications/%d", id), nil, ¬ification, nil) + _, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/notifications/%d", id), nil, ¬ification, nil) if err != nil { return nil, err } @@ -38,5 +38,6 @@ func (c *Client) GetNotification(ctx context.Context, id int64) (*Notification, // ClearNotifications clear notifications. func (c *Client) ClearNotifications(ctx context.Context) error { - return c.doAPI(ctx, http.MethodPost, "/api/v1/notifications/clear", nil, nil, nil) + _, err := c.doAPI(ctx, http.MethodPost, "/api/v1/notifications/clear", nil, nil, nil) + return err } diff --git a/notification_test.go b/notification_test.go index 87f0e32..2459b1e 100644 --- a/notification_test.go +++ b/notification_test.go @@ -32,7 +32,7 @@ func TestGetNotifications(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - ns, err := client.GetNotifications(context.Background()) + ns, _, err := client.GetNotifications(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } diff --git a/report.go b/report.go index 1e6debf..dd9c461 100644 --- a/report.go +++ b/report.go @@ -16,7 +16,7 @@ type Report struct { // GetReports return report of the current user. func (c *Client) GetReports(ctx context.Context) ([]*Report, error) { var reports []*Report - err := c.doAPI(ctx, http.MethodGet, "/api/v1/reports", nil, &reports, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/reports", nil, &reports, nil) if err != nil { return nil, err } @@ -32,7 +32,7 @@ func (c *Client) Report(ctx context.Context, accountID int64, ids []int64, comme } params.Set("comment", comment) var report Report - err := c.doAPI(ctx, http.MethodPost, "/api/v1/reports", params, &report, nil) + _, err := c.doAPI(ctx, http.MethodPost, "/api/v1/reports", params, &report, nil) if err != nil { return nil, err } diff --git a/status.go b/status.go index dbbed03..74cec09 100644 --- a/status.go +++ b/status.go @@ -48,19 +48,19 @@ type Card struct { } // GetFavourites return the favorite list of the current user. -func (c *Client) GetFavourites(ctx context.Context) ([]*Status, error) { +func (c *Client) GetFavourites(ctx context.Context, pg *Pagination) ([]*Status, *Pagination, error) { var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, "/api/v1/favourites", nil, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/favourites", nil, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // GetStatus return status specified by id. func (c *Client) GetStatus(ctx context.Context, id int64) (*Status, error) { var status Status - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d", id), nil, &status, nil) + _, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d", id), nil, &status, nil) if err != nil { return nil, err } @@ -70,7 +70,7 @@ func (c *Client) GetStatus(ctx context.Context, id int64) (*Status, error) { // GetStatusContext return status specified by id. func (c *Client) GetStatusContext(ctx context.Context, id int64) (*Context, error) { var context Context - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/context", id), nil, &context, nil) + _, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/context", id), nil, &context, nil) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func (c *Client) GetStatusContext(ctx context.Context, id int64) (*Context, erro // GetStatusCard return status specified by id. func (c *Client) GetStatusCard(ctx context.Context, id int64) (*Card, error) { var card Card - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/card", id), nil, &card, nil) + _, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/card", id), nil, &card, nil) if err != nil { return nil, err } @@ -88,29 +88,29 @@ func (c *Client) GetStatusCard(ctx context.Context, id int64) (*Card, error) { } // GetRebloggedBy returns the account list of the user who reblogged the toot of id. -func (c *Client) GetRebloggedBy(ctx context.Context, id int64) ([]*Account, error) { +func (c *Client) GetRebloggedBy(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/reblogged_by", id), nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/reblogged_by", id), nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } // GetFavouritedBy returns the account list of the user who liked the toot of id. -func (c *Client) GetFavouritedBy(ctx context.Context, id int64) ([]*Account, error) { +func (c *Client) GetFavouritedBy(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) { var accounts []*Account - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/favourited_by", id), nil, &accounts, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/favourited_by", id), nil, &accounts, pg) if err != nil { - return nil, err + return nil, nil, err } - return accounts, nil + return accounts, retPG, nil } // Reblog is reblog the toot of id and return status of reblog. func (c *Client) Reblog(ctx context.Context, id int64) (*Status, error) { var status Status - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/reblog", id), nil, &status, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/reblog", id), nil, &status, nil) if err != nil { return nil, err } @@ -120,7 +120,7 @@ func (c *Client) Reblog(ctx context.Context, id int64) (*Status, error) { // Unreblog is unreblog the toot of id and return status of the original toot. func (c *Client) Unreblog(ctx context.Context, id int64) (*Status, error) { var status Status - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unreblog", id), nil, &status, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unreblog", id), nil, &status, nil) if err != nil { return nil, err } @@ -130,7 +130,7 @@ func (c *Client) Unreblog(ctx context.Context, id int64) (*Status, error) { // Favourite is favourite the toot of id and return status of the favourite toot. func (c *Client) Favourite(ctx context.Context, id int64) (*Status, error) { var status Status - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/favourite", id), nil, &status, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/favourite", id), nil, &status, nil) if err != nil { return nil, err } @@ -140,7 +140,7 @@ func (c *Client) Favourite(ctx context.Context, id int64) (*Status, error) { // Unfavourite is unfavourite the toot of id and return status of the unfavourite toot. func (c *Client) Unfavourite(ctx context.Context, id int64) (*Status, error) { var status Status - err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unfavourite", id), nil, &status, nil) + _, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unfavourite", id), nil, &status, nil) if err != nil { return nil, err } @@ -148,48 +148,48 @@ func (c *Client) Unfavourite(ctx context.Context, id int64) (*Status, error) { } // GetTimelineHome return statuses from home timeline. -func (c *Client) GetTimelineHome(ctx context.Context) ([]*Status, error) { +func (c *Client) GetTimelineHome(ctx context.Context, pg *Pagination) ([]*Status, *Pagination, error) { var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/home", nil, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/home", nil, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // GetTimelinePublic return statuses from public timeline. -func (c *Client) GetTimelinePublic(ctx context.Context, isLocal bool) ([]*Status, error) { +func (c *Client) GetTimelinePublic(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) { params := url.Values{} if isLocal { params.Set("local", "t") } var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // GetTimelineHashtag return statuses from tagged timeline. -func (c *Client) GetTimelineHashtag(ctx context.Context, tag string, isLocal bool) ([]*Status, error) { +func (c *Client) GetTimelineHashtag(ctx context.Context, tag string, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) { params := url.Values{} if isLocal { params.Set("local", "t") } var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/tag/%s", url.PathEscape(tag)), params, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/tag/%s", url.PathEscape(tag)), params, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // GetTimelineMedia return statuses from media timeline. // NOTE: This is an experimental feature of pawoo.net. -func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool) ([]*Status, error) { +func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) { params := url.Values{} params.Set("media", "t") if isLocal { @@ -197,11 +197,11 @@ func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool) ([]*Status, } var statuses []*Status - err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, nil) + retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg) if err != nil { - return nil, err + return nil, nil, err } - return statuses, nil + return statuses, retPG, nil } // PostStatus post the toot. @@ -227,7 +227,7 @@ func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) { } var status Status - err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil) + _, err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil) if err != nil { return nil, err } @@ -236,7 +236,8 @@ func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) { // DeleteStatus delete the toot. func (c *Client) DeleteStatus(ctx context.Context, id int64) error { - return c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/statuses/%d", id), nil, nil, nil) + _, err := c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/statuses/%d", id), nil, nil, nil) + return err } // Search search content with query. @@ -245,7 +246,7 @@ func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results, params.Set("q", q) params.Set("resolve", fmt.Sprint(resolve)) var results Results - err := c.doAPI(ctx, http.MethodGet, "/api/v1/search", params, &results, nil) + _, err := c.doAPI(ctx, http.MethodGet, "/api/v1/search", params, &results, nil) if err != nil { return nil, err } @@ -255,7 +256,7 @@ func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results, // UploadMedia upload a media attachment. func (c *Client) UploadMedia(ctx context.Context, file string) (*Attachment, error) { var attachment Attachment - err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil) + _, err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil) if err != nil { return nil, err } diff --git a/status_test.go b/status_test.go index bc4eed6..3e7d7b3 100644 --- a/status_test.go +++ b/status_test.go @@ -21,7 +21,7 @@ func TestGetFavourites(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - favs, err := client.GetFavourites(context.Background()) + favs, _, err := client.GetFavourites(context.Background(), nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -152,11 +152,11 @@ func TestGetRebloggedBy(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetRebloggedBy(context.Background(), 123) + _, _, err := client.GetRebloggedBy(context.Background(), 123, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - rbs, err := client.GetRebloggedBy(context.Background(), 1234567) + rbs, _, err := client.GetRebloggedBy(context.Background(), 1234567, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -188,11 +188,11 @@ func TestGetFavouritedBy(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetFavouritedBy(context.Background(), 123) + _, _, err := client.GetFavouritedBy(context.Background(), 123, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - fbs, err := client.GetFavouritedBy(context.Background(), 1234567) + fbs, _, err := client.GetFavouritedBy(context.Background(), 1234567, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -338,11 +338,11 @@ func TestGetTimelinePublic(t *testing.T) { defer ts.Close() client := NewClient(&Config{Server: ts.URL}) - _, err := client.GetTimelinePublic(context.Background(), false) + _, _, err := client.GetTimelinePublic(context.Background(), false, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - tl, err := client.GetTimelinePublic(context.Background(), true) + tl, _, err := client.GetTimelinePublic(context.Background(), true, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -374,11 +374,11 @@ func TestGetTimelineHashtag(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetTimelineHashtag(context.Background(), "notfound", false) + _, _, err := client.GetTimelineHashtag(context.Background(), "notfound", false, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - tags, err := client.GetTimelineHashtag(context.Background(), "zzz", true) + tags, _, err := client.GetTimelineHashtag(context.Background(), "zzz", true, nil) if err != nil { t.Fatalf("should not be fail: %v", err) } @@ -410,11 +410,11 @@ func TestGetTimelineMedia(t *testing.T) { ClientSecret: "bar", AccessToken: "zoo", }) - _, err := client.GetTimelineMedia(context.Background(), false) + _, _, err := client.GetTimelineMedia(context.Background(), false, nil) if err == nil { t.Fatalf("should be fail: %v", err) } - tags, err := client.GetTimelineMedia(context.Background(), true) + tags, _, err := client.GetTimelineMedia(context.Background(), true, nil) if err != nil { t.Fatalf("should not be fail: %v", err) }