9a171b1c90
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
211 lines
5.6 KiB
Go
211 lines
5.6 KiB
Go
package geddit
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// UserService handles communication with the user
|
|
// related methods of the Reddit API
|
|
type UserService interface {
|
|
Get(ctx context.Context, username string) (*User, *Response, error)
|
|
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)
|
|
}
|
|
|
|
// UserServiceOp implements the UserService interface
|
|
type UserServiceOp struct {
|
|
client *Client
|
|
}
|
|
|
|
var _ UserService = &UserServiceOp{}
|
|
|
|
type userRoot struct {
|
|
Kind *string `json:"kind,omitempty"`
|
|
Data *User `json:"data,omitempty"`
|
|
}
|
|
|
|
// 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"`
|
|
|
|
LinkKarma int `json:"link_karma"`
|
|
CommentKarma int `json:"comment_karma"`
|
|
|
|
IsFriend bool `json:"is_friend"`
|
|
IsEmployee bool `json:"is_employee"`
|
|
HasVerifiedEmail bool `json:"has_verified_email"`
|
|
NSFW bool `json:"over_18"`
|
|
}
|
|
|
|
// 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"`
|
|
|
|
LinkKarma int `json:"link_karma"`
|
|
CommentKarma int `json:"comment_karma"`
|
|
|
|
NSFW bool `json:"profile_over_18"`
|
|
}
|
|
|
|
// 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)
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
root := new(userRoot)
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return root.Data, resp, nil
|
|
}
|
|
|
|
// 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
|
|
func (s *UserServiceOp) GetMultipleByID(ctx context.Context, ids ...string) (map[string]*UserShort, *Response, error) {
|
|
type query struct {
|
|
IDs []string `url:"ids,omitempty,comma"`
|
|
}
|
|
|
|
path := "api/user_data_by_account_ids"
|
|
path, err := addOptions(path, query{ids})
|
|
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(map[string]*UserShort)
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
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"`
|
|
}
|
|
|
|
path := "api/username_available"
|
|
path, err := addOptions(path, query{username})
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
return *root, resp, nil
|
|
}
|
|
|
|
// Friend creates or updates a "friend" relationship
|
|
// Request body contains JSON data with:
|
|
// name: existing Reddit username
|
|
// note: a string no longer than 300 characters
|
|
func (s *UserServiceOp) Friend(ctx context.Context, username string, note string) (interface{}, *Response, error) {
|
|
type request struct {
|
|
Name string `url:"name"`
|
|
Note string `url:"note"`
|
|
}
|
|
|
|
path := fmt.Sprintf("api/v1/me/friends/%s", username)
|
|
body := request{Name: username, Note: note}
|
|
|
|
_, err := s.client.NewRequest(http.MethodPut, path, body)
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
|
|
// todo: requires gold
|
|
return nil, nil, nil
|
|
}
|