From c897c14b23f9075faaff3823e3c44f04304b8507 Mon Sep 17 00:00:00 2001 From: Vartan Benohanian Date: Sun, 3 May 2020 19:17:39 -0400 Subject: [PATCH] Rename structs, move them to a separate file Signed-off-by: Vartan Benohanian --- comment.go | 9 -- geddit.go | 230 ------------------------------------------- listings.go | 24 ----- subreddit.go | 83 ++++++---------- things.go | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++ user.go | 88 ++++++++--------- 6 files changed, 343 insertions(+), 362 deletions(-) create mode 100644 things.go diff --git a/comment.go b/comment.go index d5baf3d..a745406 100644 --- a/comment.go +++ b/comment.go @@ -25,15 +25,6 @@ type CommentServiceOp struct { var _ CommentService = &CommentServiceOp{} -// CommentList holds information about a list of comments -// The after and before fields help decide the anchor point for a subsequent -// call that returns a list -type CommentList struct { - Comments []Comment `json:"comments,omitempty"` - After string `json:"after,omitempty"` - Before string `json:"before,omitempty"` -} - func (s *CommentServiceOp) isCommentID(id string) bool { return strings.HasPrefix(id, kindComment+"_") } diff --git a/geddit.go b/geddit.go index e33080e..1f92e21 100644 --- a/geddit.go +++ b/geddit.go @@ -380,233 +380,3 @@ func addOptions(s string, opt interface{}) (string, error) { origURL.RawQuery = origValues.Encode() return origURL.String(), nil } - -type root struct { - Kind string `json:"kind,omitempty"` - Data interface{} `json:"data,omitempty"` -} - -type rootListing struct { - Kind string `json:"kind,omitempty"` - Data *Listing `json:"data"` -} - -// Listing holds things coming from the Reddit API -// It also contains the after/before anchors useful for subsequent requests -type Listing struct { - Things Things `json:"children"` - After string `json:"after"` - Before string `json:"before"` -} - -// Things are stuff! -type Things struct { - Comments []Comment `json:"comments,omitempty"` - Links []Link `json:"links,omitempty"` - Subreddits []Subreddit `json:"subreddits,omitempty"` - // todo: add the other kinds of things -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (l *Things) UnmarshalJSON(b []byte) error { - var children []map[string]interface{} - if err := json.Unmarshal(b, &children); err != nil { - return err - } - - for _, child := range children { - byteValue, _ := json.Marshal(child) - switch child["kind"] { - case kindComment: - root := new(commentRoot) - if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { - l.Comments = append(l.Comments, *root.Data) - } - case kindAccount: - case kindLink: - root := new(linkRoot) - if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { - l.Links = append(l.Links, *root.Data) - } - case kindMessage: - case kindSubreddit: - root := new(subredditRoot) - if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { - l.Subreddits = append(l.Subreddits, *root.Data) - } - case kindAward: - } - } - - return nil -} - -const ( - kindListing string = "Listing" - kindComment string = "t1" - kindAccount string = "t2" - kindLink string = "t3" - kindMessage string = "t4" - kindSubreddit string = "t5" - kindAward string = "t6" -) - -type commentRoot struct { - Kind string `json:"kind,omitempty"` - Data *Comment `json:"data,omitempty"` -} - -type linkRoot struct { - Kind string `json:"kind,omitempty"` - Data *Link `json:"data,omitempty"` -} - -type subredditRoot struct { - Kind string `json:"kind,omitempty"` - Data *Subreddit `json:"data,omitempty"` -} - -// Comment is a comment posted by a user -type Comment struct { - ID string `json:"id,omitempty"` - FullID string `json:"name,omitempty"` - ParentID string `json:"parent_id,omitempty"` - Permalink string `json:"permalink,omitempty"` - - Body string `json:"body,omitempty"` - Author string `json:"author,omitempty"` - AuthorID string `json:"author_fullname,omitempty"` - AuthorFlairText string `json:"author_flair_text,omitempty"` - AuthorFlairID string `json:"author_flair_template_id,omitempty"` - - Subreddit string `json:"subreddit,omitempty"` - SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` - SubredditID string `json:"subreddit_id,omitempty"` - - Score int `json:"score"` - Controversiality int `json:"controversiality"` - - Created *Timestamp `json:"created_utc,omitempty"` - Edited *Timestamp `json:"edited,omitempty"` - - LinkID string `json:"link_id,omitempty"` - - // These don't appear when submitting a comment - LinkTitle string `json:"link_title,omitempty"` - LinkPermalink string `json:"link_permalink,omitempty"` - LinkAuthor string `json:"link_author,omitempty"` - LinkNumComments int `json:"num_comments"` - - IsSubmitter bool `json:"is_submitter"` - ScoreHidden bool `json:"score_hidden"` - Saved bool `json:"saved"` - Stickied bool `json:"stickied"` - Locked bool `json:"locked"` - CanGild bool `json:"can_gild"` - NSFW bool `json:"over_18"` - - // If a comment has no replies, its "replies" value is "", - // which the unmarshaler doesn't like - // So we capture this varying field in RepliesRaw, and then - // fill it in Replies - RepliesRaw json.RawMessage `json:"replies,omitempty"` - Replies []commentRoot `json:"-"` -} - -// Link is a submitted post on Reddit -type Link struct { - ID string `json:"id,omitempty"` - FullID string `json:"name,omitempty"` - Created *Timestamp `json:"created_utc,omitempty"` - Edited *Timestamp `json:"edited,omitempty"` - - Permalink string `json:"permalink,omitempty"` - URL string `json:"url,omitempty"` - - Title string `json:"title,omitempty"` - Body string `json:"selftext,omitempty"` - - Score int `json:"score"` - NumberOfComments int `json:"num_comments"` - - SubredditID string `json:"subreddit_id,omitempty"` - SubredditName string `json:"subreddit,omitempty"` - SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` - - AuthorID string `json:"author_fullname,omitempty"` - AuthorName string `json:"author,omitempty"` - - Spoiler bool `json:"spoiler"` - Locked bool `json:"locked"` - NSFW bool `json:"over_18"` - IsSelfPost bool `json:"is_self"` - Saved bool `json:"saved"` - Stickied bool `json:"stickied"` -} - -// Subreddit holds information about a subreddit -type Subreddit struct { - ID string `json:"id,omitempty"` - FullID string `json:"name,omitempty"` - Created *Timestamp `json:"created_utc,omitempty"` - - URL string `json:"url,omitempty"` - Name string `json:"display_name,omitempty"` - NamePrefixed string `json:"display_name_prefixed,omitempty"` - Title string `json:"title,omitempty"` - PublicDescription string `json:"public_description,omitempty"` - Type string `json:"subreddit_type,omitempty"` - SuggestedCommentSort string `json:"suggested_comment_sort,omitempty"` - - Subscribers int `json:"subscribers"` - ActiveUserCount *int `json:"active_user_count,omitempty"` - NSFW bool `json:"over18"` - UserIsMod bool `json:"user_is_moderator"` -} - -func (rl *rootListing) getAfter() string { - if rl == nil || rl.Data == nil { - return "" - } - return rl.Data.After -} - -func (rl *rootListing) getBefore() string { - if rl == nil || rl.Data == nil { - return "" - } - return rl.Data.Before -} - -func (rl *rootListing) getComments() *CommentList { - if rl == nil || rl.Data == nil { - return nil - } - return &CommentList{ - Comments: rl.Data.Things.Comments, - After: rl.Data.After, - Before: rl.Data.Before, - } -} - -func (rl *rootListing) getLinks() *LinkList { - if rl == nil || rl.Data == nil { - return nil - } - return &LinkList{ - Links: rl.Data.Things.Links, - After: rl.Data.After, - Before: rl.Data.Before, - } -} - -func (rl *rootListing) getSubreddits() *SubredditList { - if rl == nil || rl.Data == nil { - return nil - } - return &SubredditList{ - Subreddits: rl.Data.Things.Subreddits, - After: rl.Data.After, - Before: rl.Data.Before, - } -} diff --git a/listings.go b/listings.go index 31034d4..e86387f 100644 --- a/listings.go +++ b/listings.go @@ -18,30 +18,6 @@ type ListingsServiceOp struct { var _ ListingsService = &ListingsServiceOp{} -type listingRoot struct { - Kind string `json:"kind,omitempty"` - Data *struct { - Dist int `json:"dist"` - Children []map[string]interface{} `json:"children,omitempty"` - After string `json:"after,omitempty"` - Before string `json:"before,omitempty"` - } `json:"data,omitempty"` -} - -// Listing holds various types of things that all come from the Reddit API -// type Listing struct { -// Links []*Submission `json:"links,omitempty"` -// Comments []*Comment `json:"comments,omitempty"` -// Subreddits []*Subreddit `json:"subreddits,omitempty"` -// } - -// CommentsLinksSubreddits holds comments, links, and subreddits -type CommentsLinksSubreddits struct { - Comments []Comment `json:"comments,omitempty"` - Links []Link `json:"links,omitempty"` - Subreddits []Subreddit `json:"subreddits,omitempty"` -} - // Get gets a list of things based on their IDs // Only links, comments, and subreddits are allowed func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) (*CommentsLinksSubreddits, *Response, error) { diff --git a/subreddit.go b/subreddit.go index 668074a..4b0bc6d 100644 --- a/subreddit.go +++ b/subreddit.go @@ -15,22 +15,22 @@ import ( type SubredditService interface { GetByName(ctx context.Context, name string) (*Subreddit, *Response, error) - GetPopular(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetNew(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetGold(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetDefault(ctx context.Context, opts *ListOptions) (*SubredditList, *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) - GetMineWhereSubscriber(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetMineWhereContributor(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) - GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) + GetMineWhereSubscriber(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) + GetMineWhereContributor(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) + GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) + GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) - GetHotLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) - GetBestLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) - GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) - GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) - GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) - GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) + GetHotLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) + GetBestLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) + GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) + GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) + GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) + GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) // GetSticky1(ctx context.Context, name string) (interface{}, *Response, error) // GetSticky2(ctx context.Context, name string) (interface{}, *Response, error) @@ -50,25 +50,6 @@ type SubredditServiceOp struct { var _ SubredditService = &SubredditServiceOp{} -// SubredditList holds information about a list of subreddits -// The after and before fields help decide the anchor point for a subsequent -// call that returns a list -type SubredditList struct { - Subreddits []Subreddit `json:"subreddits,omitempty"` - After string `json:"after,omitempty"` - Before string `json:"before,omitempty"` -} - -// LinkList holds information about a list of links -// The after and before fields help decide the anchor point for a subsequent -// call that returns a list -// Note: not to be confused with linked lists -type LinkList struct { - Links []Link `json:"submissions,omitempty"` - After string `json:"after,omitempty"` - Before string `json:"before,omitempty"` -} - // GetByName gets a subreddit by name func (s *SubredditServiceOp) GetByName(ctx context.Context, name string) (*Subreddit, *Response, error) { if name == "" { @@ -91,42 +72,42 @@ func (s *SubredditServiceOp) GetByName(ctx context.Context, name string) (*Subre } // GetPopular returns popular subreddits -func (s *SubredditServiceOp) GetPopular(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/popular", opts) } // GetNew returns new subreddits -func (s *SubredditServiceOp) GetNew(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/new", opts) } // GetGold returns gold subreddits -func (s *SubredditServiceOp) GetGold(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetGold(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/gold", opts) } // GetDefault returns default subreddits -func (s *SubredditServiceOp) GetDefault(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetDefault(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/default", opts) } // GetMineWhereSubscriber returns the list of subreddits the client is subscribed to -func (s *SubredditServiceOp) GetMineWhereSubscriber(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetMineWhereSubscriber(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/mine/subscriber", opts) } // GetMineWhereContributor returns the list of subreddits the client is a contributor to -func (s *SubredditServiceOp) GetMineWhereContributor(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetMineWhereContributor(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/mine/contributor", opts) } // GetMineWhereModerator returns the list of subreddits the client is a moderator in -func (s *SubredditServiceOp) GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/mine/contributor", opts) } // GetMineWhereStreams returns the list of subreddits the client is subscribed to and has hosted videos in -func (s *SubredditServiceOp) GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error) { return s.getSubreddits(ctx, "subreddits/mine/contributor", opts) } @@ -154,7 +135,7 @@ var sorts = [...]string{ // If no subreddit names 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, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortHot, opts, names...) } @@ -162,31 +143,31 @@ func (s *SubredditServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions, // If no subreddit names 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, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetBestLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortBest, opts, names...) } // GetNewLinks returns the new links // If no subreddit names are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortNew, opts, names...) } // GetRisingLinks returns the rising links // If no subreddit names are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortRising, opts, names...) } // GetControversialLinks returns the controversial links // If no subreddit names are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortControversial, opts, names...) } // GetTopLinks returns the top links // If no subreddit names are provided, then it runs the search against all those the client is subscribed to -func (s *SubredditServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) { return s.getLinks(ctx, sortTop, opts, names...) } @@ -258,7 +239,7 @@ func (s *SubredditServiceOp) handleSubscription(ctx context.Context, form url.Va return resp, nil } -func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opts *ListOptions) (*SubredditList, *Response, error) { +func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opts *ListOptions) (*Subreddits, *Response, error) { path, err := addOptions(path, opts) if err != nil { return nil, nil, err @@ -275,7 +256,7 @@ func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opt return nil, resp, err } - l := new(SubredditList) + l := new(Subreddits) if root.Data != nil { l.Subreddits = root.Data.Things.Subreddits @@ -286,7 +267,7 @@ 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, names ...string) (*LinkList, *Response, error) { +func (s *SubredditServiceOp) getLinks(ctx context.Context, sort sort, opts *ListOptions, names ...string) (*Links, *Response, error) { path := sorts[sort] if len(names) > 0 { path = fmt.Sprintf("r/%s/%s", strings.Join(names, "+"), sorts[sort]) @@ -308,7 +289,7 @@ func (s *SubredditServiceOp) getLinks(ctx context.Context, sort sort, opts *List return nil, resp, err } - l := new(LinkList) + l := new(Links) if root.Data != nil { l.Links = root.Data.Things.Links diff --git a/things.go b/things.go new file mode 100644 index 0000000..cd4d9de --- /dev/null +++ b/things.go @@ -0,0 +1,271 @@ +package geddit + +import "encoding/json" + +const ( + kindComment = "t1" + kindAccount = "t2" + kindLink = "t3" + kindMessage = "t4" + kindSubreddit = "t5" + kindAward = "t6" + kindListing = "Listing" + kindUserList = "UserList" + kindMode = "more" +) + +type root struct { + Kind string `json:"kind,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +type rootListing struct { + Kind string `json:"kind,omitempty"` + Data *Listing `json:"data"` +} + +// Listing holds things coming from the Reddit API +// It also contains the after/before anchors useful for subsequent requests +type Listing struct { + Things Things `json:"children"` + After string `json:"after"` + Before string `json:"before"` +} + +// Things are stuff! +type Things struct { + Comments []Comment `json:"comments,omitempty"` + Links []Link `json:"links,omitempty"` + Subreddits []Subreddit `json:"subreddits,omitempty"` + // todo: add the other kinds of things +} + +type commentRoot struct { + Kind string `json:"kind,omitempty"` + Data *Comment `json:"data,omitempty"` +} + +type linkRoot struct { + Kind string `json:"kind,omitempty"` + Data *Link `json:"data,omitempty"` +} + +type subredditRoot struct { + Kind string `json:"kind,omitempty"` + Data *Subreddit `json:"data,omitempty"` +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (l *Things) UnmarshalJSON(b []byte) error { + var children []map[string]interface{} + if err := json.Unmarshal(b, &children); err != nil { + return err + } + + for _, child := range children { + byteValue, _ := json.Marshal(child) + switch child["kind"] { + case kindComment: + root := new(commentRoot) + if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { + l.Comments = append(l.Comments, *root.Data) + } + case kindAccount: + case kindLink: + root := new(linkRoot) + if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { + l.Links = append(l.Links, *root.Data) + } + case kindMessage: + case kindSubreddit: + root := new(subredditRoot) + if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil { + l.Subreddits = append(l.Subreddits, *root.Data) + } + case kindAward: + } + } + + return nil +} + +// Comment is a comment posted by a user +type Comment struct { + ID string `json:"id,omitempty"` + FullID string `json:"name,omitempty"` + ParentID string `json:"parent_id,omitempty"` + Permalink string `json:"permalink,omitempty"` + + Body string `json:"body,omitempty"` + Author string `json:"author,omitempty"` + AuthorID string `json:"author_fullname,omitempty"` + AuthorFlairText string `json:"author_flair_text,omitempty"` + AuthorFlairID string `json:"author_flair_template_id,omitempty"` + + Subreddit string `json:"subreddit,omitempty"` + SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` + SubredditID string `json:"subreddit_id,omitempty"` + + Score int `json:"score"` + Controversiality int `json:"controversiality"` + + Created *Timestamp `json:"created_utc,omitempty"` + Edited *Timestamp `json:"edited,omitempty"` + + LinkID string `json:"link_id,omitempty"` + + // These don't appear when submitting a comment + LinkTitle string `json:"link_title,omitempty"` + LinkPermalink string `json:"link_permalink,omitempty"` + LinkAuthor string `json:"link_author,omitempty"` + LinkNumComments int `json:"num_comments"` + + IsSubmitter bool `json:"is_submitter"` + ScoreHidden bool `json:"score_hidden"` + Saved bool `json:"saved"` + Stickied bool `json:"stickied"` + Locked bool `json:"locked"` + CanGild bool `json:"can_gild"` + NSFW bool `json:"over_18"` + + // If a comment has no replies, its "replies" value is "", + // which the unmarshaler doesn't like + // So we capture this varying field in RepliesRaw, and then + // fill it in Replies + RepliesRaw json.RawMessage `json:"replies,omitempty"` + Replies []commentRoot `json:"-"` +} + +// Link is a submitted post on Reddit +type Link struct { + ID string `json:"id,omitempty"` + FullID string `json:"name,omitempty"` + Created *Timestamp `json:"created_utc,omitempty"` + Edited *Timestamp `json:"edited,omitempty"` + + Permalink string `json:"permalink,omitempty"` + URL string `json:"url,omitempty"` + + Title string `json:"title,omitempty"` + Body string `json:"selftext,omitempty"` + + Score int `json:"score"` + NumberOfComments int `json:"num_comments"` + + SubredditID string `json:"subreddit_id,omitempty"` + SubredditName string `json:"subreddit,omitempty"` + SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` + + AuthorID string `json:"author_fullname,omitempty"` + AuthorName string `json:"author,omitempty"` + + Spoiler bool `json:"spoiler"` + Locked bool `json:"locked"` + NSFW bool `json:"over_18"` + IsSelfPost bool `json:"is_self"` + Saved bool `json:"saved"` + Stickied bool `json:"stickied"` +} + +// Subreddit holds information about a subreddit +type Subreddit struct { + ID string `json:"id,omitempty"` + FullID string `json:"name,omitempty"` + Created *Timestamp `json:"created_utc,omitempty"` + + URL string `json:"url,omitempty"` + Name string `json:"display_name,omitempty"` + NamePrefixed string `json:"display_name_prefixed,omitempty"` + Title string `json:"title,omitempty"` + PublicDescription string `json:"public_description,omitempty"` + Type string `json:"subreddit_type,omitempty"` + SuggestedCommentSort string `json:"suggested_comment_sort,omitempty"` + + Subscribers int `json:"subscribers"` + ActiveUserCount *int `json:"active_user_count,omitempty"` + NSFW bool `json:"over18"` + UserIsMod bool `json:"user_is_moderator"` +} + +func (rl *rootListing) getAfter() string { + if rl == nil || rl.Data == nil { + return "" + } + return rl.Data.After +} + +func (rl *rootListing) getBefore() string { + if rl == nil || rl.Data == nil { + return "" + } + return rl.Data.Before +} + +func (rl *rootListing) getComments() *Comments { + if rl == nil || rl.Data == nil { + return nil + } + return &Comments{ + Comments: rl.Data.Things.Comments, + After: rl.Data.After, + Before: rl.Data.Before, + } +} + +func (rl *rootListing) getLinks() *Links { + if rl == nil || rl.Data == nil { + return nil + } + return &Links{ + Links: rl.Data.Things.Links, + After: rl.Data.After, + Before: rl.Data.Before, + } +} + +func (rl *rootListing) getSubreddits() *Subreddits { + if rl == nil || rl.Data == nil { + return nil + } + return &Subreddits{ + Subreddits: rl.Data.Things.Subreddits, + After: rl.Data.After, + Before: rl.Data.Before, + } +} + +// Comments is a list of comments +type Comments struct { + Comments []Comment `json:"comments,omitempty"` + After string `json:"after"` + Before string `json:"before"` +} + +// Subreddits is a list of subreddits +type Subreddits struct { + Subreddits []Subreddit `json:"subreddits,omitempty"` + After string `json:"after"` + Before string `json:"before"` +} + +// Links is a list of links +type Links struct { + Links []Link `json:"submissions,omitempty"` + After string `json:"after"` + Before string `json:"before"` +} + +// CommentsLinks is a list of comments and links +type CommentsLinks struct { + Comments []Comment `json:"comments,omitempty"` + Links []Link `json:"links,omitempty"` + After string `json:"after"` + Before string `json:"before"` +} + +// CommentsLinksSubreddits is a list of comments, links, and subreddits +type CommentsLinksSubreddits struct { + Comments []Comment `json:"comments,omitempty"` + Links []Link `json:"links,omitempty"` + Subreddits []Subreddit `json:"subreddits,omitempty"` +} diff --git a/user.go b/user.go index 0df4625..74a9e08 100644 --- a/user.go +++ b/user.go @@ -17,34 +17,34 @@ type UserService interface { Overview(ctx context.Context, opts *ListOptions) (*CommentsLinks, *Response, error) // returns the client's links - GetHotLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) - GetNewLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) - GetTopLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) - GetControversialLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) + GetHotLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) + GetNewLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) + GetTopLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) + GetControversialLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) // returns the links of the user with the username - GetHotLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) - GetNewLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) - GetTopLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) - GetControversialLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) + GetHotLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) + GetNewLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) + GetTopLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) + GetControversialLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) - GetUpvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) - GetDownvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) - GetHidden(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) + GetUpvoted(ctx context.Context, opts *ListOptions) (*Links, *Response, error) + GetDownvoted(ctx context.Context, opts *ListOptions) (*Links, *Response, error) + GetHidden(ctx context.Context, opts *ListOptions) (*Links, *Response, error) GetSaved(ctx context.Context, opts *ListOptions) (*CommentsLinks, *Response, error) GetGilded(ctx context.Context, opts *ListOptions) (*CommentsLinks, *Response, error) // returns the client's comments - GetHotComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) - GetNewComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) - GetTopComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) - GetControversialComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) + GetHotComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) + GetNewComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) + GetTopComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) + GetControversialComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) // returns the comments of the user with the username - GetHotCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) - GetNewCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) - GetTopCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) - GetControversialCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) + GetHotCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) + GetNewCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) + GetTopCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) + GetControversialCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) Friend(ctx context.Context, username string, note string) (interface{}, *Response, error) Unblock(ctx context.Context, username string) (*Response, error) @@ -91,14 +91,6 @@ type UserShort struct { NSFW bool `json:"profile_over_18"` } -// CommentsLinks holds comments and links -type CommentsLinks struct { - Comments []Comment `json:"comments,omitempty"` - Links []Link `json:"links,omitempty"` - After string `json:"after"` - Before string `json:"before"` -} - // Get returns information about the user func (s *UserServiceOp) Get(ctx context.Context, username string) (*User, *Response, error) { path := fmt.Sprintf("user/%s/about", username) @@ -177,67 +169,67 @@ func (s *UserServiceOp) Overview(ctx context.Context, opts *ListOptions) (*Comme } // GetHotLinks returns a list of the client's hottest submissions -func (s *UserServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", s.client.Username, sorts[sortHot]) return s.getLinks(ctx, path, opts) } // GetNewLinks returns a list of the client's newest submissions -func (s *UserServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", s.client.Username, sorts[sortNew]) return s.getLinks(ctx, path, opts) } // GetTopLinks returns a list of the client's top submissions -func (s *UserServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", s.client.Username, sorts[sortTop]) return s.getLinks(ctx, path, opts) } // GetControversialLinks returns a list of the client's most controversial submissions -func (s *UserServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", s.client.Username, sorts[sortControversial]) return s.getLinks(ctx, path, opts) } // GetHotLinksOf returns a list of the user's hottest submissions -func (s *UserServiceOp) GetHotLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetHotLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", username, sorts[sortHot]) return s.getLinks(ctx, path, opts) } // GetNewLinksOf returns a list of the user's newest submissions -func (s *UserServiceOp) GetNewLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetNewLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", username, sorts[sortNew]) return s.getLinks(ctx, path, opts) } // GetTopLinksOf returns a list of the user's top submissions -func (s *UserServiceOp) GetTopLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetTopLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", username, sorts[sortTop]) return s.getLinks(ctx, path, opts) } // GetControversialLinksOf returns a list of the user's most controversial submissions -func (s *UserServiceOp) GetControversialLinksOf(ctx context.Context, username string, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetControversialLinksOf(ctx context.Context, username string, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/submitted?sort=%s", username, sorts[sortControversial]) return s.getLinks(ctx, path, opts) } // GetUpvoted returns a list of the client's upvoted submissions -func (s *UserServiceOp) GetUpvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetUpvoted(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/upvoted", s.client.Username) return s.getLinks(ctx, path, opts) } // GetDownvoted returns a list of the client's downvoted submissions -func (s *UserServiceOp) GetDownvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetDownvoted(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/downvoted", s.client.Username) return s.getLinks(ctx, path, opts) } // GetHidden returns a list of the client's hidden submissions -func (s *UserServiceOp) GetHidden(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) GetHidden(ctx context.Context, opts *ListOptions) (*Links, *Response, error) { path := fmt.Sprintf("user/%s/hidden", s.client.Username) return s.getLinks(ctx, path, opts) } @@ -255,42 +247,42 @@ func (s *UserServiceOp) GetGilded(ctx context.Context, opts *ListOptions) (*Comm } // GetHotComments returns a list of the client's hottest comments -func (s *UserServiceOp) GetHotComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetHotComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, s.client.Username, sortHot, opts) } // GetNewComments returns a list of the client's newest comments -func (s *UserServiceOp) GetNewComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetNewComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, s.client.Username, sortNew, opts) } // GetTopComments returns a list of the client's top comments -func (s *UserServiceOp) GetTopComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetTopComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, s.client.Username, sortTop, opts) } // GetControversialComments returns a list of the client's most controversial comments -func (s *UserServiceOp) GetControversialComments(ctx context.Context, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetControversialComments(ctx context.Context, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, s.client.Username, sortControversial, opts) } // GetHotCommentsOf returns a list of the user's hottest comments -func (s *UserServiceOp) GetHotCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetHotCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, username, sortHot, opts) } // GetNewCommentsOf returns a list of the user's newest comments -func (s *UserServiceOp) GetNewCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetNewCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, username, sortNew, opts) } // GetTopCommentsOf returns a list of the user's top comments -func (s *UserServiceOp) GetTopCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetTopCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, username, sortTop, opts) } // GetControversialCommentsOf returns a list of the user's most controversial comments -func (s *UserServiceOp) GetControversialCommentsOf(ctx context.Context, username string, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) GetControversialCommentsOf(ctx context.Context, username string, opts *ListOptions) (*Comments, *Response, error) { return s.getComments(ctx, username, sortControversial, opts) } @@ -344,7 +336,7 @@ func (s *UserServiceOp) Unfriend(ctx context.Context, username string) (*Respons return s.client.Do(ctx, req, nil) } -func (s *UserServiceOp) getLinks(ctx context.Context, path string, opts *ListOptions) (*LinkList, *Response, error) { +func (s *UserServiceOp) getLinks(ctx context.Context, path string, opts *ListOptions) (*Links, *Response, error) { path, err := addOptions(path, opts) if err != nil { return nil, nil, err @@ -364,7 +356,7 @@ func (s *UserServiceOp) getLinks(ctx context.Context, path string, opts *ListOpt return root.getLinks(), resp, nil } -func (s *UserServiceOp) getComments(ctx context.Context, username string, sort sort, opts *ListOptions) (*CommentList, *Response, error) { +func (s *UserServiceOp) getComments(ctx context.Context, username string, sort sort, opts *ListOptions) (*Comments, *Response, error) { path := fmt.Sprintf("user/%s/comments?sort=%s", username, sorts[sort]) path, err := addOptions(path, opts) if err != nil {