diff --git a/account.go b/account.go index 05935dc..5e22055 100644 --- a/account.go +++ b/account.go @@ -2,6 +2,8 @@ package geddit import ( "context" + "encoding/json" + "errors" "net/http" ) @@ -301,3 +303,67 @@ func (s *AccountService) Trophies(ctx context.Context) ([]Trophy, *Response, err return trophies, resp, nil } + +type rootFriendList struct { + Friends []Friendship +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (l *rootFriendList) UnmarshalJSON(b []byte) error { + var resBody []interface{} + err := json.Unmarshal(b, &resBody) + if err != nil { + return err + } + + if len(resBody) == 0 { + return errors.New("unexpected data length received") + } + + data, ok := resBody[0].(map[string]interface{}) + if !ok { + return errors.New("unexpected data type received") + } + + dataMap, ok := data["data"].(map[string]interface{}) + if !ok { + return errors.New("data does not contain expected field") + } + + children, ok := dataMap["children"].([]interface{}) + if !ok { + return errors.New("data does not contain expected field") + } + + byteValue, err := json.Marshal(children) + if err != nil { + return nil + } + + var friends []Friendship + err = json.Unmarshal(byteValue, &friends) + if err != nil { + return err + } + + l.Friends = friends + return nil +} + +// Friends returns a list of your friends. +func (s *AccountService) Friends(ctx context.Context) ([]Friendship, *Response, error) { + path := "prefs/friends" + + req, err := s.client.NewRequest(http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(rootFriendList) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.Friends, resp, nil +} diff --git a/account_test.go b/account_test.go index 4192009..830336b 100644 --- a/account_test.go +++ b/account_test.go @@ -97,6 +97,21 @@ var expectedSettings = &Settings{ EnableVideoAutoplay: Bool(true), } +var expectedFriends = []Friendship{ + { + ID: "r9_1r4879", + Friend: "test1", + FriendID: "t2_test1", + Created: &Timestamp{time.Date(2020, 6, 28, 16, 43, 55, 0, time.UTC)}, + }, + { + ID: "r9_1re930", + Friend: "test2", + FriendID: "t2_test2", + Created: &Timestamp{time.Date(2020, 6, 28, 16, 44, 2, 0, time.UTC)}, + }, +} + func TestAccountService_Info(t *testing.T) { setup() defer teardown() @@ -183,3 +198,19 @@ func TestAccountService_Trophies(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expectedTrophies, trophies) } + +func TestAccountService_Friends(t *testing.T) { + setup() + defer teardown() + + blob := readFileContents(t, "testdata/account/friends.json") + + mux.HandleFunc("/prefs/friends", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method) + fmt.Fprint(w, blob) + }) + + friends, _, err := client.Account.Friends(ctx) + assert.NoError(t, err) + assert.Equal(t, expectedFriends, friends) +} diff --git a/testdata/account/friends.json b/testdata/account/friends.json new file mode 100644 index 0000000..f16ad62 --- /dev/null +++ b/testdata/account/friends.json @@ -0,0 +1,27 @@ +[ + { + "kind": "UserList", + "data": { + "children": [ + { + "date": 1593362635, + "rel_id": "r9_1r4879", + "name": "test1", + "id": "t2_test1" + }, + { + "date": 1593362642, + "rel_id": "r9_1re930", + "name": "test2", + "id": "t2_test2" + } + ] + } + }, + { + "kind": "UserList", + "data": { + "children": [] + } + } +] diff --git a/things.go b/things.go index 1a10d7d..8204f05 100644 --- a/things.go +++ b/things.go @@ -3,6 +3,8 @@ package geddit import ( "encoding/json" "errors" + "fmt" + "strings" ) const ( @@ -229,11 +231,14 @@ type Comment struct { PostID string `json:"link_id,omitempty"` - // These don't appear when submitting a comment - PostTitle string `json:"link_title,omitempty"` - PostPermalink string `json:"link_permalink,omitempty"` - PostAuthor string `json:"link_author,omitempty"` - PostNumComments int `json:"num_comments"` + // This doesn't appear when submitting a comment. + PostTitle string `json:"link_title,omitempty"` + // This doesn't appear when submitting a comment. + PostPermalink string `json:"link_permalink,omitempty"` + // This doesn't appear when submitting a comment. + PostAuthor string `json:"link_author,omitempty"` + // This doesn't appear when submitting a comment. + PostNumComments int `json:"num_comments"` IsSubmitter bool `json:"is_submitter"` ScoreHidden bool `json:"score_hidden"` @@ -302,6 +307,18 @@ type Post struct { Stickied bool `json:"stickied"` } +func (p Post) String() string { + chunks := []string{ + fmt.Sprintf("[%d]", p.Score), + p.SubredditNamePrefixed, + "-", + p.Title, + "-", + string(p.Permalink), + } + return strings.Join(chunks, " ") +} + // Subreddit holds information about a subreddit type Subreddit struct { ID string `json:"id,omitempty"`