diff --git a/comment.go b/comment.go index 343916e..0f49eba 100644 --- a/comment.go +++ b/comment.go @@ -10,20 +10,26 @@ import ( // CommentService handles communication with the comment // related methods of the Reddit API. +// +// Reddit API docs: https://www.reddit.com/dev/api/#section_links_and_comments type CommentService service -func (s *CommentService) isCommentID(id string) bool { - return strings.HasPrefix(id, kindComment+"_") +func (s *CommentService) validateCommentID(id string) error { + if strings.HasPrefix(id, kindComment+"_") { + return nil + } + return fmt.Errorf("comment id %s does not start with %s_", id, kindComment) } -// Submit submits a comment as a reply to a post or to another comment. -func (s *CommentService) Submit(ctx context.Context, id string, text string) (*Comment, *Response, error) { +// Submit submits a comment as a reply to a post, comment, or message. +// parentID is the full ID of the thing being replied to. +func (s *CommentService) Submit(ctx context.Context, parentID string, text string) (*Comment, *Response, error) { path := "api/comment" form := url.Values{} form.Set("api_type", "json") form.Set("return_rtjson", "true") - form.Set("parent", id) + form.Set("parent", parentID) form.Set("text", text) req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) @@ -40,13 +46,8 @@ func (s *CommentService) Submit(ctx context.Context, id string, text string) (*C return root, resp, nil } -// Edit edits the comment with the id provided. -// todo: don't forget to do this for posts +// Edit edits a comment. func (s *CommentService) Edit(ctx context.Context, id string, text string) (*Comment, *Response, error) { - if !s.isCommentID(id) { - return nil, nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) - } - path := "api/editusertext" form := url.Values{} @@ -68,76 +69,3 @@ func (s *CommentService) Edit(ctx context.Context, id string, text string) (*Com return root, resp, nil } - -// Delete deletes a comment via the id. -// todo: don't forget to do this for posts. -func (s *CommentService) Delete(ctx context.Context, id string) (*Response, error) { - if !s.isCommentID(id) { - return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) - } - - path := "api/del" - - form := url.Values{} - form.Set("id", id) - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// Save saves a comment. -func (s *CommentService) Save(ctx context.Context, id string) (*Response, error) { - if !s.isCommentID(id) { - return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) - } - - path := "api/save" - - form := url.Values{} - form.Set("id", id) - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// Unsave unsaves a comment. -func (s *CommentService) Unsave(ctx context.Context, id string) (*Response, error) { - if !s.isCommentID(id) { - return nil, fmt.Errorf("must provide comment id (starting with t1_); id provided: %q", id) - } - - path := "api/unsave" - - form := url.Values{} - form.Set("id", id) - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} diff --git a/comment_test.go b/comment_test.go index 83f47a7..70393fd 100644 --- a/comment_test.go +++ b/comment_test.go @@ -87,81 +87,7 @@ func TestCommentService_Edit(t *testing.T) { fmt.Fprint(w, blob) }) - _, _, err := client.Comment.Edit(ctx, "t3_test", "test comment") - assert.EqualError(t, err, `must provide comment id (starting with t1_); id provided: "t3_test"`) - comment, _, err := client.Comment.Edit(ctx, "t1_test", "test comment") assert.NoError(t, err) assert.Equal(t, expectedCommentSubmitOrEdit, comment) } - -func TestCommentService_Delete(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/del", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t1_test") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - - fmt.Fprint(w, `{}`) - }) - - _, err := client.Comment.Delete(ctx, "t3_test") - assert.EqualError(t, err, `must provide comment id (starting with t1_); id provided: "t3_test"`) - - res, err := client.Comment.Delete(ctx, "t1_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -} - -func TestCommentService_Save(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/save", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t1_test") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - }) - - _, err := client.Comment.Save(ctx, "t3_test") - assert.EqualError(t, err, `must provide comment id (starting with t1_); id provided: "t3_test"`) - - res, err := client.Comment.Save(ctx, "t1_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -} - -func TestCommentService_Unsave(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/unsave", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t1_test") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - }) - - _, err := client.Comment.Unsave(ctx, "t3_test") - assert.EqualError(t, err, `must provide comment id (starting with t1_); id provided: "t3_test"`) - - res, err := client.Comment.Unsave(ctx, "t1_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -} diff --git a/geddit.go b/geddit.go index 864cdd9..222c685 100644 --- a/geddit.go +++ b/geddit.go @@ -94,17 +94,17 @@ type Client struct { // Reuse a single struct instead of allocating one for each service on the heap. common service - Account *AccountService - Comment *CommentService - Flair *FlairService - Listings *ListingsService - Moderation *ModerationService - Multi *MultiService - Post *PostService - Search *SearchService - Subreddit *SubredditService - User *UserService - Vote *VoteService + Account *AccountService + Comment *CommentService + Flair *FlairService + Listings *ListingsService + Moderation *ModerationService + Multi *MultiService + Post *PostService + PostAndComment *PostAndCommentService + Search *SearchService + Subreddit *SubredditService + User *UserService oauth2Transport *oauth2.Transport @@ -138,10 +138,10 @@ func newClient(httpClient *http.Client) *Client { c.Moderation = (*ModerationService)(&c.common) c.Multi = (*MultiService)(&c.common) c.Post = (*PostService)(&c.common) + c.PostAndComment = (*PostAndCommentService)(&c.common) c.Search = (*SearchService)(&c.common) c.Subreddit = (*SubredditService)(&c.common) c.User = (*UserService)(&c.common) - c.Vote = (*VoteService)(&c.common) return c } diff --git a/geddit_test.go b/geddit_test.go index dec2fba..4ab5036 100644 --- a/geddit_test.go +++ b/geddit_test.go @@ -70,11 +70,13 @@ func testClientServices(t *testing.T, c *Client) { "Comment", "Flair", "Listings", + "Moderation", + "Multi", "Post", + "PostAndComment", "Search", "Subreddit", "User", - "Vote", } cp := reflect.ValueOf(c) diff --git a/post-and-comment.go b/post-and-comment.go new file mode 100644 index 0000000..42d33e1 --- /dev/null +++ b/post-and-comment.go @@ -0,0 +1,162 @@ +package reddit + +import ( + "context" + "fmt" + "net/http" + "net/url" +) + +// PostAndCommentService handles communication with the post and comment +// related methods of the Reddit API. +// This service holds functionality common to both posts and comments. +// +// Reddit API docs: https://www.reddit.com/dev/api/#section_links_and_comments +type PostAndCommentService service + +type vote int + +// Reddit interprets -1, 0, 1 as downvote, no vote, and upvote, respectively. +const ( + downvote vote = iota - 1 + novote + upvote +) + +// Delete deletes a post or comment via its full ID. +func (s *PostAndCommentService) Delete(ctx context.Context, id string) (*Response, error) { + path := "api/del" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Save saves a post or comment. +func (s *PostAndCommentService) Save(ctx context.Context, id string) (*Response, error) { + path := "api/save" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Unsave unsaves a post or comment. +func (s *PostAndCommentService) Unsave(ctx context.Context, id string) (*Response, error) { + path := "api/unsave" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// EnableReplies enables inbox replies for one of your posts or comments. +func (s *PostAndCommentService) EnableReplies(ctx context.Context, id string) (*Response, error) { + path := "api/sendreplies" + + form := url.Values{} + form.Set("id", id) + form.Set("state", "true") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// DisableReplies dsables inbox replies for one of your posts or comments. +func (s *PostAndCommentService) DisableReplies(ctx context.Context, id string) (*Response, error) { + path := "api/sendreplies" + + form := url.Values{} + form.Set("id", id) + form.Set("state", "false") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Lock locks a post or comment, preventing it from receiving new comments. +func (s *PostAndCommentService) Lock(ctx context.Context, id string) (*Response, error) { + path := "api/lock" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Unlock unlocks a post or comment, allowing it to receive new comments. +func (s *PostAndCommentService) Unlock(ctx context.Context, id string) (*Response, error) { + path := "api/unlock" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +func (s *PostAndCommentService) vote(ctx context.Context, id string, vote vote) (*Response, error) { + path := "api/vote" + + form := url.Values{} + form.Set("id", id) + form.Set("dir", fmt.Sprint(vote)) + form.Set("rank", "10") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Upvote upvotes a post or a comment. +func (s *PostAndCommentService) Upvote(ctx context.Context, id string) (*Response, error) { + return s.vote(ctx, id, upvote) +} + +// Downvote downvotes a post or a comment. +func (s *PostAndCommentService) Downvote(ctx context.Context, id string) (*Response, error) { + return s.vote(ctx, id, downvote) +} + +// RemoveVote removes your vote on a post or a comment. +func (s *PostAndCommentService) RemoveVote(ctx context.Context, id string) (*Response, error) { + return s.vote(ctx, id, novote) +} diff --git a/post-and-comment_test.go b/post-and-comment_test.go new file mode 100644 index 0000000..614f86a --- /dev/null +++ b/post-and-comment_test.go @@ -0,0 +1,218 @@ +package reddit + +import ( + "fmt" + "net/http" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPostAndCommentService_Delete(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/del", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Delete(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Save(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/save", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Save(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Unsave(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/unsave", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Unsave(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_EnableReplies(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/sendreplies", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + form.Set("state", "true") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.EnableReplies(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_DisableReplies(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/sendreplies", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + form.Set("state", "false") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.DisableReplies(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Lock(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/lock", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Lock(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Unlock(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/unlock", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Unlock(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Upvote(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + form.Set("dir", fmt.Sprint(upvote)) + form.Set("rank", "10") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Upvote(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_Downvote(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + form.Set("dir", fmt.Sprint(downvote)) + form.Set("rank", "10") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.Downvote(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostAndCommentService_RemoveVote(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + form.Set("dir", fmt.Sprint(novote)) + form.Set("rank", "10") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.PostAndComment.RemoveVote(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} diff --git a/post.go b/post.go index 70a902e..9a58a4b 100644 --- a/post.go +++ b/post.go @@ -12,6 +12,8 @@ import ( // PostService handles communication with the post // related methods of the Reddit API. +// +// Reddit API docs: https://www.reddit.com/dev/api/#section_links_and_comments type PostService service type submittedLinkRoot struct { @@ -27,8 +29,8 @@ type Submitted struct { URL string `json:"url,omitempty"` } -// SubmitSelfOptions are options used for selftext posts. -type SubmitSelfOptions struct { +// SubmitTextOptions are options used for text posts. +type SubmitTextOptions struct { Subreddit string `url:"sr,omitempty"` Title string `url:"title,omitempty"` Text string `url:"text,omitempty"` @@ -41,8 +43,8 @@ type SubmitSelfOptions struct { Spoiler bool `url:"spoiler,omitempty"` } -// SubmitURLOptions are options used for link posts. -type SubmitURLOptions struct { +// SubmitLinkOptions are options used for link posts. +type SubmitLinkOptions struct { Subreddit string `url:"sr,omitempty"` Title string `url:"title,omitempty"` URL string `url:"url,omitempty"` @@ -56,24 +58,6 @@ type SubmitURLOptions struct { Spoiler bool `url:"spoiler,omitempty"` } -// SubmitSelf submits a self text post. -func (s *PostService) SubmitSelf(ctx context.Context, opts SubmitSelfOptions) (*Submitted, *Response, error) { - type submit struct { - SubmitSelfOptions - Kind string `url:"kind,omitempty"` - } - return s.submit(ctx, &submit{opts, "self"}) -} - -// SubmitURL submits a link post. -func (s *PostService) SubmitURL(ctx context.Context, opts SubmitURLOptions) (*Submitted, *Response, error) { - type submit struct { - SubmitURLOptions - Kind string `url:"kind,omitempty"` - } - return s.submit(ctx, &submit{opts, "link"}) -} - func (s *PostService) submit(ctx context.Context, v interface{}) (*Submitted, *Response, error) { path := "api/submit" @@ -97,13 +81,58 @@ func (s *PostService) submit(ctx context.Context, v interface{}) (*Submitted, *R return root.JSON.Data, resp, nil } -// EnableReplies enables inbox replies for a thing created by the client. -func (s *PostService) EnableReplies(ctx context.Context, id string) (*Response, error) { - path := "api/sendreplies" +// SubmitText submits a text post. +func (s *PostService) SubmitText(ctx context.Context, opts SubmitTextOptions) (*Submitted, *Response, error) { + type submit struct { + SubmitTextOptions + Kind string `url:"kind,omitempty"` + } + return s.submit(ctx, &submit{opts, "self"}) +} + +// SubmitLink submits a link post. +func (s *PostService) SubmitLink(ctx context.Context, opts SubmitLinkOptions) (*Submitted, *Response, error) { + type submit struct { + SubmitLinkOptions + Kind string `url:"kind,omitempty"` + } + return s.submit(ctx, &submit{opts, "link"}) +} + +// Edit edits a post. +func (s *PostService) Edit(ctx context.Context, id string, text string) (*Post, *Response, error) { + path := "api/editusertext" form := url.Values{} - form.Set("id", id) - form.Set("state", "true") + form.Set("api_type", "json") + form.Set("return_rtjson", "true") + form.Set("thing_id", id) + form.Set("text", text) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, nil, err + } + + root := new(Post) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, nil +} + +// Hide hides posts. +func (s *PostService) Hide(ctx context.Context, ids ...string) (*Response, error) { + if len(ids) == 0 { + return nil, errors.New("must provide at least 1 id") + } + + path := "api/hide" + + form := url.Values{} + form.Set("id", strings.Join(ids, ",")) req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) if err != nil { @@ -113,13 +142,16 @@ func (s *PostService) EnableReplies(ctx context.Context, id string) (*Response, return s.client.Do(ctx, req, nil) } -// DisableReplies dsables inbox replies for a thing created by the client. -func (s *PostService) DisableReplies(ctx context.Context, id string) (*Response, error) { - path := "api/sendreplies" +// Unhide unhides posts. +func (s *PostService) Unhide(ctx context.Context, ids ...string) (*Response, error) { + if len(ids) == 0 { + return nil, errors.New("must provide at least 1 id") + } + + path := "api/unhide" form := url.Values{} - form.Set("id", id) - form.Set("state", "false") + form.Set("id", strings.Join(ids, ",")) req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) if err != nil { @@ -188,41 +220,3 @@ func (s *PostService) Unspoiler(ctx context.Context, id string) (*Response, erro return s.client.Do(ctx, req, nil) } - -// Hide hides links with the specified ids. -func (s *PostService) Hide(ctx context.Context, ids ...string) (*Response, error) { - if len(ids) == 0 { - return nil, errors.New("must provide at least 1 id") - } - - path := "api/hide" - - form := url.Values{} - form.Set("id", strings.Join(ids, ",")) - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Unhide unhides links with the specified ids. -func (s *PostService) Unhide(ctx context.Context, ids ...string) (*Response, error) { - if len(ids) == 0 { - return nil, errors.New("must provide at least 1 id") - } - - path := "api/unhide" - - form := url.Values{} - form.Set("id", strings.Join(ids, ",")) - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/post_test.go b/post_test.go index 0099b27..4f09d9c 100644 --- a/post_test.go +++ b/post_test.go @@ -53,3 +53,83 @@ func TestPostService_Unhide(t *testing.T) { assert.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) } + +func TestPostService_MarkNSFW(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/marknsfw", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.Post.MarkNSFW(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostService_UnmarkNSFW(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/unmarknsfw", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.Post.UnmarkNSFW(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostService_Spoiler(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/spoiler", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.Post.Spoiler(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} + +func TestPostService_Unspoiler(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/unspoiler", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t1_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.PostForm) + }) + + res, err := client.Post.Unspoiler(ctx, "t1_test") + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) +} diff --git a/vote.go b/vote.go deleted file mode 100644 index 5734b99..0000000 --- a/vote.go +++ /dev/null @@ -1,54 +0,0 @@ -package reddit - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// VoteService handles communication with the upvote/downvote -// related methods of the Reddit API. -// -// Reddit API docs: https://www.reddit.com/dev/api/#POST_api_vote -type VoteService service - -type vote int - -// Reddit interprets -1, 0, 1 as downvote, no vote, and upvote, respectively. -const ( - downvote vote = iota - 1 - novote - upvote -) - -func (s *VoteService) vote(ctx context.Context, id string, vote vote) (*Response, error) { - path := "api/vote" - - form := url.Values{} - form.Set("id", id) - form.Set("dir", fmt.Sprint(vote)) - form.Set("rank", "10") - - req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Up upvotes a post or a comment. -func (s *VoteService) Up(ctx context.Context, id string) (*Response, error) { - return s.vote(ctx, id, upvote) -} - -// Down downvotes a post or a comment. -func (s *VoteService) Down(ctx context.Context, id string) (*Response, error) { - return s.vote(ctx, id, downvote) -} - -// Remove removes the user's vote on a post or a comment. -func (s *VoteService) Remove(ctx context.Context, id string) (*Response, error) { - return s.vote(ctx, id, novote) -} diff --git a/vote_test.go b/vote_test.go deleted file mode 100644 index 3f01343..0000000 --- a/vote_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package reddit - -import ( - "fmt" - "net/http" - "net/url" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestVoteService_Up(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t3_test") - form.Set("dir", fmt.Sprint(upvote)) - form.Set("rank", "10") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - }) - - res, err := client.Vote.Up(ctx, "t3_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -} - -func TestVoteService_Down(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t3_test") - form.Set("dir", fmt.Sprint(downvote)) - form.Set("rank", "10") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - }) - - res, err := client.Vote.Down(ctx, "t3_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -} - -func TestVoteService_Remove(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/api/vote", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - form := url.Values{} - form.Set("id", "t3_test") - form.Set("dir", fmt.Sprint(novote)) - form.Set("rank", "10") - - err := r.ParseForm() - assert.NoError(t, err) - assert.Equal(t, form, r.PostForm) - }) - - res, err := client.Vote.Remove(ctx, "t3_test") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) -}