From 838db037b932acb39e11b831eed6e327585573af Mon Sep 17 00:00:00 2001 From: Vartan Benohanian Date: Mon, 13 Jul 2020 19:52:39 -0400 Subject: [PATCH] Add more methods to moderation service Signed-off-by: Vartan Benohanian --- moderation.go | 115 ++++++++++++++++++++++++++++++++--- moderation_test.go | 145 +++++++++++++++++++++++++++++++++++++++++++++ search.go | 2 + 3 files changed, 255 insertions(+), 7 deletions(-) diff --git a/moderation.go b/moderation.go index 9822306..16dcaeb 100644 --- a/moderation.go +++ b/moderation.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" ) // ModerationService handles communication with the moderation @@ -37,6 +38,7 @@ type ModAction struct { } // GetActions gets a list of moderator actions on a subreddit. +// By default, the limit parameter is 25; max is 500. func (s *ModerationService) GetActions(ctx context.Context, subreddit string, opts ...SearchOptionSetter) (*ModActions, *Response, error) { form := newSearchOptions(opts...) @@ -57,11 +59,110 @@ func (s *ModerationService) GetActions(ctx context.Context, subreddit string, op return root.getModeratorActions(), resp, nil } -/* -type rootTrophyListing struct { - Kind string `json:"kind,omitempty"` - Data struct { - Trophies []rootTrophy `json:"trophies"` - } `json:"data"` +// GetActionsByType gets a list of moderator actions of the specified type on a subreddit. +// By default, the limit parameter is 25; max is 500. +// The type should be one of: banuser, unbanuser, spamlink, removelink, approvelink, spamcomment, +// removecomment, approvecomment, addmoderator, showcomment, invitemoderator, uninvitemoderator, +// acceptmoderatorinvite, removemoderator, addcontributor, removecontributor, editsettings, editflair, +// distinguish, marknsfw, wikibanned, wikicontributor, wikiunbanned, wikipagelisted, removewikicontributor, +// wikirevise, wikipermlevel, ignorereports, unignorereports, setpermissions, setsuggestedsort, sticky, +// unsticky, setcontestmode, unsetcontestmode, lock, unlock, muteuser, unmuteuser, createrule, editrule, +// reorderrules, deleterule, spoiler, unspoiler, modmail_enrollment, community_styling, community_widgets, +// markoriginalcontent, collections, events, hidden_award, add_community_topics, remove_community_topics, +// create_scheduled_post, edit_scheduled_post, delete_scheduled_post, submit_scheduled_post, edit_post_requirements +func (s *ModerationService) GetActionsByType(ctx context.Context, subreddit string, actionType string, opts ...SearchOptionSetter) (*ModActions, *Response, error) { + opts = append(opts, setType(actionType)) + return s.GetActions(ctx, subreddit, opts...) +} + +// AcceptInvite accepts a pending invite to moderate the specified subreddit. +func (s *ModerationService) AcceptInvite(ctx context.Context, subreddit string) (*Response, error) { + path := fmt.Sprintf("r/%s/api/accept_moderator_invite", subreddit) + + form := url.Values{} + form.Set("api_type", "json") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Approve approves a post or comment via its full ID. +func (s *ModerationService) Approve(ctx context.Context, id string) (*Response, error) { + path := "api/approve" + + form := url.Values{} + form.Set("id", id) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Remove removes a post, comment or modmail message via its full ID. +func (s *ModerationService) Remove(ctx context.Context, id string) (*Response, error) { + path := "api/remove" + + form := url.Values{} + form.Set("id", id) + form.Set("spam", "false") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// RemoveSpam removes a post, comment or modmail message via its full ID and marks it as spam. +func (s *ModerationService) RemoveSpam(ctx context.Context, id string) (*Response, error) { + path := "api/remove" + + form := url.Values{} + form.Set("id", id) + form.Set("spam", "true") + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// Leave abdicates your moderator status in a subreddit via its full ID. +func (s *ModerationService) Leave(ctx context.Context, subredditID string) (*Response, error) { + path := "api/leavemoderator" + + form := url.Values{} + form.Set("id", subredditID) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// LeaveContributor abdicates your approved user status in a subreddit via its full ID. +func (s *ModerationService) LeaveContributor(ctx context.Context, subredditID string) (*Response, error) { + path := "api/leavecontributor" + + form := url.Values{} + form.Set("id", subredditID) + + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) } -*/ diff --git a/moderation_test.go b/moderation_test.go index fc949a5..52c56e4 100644 --- a/moderation_test.go +++ b/moderation_test.go @@ -3,6 +3,7 @@ package reddit import ( "fmt" "net/http" + "net/url" "testing" "time" @@ -63,3 +64,147 @@ func TestModerationService_GetActions(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expectedModActionsResult, result) } + +func TestModerationService_GetActionsByType(t *testing.T) { + setup() + defer teardown() + + blob := readFileContents(t, "testdata/moderation/actions.json") + + mux.HandleFunc("/r/testsubreddit/about/log", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method) + + form := url.Values{} + form.Set("type", "testtype") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + + fmt.Fprint(w, blob) + }) + + result, _, err := client.Moderation.GetActionsByType(ctx, "testsubreddit", "testtype") + assert.NoError(t, err) + assert.Equal(t, expectedModActionsResult, result) +} + +func TestModerationService_AcceptInvite(t *testing.T) { + setup() + defer teardown() + + blob := readFileContents(t, "testdata/moderation/actions.json") + + mux.HandleFunc("/r/testsubreddit/api/accept_moderator_invite", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("api_type", "json") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + + fmt.Fprint(w, blob) + }) + + _, err := client.Moderation.AcceptInvite(ctx, "testsubreddit") + assert.NoError(t, err) +} + +func TestModerationService_Approve(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/approve", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t3_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + }) + + _, err := client.Moderation.Approve(ctx, "t3_test") + assert.NoError(t, err) +} + +func TestModerationService_Remove(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/remove", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t3_test") + form.Set("spam", "false") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + }) + + _, err := client.Moderation.Remove(ctx, "t3_test") + assert.NoError(t, err) +} + +func TestModerationService_RemoveSpam(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/remove", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t3_test") + form.Set("spam", "true") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + }) + + _, err := client.Moderation.RemoveSpam(ctx, "t3_test") + assert.NoError(t, err) +} + +func TestModerationService_Leave(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/leavemoderator", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t5_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + }) + + _, err := client.Moderation.Leave(ctx, "t5_test") + assert.NoError(t, err) +} + +func TestModerationService_LeaveContributor(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/api/leavecontributor", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + + form := url.Values{} + form.Set("id", "t5_test") + + err := r.ParseForm() + assert.NoError(t, err) + assert.Equal(t, form, r.Form) + }) + + _, err := client.Moderation.LeaveContributor(ctx, "t5_test") + assert.NoError(t, err) +} diff --git a/search.go b/search.go index b2f2cc1..daff974 100644 --- a/search.go +++ b/search.go @@ -68,6 +68,8 @@ func SetTimespan(v Timespan) SearchOptionSetter { } // setType sets the type option. +// It could be user, link, sr (subreddit). +// For mod actions, it's for the type of action (e.g. "banuser", "spamcomment"). func setType(v string) SearchOptionSetter { return func(opts url.Values) { opts.Set("type", v)