WIP: Account service
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
parent
3bb31e2b43
commit
bdd39f5d21
7 changed files with 305 additions and 0 deletions
172
account.go
Normal file
172
account.go
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
package geddit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountService handles communication with the account
|
||||||
|
// related methods of the Reddit API.
|
||||||
|
type AccountService interface {
|
||||||
|
Karma(ctx context.Context) ([]SubredditKarma, *Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountServiceOp implements the AccountService interface.
|
||||||
|
type AccountServiceOp struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ AccountService = &AccountServiceOp{}
|
||||||
|
|
||||||
|
type rootSubredditKarma struct {
|
||||||
|
Kind string `json:"kind,omitempty"`
|
||||||
|
Data []SubredditKarma `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubredditKarma holds user karma data for the subreddit.
|
||||||
|
type SubredditKarma struct {
|
||||||
|
Subreddit string `json:"sr"`
|
||||||
|
PostKarma int `json:"link_karma"`
|
||||||
|
CommentKarma int `json:"comment_karma"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings are the user's account settings.
|
||||||
|
// Some of the fields' descriptions are taken from:
|
||||||
|
// https://praw.readthedocs.io/en/latest/code_overview/other/preferences.html#praw.models.Preferences.update
|
||||||
|
// todo: these should probably be pointers with omitempty
|
||||||
|
type Settings struct {
|
||||||
|
AcceptPrivateMessages bool `json:"accept_pms"`
|
||||||
|
// Allow Reddit to use your activity on Reddit to show you more relevant advertisements.
|
||||||
|
ActivityRelevantAds bool `json:"activity_relevant_ads"`
|
||||||
|
// Allow reddit to log my outbound clicks for personalization.
|
||||||
|
AllowClickTracking bool `json:"allow_clicktracking"`
|
||||||
|
|
||||||
|
// I would like to beta test features for reddit. By enabling, you will join r/beta immediately.
|
||||||
|
Beta bool `json:"beta"`
|
||||||
|
ClickGadget bool `json:"clickgadget"`
|
||||||
|
CollapseReadMessages bool `json:"collapse_read_messages"`
|
||||||
|
Compress bool `json:"compress"`
|
||||||
|
CredditAutorenew bool `json:"creddit_autorenew"`
|
||||||
|
DefaultCommentSort string `json:"default_comment_sort"`
|
||||||
|
ShowDomainDetails bool `json:"domain_details"`
|
||||||
|
SendEmailDigests bool `json:"email_digests"`
|
||||||
|
SendMessagesAsEmails bool `json:"email_messages"`
|
||||||
|
UnsubscribeFromAllEmails bool `json:"email_unsubscribe_all"`
|
||||||
|
DisableCustomThemes bool `json:"enable_default_themes"`
|
||||||
|
Location string `json:"g"`
|
||||||
|
HideAds bool `json:"hide_ads"`
|
||||||
|
|
||||||
|
// Don't allow search engines to index my user profile.
|
||||||
|
HideFromSearchEngines bool `json:"hide_from_robots"`
|
||||||
|
|
||||||
|
HideUpvotedPosts bool `json:"hide_ups"`
|
||||||
|
HideDownvotedPosts bool `json:"hide_downs"`
|
||||||
|
|
||||||
|
HighlightControversialComments bool `json:"highlight_controversial"`
|
||||||
|
HighlightNewComments bool `json:"highlight_new_comments"`
|
||||||
|
IgnoreSuggestedSorts bool `json:"ignore_suggested_sort"`
|
||||||
|
// Use new Reddit as my default experience.
|
||||||
|
UseNewReddit bool `json:"in_redesign_beta"`
|
||||||
|
LabelNSFW bool `json:"label_nsfw"`
|
||||||
|
Language string `json:"lang"`
|
||||||
|
ShowOldSearchPage bool `json:"legacy_search"`
|
||||||
|
EnableNotifications bool `json:"live_orangereds"`
|
||||||
|
MarkMessagesAsRead bool `json:"mark_messages_read"`
|
||||||
|
|
||||||
|
// Determine whether to show thumbnails next to posts in subreddits.
|
||||||
|
// - "on": show thumbnails next to posts
|
||||||
|
// - "off": do not show thumbnails next to posts
|
||||||
|
// - "subreddit": show thumbnails next to posts based on the subreddit's preferences
|
||||||
|
ShowThumbnails string `json:"media"`
|
||||||
|
|
||||||
|
// Determine whether to auto-expand media in subreddits.
|
||||||
|
// - "on": auto-expand media previews
|
||||||
|
// - "off": do not auto-expand media previews
|
||||||
|
// - "subreddit": auto-expand media previews based on the subreddit's preferences
|
||||||
|
AutoExpandMedia string `json:"media_preview"`
|
||||||
|
MinimumCommentScore *int `json:"min_comment_score"`
|
||||||
|
MinimumPostScore *int `json:"min_link_score"`
|
||||||
|
EnableMentionNotifications bool `json:"monitor_mentions"`
|
||||||
|
OpenLinksInNewWindow bool `json:"newwindow"`
|
||||||
|
// todo: test this
|
||||||
|
DarkMode bool `json:"nightmode"`
|
||||||
|
DisableProfanity bool `json:"no_profanity"`
|
||||||
|
NumComments int `json:"num_comments,omitempty"`
|
||||||
|
NumPosts int `json:"numsites,omitempty"`
|
||||||
|
ShowSpotlightBox bool `json:"organic"`
|
||||||
|
// todo: test this
|
||||||
|
SubredditTheme string `json:"other_theme"`
|
||||||
|
ShowNSFW bool `json:"over_18"`
|
||||||
|
EnablePrivateRSSFeeds bool `json:"private_feeds"`
|
||||||
|
ProfileOptOut bool `json:"profile_opt_out"`
|
||||||
|
// Make my upvotes and downvotes public.
|
||||||
|
PublicizeVotes bool `json:"public_votes"`
|
||||||
|
|
||||||
|
// Allow my data to be used for research purposes.
|
||||||
|
AllowResearch bool `json:"research"`
|
||||||
|
IncludeNSFWSearchResults bool `json:"search_include_over_18"`
|
||||||
|
ReceiveCrosspostMessages bool `json:"send_crosspost_messages"`
|
||||||
|
ReceiveWelcomeMessages bool `json:"send_welcome_messages"`
|
||||||
|
|
||||||
|
// Show a user's flair (next to their name on a post or comment).
|
||||||
|
ShowUserFlair bool `json:"show_flair"`
|
||||||
|
// Show a post's flair.
|
||||||
|
ShowPostFlair bool `json:"show_link_flair"`
|
||||||
|
|
||||||
|
ShowGoldExpiration bool `json:"show_gold_expiration"`
|
||||||
|
ShowLocationBasedRecommendations bool `json:"show_location_based_recommendations"`
|
||||||
|
ShowPromote bool `json:"show_promote"`
|
||||||
|
ShowCustomSubredditThemes bool `json:"show_stylesheets"`
|
||||||
|
ShowTrendingSubreddits bool `json:"show_trending"`
|
||||||
|
ShowTwitter bool `json:"show_twitter"`
|
||||||
|
StoreVisits bool `json:"store_visits"`
|
||||||
|
ThemeSelector string `json:"theme_selector"`
|
||||||
|
|
||||||
|
// Allow Reddit to use data provided by third-parties to show you more relevant advertisements on Reddit.i
|
||||||
|
AllowThirdPartyDataAdPersonalization bool `json:"third_party_data_personalized_ads"`
|
||||||
|
// Allow personalization of advertisements using data from third-party websites.
|
||||||
|
AllowThirdPartySiteDataAdPersonalization bool `json:"third_party_site_data_personalized_ads"`
|
||||||
|
// Allow personalization of content using data from third-party websites.
|
||||||
|
AllowThirdPartySiteDataContentPersonalization bool `json:"third_party_site_data_personalized_content"`
|
||||||
|
|
||||||
|
EnableThreadedMessages bool `json:"threaded_messages"`
|
||||||
|
EnableThreadedModmail bool `json:"threaded_modmail"`
|
||||||
|
TopKarmaSubreddits bool `json:"top_karma_subreddits"`
|
||||||
|
UseGlobalDefaults bool `json:"use_global_defaults"`
|
||||||
|
// todo: test this, no_video_autoplay
|
||||||
|
EnableVideoAutoplay bool `json:"video_autoplay"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Karma returns a breakdown of your karma per subreddit.
|
||||||
|
func (s *AccountServiceOp) Karma(ctx context.Context) ([]SubredditKarma, *Response, error) {
|
||||||
|
path := "api/v1/me/karma"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(rootSubredditKarma)
|
||||||
|
resp, err := s.client.Do(ctx, req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Data, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings returns your account settings.
|
||||||
|
func (s *AccountServiceOp) Settings(ctx context.Context) {
|
||||||
|
path := "api/v1/me/prefs"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(req)
|
||||||
|
|
||||||
|
root := new(Settings)
|
||||||
|
fmt.Println(root.ShowThumbnails)
|
||||||
|
}
|
32
account_test.go
Normal file
32
account_test.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package geddit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var expectedKarma = []SubredditKarma{
|
||||||
|
{Subreddit: "nba", PostKarma: 144, CommentKarma: 21999},
|
||||||
|
{Subreddit: "redditdev", PostKarma: 19, CommentKarma: 4},
|
||||||
|
{Subreddit: "test", PostKarma: 1, CommentKarma: 0},
|
||||||
|
{Subreddit: "golang", PostKarma: 1, CommentKarma: 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountServiceOp_Karma(t *testing.T) {
|
||||||
|
setup()
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
blob := readFileContents(t, "testdata/account/karma.json")
|
||||||
|
|
||||||
|
mux.HandleFunc("/api/v1/me/karma", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
assert.Equal(t, http.MethodGet, r.Method)
|
||||||
|
fmt.Fprint(w, blob)
|
||||||
|
})
|
||||||
|
|
||||||
|
karma, _, err := client.Account.Karma(ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedKarma, karma)
|
||||||
|
}
|
|
@ -91,6 +91,7 @@ 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
|
||||||
Comment CommentService
|
Comment CommentService
|
||||||
Flair FlairService
|
Flair FlairService
|
||||||
Listings ListingsService
|
Listings ListingsService
|
||||||
|
@ -120,6 +121,7 @@ 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.Comment = &CommentServiceOp{client: c}
|
c.Comment = &CommentServiceOp{client: c}
|
||||||
c.Flair = &FlairServiceOp{client: c}
|
c.Flair = &FlairServiceOp{client: c}
|
||||||
c.Listings = &ListingsServiceOp{client: c}
|
c.Listings = &ListingsServiceOp{client: c}
|
||||||
|
|
25
testdata/account/karma.json
vendored
Normal file
25
testdata/account/karma.json
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"kind": "KarmaList",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"sr": "nba",
|
||||||
|
"comment_karma": 21999,
|
||||||
|
"link_karma": 144
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sr": "redditdev",
|
||||||
|
"comment_karma": 4,
|
||||||
|
"link_karma": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sr": "test",
|
||||||
|
"comment_karma": 0,
|
||||||
|
"link_karma": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sr": "golang",
|
||||||
|
"comment_karma": 0,
|
||||||
|
"link_karma": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
69
testdata/account/settings.json
vendored
Normal file
69
testdata/account/settings.json
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"default_theme_sr": null,
|
||||||
|
"threaded_messages": true,
|
||||||
|
"hide_downs": false,
|
||||||
|
"label_nsfw": true,
|
||||||
|
"activity_relevant_ads": false,
|
||||||
|
"email_messages": false,
|
||||||
|
"profile_opt_out": false,
|
||||||
|
"video_autoplay": true,
|
||||||
|
"third_party_site_data_personalized_content": false,
|
||||||
|
"show_link_flair": true,
|
||||||
|
"show_trending": true,
|
||||||
|
"private_feeds": true,
|
||||||
|
"monitor_mentions": true,
|
||||||
|
"public_server_seconds": false,
|
||||||
|
"research": false,
|
||||||
|
"ignore_suggested_sort": true,
|
||||||
|
"send_crosspost_messages": false,
|
||||||
|
"email_digests": false,
|
||||||
|
"layout": 0,
|
||||||
|
"num_comments": 200,
|
||||||
|
"clickgadget": true,
|
||||||
|
"use_global_defaults": false,
|
||||||
|
"show_snoovatar": false,
|
||||||
|
"over_18": true,
|
||||||
|
"show_stylesheets": true,
|
||||||
|
"live_orangereds": true,
|
||||||
|
"enable_default_themes": false,
|
||||||
|
"legacy_search": false,
|
||||||
|
"domain_details": false,
|
||||||
|
"collapse_left_bar": false,
|
||||||
|
"lang": "en-ca",
|
||||||
|
"hide_ups": false,
|
||||||
|
"third_party_data_personalized_ads": false,
|
||||||
|
"allow_clicktracking": false,
|
||||||
|
"hide_from_robots": false,
|
||||||
|
"show_twitter": false,
|
||||||
|
"compress": false,
|
||||||
|
"store_visits": false,
|
||||||
|
"threaded_modmail": false,
|
||||||
|
"design_beta": false,
|
||||||
|
"min_link_score": null,
|
||||||
|
"media_preview": "off",
|
||||||
|
"show_location_based_recommendations": false,
|
||||||
|
"nightmode": false,
|
||||||
|
"highlight_controversial": true,
|
||||||
|
"geopopular": "GLOBAL",
|
||||||
|
"third_party_site_data_personalized_ads": false,
|
||||||
|
"survey_last_seen_time": null,
|
||||||
|
"min_comment_score": null,
|
||||||
|
"public_votes": false,
|
||||||
|
"collapse_read_messages": false,
|
||||||
|
"show_flair": true,
|
||||||
|
"mark_messages_read": true,
|
||||||
|
"search_include_over_18": true,
|
||||||
|
"no_profanity": false,
|
||||||
|
"hide_ads": false,
|
||||||
|
"beta": false,
|
||||||
|
"top_karma_subreddits": false,
|
||||||
|
"newwindow": true,
|
||||||
|
"numsites": 25,
|
||||||
|
"media": "subreddit",
|
||||||
|
"send_welcome_messages": true,
|
||||||
|
"show_gold_expiration": false,
|
||||||
|
"highlight_new_comments": true,
|
||||||
|
"email_unsubscribe_all": false,
|
||||||
|
"default_comment_sort": "top",
|
||||||
|
"accept_pms": "everyone"
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ const (
|
||||||
kindSubreddit = "t5"
|
kindSubreddit = "t5"
|
||||||
kindAward = "t6"
|
kindAward = "t6"
|
||||||
kindListing = "Listing"
|
kindListing = "Listing"
|
||||||
|
kingKarmaList = "KarmaList"
|
||||||
kingTrophyList = "TrophyList"
|
kingTrophyList = "TrophyList"
|
||||||
kindUserList = "UserList"
|
kindUserList = "UserList"
|
||||||
kindMode = "more"
|
kindMode = "more"
|
||||||
|
|
4
user.go
4
user.go
|
@ -26,6 +26,7 @@ type UserService interface {
|
||||||
CommentsOf(ctx context.Context, username string, 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)
|
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)
|
Upvoted(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
|
||||||
Downvoted(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)
|
Hidden(ctx context.Context, opts ...SearchOptionSetter) (*Posts, *Response, error)
|
||||||
|
@ -36,6 +37,7 @@ type UserService interface {
|
||||||
Unfriend(ctx context.Context, username string) (*Response, error)
|
Unfriend(ctx context.Context, username string) (*Response, error)
|
||||||
|
|
||||||
Block(ctx context.Context, username string) (*Blocked, *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)
|
// BlockByID(ctx context.Context, id string) (*Blocked, *Response, error)
|
||||||
Unblock(ctx context.Context, username string) (*Response, error)
|
Unblock(ctx context.Context, username string) (*Response, error)
|
||||||
// UnblockByID(ctx context.Context, id string) (*Response, error)
|
// UnblockByID(ctx context.Context, id string) (*Response, error)
|
||||||
|
@ -108,6 +110,8 @@ type Trophy struct {
|
||||||
// Trophies is a list of trophies.
|
// Trophies is a list of trophies.
|
||||||
type Trophies []Trophy
|
type Trophies []Trophy
|
||||||
|
|
||||||
|
// todo: we don't really need this. just make a rootTrophyListingData struct or something and use the default unmarshaler for that
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
func (t *Trophies) UnmarshalJSON(b []byte) error {
|
func (t *Trophies) UnmarshalJSON(b []byte) error {
|
||||||
var data map[string]interface{}
|
var data map[string]interface{}
|
||||||
|
|
Loading…
Reference in a new issue