diff --git a/comment.go b/comment.go index cf6b140..a0c670e 100644 --- a/comment.go +++ b/comment.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" "net/url" + "strings" ) // CommentService handles communication with the comment @@ -78,19 +79,16 @@ func (s *CommentService) LoadMoreReplies(ctx context.Context, comment *Comment) postID := comment.PostID commentIDs := comment.Replies.More.Children - type params struct { - PostID string `url:"link_id"` - IDs []string `url:"children,comma"` - APIType string `url:"api_type"` - } + form := url.Values{} + form.Set("api_type", "json") + form.Set("link_id", postID) + form.Set("children", strings.Join(commentIDs, ",")) path := "api/morechildren" - path, err := addOptions(path, params{postID, commentIDs, "json"}) - if err != nil { - return nil, err - } - req, err := s.client.NewRequest(http.MethodGet, path, nil) + // This was originally a GET, but with POST you can send a bigger payload + // since it's in the body and not the URI. + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) if err != nil { return nil, err } diff --git a/comment_test.go b/comment_test.go index 95de9d0..69040d1 100644 --- a/comment_test.go +++ b/comment_test.go @@ -301,3 +301,49 @@ func TestCommentService_RemoveVote(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) } + +func TestCommentService_LoadMoreReplies(t *testing.T) { + setup() + defer teardown() + + blob, err := readFileContents("testdata/comment/more.json") + require.NoError(t, err) + + mux.HandleFunc("/api/morechildren", func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("link_id", "t3_123") + form.Set("children", "def,ghi,jkl") + form.Set("api_type", "json") + + err := r.ParseForm() + require.NoError(t, err) + require.Equal(t, form, r.PostForm) + + fmt.Fprint(w, blob) + }) + + _, err = client.Comment.LoadMoreReplies(ctx, nil) + require.EqualError(t, err, "comment: cannot be nil") + + resp, err := client.Comment.LoadMoreReplies(ctx, &Comment{}) + require.Nil(t, resp) + require.Nil(t, err) + + comment := &Comment{ + FullID: "t1_abc", + PostID: "t3_123", + Replies: Replies{ + More: &More{ + Children: []string{"def", "ghi", "jkl"}, + }, + }, + } + + _, err = client.Comment.LoadMoreReplies(ctx, comment) + require.Nil(t, err) + require.False(t, comment.HasMore()) + require.Len(t, comment.Replies.Comments, 2) + require.Len(t, comment.Replies.Comments[0].Replies.Comments, 1) +} diff --git a/post.go b/post.go index ced6f9b..4947d93 100644 --- a/post.go +++ b/post.go @@ -471,7 +471,7 @@ func (s *PostService) LoadMoreComments(ctx context.Context, pc *PostAndComments) } postID := pc.Post.FullID - commentIDs := pc.MoreComments.Children + commentIDs := pc.More.Children form := url.Values{} form.Set("api_type", "json") @@ -515,7 +515,7 @@ func (s *PostService) LoadMoreComments(ctx context.Context, pc *PostAndComments) } if noMore { - pc.MoreComments = nil + pc.More = nil } return resp, nil diff --git a/post_test.go b/post_test.go index 8d56c95..9044628 100644 --- a/post_test.go +++ b/post_test.go @@ -820,72 +820,56 @@ func TestPostService_DisableContestMode(t *testing.T) { require.Equal(t, http.StatusOK, res.StatusCode) } -func TestPostService_More(t *testing.T) { +func TestPostService_LoadMoreReplies(t *testing.T) { setup() defer teardown() - parentComment := &Comment{ - FullID: "t1_abc", - ParentID: "t3_123", - PostID: "t3_123", - Replies: Replies{ - More: &More{ - Children: []string{"def,ghi"}, - }, - }, - } - blob, err := readFileContents("testdata/post/more.json") require.NoError(t, err) mux.HandleFunc("/api/morechildren", func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, http.MethodGet, r.Method) + require.Equal(t, http.MethodPost, r.Method) form := url.Values{} form.Set("link_id", "t3_123") - form.Set("children", "def,ghi") + form.Set("children", "def,ghi,jkl") form.Set("api_type", "json") err := r.ParseForm() require.NoError(t, err) - require.Equal(t, form, r.Form) + require.Equal(t, form, r.PostForm) fmt.Fprint(w, blob) }) - _, err = client.Comment.LoadMoreReplies(ctx, parentComment) - require.NoError(t, err) - require.Nil(t, parentComment.Replies.More) - require.Len(t, parentComment.Replies.Comments, 1) - require.Len(t, parentComment.Replies.Comments[0].Replies.Comments, 1) -} + _, err = client.Post.LoadMoreComments(ctx, nil) + require.EqualError(t, err, "pc: cannot be nil") -func TestPostService_MoreNil(t *testing.T) { - setup() - defer teardown() + resp, err := client.Post.LoadMoreComments(ctx, &PostAndComments{}) + require.Nil(t, resp) + require.Nil(t, err) - _, err := client.Comment.LoadMoreReplies(ctx, nil) - require.EqualError(t, err, "comment: cannot be nil") - - parentComment := &Comment{ - Replies: Replies{ - More: nil, + pc := &PostAndComments{ + Post: &Post{ + FullID: "t3_123", + }, + Comments: []*Comment{ + { + FullID: "t1_abc", + }, + }, + More: &More{ + Children: []string{"def", "ghi", "jkl"}, }, } - // should return nil, nil since comment does not have More struct - resp, err := client.Comment.LoadMoreReplies(ctx, parentComment) + _, err = client.Post.LoadMoreComments(ctx, pc) require.NoError(t, err) - require.Nil(t, resp) - - parentComment.Replies.More = &More{ - Children: []string{}, - } - - // should return nil, nil since comment's More struct has 0 children - resp, err = client.Comment.LoadMoreReplies(ctx, parentComment) - require.NoError(t, err) - require.Nil(t, resp) + require.False(t, pc.HasMore()) + require.Len(t, pc.Comments, 2) + require.True(t, pc.Comments[1].HasMore()) + require.Len(t, pc.Comments[0].Replies.Comments, 1) + require.Len(t, pc.Comments[0].Replies.Comments[0].Replies.Comments, 1) } func TestPostService_RandomFromSubreddits(t *testing.T) { @@ -1162,6 +1146,9 @@ func TestPostService_MarkVisited(t *testing.T) { require.Equal(t, form, r.PostForm) }) - _, err := client.Post.MarkVisited(ctx, "t3_test1", "t3_test2", "t3_test3") + _, err := client.Post.MarkVisited(ctx) + require.EqualError(t, err, "must provide at least 1 id") + + _, err = client.Post.MarkVisited(ctx, "t3_test1", "t3_test2", "t3_test3") require.NoError(t, err) } diff --git a/testdata/comment/more.json b/testdata/comment/more.json new file mode 100644 index 0000000..58c60d8 --- /dev/null +++ b/testdata/comment/more.json @@ -0,0 +1,222 @@ +{ + "json": { + "errors": [], + "data": { + "things": [ + { + "kind": "t1", + "data": { + "total_awards_received": 0, + "approved_at_utc": null, + "edited": false, + "mod_reason_by": null, + "banned_by": null, + "author_flair_type": "text", + "removal_reason": null, + "link_id": "t3_123", + "author_flair_template_id": null, + "likes": null, + "replies": "", + "user_reports": [], + "saved": false, + "id": "def", + "banned_at_utc": null, + "mod_reason_title": null, + "gilded": 0, + "archived": false, + "no_follow": false, + "author": "testuser1", + "can_mod_post": false, + "send_replies": true, + "parent_id": "t1_abc", + "score": 5, + "author_fullname": "t2_user1", + "approved_by": null, + "mod_note": null, + "all_awardings": [], + "subreddit_id": "t5_2qh1i", + "body": "Wow, I came here to say exactly this and figured it would be buried. Pleasantly shocked to see your comment as the top comment! So. Good. Thanks, random internet friend!", + "awarders": [], + "downs": 0, + "author_flair_css_class": null, + "name": "t1_def", + "author_patreon_flair": false, + "collapsed": false, + "author_flair_richtext": [], + "is_submitter": false, + "body_html": "<div class=\"md\"><p>Wow, I came here to say exactly this and figured it would be buried. Pleasantly shocked to see your comment as the top comment! So. Good. Thanks, random internet friend!</p>\n</div>", + "gildings": {}, + "collapsed_reason": null, + "distinguished": null, + "associated_award": null, + "stickied": false, + "author_premium": false, + "can_gild": true, + "top_awarded_type": null, + "author_flair_text_color": null, + "score_hidden": false, + "permalink": "/r/AskReddit/comments/123/which_scene_from_an_animated_film_will_always_be/def/", + "num_reports": null, + "locked": false, + "report_reasons": null, + "created": 1595301409.0, + "subreddit": "AskReddit", + "author_flair_text": null, + "treatment_tags": [], + "created_utc": 1595272609.0, + "subreddit_name_prefixed": "r/AskReddit", + "controversiality": 0, + "depth": 1, + "author_flair_background_color": null, + "collapsed_because_crowd_control": null, + "mod_reports": [], + "subreddit_type": "public", + "ups": 5 + } + }, + { + "kind": "t1", + "data": { + "total_awards_received": 0, + "approved_at_utc": null, + "edited": false, + "mod_reason_by": null, + "banned_by": null, + "author_flair_type": "text", + "removal_reason": null, + "link_id": "t3_123", + "author_flair_template_id": null, + "likes": null, + "replies": "", + "user_reports": [], + "saved": false, + "id": "ghi", + "banned_at_utc": null, + "mod_reason_title": null, + "gilded": 0, + "archived": false, + "no_follow": true, + "author": "testuser2", + "can_mod_post": false, + "send_replies": true, + "parent_id": "t1_abc", + "score": 1, + "author_fullname": "t2_user2", + "approved_by": null, + "mod_note": null, + "all_awardings": [], + "subreddit_id": "t5_2qh1i", + "body": "Oh my god yes best movie ever love that scene", + "awarders": [], + "downs": 0, + "author_flair_css_class": null, + "name": "t1_ghi", + "author_patreon_flair": false, + "collapsed": false, + "author_flair_richtext": [], + "is_submitter": false, + "body_html": "<div class=\"md\"><p>Oh my god yes best movie ever love that scene</p>\n</div>", + "gildings": {}, + "collapsed_reason": null, + "distinguished": null, + "associated_award": null, + "stickied": false, + "author_premium": false, + "can_gild": true, + "top_awarded_type": null, + "author_flair_text_color": null, + "score_hidden": false, + "permalink": "/r/AskReddit/comments/123/which_scene_from_an_animated_film_will_always_be/ghi/", + "num_reports": null, + "locked": false, + "report_reasons": null, + "created": 1595308578.0, + "subreddit": "AskReddit", + "author_flair_text": null, + "treatment_tags": [], + "created_utc": 1595279778.0, + "subreddit_name_prefixed": "r/AskReddit", + "controversiality": 0, + "depth": 1, + "author_flair_background_color": null, + "collapsed_because_crowd_control": null, + "mod_reports": [], + "subreddit_type": "public", + "ups": 1 + } + }, + { + "kind": "t1", + "data": { + "total_awards_received": 0, + "approved_at_utc": null, + "edited": false, + "mod_reason_by": null, + "banned_by": null, + "author_flair_type": "text", + "removal_reason": null, + "link_id": "t3_123", + "author_flair_template_id": null, + "likes": null, + "replies": "", + "user_reports": [], + "saved": false, + "id": "jkl", + "banned_at_utc": null, + "mod_reason_title": null, + "gilded": 0, + "archived": false, + "no_follow": true, + "author": "testuser2", + "can_mod_post": false, + "send_replies": true, + "parent_id": "t1_def", + "score": 1, + "author_fullname": "t2_user2", + "approved_by": null, + "mod_note": null, + "all_awardings": [], + "subreddit_id": "t5_2qh1i", + "body": "Hello this is a test", + "awarders": [], + "downs": 0, + "author_flair_css_class": null, + "name": "t1_jkl", + "author_patreon_flair": false, + "collapsed": false, + "author_flair_richtext": [], + "is_submitter": false, + "body_html": "<div class=\"md\"><p>Hello this is a test</p>\n</div>", + "gildings": {}, + "collapsed_reason": null, + "distinguished": null, + "associated_award": null, + "stickied": false, + "author_premium": false, + "can_gild": true, + "top_awarded_type": null, + "author_flair_text_color": null, + "score_hidden": false, + "permalink": "/r/AskReddit/comments/123/which_scene_from_an_animated_film_will_always_be/ghi/", + "num_reports": null, + "locked": false, + "report_reasons": null, + "created": 1595308578.0, + "subreddit": "AskReddit", + "author_flair_text": null, + "treatment_tags": [], + "created_utc": 1595279778.0, + "subreddit_name_prefixed": "r/AskReddit", + "controversiality": 0, + "depth": 1, + "author_flair_background_color": null, + "collapsed_because_crowd_control": null, + "mod_reports": [], + "subreddit_type": "public", + "ups": 1 + } + } + ] + } + } +} diff --git a/testdata/post/more.json b/testdata/post/more.json index 0837487..052be77 100644 --- a/testdata/post/more.json +++ b/testdata/post/more.json @@ -144,6 +144,88 @@ "subreddit_type": "public", "ups": 1 } + }, + { + "kind": "t1", + "data": { + "total_awards_received": 0, + "approved_at_utc": null, + "edited": false, + "mod_reason_by": null, + "banned_by": null, + "author_flair_type": "text", + "removal_reason": null, + "link_id": "t3_123", + "author_flair_template_id": null, + "likes": null, + "replies": "", + "user_reports": [], + "saved": false, + "id": "jkl", + "banned_at_utc": null, + "mod_reason_title": null, + "gilded": 0, + "archived": false, + "no_follow": true, + "author": "testuser2", + "can_mod_post": false, + "send_replies": true, + "parent_id": "t3_123", + "score": 1, + "author_fullname": "t2_user2", + "approved_by": null, + "mod_note": null, + "all_awardings": [], + "subreddit_id": "t5_2qh1i", + "body": "Hello this is a test", + "awarders": [], + "downs": 0, + "author_flair_css_class": null, + "name": "t1_jkl", + "author_patreon_flair": false, + "collapsed": false, + "author_flair_richtext": [], + "is_submitter": false, + "body_html": "<div class=\"md\"><p>Hello this is a test</p>\n</div>", + "gildings": {}, + "collapsed_reason": null, + "distinguished": null, + "associated_award": null, + "stickied": false, + "author_premium": false, + "can_gild": true, + "top_awarded_type": null, + "author_flair_text_color": null, + "score_hidden": false, + "permalink": "/r/AskReddit/comments/123/which_scene_from_an_animated_film_will_always_be/ghi/", + "num_reports": null, + "locked": false, + "report_reasons": null, + "created": 1595308578.0, + "subreddit": "AskReddit", + "author_flair_text": null, + "treatment_tags": [], + "created_utc": 1595279778.0, + "subreddit_name_prefixed": "r/AskReddit", + "controversiality": 0, + "depth": 1, + "author_flair_background_color": null, + "collapsed_because_crowd_control": null, + "mod_reports": [], + "subreddit_type": "public", + "ups": 1 + } + }, + { + "kind": "more", + "data": { + "count": 1, + "name": "t1_fye3844", + "id": "fye3844", + "parent_id": "t1_jkl", + "depth": 6, + "children": ["fye3844"] + } } ] } diff --git a/things.go b/things.go index 517bce7..2e9560e 100644 --- a/things.go +++ b/things.go @@ -221,7 +221,7 @@ func (r *Replies) UnmarshalJSON(data []byte) error { } r.Comments = root.Data.Things.Comments - r.More = root.getFirstMoreComments() + r.More = root.getFirstMore() return nil } @@ -311,11 +311,7 @@ func (l *rootListing) getComments() *Comments { } } -func (l *rootListing) getMoreComments() []*More { - return l.Data.Things.Mores -} - -func (l *rootListing) getFirstMoreComments() *More { +func (l *rootListing) getFirstMore() *More { if len(l.Data.Things.Mores) == 0 { return nil } @@ -391,9 +387,9 @@ type ModActions struct { // PostAndComments is a post and its comments. type PostAndComments struct { - Post *Post `json:"post"` - Comments []*Comment `json:"comments"` - MoreComments *More `json:"-"` + Post *Post `json:"post"` + Comments []*Comment `json:"comments"` + More *More `json:"-"` } // UnmarshalJSON implements the json.Unmarshaler interface. @@ -410,18 +406,18 @@ func (pc *PostAndComments) UnmarshalJSON(data []byte) error { post := l[0].getPosts().Posts[0] comments := l[1].getComments().Comments - moreComments := l[1].getFirstMoreComments() + moreComments := l[1].getFirstMore() pc.Post = post pc.Comments = comments - pc.MoreComments = moreComments + pc.More = moreComments return nil } // HasMore determines whether the post has more replies to load in its reply tree. func (pc *PostAndComments) HasMore() bool { - return pc.MoreComments != nil && len(pc.MoreComments.Children) > 0 + return pc.More != nil && len(pc.More.Children) > 0 } func (pc *PostAndComments) addCommentToTree(comment *Comment) { @@ -437,7 +433,7 @@ func (pc *PostAndComments) addCommentToTree(comment *Comment) { func (pc *PostAndComments) addMoreToTree(more *More) { if pc.Post.FullID == more.ParentID { - pc.MoreComments = more + pc.More = more } for _, reply := range pc.Comments {