Reuse common service struct

Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
Vartan Benohanian
2020-06-27 23:53:59 -04:00
parent c8d7abf216
commit 33294aa036
18 changed files with 172 additions and 339 deletions
+8 -19
View File
@@ -7,20 +7,9 @@ import (
// AccountService handles communication with the account // AccountService handles communication with the account
// related methods of the Reddit API. // related methods of the Reddit API.
type AccountService interface { //
Info(ctx context.Context) (*User, *Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#section_account
Karma(ctx context.Context) ([]SubredditKarma, *Response, error) type AccountService service
Settings(ctx context.Context) (*Settings, *Response, error)
UpdateSettings(ctx context.Context, settings *Settings) (*Settings, *Response, error)
Trophies(ctx context.Context) ([]Trophy, *Response, error)
}
// AccountServiceOp implements the AccountService interface.
type AccountServiceOp struct {
client *Client
}
var _ AccountService = &AccountServiceOp{}
type rootSubredditKarma struct { type rootSubredditKarma struct {
Kind string `json:"kind,omitempty"` Kind string `json:"kind,omitempty"`
@@ -219,7 +208,7 @@ type Settings struct {
} }
// Info returns some general information about your account. // Info returns some general information about your account.
func (s *AccountServiceOp) Info(ctx context.Context) (*User, *Response, error) { func (s *AccountService) Info(ctx context.Context) (*User, *Response, error) {
path := "api/v1/me" path := "api/v1/me"
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -237,7 +226,7 @@ func (s *AccountServiceOp) Info(ctx context.Context) (*User, *Response, error) {
} }
// Karma returns a breakdown of your karma per subreddit. // Karma returns a breakdown of your karma per subreddit.
func (s *AccountServiceOp) Karma(ctx context.Context) ([]SubredditKarma, *Response, error) { func (s *AccountService) Karma(ctx context.Context) ([]SubredditKarma, *Response, error) {
path := "api/v1/me/karma" path := "api/v1/me/karma"
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -255,7 +244,7 @@ func (s *AccountServiceOp) Karma(ctx context.Context) ([]SubredditKarma, *Respon
} }
// Settings returns your account settings. // Settings returns your account settings.
func (s *AccountServiceOp) Settings(ctx context.Context) (*Settings, *Response, error) { func (s *AccountService) Settings(ctx context.Context) (*Settings, *Response, error) {
path := "api/v1/me/prefs" path := "api/v1/me/prefs"
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -273,7 +262,7 @@ func (s *AccountServiceOp) Settings(ctx context.Context) (*Settings, *Response,
} }
// UpdateSettings updates your account settings and returns the modified version. // UpdateSettings updates your account settings and returns the modified version.
func (s *AccountServiceOp) UpdateSettings(ctx context.Context, settings *Settings) (*Settings, *Response, error) { func (s *AccountService) UpdateSettings(ctx context.Context, settings *Settings) (*Settings, *Response, error) {
path := "api/v1/me/prefs" path := "api/v1/me/prefs"
req, err := s.client.NewRequest(http.MethodPatch, path, settings) req, err := s.client.NewRequest(http.MethodPatch, path, settings)
@@ -291,7 +280,7 @@ func (s *AccountServiceOp) UpdateSettings(ctx context.Context, settings *Setting
} }
// Trophies returns a list of your trophies. // Trophies returns a list of your trophies.
func (s *AccountServiceOp) Trophies(ctx context.Context) ([]Trophy, *Response, error) { func (s *AccountService) Trophies(ctx context.Context) ([]Trophy, *Response, error) {
path := "api/v1/me/trophies" path := "api/v1/me/trophies"
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
+4 -4
View File
@@ -97,7 +97,7 @@ var expectedSettings = &Settings{
EnableVideoAutoplay: Bool(true), EnableVideoAutoplay: Bool(true),
} }
func TestAccountServiceOp_Info(t *testing.T) { func TestAccountService_Info(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -113,7 +113,7 @@ func TestAccountServiceOp_Info(t *testing.T) {
assert.Equal(t, expectedInfo, info) assert.Equal(t, expectedInfo, info)
} }
func TestAccountServiceOp_Karma(t *testing.T) { func TestAccountService_Karma(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -129,7 +129,7 @@ func TestAccountServiceOp_Karma(t *testing.T) {
assert.Equal(t, expectedKarma, karma) assert.Equal(t, expectedKarma, karma)
} }
func TestAccountServiceOp_Settings(t *testing.T) { func TestAccountService_Settings(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -145,7 +145,7 @@ func TestAccountServiceOp_Settings(t *testing.T) {
assert.Equal(t, expectedSettings, settings) assert.Equal(t, expectedSettings, settings)
} }
func TestAccountServiceOp_UpdateSettings(t *testing.T) { func TestAccountService_UpdateSettings(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
+7 -21
View File
@@ -9,28 +9,14 @@ import (
// CommentService handles communication with the comment // CommentService handles communication with the comment
// related methods of the Reddit API. // related methods of the Reddit API.
type CommentService interface { type CommentService service
Submit(ctx context.Context, id string, text string) (*Comment, *Response, error)
Edit(ctx context.Context, id string, text string) (*Comment, *Response, error)
Delete(ctx context.Context, id string) (*Response, error)
Save(ctx context.Context, id string) (*Response, error) func (s *CommentService) isCommentID(id string) bool {
Unsave(ctx context.Context, id string) (*Response, error)
}
// CommentServiceOp implements the CommentService interface.
type CommentServiceOp struct {
client *Client
}
var _ CommentService = &CommentServiceOp{}
func (s *CommentServiceOp) isCommentID(id string) bool {
return strings.HasPrefix(id, kindComment+"_") return strings.HasPrefix(id, kindComment+"_")
} }
// Submit submits a comment as a reply to a post or to another comment. // Submit submits a comment as a reply to a post or to another comment.
func (s *CommentServiceOp) Submit(ctx context.Context, id string, text string) (*Comment, *Response, error) { func (s *CommentService) Submit(ctx context.Context, id string, text string) (*Comment, *Response, error) {
path := "api/comment" path := "api/comment"
form := url.Values{} form := url.Values{}
@@ -55,7 +41,7 @@ func (s *CommentServiceOp) Submit(ctx context.Context, id string, text string) (
// Edit edits the comment with the id provided. // Edit edits the comment with the id provided.
// todo: don't forget to do this for posts // todo: don't forget to do this for posts
func (s *CommentServiceOp) Edit(ctx context.Context, id string, text string) (*Comment, *Response, error) { func (s *CommentService) Edit(ctx context.Context, id string, text string) (*Comment, *Response, error) {
if !s.isCommentID(id) { if !s.isCommentID(id) {
return nil, nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) return nil, nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id)
} }
@@ -84,7 +70,7 @@ func (s *CommentServiceOp) Edit(ctx context.Context, id string, text string) (*C
// Delete deletes a comment via the id. // Delete deletes a comment via the id.
// todo: don't forget to do this for posts. // todo: don't forget to do this for posts.
func (s *CommentServiceOp) Delete(ctx context.Context, id string) (*Response, error) { func (s *CommentService) Delete(ctx context.Context, id string) (*Response, error) {
if !s.isCommentID(id) { if !s.isCommentID(id) {
return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id)
} }
@@ -108,7 +94,7 @@ func (s *CommentServiceOp) Delete(ctx context.Context, id string) (*Response, er
} }
// Save saves a comment. // Save saves a comment.
func (s *CommentServiceOp) Save(ctx context.Context, id string) (*Response, error) { func (s *CommentService) Save(ctx context.Context, id string) (*Response, error) {
if !s.isCommentID(id) { if !s.isCommentID(id) {
return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id) return nil, fmt.Errorf("must provide comment id (starting with %s_); id provided: %q", kindComment, id)
} }
@@ -132,7 +118,7 @@ func (s *CommentServiceOp) Save(ctx context.Context, id string) (*Response, erro
} }
// Unsave unsaves a comment. // Unsave unsaves a comment.
func (s *CommentServiceOp) Unsave(ctx context.Context, id string) (*Response, error) { func (s *CommentService) Unsave(ctx context.Context, id string) (*Response, error) {
if !s.isCommentID(id) { if !s.isCommentID(id) {
return nil, fmt.Errorf("must provide comment id (starting with t1_); id provided: %q", id) return nil, fmt.Errorf("must provide comment id (starting with t1_); id provided: %q", id)
} }
+9 -13
View File
@@ -38,11 +38,11 @@ var expectedCommentSubmitOrEdit = &Comment{
PostID: "t3_link1", PostID: "t3_link1",
} }
func TestCommentServiceOp_Submit(t *testing.T) { func TestCommentService_Submit(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
commentBlob := readFileContents(t, "testdata/comment-submit-edit.json") blob := readFileContents(t, "testdata/comment-submit-edit.json")
mux.HandleFunc("/api/comment", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/api/comment", func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, http.MethodPost, r.Method)
@@ -57,7 +57,7 @@ func TestCommentServiceOp_Submit(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, commentBlob) fmt.Fprint(w, blob)
}) })
comment, _, err := client.Comment.Submit(ctx, "t1_test", "test comment") comment, _, err := client.Comment.Submit(ctx, "t1_test", "test comment")
@@ -65,11 +65,11 @@ func TestCommentServiceOp_Submit(t *testing.T) {
assert.Equal(t, expectedCommentSubmitOrEdit, comment) assert.Equal(t, expectedCommentSubmitOrEdit, comment)
} }
func TestCommentServiceOp_Edit(t *testing.T) { func TestCommentService_Edit(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
commentBlob := readFileContents(t, "testdata/comment-submit-edit.json") blob := readFileContents(t, "testdata/comment-submit-edit.json")
mux.HandleFunc("/api/editusertext", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/api/editusertext", func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, http.MethodPost, r.Method)
@@ -84,7 +84,7 @@ func TestCommentServiceOp_Edit(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, commentBlob) fmt.Fprint(w, blob)
}) })
_, _, err := client.Comment.Edit(ctx, "t3_test", "test comment") _, _, err := client.Comment.Edit(ctx, "t3_test", "test comment")
@@ -95,7 +95,7 @@ func TestCommentServiceOp_Edit(t *testing.T) {
assert.Equal(t, expectedCommentSubmitOrEdit, comment) assert.Equal(t, expectedCommentSubmitOrEdit, comment)
} }
func TestCommentServiceOp_Delete(t *testing.T) { func TestCommentService_Delete(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -120,7 +120,7 @@ func TestCommentServiceOp_Delete(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, http.StatusOK, res.StatusCode)
} }
func TestCommentServiceOp_Save(t *testing.T) { func TestCommentService_Save(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -133,8 +133,6 @@ func TestCommentServiceOp_Save(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
_, err := client.Comment.Save(ctx, "t3_test") _, err := client.Comment.Save(ctx, "t3_test")
@@ -145,7 +143,7 @@ func TestCommentServiceOp_Save(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, http.StatusOK, res.StatusCode)
} }
func TestCommentServiceOp_Unsave(t *testing.T) { func TestCommentService_Unsave(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -158,8 +156,6 @@ func TestCommentServiceOp_Unsave(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
_, err := client.Comment.Unsave(ctx, "t3_test") _, err := client.Comment.Unsave(ctx, "t3_test")
+7 -15
View File
@@ -6,19 +6,11 @@ import (
"net/http" "net/http"
) )
// FlairService handles communication with the user // FlairService handles communication with the flair
// related methods of the Reddit API // related methods of the Reddit API.
type FlairService interface { //
GetFromSubreddit(ctx context.Context, name string) ([]Flair, *Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#section_flair
GetFromSubredditV2(ctx context.Context, name string) ([]FlairV2, *Response, error) type FlairService service
}
// FlairServiceOp implements the FlairService interface
type FlairServiceOp struct {
client *Client
}
var _ FlairService = &FlairServiceOp{}
// Flair is a flair on Reddit // Flair is a flair on Reddit
type Flair struct { type Flair struct {
@@ -38,7 +30,7 @@ type FlairV2 struct {
} }
// GetFromSubreddit returns the flairs from the subreddit // GetFromSubreddit returns the flairs from the subreddit
func (s *FlairServiceOp) GetFromSubreddit(ctx context.Context, name string) ([]Flair, *Response, error) { func (s *FlairService) GetFromSubreddit(ctx context.Context, name string) ([]Flair, *Response, error) {
path := fmt.Sprintf("r/%s/api/user_flair", name) path := fmt.Sprintf("r/%s/api/user_flair", name)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -56,7 +48,7 @@ func (s *FlairServiceOp) GetFromSubreddit(ctx context.Context, name string) ([]F
} }
// GetFromSubredditV2 returns the flairs from the subreddit // GetFromSubredditV2 returns the flairs from the subreddit
func (s *FlairServiceOp) GetFromSubredditV2(ctx context.Context, name string) ([]FlairV2, *Response, error) { func (s *FlairService) GetFromSubredditV2(ctx context.Context, name string) ([]FlairV2, *Response, error) {
path := fmt.Sprintf("r/%s/api/user_flair_v2", name) path := fmt.Sprintf("r/%s/api/user_flair_v2", name)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
+6 -6
View File
@@ -40,15 +40,15 @@ var expectedFlairsV2 = []FlairV2{
}, },
} }
func TestFlairServiceOp_GetFlairs(t *testing.T) { func TestFlairService_GetFlairs(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
flairsBlob := readFileContents(t, "testdata/flairs.json") blob := readFileContents(t, "testdata/flairs.json")
mux.HandleFunc("/r/subreddit/api/user_flair", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/r/subreddit/api/user_flair", func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method) assert.Equal(t, http.MethodGet, r.Method)
fmt.Fprint(w, flairsBlob) fmt.Fprint(w, blob)
}) })
flairs, _, err := client.Flair.GetFromSubreddit(ctx, "subreddit") flairs, _, err := client.Flair.GetFromSubreddit(ctx, "subreddit")
@@ -56,15 +56,15 @@ func TestFlairServiceOp_GetFlairs(t *testing.T) {
assert.Equal(t, expectedFlairs, flairs) assert.Equal(t, expectedFlairs, flairs)
} }
func TestFlairServiceOp_GetFlairsV2(t *testing.T) { func TestFlairService_GetFlairsV2(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
flairsV2Blob := readFileContents(t, "testdata/flairs-v2.json") blob := readFileContents(t, "testdata/flairs-v2.json")
mux.HandleFunc("/r/subreddit/api/user_flair_v2", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/r/subreddit/api/user_flair_v2", func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method) assert.Equal(t, http.MethodGet, r.Method)
fmt.Fprint(w, flairsV2Blob) fmt.Fprint(w, blob)
}) })
flairs, _, err := client.Flair.GetFromSubredditV2(ctx, "subreddit") flairs, _, err := client.Flair.GetFromSubredditV2(ctx, "subreddit")
+26 -18
View File
@@ -91,21 +91,28 @@ type Client struct {
// This is the client's user ID in Reddit's database. // This is the client's user ID in Reddit's database.
redditID string redditID string
Account AccountService // Reuse a single struct instead of allocating one for each service on the heap.
Comment CommentService common service
Flair FlairService
Listings ListingsService Account *AccountService
Post PostService Comment *CommentService
Search SearchService Flair *FlairService
Subreddit SubredditService Listings *ListingsService
User UserService Post *PostService
Vote VoteService Search *SearchService
Subreddit *SubredditService
User *UserService
Vote *VoteService
oauth2Transport *oauth2.Transport oauth2Transport *oauth2.Transport
onRequestCompleted RequestCompletionCallback onRequestCompleted RequestCompletionCallback
} }
type service struct {
client *Client
}
// OnRequestCompleted sets the client's request completion callback. // OnRequestCompleted sets the client's request completion callback.
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) { func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
c.onRequestCompleted = rc c.onRequestCompleted = rc
@@ -121,15 +128,16 @@ func newClient(httpClient *http.Client) *Client {
c := &Client{client: httpClient, BaseURL: baseURL, TokenURL: tokenURL} c := &Client{client: httpClient, BaseURL: baseURL, TokenURL: tokenURL}
c.Account = &AccountServiceOp{client: c} c.common.client = c
c.Comment = &CommentServiceOp{client: c} c.Account = (*AccountService)(&c.common)
c.Flair = &FlairServiceOp{client: c} c.Comment = (*CommentService)(&c.common)
c.Listings = &ListingsServiceOp{client: c} c.Flair = (*FlairService)(&c.common)
c.Post = &PostServiceOp{client: c} c.Listings = (*ListingsService)(&c.common)
c.Search = &SearchServiceOp{client: c} c.Post = (*PostService)(&c.common)
c.Subreddit = &SubredditServiceOp{client: c} c.Search = (*SearchService)(&c.common)
c.User = &UserServiceOp{client: c} c.Subreddit = (*SubredditService)(&c.common)
c.Vote = &VoteServiceOp{client: c} c.User = (*UserService)(&c.common)
c.Vote = (*VoteService)(&c.common)
return c return c
} }
+2
View File
@@ -66,10 +66,12 @@ func readFileContents(t *testing.T, filepath string) string {
func testClientServices(t *testing.T, c *Client) { func testClientServices(t *testing.T, c *Client) {
services := []string{ services := []string{
"Account",
"Comment", "Comment",
"Flair", "Flair",
"Listings", "Listings",
"Post", "Post",
"Search",
"Subreddit", "Subreddit",
"User", "User",
"Vote", "Vote",
+7 -16
View File
@@ -8,23 +8,14 @@ import (
"strings" "strings"
) )
// ListingsService handles communication with the post // ListingsService handles communication with the listing
// related methods of the Reddit API. // related methods of the Reddit API.
type ListingsService interface { //
Get(ctx context.Context, ids ...string) ([]Post, []Comment, []Subreddit, *Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#section_listings
GetPosts(ctx context.Context, ids ...string) ([]Post, *Response, error) type ListingsService service
GetPost(ctx context.Context, id string) (*PostAndComments, *Response, error)
}
// ListingsServiceOp implements the Vote interface.
type ListingsServiceOp struct {
client *Client
}
var _ ListingsService = &ListingsServiceOp{}
// Get returns posts, comments, and subreddits from their IDs. // Get returns posts, comments, and subreddits from their IDs.
func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) ([]Post, []Comment, []Subreddit, *Response, error) { func (s *ListingsService) Get(ctx context.Context, ids ...string) ([]Post, []Comment, []Subreddit, *Response, error) {
type query struct { type query struct {
IDs []string `url:"id,comma"` IDs []string `url:"id,comma"`
} }
@@ -54,7 +45,7 @@ func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) ([]Post, []C
} }
// GetPosts returns posts from their full IDs. // GetPosts returns posts from their full IDs.
func (s *ListingsServiceOp) GetPosts(ctx context.Context, ids ...string) ([]Post, *Response, error) { func (s *ListingsService) GetPosts(ctx context.Context, ids ...string) ([]Post, *Response, error) {
if len(ids) == 0 { if len(ids) == 0 {
return nil, nil, errors.New("must provide at least 1 id") return nil, nil, errors.New("must provide at least 1 id")
} }
@@ -77,7 +68,7 @@ func (s *ListingsServiceOp) GetPosts(ctx context.Context, ids ...string) ([]Post
// GetPost returns a post with its comments. // GetPost returns a post with its comments.
// The id here is the ID36 of the post, not its full id. // The id here is the ID36 of the post, not its full id.
// Example: instead of t3_abc123, use abc123. // Example: instead of t3_abc123, use abc123.
func (s *ListingsServiceOp) GetPost(ctx context.Context, id string) (*PostAndComments, *Response, error) { func (s *ListingsService) GetPost(ctx context.Context, id string) (*PostAndComments, *Response, error) {
path := fmt.Sprintf("comments/%s", id) path := fmt.Sprintf("comments/%s", id)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
if err != nil { if err != nil {
+13 -35
View File
@@ -9,31 +9,9 @@ import (
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
) )
// PostService handles communication with the link (post) // PostService handles communication with the post
// related methods of the Reddit API. // related methods of the Reddit API.
type PostService interface { type PostService service
SubmitSelf(ctx context.Context, opts SubmitSelfOptions) (*Submitted, *Response, error)
SubmitURL(ctx context.Context, opts SubmitURLOptions) (*Submitted, *Response, error)
EnableReplies(ctx context.Context, id string) (*Response, error)
DisableReplies(ctx context.Context, id string) (*Response, error)
MarkNSFW(ctx context.Context, id string) (*Response, error)
UnmarkNSFW(ctx context.Context, id string) (*Response, error)
Spoiler(ctx context.Context, id string) (*Response, error)
Unspoiler(ctx context.Context, id string) (*Response, error)
Hide(ctx context.Context, ids ...string) (*Response, error)
Unhide(ctx context.Context, ids ...string) (*Response, error)
}
// PostServiceOp implements the PostService interface.
type PostServiceOp struct {
client *Client
}
var _ PostService = &PostServiceOp{}
type submittedLinkRoot struct { type submittedLinkRoot struct {
JSON struct { JSON struct {
@@ -78,7 +56,7 @@ type SubmitURLOptions struct {
} }
// SubmitSelf submits a self text post. // SubmitSelf submits a self text post.
func (s *PostServiceOp) SubmitSelf(ctx context.Context, opts SubmitSelfOptions) (*Submitted, *Response, error) { func (s *PostService) SubmitSelf(ctx context.Context, opts SubmitSelfOptions) (*Submitted, *Response, error) {
type submit struct { type submit struct {
SubmitSelfOptions SubmitSelfOptions
Kind string `url:"kind,omitempty"` Kind string `url:"kind,omitempty"`
@@ -87,7 +65,7 @@ func (s *PostServiceOp) SubmitSelf(ctx context.Context, opts SubmitSelfOptions)
} }
// SubmitURL submits a link post. // SubmitURL submits a link post.
func (s *PostServiceOp) SubmitURL(ctx context.Context, opts SubmitURLOptions) (*Submitted, *Response, error) { func (s *PostService) SubmitURL(ctx context.Context, opts SubmitURLOptions) (*Submitted, *Response, error) {
type submit struct { type submit struct {
SubmitURLOptions SubmitURLOptions
Kind string `url:"kind,omitempty"` Kind string `url:"kind,omitempty"`
@@ -95,7 +73,7 @@ func (s *PostServiceOp) SubmitURL(ctx context.Context, opts SubmitURLOptions) (*
return s.submit(ctx, &submit{opts, "link"}) return s.submit(ctx, &submit{opts, "link"})
} }
func (s *PostServiceOp) submit(ctx context.Context, v interface{}) (*Submitted, *Response, error) { func (s *PostService) submit(ctx context.Context, v interface{}) (*Submitted, *Response, error) {
path := "api/submit" path := "api/submit"
form, err := query.Values(v) form, err := query.Values(v)
@@ -119,7 +97,7 @@ func (s *PostServiceOp) submit(ctx context.Context, v interface{}) (*Submitted,
} }
// EnableReplies enables inbox replies for a thing created by the client. // EnableReplies enables inbox replies for a thing created by the client.
func (s *PostServiceOp) EnableReplies(ctx context.Context, id string) (*Response, error) { func (s *PostService) EnableReplies(ctx context.Context, id string) (*Response, error) {
path := "api/sendreplies" path := "api/sendreplies"
form := url.Values{} form := url.Values{}
@@ -135,7 +113,7 @@ func (s *PostServiceOp) EnableReplies(ctx context.Context, id string) (*Response
} }
// DisableReplies dsables inbox replies for a thing created by the client. // DisableReplies dsables inbox replies for a thing created by the client.
func (s *PostServiceOp) DisableReplies(ctx context.Context, id string) (*Response, error) { func (s *PostService) DisableReplies(ctx context.Context, id string) (*Response, error) {
path := "api/sendreplies" path := "api/sendreplies"
form := url.Values{} form := url.Values{}
@@ -151,7 +129,7 @@ func (s *PostServiceOp) DisableReplies(ctx context.Context, id string) (*Respons
} }
// MarkNSFW marks a post as NSFW. // MarkNSFW marks a post as NSFW.
func (s *PostServiceOp) MarkNSFW(ctx context.Context, id string) (*Response, error) { func (s *PostService) MarkNSFW(ctx context.Context, id string) (*Response, error) {
path := "api/marknsfw" path := "api/marknsfw"
form := url.Values{} form := url.Values{}
@@ -166,7 +144,7 @@ func (s *PostServiceOp) MarkNSFW(ctx context.Context, id string) (*Response, err
} }
// UnmarkNSFW unmarks a post as NSFW. // UnmarkNSFW unmarks a post as NSFW.
func (s *PostServiceOp) UnmarkNSFW(ctx context.Context, id string) (*Response, error) { func (s *PostService) UnmarkNSFW(ctx context.Context, id string) (*Response, error) {
path := "api/unmarknsfw" path := "api/unmarknsfw"
form := url.Values{} form := url.Values{}
@@ -181,7 +159,7 @@ func (s *PostServiceOp) UnmarkNSFW(ctx context.Context, id string) (*Response, e
} }
// Spoiler marks a post as a spoiler. // Spoiler marks a post as a spoiler.
func (s *PostServiceOp) Spoiler(ctx context.Context, id string) (*Response, error) { func (s *PostService) Spoiler(ctx context.Context, id string) (*Response, error) {
path := "api/spoiler" path := "api/spoiler"
form := url.Values{} form := url.Values{}
@@ -196,7 +174,7 @@ func (s *PostServiceOp) Spoiler(ctx context.Context, id string) (*Response, erro
} }
// Unspoiler unmarks a post as a spoiler. // Unspoiler unmarks a post as a spoiler.
func (s *PostServiceOp) Unspoiler(ctx context.Context, id string) (*Response, error) { func (s *PostService) Unspoiler(ctx context.Context, id string) (*Response, error) {
path := "api/unspoiler" path := "api/unspoiler"
form := url.Values{} form := url.Values{}
@@ -211,7 +189,7 @@ func (s *PostServiceOp) Unspoiler(ctx context.Context, id string) (*Response, er
} }
// Hide hides links with the specified ids. // Hide hides links with the specified ids.
func (s *PostServiceOp) Hide(ctx context.Context, ids ...string) (*Response, error) { func (s *PostService) Hide(ctx context.Context, ids ...string) (*Response, error) {
if len(ids) == 0 { if len(ids) == 0 {
return nil, errors.New("must provide at least 1 id") return nil, errors.New("must provide at least 1 id")
} }
@@ -230,7 +208,7 @@ func (s *PostServiceOp) Hide(ctx context.Context, ids ...string) (*Response, err
} }
// Unhide unhides links with the specified ids. // Unhide unhides links with the specified ids.
func (s *PostServiceOp) Unhide(ctx context.Context, ids ...string) (*Response, error) { func (s *PostService) Unhide(ctx context.Context, ids ...string) (*Response, error) {
if len(ids) == 0 { if len(ids) == 0 {
return nil, errors.New("must provide at least 1 id") return nil, errors.New("must provide at least 1 id")
} }
+2 -7
View File
@@ -1,7 +1,6 @@
package geddit package geddit
import ( import (
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
@@ -9,7 +8,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestPostServiceOp_Hide(t *testing.T) { func TestPostService_Hide(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -22,8 +21,6 @@ func TestPostServiceOp_Hide(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
_, err := client.Post.Hide(ctx) _, err := client.Post.Hide(ctx)
@@ -34,7 +31,7 @@ func TestPostServiceOp_Hide(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, http.StatusOK, res.StatusCode)
} }
func TestPostServiceOp_Unhide(t *testing.T) { func TestPostService_Unhide(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -47,8 +44,6 @@ func TestPostServiceOp_Unhide(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
_, err := client.Post.Unhide(ctx) _, err := client.Post.Unhide(ctx)
+12 -20
View File
@@ -9,24 +9,16 @@ import (
) )
// SearchService handles communication with the search // SearchService handles communication with the search
// related methods of the Reddit API // related methods of the Reddit API.
// IMPORTANT: for searches to include NSFW results, the //
// user must check the following in their preferences: // For searches to include NSFW results, the user must
// enable the following setting in their preferences:
// "include not safe for work (NSFW) search results in searches" // "include not safe for work (NSFW) search results in searches"
// Note: The "limit" parameter in searches is prone to inconsistent // Note: The "limit" parameter in searches is prone to inconsistent
// behaviour. // behaviour, e.g. sometimes limit=1 returns nothing when it should.
type SearchService interface { //
Posts(ctx context.Context, query string, subreddits []string, opts ...SearchOptionSetter) (*Posts, *Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#section_search
Subreddits(ctx context.Context, query string, opts ...SearchOptionSetter) (*Subreddits, *Response, error) type SearchService service
Users(ctx context.Context, query string, opts ...SearchOptionSetter) (*Users, *Response, error)
}
// SearchServiceOp implements the VoteService interface
type SearchServiceOp struct {
client *Client
}
var _ SearchService = &SearchServiceOp{}
// SearchOptions define options used in search queries. // SearchOptions define options used in search queries.
type SearchOptions = url.Values type SearchOptions = url.Values
@@ -98,8 +90,8 @@ func setRestrict(opts SearchOptions) {
} }
// Posts searches for posts. // Posts searches for posts.
// If the list of subreddits is empty, the search is run against r/all. // If the list of subreddits provided is empty, the search is run against r/all.
func (s *SearchServiceOp) Posts(ctx context.Context, query string, subreddits []string, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *SearchService) Posts(ctx context.Context, query string, subreddits []string, opts ...SearchOptionSetter) (*Posts, *Response, error) {
opts = append(opts, setType("link"), setQuery(query)) opts = append(opts, setType("link"), setQuery(query))
path := "search" path := "search"
@@ -127,7 +119,7 @@ func (s *SearchServiceOp) Posts(ctx context.Context, query string, subreddits []
// Subreddits searches for subreddits. // Subreddits searches for subreddits.
// The Sort and Timespan options don't affect the results for this search. // The Sort and Timespan options don't affect the results for this search.
func (s *SearchServiceOp) Subreddits(ctx context.Context, query string, opts ...SearchOptionSetter) (*Subreddits, *Response, error) { func (s *SearchService) Subreddits(ctx context.Context, query string, opts ...SearchOptionSetter) (*Subreddits, *Response, error) {
opts = append(opts, setType("sr"), setQuery(query)) opts = append(opts, setType("sr"), setQuery(query))
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
@@ -150,7 +142,7 @@ func (s *SearchServiceOp) Subreddits(ctx context.Context, query string, opts ...
// Users searches for users. // Users searches for users.
// The Sort and Timespan options don't affect the results for this search. // The Sort and Timespan options don't affect the results for this search.
func (s *SearchServiceOp) Users(ctx context.Context, query string, opts ...SearchOptionSetter) (*Users, *Response, error) { func (s *SearchService) Users(ctx context.Context, query string, opts ...SearchOptionSetter) (*Users, *Response, error) {
opts = append(opts, setType("user"), setQuery(query)) opts = append(opts, setType("user"), setQuery(query))
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
+24 -53
View File
@@ -10,39 +10,10 @@ import (
) )
// SubredditService handles communication with the subreddit // SubredditService handles communication with the subreddit
// related methods of the Reddit API // related methods of the Reddit API.
type SubredditService interface { //
GetPosts() *PostFinder // Reddit API docs: https://www.reddit.com/dev/api/#section_subreddits
type SubredditService service
GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error)
GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetGold(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetDefault(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetSubscribed(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetApproved(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetModerated(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
GetSticky1(ctx context.Context, subreddit string) (*PostAndComments, *Response, error)
GetSticky2(ctx context.Context, subreddit string) (*PostAndComments, *Response, error)
Subscribe(ctx context.Context, subreddits ...string) (*Response, error)
SubscribeByID(ctx context.Context, ids ...string) (*Response, error)
Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error)
UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error)
SearchSubredditNames(ctx context.Context, query string) ([]string, *Response, error)
SearchSubredditInfo(ctx context.Context, query string) ([]SubredditShort, *Response, error)
}
// SubredditServiceOp implements the SubredditService interface
type SubredditServiceOp struct {
client *Client
}
var _ SubredditService = &SubredditServiceOp{}
type subredditNamesRoot struct { type subredditNamesRoot struct {
Names []string `json:"names,omitempty"` Names []string `json:"names,omitempty"`
@@ -63,14 +34,14 @@ type SubredditShort struct {
// By default, it'll look for the hottest posts from r/all. // By default, it'll look for the hottest posts from r/all.
// Note: when looking for hot posts in a subreddit, it will include the // Note: when looking for hot posts in a subreddit, it will include the
// sticked posts (if any) PLUS posts from the limit parameter (25 by default). // sticked posts (if any) PLUS posts from the limit parameter (25 by default).
func (s *SubredditServiceOp) GetPosts() *PostFinder { func (s *SubredditService) GetPosts() *PostFinder {
f := new(PostFinder) f := new(PostFinder)
f.client = s.client f.client = s.client
return f.Sort(SortHot).FromAll() return f.Sort(SortHot).FromAll()
} }
// GetByName gets a subreddit by name // GetByName gets a subreddit by name
func (s *SubredditServiceOp) GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error) { func (s *SubredditService) GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error) {
if subreddit == "" { if subreddit == "" {
return nil, nil, errors.New("empty subreddit name provided") return nil, nil, errors.New("empty subreddit name provided")
} }
@@ -91,52 +62,52 @@ func (s *SubredditServiceOp) GetByName(ctx context.Context, subreddit string) (*
} }
// GetPopular returns popular subreddits. // GetPopular returns popular subreddits.
func (s *SubredditServiceOp) GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/popular", opts) return s.getSubreddits(ctx, "subreddits/popular", opts)
} }
// GetNew returns new subreddits. // GetNew returns new subreddits.
func (s *SubredditServiceOp) GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/new", opts) return s.getSubreddits(ctx, "subreddits/new", opts)
} }
// GetGold returns gold subreddits. // GetGold returns gold subreddits.
func (s *SubredditServiceOp) GetGold(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetGold(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/gold", opts) return s.getSubreddits(ctx, "subreddits/gold", opts)
} }
// GetDefault returns default subreddits. // GetDefault returns default subreddits.
func (s *SubredditServiceOp) GetDefault(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetDefault(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/default", opts) return s.getSubreddits(ctx, "subreddits/default", opts)
} }
// GetSubscribed returns the list of subreddits the client is subscribed to. // GetSubscribed returns the list of subreddits the client is subscribed to.
func (s *SubredditServiceOp) GetSubscribed(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetSubscribed(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/mine/subscriber", opts) return s.getSubreddits(ctx, "subreddits/mine/subscriber", opts)
} }
// GetApproved returns the list of subreddits the client is an approved user in. // GetApproved returns the list of subreddits the client is an approved user in.
func (s *SubredditServiceOp) GetApproved(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetApproved(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/mine/contributor", opts) return s.getSubreddits(ctx, "subreddits/mine/contributor", opts)
} }
// GetModerated returns the list of subreddits the client is a moderator of. // GetModerated returns the list of subreddits the client is a moderator of.
func (s *SubredditServiceOp) GetModerated(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) GetModerated(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) {
return s.getSubreddits(ctx, "subreddits/mine/moderator", opts) return s.getSubreddits(ctx, "subreddits/mine/moderator", opts)
} }
// GetSticky1 returns the first stickied post on a subreddit (if it exists). // GetSticky1 returns the first stickied post on a subreddit (if it exists).
func (s *SubredditServiceOp) GetSticky1(ctx context.Context, name string) (*PostAndComments, *Response, error) { func (s *SubredditService) GetSticky1(ctx context.Context, name string) (*PostAndComments, *Response, error) {
return s.getSticky(ctx, name, 1) return s.getSticky(ctx, name, 1)
} }
// GetSticky2 returns the second stickied post on a subreddit (if it exists). // GetSticky2 returns the second stickied post on a subreddit (if it exists).
func (s *SubredditServiceOp) GetSticky2(ctx context.Context, name string) (*PostAndComments, *Response, error) { func (s *SubredditService) GetSticky2(ctx context.Context, name string) (*PostAndComments, *Response, error) {
return s.getSticky(ctx, name, 2) return s.getSticky(ctx, name, 2)
} }
// Subscribe subscribes to subreddits based on their names. // Subscribe subscribes to subreddits based on their names.
func (s *SubredditServiceOp) Subscribe(ctx context.Context, subreddits ...string) (*Response, error) { func (s *SubredditService) Subscribe(ctx context.Context, subreddits ...string) (*Response, error) {
form := url.Values{} form := url.Values{}
form.Set("action", "sub") form.Set("action", "sub")
form.Set("sr_name", strings.Join(subreddits, ",")) form.Set("sr_name", strings.Join(subreddits, ","))
@@ -144,7 +115,7 @@ func (s *SubredditServiceOp) Subscribe(ctx context.Context, subreddits ...string
} }
// SubscribeByID subscribes to subreddits based on their id. // SubscribeByID subscribes to subreddits based on their id.
func (s *SubredditServiceOp) SubscribeByID(ctx context.Context, ids ...string) (*Response, error) { func (s *SubredditService) SubscribeByID(ctx context.Context, ids ...string) (*Response, error) {
form := url.Values{} form := url.Values{}
form.Set("action", "sub") form.Set("action", "sub")
form.Set("sr", strings.Join(ids, ",")) form.Set("sr", strings.Join(ids, ","))
@@ -152,7 +123,7 @@ func (s *SubredditServiceOp) SubscribeByID(ctx context.Context, ids ...string) (
} }
// Unsubscribe unsubscribes from subreddits based on their names. // Unsubscribe unsubscribes from subreddits based on their names.
func (s *SubredditServiceOp) Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error) { func (s *SubredditService) Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error) {
form := url.Values{} form := url.Values{}
form.Set("action", "unsub") form.Set("action", "unsub")
form.Set("sr_name", strings.Join(subreddits, ",")) form.Set("sr_name", strings.Join(subreddits, ","))
@@ -160,7 +131,7 @@ func (s *SubredditServiceOp) Unsubscribe(ctx context.Context, subreddits ...stri
} }
// UnsubscribeByID unsubscribes from subreddits based on their id. // UnsubscribeByID unsubscribes from subreddits based on their id.
func (s *SubredditServiceOp) UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error) { func (s *SubredditService) UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error) {
form := url.Values{} form := url.Values{}
form.Set("action", "unsub") form.Set("action", "unsub")
form.Set("sr", strings.Join(ids, ",")) form.Set("sr", strings.Join(ids, ","))
@@ -168,7 +139,7 @@ func (s *SubredditServiceOp) UnsubscribeByID(ctx context.Context, ids ...string)
} }
// SearchSubredditNames searches for subreddits with names beginning with the query provided. // SearchSubredditNames searches for subreddits with names beginning with the query provided.
func (s *SubredditServiceOp) SearchSubredditNames(ctx context.Context, query string) ([]string, *Response, error) { func (s *SubredditService) SearchSubredditNames(ctx context.Context, query string) ([]string, *Response, error) {
path := fmt.Sprintf("api/search_reddit_names?query=%s", query) path := fmt.Sprintf("api/search_reddit_names?query=%s", query)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -187,7 +158,7 @@ func (s *SubredditServiceOp) SearchSubredditNames(ctx context.Context, query str
// SearchSubredditInfo searches for subreddits with names beginning with the query provided. // SearchSubredditInfo searches for subreddits with names beginning with the query provided.
// They hold a bit more info that just the name, but still not much. // They hold a bit more info that just the name, but still not much.
func (s *SubredditServiceOp) SearchSubredditInfo(ctx context.Context, query string) ([]SubredditShort, *Response, error) { func (s *SubredditService) SearchSubredditInfo(ctx context.Context, query string) ([]SubredditShort, *Response, error) {
path := fmt.Sprintf("api/search_subreddits?query=%s", query) path := fmt.Sprintf("api/search_subreddits?query=%s", query)
req, err := s.client.NewRequest(http.MethodPost, path, nil) req, err := s.client.NewRequest(http.MethodPost, path, nil)
@@ -204,7 +175,7 @@ func (s *SubredditServiceOp) SearchSubredditInfo(ctx context.Context, query stri
return root.Subreddits, resp, nil return root.Subreddits, resp, nil
} }
func (s *SubredditServiceOp) handleSubscription(ctx context.Context, form url.Values) (*Response, error) { func (s *SubredditService) handleSubscription(ctx context.Context, form url.Values) (*Response, error) {
path := "api/subscribe" path := "api/subscribe"
req, err := s.client.NewPostForm(path, form) req, err := s.client.NewPostForm(path, form)
if err != nil { if err != nil {
@@ -219,7 +190,7 @@ func (s *SubredditServiceOp) handleSubscription(ctx context.Context, form url.Va
return resp, nil return resp, nil
} }
func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opts *ListOptions) (*Subreddits, *Response, error) { func (s *SubredditService) getSubreddits(ctx context.Context, path string, opts *ListOptions) (*Subreddits, *Response, error) {
path, err := addOptions(path, opts) path, err := addOptions(path, opts)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -249,7 +220,7 @@ func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opt
// getSticky returns one of the 2 stickied posts of the subreddit (if they exist). // getSticky returns one of the 2 stickied posts of the subreddit (if they exist).
// Num should be equal to 1 or 2, depending on which one you want. // Num should be equal to 1 or 2, depending on which one you want.
func (s *SubredditServiceOp) getSticky(ctx context.Context, subreddit string, num int) (*PostAndComments, *Response, error) { func (s *SubredditService) getSticky(ctx context.Context, subreddit string, num int) (*PostAndComments, *Response, error) {
type query struct { type query struct {
Num int `url:"num"` Num int `url:"num"`
} }
+9 -9
View File
@@ -110,7 +110,7 @@ var expectedSticky = &PostAndComments{
}, },
} }
func TestSubredditServiceOp_GetByName(t *testing.T) { func TestSubredditService_GetByName(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -126,7 +126,7 @@ func TestSubredditServiceOp_GetByName(t *testing.T) {
assert.Equal(t, expectedSubreddit, subreddit) assert.Equal(t, expectedSubreddit, subreddit)
} }
func TestSubredditServiceOp_GetPopular(t *testing.T) { func TestSubredditService_GetPopular(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -142,7 +142,7 @@ func TestSubredditServiceOp_GetPopular(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetNew(t *testing.T) { func TestSubredditService_GetNew(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -158,7 +158,7 @@ func TestSubredditServiceOp_GetNew(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetGold(t *testing.T) { func TestSubredditService_GetGold(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -174,7 +174,7 @@ func TestSubredditServiceOp_GetGold(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetDefault(t *testing.T) { func TestSubredditService_GetDefault(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -190,7 +190,7 @@ func TestSubredditServiceOp_GetDefault(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetSubscribed(t *testing.T) { func TestSubredditService_GetSubscribed(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -206,7 +206,7 @@ func TestSubredditServiceOp_GetSubscribed(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetApproved(t *testing.T) { func TestSubredditService_GetApproved(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -222,7 +222,7 @@ func TestSubredditServiceOp_GetApproved(t *testing.T) {
assert.Equal(t, expectedSubreddits, subreddits) assert.Equal(t, expectedSubreddits, subreddits)
} }
func TestSubredditServiceOp_GetModerated(t *testing.T) { func TestSubredditService_GetModerated(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -239,7 +239,7 @@ func TestSubredditServiceOp_GetModerated(t *testing.T) {
} }
// todo: WIP // todo: WIP
func TestSubredditServiceOp_GetSticky1(t *testing.T) { func TestSubredditService_GetSticky1(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
+26 -64
View File
@@ -9,47 +9,9 @@ import (
// UserService handles communication with the user // UserService handles communication with the user
// related methods of the Reddit API. // related methods of the Reddit API.
type UserService interface { //
Get(ctx context.Context, username string) (*User, *Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#section_users
GetMultipleByID(ctx context.Context, ids ...string) (map[string]*UserShort, *Response, error) type UserService service
UsernameAvailable(ctx context.Context, username string) (bool, *Response, error)
Overview(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error)
OverviewOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error)
Posts(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
PostsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Response, error)
Comments(ctx context.Context, opts ...SearchOptionSetter) (*Comments, *Response, error)
CommentsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Comments, *Response, error)
Saved(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error)
// todo: votes can be public (they're private by default) so make UpvotedOf and DownvotedOf as well
Upvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
Downvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
Hidden(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
Gilded(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
GetFriendship(ctx context.Context, username string) (*Friendship, *Response, error)
Friend(ctx context.Context, username string) (*Friendship, *Response, error)
Unfriend(ctx context.Context, username string) (*Response, error)
Block(ctx context.Context, username string) (*Blocked, *Response, error)
// todo: decide if you wanna keep these
// BlockByID(ctx context.Context, id string) (*Blocked, *Response, error)
Unblock(ctx context.Context, username string) (*Response, error)
// UnblockByID(ctx context.Context, id string) (*Response, error)
Trophies(ctx context.Context) ([]Trophy, *Response, error)
TrophiesOf(ctx context.Context, username string) ([]Trophy, *Response, error)
}
// UserServiceOp implements the UserService interface.
type UserServiceOp struct {
client *Client
}
var _ UserService = &UserServiceOp{}
// User represents a Reddit user. // User represents a Reddit user.
type User struct { type User struct {
@@ -115,7 +77,7 @@ type Trophy struct {
} }
// Get returns information about the user. // Get returns information about the user.
func (s *UserServiceOp) Get(ctx context.Context, username string) (*User, *Response, error) { func (s *UserService) Get(ctx context.Context, username string) (*User, *Response, error) {
path := fmt.Sprintf("user/%s/about", username) path := fmt.Sprintf("user/%s/about", username)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
if err != nil { if err != nil {
@@ -133,7 +95,7 @@ func (s *UserServiceOp) Get(ctx context.Context, username string) (*User, *Respo
// GetMultipleByID returns multiple users from their full IDs. // GetMultipleByID returns multiple users from their full IDs.
// The response body is a map where the keys are the IDs (if they exist), and the value is the user // The response body is a map where the keys are the IDs (if they exist), and the value is the user
func (s *UserServiceOp) GetMultipleByID(ctx context.Context, ids ...string) (map[string]*UserShort, *Response, error) { func (s *UserService) GetMultipleByID(ctx context.Context, ids ...string) (map[string]*UserShort, *Response, error) {
type query struct { type query struct {
IDs []string `url:"ids,omitempty,comma"` IDs []string `url:"ids,omitempty,comma"`
} }
@@ -159,7 +121,7 @@ func (s *UserServiceOp) GetMultipleByID(ctx context.Context, ids ...string) (map
} }
// UsernameAvailable checks whether a username is available for registration. // UsernameAvailable checks whether a username is available for registration.
func (s *UserServiceOp) UsernameAvailable(ctx context.Context, username string) (bool, *Response, error) { func (s *UserService) UsernameAvailable(ctx context.Context, username string) (bool, *Response, error) {
type query struct { type query struct {
User string `url:"user,omitempty"` User string `url:"user,omitempty"`
} }
@@ -185,12 +147,12 @@ func (s *UserServiceOp) UsernameAvailable(ctx context.Context, username string)
} }
// Overview returns a list of the client's posts and comments. // Overview returns a list of the client's posts and comments.
func (s *UserServiceOp) Overview(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) { func (s *UserService) Overview(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) {
return s.OverviewOf(ctx, s.client.Username, opts...) return s.OverviewOf(ctx, s.client.Username, opts...)
} }
// OverviewOf returns a list of the user's posts and comments. // OverviewOf returns a list of the user's posts and comments.
func (s *UserServiceOp) OverviewOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) { func (s *UserService) OverviewOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/overview", username) path := fmt.Sprintf("user/%s/overview", username)
@@ -211,12 +173,12 @@ func (s *UserServiceOp) OverviewOf(ctx context.Context, username string, opts ..
} }
// Posts returns a list of the client's posts. // Posts returns a list of the client's posts.
func (s *UserServiceOp) Posts(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) Posts(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) {
return s.PostsOf(ctx, s.client.Username, opts...) return s.PostsOf(ctx, s.client.Username, opts...)
} }
// PostsOf returns a list of the user's posts. // PostsOf returns a list of the user's posts.
func (s *UserServiceOp) PostsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) PostsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Posts, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/submitted", username) path := fmt.Sprintf("user/%s/submitted", username)
@@ -237,12 +199,12 @@ func (s *UserServiceOp) PostsOf(ctx context.Context, username string, opts ...Se
} }
// Comments returns a list of the client's comments. // Comments returns a list of the client's comments.
func (s *UserServiceOp) Comments(ctx context.Context, opts ...SearchOptionSetter) (*Comments, *Response, error) { func (s *UserService) Comments(ctx context.Context, opts ...SearchOptionSetter) (*Comments, *Response, error) {
return s.CommentsOf(ctx, s.client.Username, opts...) return s.CommentsOf(ctx, s.client.Username, opts...)
} }
// CommentsOf returns a list of the user's comments. // CommentsOf returns a list of the user's comments.
func (s *UserServiceOp) CommentsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Comments, *Response, error) { func (s *UserService) CommentsOf(ctx context.Context, username string, opts ...SearchOptionSetter) (*Comments, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/comments", username) path := fmt.Sprintf("user/%s/comments", username)
@@ -263,7 +225,7 @@ func (s *UserServiceOp) CommentsOf(ctx context.Context, username string, opts ..
} }
// Saved returns a list of the user's saved posts and comments. // Saved returns a list of the user's saved posts and comments.
func (s *UserServiceOp) Saved(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) { func (s *UserService) Saved(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Comments, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/saved", s.client.Username) path := fmt.Sprintf("user/%s/saved", s.client.Username)
@@ -284,7 +246,7 @@ func (s *UserServiceOp) Saved(ctx context.Context, opts ...SearchOptionSetter) (
} }
// Upvoted returns a list of the user's upvoted posts. // Upvoted returns a list of the user's upvoted posts.
func (s *UserServiceOp) Upvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) Upvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/upvoted", s.client.Username) path := fmt.Sprintf("user/%s/upvoted", s.client.Username)
@@ -305,7 +267,7 @@ func (s *UserServiceOp) Upvoted(ctx context.Context, opts ...SearchOptionSetter)
} }
// Downvoted returns a list of the user's downvoted posts. // Downvoted returns a list of the user's downvoted posts.
func (s *UserServiceOp) Downvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) Downvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/downvoted", s.client.Username) path := fmt.Sprintf("user/%s/downvoted", s.client.Username)
@@ -326,7 +288,7 @@ func (s *UserServiceOp) Downvoted(ctx context.Context, opts ...SearchOptionSette
} }
// Hidden returns a list of the user's hidden posts. // Hidden returns a list of the user's hidden posts.
func (s *UserServiceOp) Hidden(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) Hidden(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/hidden", s.client.Username) path := fmt.Sprintf("user/%s/hidden", s.client.Username)
@@ -347,7 +309,7 @@ func (s *UserServiceOp) Hidden(ctx context.Context, opts ...SearchOptionSetter)
} }
// Gilded returns a list of the user's gilded posts. // Gilded returns a list of the user's gilded posts.
func (s *UserServiceOp) Gilded(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) { func (s *UserService) Gilded(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error) {
form := newSearchOptions(opts...) form := newSearchOptions(opts...)
path := fmt.Sprintf("user/%s/gilded", s.client.Username) path := fmt.Sprintf("user/%s/gilded", s.client.Username)
@@ -369,7 +331,7 @@ func (s *UserServiceOp) Gilded(ctx context.Context, opts ...SearchOptionSetter)
// GetFriendship returns friendship details with the specified user. // GetFriendship returns friendship details with the specified user.
// If the user is not your friend, it will return an error. // If the user is not your friend, it will return an error.
func (s *UserServiceOp) GetFriendship(ctx context.Context, username string) (*Friendship, *Response, error) { func (s *UserService) GetFriendship(ctx context.Context, username string) (*Friendship, *Response, error) {
path := fmt.Sprintf("api/v1/me/friends/%s", username) path := fmt.Sprintf("api/v1/me/friends/%s", username)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
@@ -387,7 +349,7 @@ func (s *UserServiceOp) GetFriendship(ctx context.Context, username string) (*Fr
} }
// Friend friends a user. // Friend friends a user.
func (s *UserServiceOp) Friend(ctx context.Context, username string) (*Friendship, *Response, error) { func (s *UserService) Friend(ctx context.Context, username string) (*Friendship, *Response, error) {
type request struct { type request struct {
Username string `json:"name"` Username string `json:"name"`
} }
@@ -410,7 +372,7 @@ func (s *UserServiceOp) Friend(ctx context.Context, username string) (*Friendshi
} }
// Unfriend unfriends a user. // Unfriend unfriends a user.
func (s *UserServiceOp) Unfriend(ctx context.Context, username string) (*Response, error) { func (s *UserService) Unfriend(ctx context.Context, username string) (*Response, error) {
path := fmt.Sprintf("api/v1/me/friends/%s", username) path := fmt.Sprintf("api/v1/me/friends/%s", username)
req, err := s.client.NewRequest(http.MethodDelete, path, nil) req, err := s.client.NewRequest(http.MethodDelete, path, nil)
if err != nil { if err != nil {
@@ -420,7 +382,7 @@ func (s *UserServiceOp) Unfriend(ctx context.Context, username string) (*Respons
} }
// Block blocks a user. // Block blocks a user.
func (s *UserServiceOp) Block(ctx context.Context, username string) (*Blocked, *Response, error) { func (s *UserService) Block(ctx context.Context, username string) (*Blocked, *Response, error) {
path := "api/block_user" path := "api/block_user"
form := url.Values{} form := url.Values{}
@@ -441,7 +403,7 @@ func (s *UserServiceOp) Block(ctx context.Context, username string) (*Blocked, *
} }
// // BlockByID blocks a user via their full id. // // BlockByID blocks a user via their full id.
// func (s *UserServiceOp) BlockByID(ctx context.Context, id string) (*Blocked, *Response, error) { // func (s *UserService) BlockByID(ctx context.Context, id string) (*Blocked, *Response, error) {
// path := "api/block_user" // path := "api/block_user"
// form := url.Values{} // form := url.Values{}
@@ -462,7 +424,7 @@ func (s *UserServiceOp) Block(ctx context.Context, username string) (*Blocked, *
// } // }
// Unblock unblocks a user. // Unblock unblocks a user.
func (s *UserServiceOp) Unblock(ctx context.Context, username string) (*Response, error) { func (s *UserService) Unblock(ctx context.Context, username string) (*Response, error) {
selfID, err := s.client.GetRedditID(ctx) selfID, err := s.client.GetRedditID(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -484,7 +446,7 @@ func (s *UserServiceOp) Unblock(ctx context.Context, username string) (*Response
} }
// // UnblockByID unblocks a user via their full id. // // UnblockByID unblocks a user via their full id.
// func (s *UserServiceOp) UnblockByID(ctx context.Context, id string) (*Response, error) { // func (s *UserService) UnblockByID(ctx context.Context, id string) (*Response, error) {
// selfID, err := s.client.GetRedditID(ctx) // selfID, err := s.client.GetRedditID(ctx)
// if err != nil { // if err != nil {
// return nil, err // return nil, err
@@ -506,12 +468,12 @@ func (s *UserServiceOp) Unblock(ctx context.Context, username string) (*Response
// } // }
// Trophies returns a list of your trophies. // Trophies returns a list of your trophies.
func (s *UserServiceOp) Trophies(ctx context.Context) ([]Trophy, *Response, error) { func (s *UserService) Trophies(ctx context.Context) ([]Trophy, *Response, error) {
return s.TrophiesOf(ctx, s.client.Username) return s.TrophiesOf(ctx, s.client.Username)
} }
// TrophiesOf returns a list of the specified user's trophies. // TrophiesOf returns a list of the specified user's trophies.
func (s *UserServiceOp) TrophiesOf(ctx context.Context, username string) ([]Trophy, *Response, error) { func (s *UserService) TrophiesOf(ctx context.Context, username string) ([]Trophy, *Response, error) {
path := fmt.Sprintf("api/v1/user/%s/trophies", username) path := fmt.Sprintf("api/v1/user/%s/trophies", username)
req, err := s.client.NewRequest(http.MethodGet, path, nil) req, err := s.client.NewRequest(http.MethodGet, path, nil)
-14
View File
@@ -205,8 +205,6 @@ func TestUserService_Overview(t *testing.T) {
posts, comments, _, err := client.User.Overview(ctx) posts, comments, _, err := client.User.Overview(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.NotNil(t, comments)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -232,8 +230,6 @@ func TestUserService_OverviewOf(t *testing.T) {
posts, comments, _, err := client.User.OverviewOf(ctx, "user2") posts, comments, _, err := client.User.OverviewOf(ctx, "user2")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.NotNil(t, comments)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -284,7 +280,6 @@ func TestUserService_Posts(t *testing.T) {
posts, _, err := client.User.Posts(ctx) posts, _, err := client.User.Posts(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -305,7 +300,6 @@ func TestUserService_PostsOf(t *testing.T) {
posts, _, err := client.User.PostsOf(ctx, "user2") posts, _, err := client.User.PostsOf(ctx, "user2")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -350,7 +344,6 @@ func TestUserService_Comments(t *testing.T) {
comments, _, err := client.User.Comments(ctx) comments, _, err := client.User.Comments(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, comments)
assert.Len(t, comments.Comments, 1) assert.Len(t, comments.Comments, 1)
assert.Equal(t, expectedComment, comments.Comments[0]) assert.Equal(t, expectedComment, comments.Comments[0])
@@ -371,7 +364,6 @@ func TestUserService_CommentsOf(t *testing.T) {
comments, _, err := client.User.CommentsOf(ctx, "user2") comments, _, err := client.User.CommentsOf(ctx, "user2")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, comments)
assert.Len(t, comments.Comments, 1) assert.Len(t, comments.Comments, 1)
assert.Equal(t, expectedComment, comments.Comments[0]) assert.Equal(t, expectedComment, comments.Comments[0])
@@ -417,8 +409,6 @@ func TestUserService_Saved(t *testing.T) {
posts, comments, _, err := client.User.Saved(ctx) posts, comments, _, err := client.User.Saved(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.NotNil(t, comments)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -469,7 +459,6 @@ func TestUserService_Upvoted(t *testing.T) {
posts, _, err := client.User.Upvoted(ctx) posts, _, err := client.User.Upvoted(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -515,7 +504,6 @@ func TestUserService_Downvoted(t *testing.T) {
posts, _, err := client.User.Downvoted(ctx) posts, _, err := client.User.Downvoted(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -562,7 +550,6 @@ func TestUserService_Hidden(t *testing.T) {
posts, _, err := client.User.Hidden(ctx) posts, _, err := client.User.Hidden(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
@@ -584,7 +571,6 @@ func TestUserService_Gilded(t *testing.T) {
posts, _, err := client.User.Gilded(ctx) posts, _, err := client.User.Gilded(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, posts)
assert.Len(t, posts.Posts, 1) assert.Len(t, posts.Posts, 1)
assert.Equal(t, expectedPost, posts.Posts[0]) assert.Equal(t, expectedPost, posts.Posts[0])
+7 -16
View File
@@ -8,18 +8,9 @@ import (
// VoteService handles communication with the upvote/downvote // VoteService handles communication with the upvote/downvote
// related methods of the Reddit API. // related methods of the Reddit API.
type VoteService interface { //
Up(ctx context.Context, id string) (*Response, error) // Reddit API docs: https://www.reddit.com/dev/api/#POST_api_vote
Down(ctx context.Context, id string) (*Response, error) type VoteService service
Remove(ctx context.Context, id string) (*Response, error)
}
// VoteServiceOp implements the Vote interface.
type VoteServiceOp struct {
client *Client
}
var _ VoteService = &VoteServiceOp{}
type vote int type vote int
@@ -30,7 +21,7 @@ const (
upvote upvote
) )
func (s *VoteServiceOp) vote(ctx context.Context, id string, vote vote) (*Response, error) { func (s *VoteService) vote(ctx context.Context, id string, vote vote) (*Response, error) {
path := "api/vote" path := "api/vote"
form := url.Values{} form := url.Values{}
@@ -47,16 +38,16 @@ func (s *VoteServiceOp) vote(ctx context.Context, id string, vote vote) (*Respon
} }
// Up upvotes a post or a comment. // Up upvotes a post or a comment.
func (s *VoteServiceOp) Up(ctx context.Context, id string) (*Response, error) { func (s *VoteService) Up(ctx context.Context, id string) (*Response, error) {
return s.vote(ctx, id, upvote) return s.vote(ctx, id, upvote)
} }
// Down downvotes a post or a comment. // Down downvotes a post or a comment.
func (s *VoteServiceOp) Down(ctx context.Context, id string) (*Response, error) { func (s *VoteService) Down(ctx context.Context, id string) (*Response, error) {
return s.vote(ctx, id, downvote) return s.vote(ctx, id, downvote)
} }
// Remove removes the user's vote on a post or a comment. // Remove removes the user's vote on a post or a comment.
func (s *VoteServiceOp) Remove(ctx context.Context, id string) (*Response, error) { func (s *VoteService) Remove(ctx context.Context, id string) (*Response, error) {
return s.vote(ctx, id, novote) return s.vote(ctx, id, novote)
} }
+3 -9
View File
@@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestVoteServiceOp_Up(t *testing.T) { func TestVoteService_Up(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -24,8 +24,6 @@ func TestVoteServiceOp_Up(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
res, err := client.Vote.Up(ctx, "t3_test") res, err := client.Vote.Up(ctx, "t3_test")
@@ -33,7 +31,7 @@ func TestVoteServiceOp_Up(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, http.StatusOK, res.StatusCode)
} }
func TestVoteServiceOp_Down(t *testing.T) { func TestVoteService_Down(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -48,8 +46,6 @@ func TestVoteServiceOp_Down(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
res, err := client.Vote.Down(ctx, "t3_test") res, err := client.Vote.Down(ctx, "t3_test")
@@ -57,7 +53,7 @@ func TestVoteServiceOp_Down(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, http.StatusOK, res.StatusCode)
} }
func TestVoteServiceOp_Remove(t *testing.T) { func TestVoteService_Remove(t *testing.T) {
setup() setup()
defer teardown() defer teardown()
@@ -72,8 +68,6 @@ func TestVoteServiceOp_Remove(t *testing.T) {
err := r.ParseForm() err := r.ParseForm()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, form, r.PostForm) assert.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{}`)
}) })
res, err := client.Vote.Remove(ctx, "t3_test") res, err := client.Vote.Remove(ctx, "t3_test")