Handle listings better by using custom unmarshaling
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
@@ -2,9 +2,9 @@ package geddit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// UserService handles communication with the user
|
||||
@@ -14,8 +14,36 @@ type UserService interface {
|
||||
GetMultipleByID(ctx context.Context, ids ...string) (map[string]*UserShort, *Response, error)
|
||||
UsernameAvailable(ctx context.Context, username string) (bool, *Response, error)
|
||||
|
||||
GetComments(ctx context.Context, sort sort, opts *ListOptions) (*CommentList, *Response, error)
|
||||
GetCommentsOf(ctx context.Context, username string, sort sort, opts *ListOptions) (*CommentList, *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)
|
||||
|
||||
// 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)
|
||||
|
||||
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)
|
||||
|
||||
// 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)
|
||||
|
||||
// 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)
|
||||
|
||||
Unblock(ctx context.Context, username string) (*Response, error)
|
||||
Unfriend(ctx context.Context, username string) (*Response, error)
|
||||
}
|
||||
|
||||
// UserServiceOp implements the UserService interface
|
||||
@@ -32,10 +60,10 @@ type userRoot struct {
|
||||
|
||||
// User represents a Reddit user
|
||||
type User struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Created float64 `json:"created"`
|
||||
CreatedUTC float64 `json:"created_utc"`
|
||||
// is not the full ID, watch out
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Created *Timestamp `json:"created_utc,omitempty"`
|
||||
|
||||
LinkKarma int `json:"link_karma"`
|
||||
CommentKarma int `json:"comment_karma"`
|
||||
@@ -49,8 +77,8 @@ type User struct {
|
||||
// UserShort represents a Reddit user, but contains fewer pieces of information
|
||||
// It is returned from the GET /api/user_data_by_account_ids endpoint
|
||||
type UserShort struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
CreatedUTC float64 `json:"created_utc"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Created *Timestamp `json:"created_utc,omitempty"`
|
||||
|
||||
LinkKarma int `json:"link_karma"`
|
||||
CommentKarma int `json:"comment_karma"`
|
||||
@@ -102,63 +130,8 @@ func (s *UserServiceOp) GetMultipleByID(ctx context.Context, ids ...string) (map
|
||||
return *root, resp, nil
|
||||
}
|
||||
|
||||
// GetComments returns a list of the client's comments
|
||||
func (s *UserServiceOp) GetComments(ctx context.Context, sort sort, opts *ListOptions) (*CommentList, *Response, error) {
|
||||
return s.GetCommentsOf(ctx, s.client.Username, sort, opts)
|
||||
}
|
||||
|
||||
// GetCommentsOf returns a list of the user's comments
|
||||
func (s *UserServiceOp) GetCommentsOf(ctx context.Context, username string, sort sort, opts *ListOptions) (*CommentList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/comments?sort=%s", username, sorts[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(commentRootListing)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
if root.Data == nil {
|
||||
return nil, resp, nil
|
||||
}
|
||||
|
||||
cl := new(CommentList)
|
||||
var comments []Comment
|
||||
|
||||
for _, child := range root.Data.Roots {
|
||||
comments = append(comments, *child.Data)
|
||||
}
|
||||
cl.Comments = comments
|
||||
cl.After = root.Data.After
|
||||
cl.Before = root.Data.Before
|
||||
|
||||
return cl, resp, nil
|
||||
}
|
||||
|
||||
// UsernameAvailable checks whether a username is available for registration
|
||||
// If a valid username is provided, this endpoint returns a body with just "true" or "false"
|
||||
// If an invalid username is provided, it returns the following:
|
||||
/*
|
||||
{
|
||||
"json": {
|
||||
"errors": [
|
||||
[
|
||||
"BAD_USERNAME",
|
||||
"invalid username",
|
||||
"user"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
*/
|
||||
func (s *UserServiceOp) UsernameAvailable(ctx context.Context, username string) (bool, *Response, error) {
|
||||
type query struct {
|
||||
User string `url:"user,omitempty"`
|
||||
@@ -177,9 +150,6 @@ func (s *UserServiceOp) UsernameAvailable(ctx context.Context, username string)
|
||||
|
||||
root := new(bool)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if _, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return false, resp, fmt.Errorf("must provide username conforming to Reddit's criteria; username provided: %q", username)
|
||||
}
|
||||
if err != nil {
|
||||
return false, resp, err
|
||||
}
|
||||
@@ -208,3 +178,219 @@ func (s *UserServiceOp) Friend(ctx context.Context, username string, note string
|
||||
// todo: requires gold
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// Unblock unblocks a user
|
||||
func (s *UserServiceOp) Unblock(ctx context.Context, username string) (*Response, error) {
|
||||
path := "api/unfriend"
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("name", username)
|
||||
form.Set("type", "enemy")
|
||||
form.Set("container", "todo: this should be the current user's full id")
|
||||
|
||||
req, err := s.client.NewPostForm(path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// Unfriend unfriends a user
|
||||
func (s *UserServiceOp) Unfriend(ctx context.Context, username string) (*Response, error) {
|
||||
path := fmt.Sprintf("api/v1/me/friends/%s", username)
|
||||
req, err := s.client.NewRequest(http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// GetUpvoted returns a list of the client's upvoted submissions
|
||||
func (s *UserServiceOp) GetUpvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/upvoted", s.client.Username)
|
||||
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
|
||||
}
|
||||
|
||||
return root.getLinks(), resp, nil
|
||||
}
|
||||
|
||||
// GetDownvoted returns a list of the client's downvoted submissions
|
||||
func (s *UserServiceOp) GetDownvoted(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/downvoted", s.client.Username)
|
||||
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
|
||||
}
|
||||
|
||||
return root.getLinks(), resp, nil
|
||||
}
|
||||
|
||||
// GetHidden returns a list of the client's hidden submissions
|
||||
func (s *UserServiceOp) GetHidden(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/hidden", s.client.Username)
|
||||
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
|
||||
}
|
||||
|
||||
return root.getLinks(), resp, nil
|
||||
}
|
||||
|
||||
// GetHotLinks returns a list of the client's hottest submissions
|
||||
func (s *UserServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
return s.getLinks(ctx, s.client.Username, sortHot, opts)
|
||||
}
|
||||
|
||||
// GetNewLinks returns a list of the client's newest submissions
|
||||
func (s *UserServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
return s.getLinks(ctx, s.client.Username, sortNew, opts)
|
||||
}
|
||||
|
||||
// GetTopLinks returns a list of the client's top submissions
|
||||
func (s *UserServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
return s.getLinks(ctx, s.client.Username, sortTop, opts)
|
||||
}
|
||||
|
||||
// GetControversialLinks returns a list of the client's most controversial submissions
|
||||
func (s *UserServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
return s.getLinks(ctx, s.client.Username, sortControversial, 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) {
|
||||
return s.getLinks(ctx, username, sortHot, 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) {
|
||||
return s.getLinks(ctx, username, sortNew, 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) {
|
||||
return s.getLinks(ctx, username, sortTop, 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) {
|
||||
return s.getLinks(ctx, username, sortControversial, opts)
|
||||
}
|
||||
|
||||
// GetHotComments returns a list of the client's hottest comments
|
||||
func (s *UserServiceOp) GetHotComments(ctx context.Context, opts *ListOptions) (*CommentList, *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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return s.getComments(ctx, username, sortControversial, opts)
|
||||
}
|
||||
|
||||
func (s *UserServiceOp) getLinks(ctx context.Context, username string, sort sort, opts *ListOptions) (*LinkList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/submitted?sort=%s", username, sorts[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
|
||||
}
|
||||
|
||||
return root.getLinks(), resp, nil
|
||||
}
|
||||
|
||||
func (s *UserServiceOp) getComments(ctx context.Context, username string, sort sort, opts *ListOptions) (*CommentList, *Response, error) {
|
||||
path := fmt.Sprintf("user/%s/comments?sort=%s", username, sorts[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
|
||||
}
|
||||
|
||||
return root.getComments(), resp, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user