From 01fad4ece517c19d5ebe860cc9cf9c0823189ba4 Mon Sep 17 00:00:00 2001 From: Vartan Benohanian Date: Sat, 16 May 2020 22:34:01 -0400 Subject: [PATCH] Add method chaining for getting posts from subreddits Signed-off-by: Vartan Benohanian --- search.go | 14 +++-- subreddit.go | 174 ++++++++++++++++++++++++++++----------------------- 2 files changed, 102 insertions(+), 86 deletions(-) diff --git a/search.go b/search.go index 0989997..f7df24a 100644 --- a/search.go +++ b/search.go @@ -36,9 +36,7 @@ func (s *SearchServiceOp) Posts(query string) *PostSearchBuilder { b.client = s.client b.opts.Query = query b.opts.Type = "link" - b.opts.Sort = SortRelevance.String() - b.opts.Timespan = TimespanAll.String() - return b + return b.Sort(SortRelevance).Timespan(TimespanAll) } // Subreddits searches for subreddits. @@ -95,14 +93,18 @@ func (b *PostSearchBuilder) Limit(limit int) *PostSearchBuilder { return b } -// InSubreddits restricts the search to happen in the specified subreddits only. -// If none are set, the search is run against r/all. -func (b *PostSearchBuilder) InSubreddits(subreddits ...string) *PostSearchBuilder { +// FromSubreddits restricts the search to happen in the specified subreddits only. +func (b *PostSearchBuilder) FromSubreddits(subreddits ...string) *PostSearchBuilder { b.subreddits = subreddits b.opts.RestrictSubreddits = len(subreddits) > 0 return b } +// FromAll runs the search against r/all. +func (b *PostSearchBuilder) FromAll() *PostSearchBuilder { + return b.FromSubreddits() +} + // Sort sets the sort option. func (b *PostSearchBuilder) Sort(sort Sort) *PostSearchBuilder { b.opts.Sort = sort.String() diff --git a/subreddit.go b/subreddit.go index 4615a54..a9ff3ab 100644 --- a/subreddit.go +++ b/subreddit.go @@ -12,6 +12,8 @@ import ( // SubredditService handles communication with the subreddit // related methods of the Reddit API type SubredditService interface { + GetPosts() *PostFinder + GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error) GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) @@ -24,13 +26,6 @@ type SubredditService interface { GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) - GetHotLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetBestLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetNewLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetRisingLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetControversialLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetTopLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) - GetSticky1(ctx context.Context, subreddit string) (*LinkAndComments, *Response, error) GetSticky2(ctx context.Context, subreddit string) (*LinkAndComments, *Response, error) @@ -65,6 +60,16 @@ type SubredditShort struct { ActiveUsers int `json:"active_user_count"` } +// GetPosts returns posts. +// 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 +// sticked posts (if any) PLUS posts from the limit parameter (25 by default). +func (s *SubredditServiceOp) GetPosts() *PostFinder { + f := new(PostFinder) + f.client = s.client + return f.Sort(SortHot).FromAll() +} + // GetByName gets a subreddit by name func (s *SubredditServiceOp) GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error) { if subreddit == "" { @@ -126,46 +131,6 @@ func (s *SubredditServiceOp) GetMineWhereStreams(ctx context.Context, opts *List return s.getSubreddits(ctx, "subreddits/mine/contributor", opts) } -// GetHotLinks returns the hot links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -// IMPORTANT: for subreddits, this will include the stickied posts (if any) -// PLUS the number of posts from the limit parameter (which is 25 by default) -func (s *SubredditServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortHot, opts, subreddits...) -} - -// GetBestLinks returns the best links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -// IMPORTANT: for subreddits, this will include the stickied posts (if any) -// PLUS the number of posts from the limit parameter (which is 25 by default) -func (s *SubredditServiceOp) GetBestLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortBest, opts, subreddits...) -} - -// GetNewLinks returns the new links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortNew, opts, subreddits...) -} - -// GetRisingLinks returns the rising links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetRisingLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortRising, opts, subreddits...) -} - -// GetControversialLinks returns the controversial links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortControversial, opts, subreddits...) -} - -// GetTopLinks returns the top links -// If no subreddit are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - return s.getLinks(ctx, SortTop, opts, subreddits...) -} - // GetSticky1 returns the first stickied post on a subreddit (if it exists) func (s *SubredditServiceOp) GetSticky1(ctx context.Context, name string) (*LinkAndComments, *Response, error) { return s.getSticky(ctx, name, sticky1) @@ -292,39 +257,6 @@ func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opt return l, resp, nil } -func (s *SubredditServiceOp) getLinks(ctx context.Context, sort Sort, opts *ListOptions, subreddits ...string) (*Links, *Response, error) { - path := sorts[sort] - if len(subreddits) > 0 { - path = fmt.Sprintf("r/%s/%s", strings.Join(subreddits, "+"), sort) - } - - path, err := addOptions(path, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest(http.MethodGet, path, nil) - if err != nil { - return nil, nil, err - } - - root := new(rootListing) - resp, err := s.client.Do(ctx, req, root) - if err != nil { - return nil, resp, err - } - - l := new(Links) - - if root.Data != nil { - l.Links = root.Data.Things.Links - l.After = root.Data.After - l.Before = root.Data.Before - } - - return l, resp, nil -} - // 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 // If it's <= 1, it's 1 @@ -353,3 +285,85 @@ func (s *SubredditServiceOp) getSticky(ctx context.Context, subreddit string, nu return root, resp, nil } + +// PostFinder finds posts from the specified subreddits. +// If no subreddits are specified, it finds posts from the ones the client is subscribed to. +type PostFinder struct { + client *Client + subreddits []string + sort string + opts struct { + After string `url:"after,omitempty"` + Before string `url:"before,omitempty"` + Limit int `url:"limit,omitempty"` + Timespan string `url:"t,omitempty"` + } +} + +// After sets the after option. +func (f *PostFinder) After(after string) *PostFinder { + f.opts.After = after + return f +} + +// Before sets the before option. +func (f *PostFinder) Before(before string) *PostFinder { + f.opts.Before = before + return f +} + +// Limit sets the limit option. +func (f *PostFinder) Limit(limit int) *PostFinder { + f.opts.Limit = limit + return f +} + +// FromSubreddits restricts the search to the subreddits. +func (f *PostFinder) FromSubreddits(subreddits ...string) *PostFinder { + f.subreddits = subreddits + return f +} + +// FromAll allows the finder to find posts from r/all. +func (f *PostFinder) FromAll() *PostFinder { + f.subreddits = []string{"all"} + return f +} + +// Sort sets the sort option. +func (f *PostFinder) Sort(sort Sort) *PostFinder { + f.sort = sort.String() + return f +} + +// Timespan sets the timespan option. +func (f *PostFinder) Timespan(timespan Timespan) *PostFinder { + f.opts.Timespan = timespan.String() + return f +} + +// Do conducts the search. +func (f *PostFinder) Do(ctx context.Context) (*Links, *Response, error) { + path := f.sort + if len(f.subreddits) > 0 { + path = fmt.Sprintf("r/%s/%s", strings.Join(f.subreddits, "+"), f.sort) + } + + path, err := addOptions(path, f.opts) + if err != nil { + return nil, nil, err + } + + req, err := f.client.NewRequest(http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(rootListing) + resp, err := f.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.getLinks(), resp, nil +}