Finish WikiService

Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
Vartan Benohanian
2020-09-06 14:58:49 -04:00
parent a9e42b21b1
commit 24a87a260b
3 changed files with 779 additions and 41 deletions
+211 -24
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"net/url"
"strings"
"github.com/google/go-querystring/query"
)
@@ -61,6 +62,15 @@ func (p *WikiPage) UnmarshalJSON(b []byte) error {
return nil
}
// WikiPageEditRequest represents a request to edit a wiki page in a subreddit.
type WikiPageEditRequest struct {
Subreddit string `url:"-"`
Page string `url:"page"`
Content string `url:"content"`
// Optional, up to 256 characters long.
Reason string `url:"reason,omitempty"`
}
// WikiPagePermissionLevel defines who can edit a specific wiki page in a subreddit.
type WikiPagePermissionLevel int
@@ -113,10 +123,80 @@ func (s *WikiPageSettings) UnmarshalJSON(b []byte) error {
return nil
}
type wikiPageRevisionListing struct {
Data struct {
Revisions []*WikiPageRevision `json:"children"`
After string `json:"after"`
Before string `json:"before"`
} `json:"data"`
}
func (l *wikiPageRevisionListing) After() string {
return l.Data.After
}
func (l *wikiPageRevisionListing) Before() string {
return l.Data.Before
}
// WikiPageRevision is a revision of a wiki page.
type WikiPageRevision struct {
ID string `json:"id,omitempty"`
Page string `json:"page,omitempty"`
Created *Timestamp `json:"timestamp,omitempty"`
Reason string `json:"reason,omitempty"`
Hidden bool `json:"revision_hidden"`
Author *User `json:"author,omitempty"`
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (r *WikiPageRevision) UnmarshalJSON(b []byte) error {
root := new(struct {
ID string `json:"id,omitempty"`
Page string `json:"page,omitempty"`
Created *Timestamp `json:"timestamp,omitempty"`
Reason string `json:"reason,omitempty"`
Hidden bool `json:"revision_hidden"`
Author thing `json:"author,omitempty"`
})
err := json.Unmarshal(b, root)
if err != nil {
return err
}
r.ID = root.ID
r.Page = root.Page
r.Created = root.Created
r.Reason = root.Reason
r.Hidden = root.Hidden
if user, ok := root.Author.User(); ok {
r.Author = user
}
return nil
}
// Page gets a wiki page.
func (s *WikiService) Page(ctx context.Context, subreddit, page string) (*WikiPage, *Response, error) {
return s.PageRevision(ctx, subreddit, page, "")
}
// PageRevision gets a wiki page at the version it was at the revisionID provided.
// If revisionID is an empty string, it will get the most recent version.
func (s *WikiService) PageRevision(ctx context.Context, subreddit, page, revisionID string) (*WikiPage, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/%s", subreddit, page)
params := struct {
RevisionID string `url:"v,omitempty"`
}{revisionID}
path, err := addOptions(path, params)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest(http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
@@ -132,7 +212,7 @@ func (s *WikiService) Page(ctx context.Context, subreddit, page string) (*WikiPa
return wikiPage, resp, nil
}
// Pages retrieves a list of wiki pages in the subreddit.
// Pages gets a list of wiki pages in the subreddit.
// Returns 403 Forbidden if the wiki is disabled.
func (s *WikiService) Pages(ctx context.Context, subreddit string) ([]string, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/pages", subreddit)
@@ -152,6 +232,42 @@ func (s *WikiService) Pages(ctx context.Context, subreddit string) ([]string, *R
return wikiPages, resp, nil
}
// Edit a wiki page.
func (s *WikiService) Edit(ctx context.Context, editRequest *WikiPageEditRequest) (*Response, error) {
if editRequest == nil {
return nil, errors.New("editRequest: cannot be nil")
}
form, err := query.Values(editRequest)
if err != nil {
return nil, err
}
path := fmt.Sprintf("r/%s/api/wiki/edit", editRequest.Subreddit)
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// Revert a wiki page to a specific revision.
func (s *WikiService) Revert(ctx context.Context, subreddit, page, revisionID string) (*Response, error) {
path := fmt.Sprintf("r/%s/api/wiki/revert", subreddit)
form := url.Values{}
form.Set("page", page)
form.Set("revision", revisionID)
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// Settings gets the subreddit's wiki page's settings.
func (s *WikiService) Settings(ctx context.Context, subreddit, page string) (*WikiPageSettings, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/settings/%s", subreddit, page)
@@ -198,6 +314,100 @@ func (s *WikiService) UpdateSettings(ctx context.Context, subreddit, page string
return settings, resp, nil
}
// Discussions gets a list of discussions (posts) about the wiki page.
func (s *WikiService) Discussions(ctx context.Context, subreddit, page string, opts *ListOptions) ([]*Post, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/discussions/%s", subreddit, page)
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(thing)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
listing, _ := root.Listing()
return listing.Posts(), resp, nil
}
// ToggleVisibility toggles the public visibility of a wiki page revision.
// The returned bool is whether the page was set to hidden or not.
func (s *WikiService) ToggleVisibility(ctx context.Context, subreddit, page, revisionID string) (bool, *Response, error) {
path := fmt.Sprintf("r/%s/api/wiki/hide", subreddit)
form := url.Values{}
form.Set("page", page)
form.Set("revision", revisionID)
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
if err != nil {
return false, nil, err
}
root := new(struct {
Status bool `json:"status"`
})
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return false, resp, err
}
return root.Status, resp, nil
}
func (s *WikiService) revisions(ctx context.Context, subreddit, page string, opts *ListOptions) ([]*WikiPageRevision, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/revisions", subreddit)
if page != "" {
path += "/" + page
}
if opts != nil {
idPrefix := "WikiRevision_"
if opts.After != "" && !strings.HasPrefix(opts.After, idPrefix) {
opts.After = idPrefix + opts.After
}
if opts.Before != "" && !strings.HasPrefix(opts.Before, idPrefix) {
opts.Before = idPrefix + opts.Before
}
}
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(wikiPageRevisionListing)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Data.Revisions, resp, nil
}
// Revisions gets revisions of all pages in the wiki.
func (s *WikiService) Revisions(ctx context.Context, subreddit string, opts *ListOptions) ([]*WikiPageRevision, *Response, error) {
return s.revisions(ctx, subreddit, "", opts)
}
// RevisionsPage gets revisions of the specific wiki page.
// If page is an empty string, it gets revisions of all pages in the wiki.
func (s *WikiService) RevisionsPage(ctx context.Context, subreddit, page string, opts *ListOptions) ([]*WikiPageRevision, *Response, error) {
return s.revisions(ctx, subreddit, page, opts)
}
// Allow the user to edit the specified wiki page in the subreddit.
func (s *WikiService) Allow(ctx context.Context, subreddit, page, username string) (*Response, error) {
path := fmt.Sprintf("r/%s/api/wiki/alloweditor/add", subreddit)
@@ -229,26 +439,3 @@ func (s *WikiService) Deny(ctx context.Context, subreddit, page, username string
return s.client.Do(ctx, req, nil)
}
// Discussions gets a list of discussions (posts) about the wiki page.
func (s *WikiService) Discussions(ctx context.Context, subreddit, page string, opts *ListOptions) ([]*Post, *Response, error) {
path := fmt.Sprintf("r/%s/wiki/discussions/%s", subreddit, page)
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(thing)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
listing, _ := root.Listing()
return listing.Posts(), resp, nil
}
+201 -17
View File
@@ -75,6 +75,45 @@ var expectedWikiPageDiscussions = []*Post{
},
}
var expectedWikiPageRevisions = []*WikiPageRevision{
{
ID: "3b28c343-effb-11ea-859e-0efe313b2cd3",
Page: "index",
Created: &Timestamp{time.Date(2020, 9, 6, 4, 41, 29, 0, time.UTC)},
Reason: "reverted back 1 day",
Hidden: false,
Author: &User{
ID: "164ab8",
Name: "v_95",
Created: &Timestamp{time.Date(2017, 3, 12, 4, 56, 47, 0, time.UTC)},
PostKarma: 691,
CommentKarma: 22235,
HasVerifiedEmail: true,
NSFW: true,
},
},
{
ID: "d217592d-effa-11ea-90af-0e913d9ded0b",
Page: "index",
Created: &Timestamp{time.Date(2020, 9, 6, 4, 38, 33, 0, time.UTC)},
Reason: "reverted back 10 minutes",
Hidden: false,
Author: &User{
ID: "164ab8",
Name: "v_95",
Created: &Timestamp{time.Date(2017, 3, 12, 4, 56, 47, 0, time.UTC)},
PostKarma: 691,
CommentKarma: 22235,
HasVerifiedEmail: true,
NSFW: true,
},
},
}
func TestWikiService_Page(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
@@ -92,6 +131,31 @@ func TestWikiService_Page(t *testing.T) {
require.Equal(t, expectedWikiPage, wikiPage)
}
func TestWikiService_PageRevision(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
blob, err := readFileContents("../testdata/wiki/page.json")
require.NoError(t, err)
mux.HandleFunc("/r/testsubreddit/wiki/testpage", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
form := url.Values{}
form.Set("v", "testrevision")
err := r.ParseForm()
require.NoError(t, err)
require.Equal(t, form, r.Form)
fmt.Fprint(w, blob)
})
wikiPage, _, err := client.Wiki.PageRevision(ctx, "testsubreddit", "testpage", "testrevision")
require.NoError(t, err)
require.Equal(t, expectedWikiPage, wikiPage)
}
func TestWikiService_Pages(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
@@ -112,6 +176,55 @@ func TestWikiService_Pages(t *testing.T) {
require.Equal(t, []string{"faq", "index"}, wikiPages)
}
func TestWikiService_Edit(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
mux.HandleFunc("/r/testsubreddit/api/wiki/edit", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
form := url.Values{}
form.Set("page", "testpage")
form.Set("content", "testcontent")
form.Set("reason", "testreason")
err := r.ParseForm()
require.NoError(t, err)
require.Equal(t, form, r.PostForm)
})
_, err := client.Wiki.Edit(ctx, nil)
require.EqualError(t, err, "editRequest: cannot be nil")
_, err = client.Wiki.Edit(ctx, &WikiPageEditRequest{
Subreddit: "testsubreddit",
Page: "testpage",
Content: "testcontent",
Reason: "testreason",
})
require.NoError(t, err)
}
func TestWikiService_Revert(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
mux.HandleFunc("/r/testsubreddit/api/wiki/revert", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
form := url.Values{}
form.Set("page", "testpage")
form.Set("revision", "testrevision")
err := r.ParseForm()
require.NoError(t, err)
require.Equal(t, form, r.PostForm)
})
_, err := client.Wiki.Revert(ctx, "testsubreddit", "testpage", "testrevision")
require.NoError(t, err)
}
func TestWikiService_Settings(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
@@ -161,6 +274,94 @@ func TestWikiService_UpdateSettings(t *testing.T) {
require.Equal(t, expectedWikiPageSettings, wikiPageSettings)
}
func TestWikiService_Discussions(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
blob, err := readFileContents("../testdata/wiki/discussions.json")
require.NoError(t, err)
mux.HandleFunc("/r/testsubreddit/wiki/discussions/testpage", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
fmt.Fprint(w, blob)
})
wikiPageDiscussions, _, err := client.Wiki.Discussions(ctx, "testsubreddit", "testpage", nil)
require.NoError(t, err)
require.Equal(t, expectedWikiPageDiscussions, wikiPageDiscussions)
}
func TestWikiService_ToggleVisibility(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
mux.HandleFunc("/r/testsubreddit/api/wiki/hide", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
form := url.Values{}
form.Set("page", "testpage")
form.Set("revision", "testrevision")
err := r.ParseForm()
require.NoError(t, err)
require.Equal(t, form, r.PostForm)
fmt.Fprint(w, `{"status": true}`)
})
hidden, _, err := client.Wiki.ToggleVisibility(ctx, "testsubreddit", "testpage", "testrevision")
require.NoError(t, err)
require.True(t, hidden)
}
func TestWikiService_Revisions(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
blob, err := readFileContents("../testdata/wiki/revisions.json")
require.NoError(t, err)
mux.HandleFunc("/r/testsubreddit/wiki/revisions", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
fmt.Fprint(w, blob)
})
wikiPageRevisions, _, err := client.Wiki.Revisions(ctx, "testsubreddit", nil)
require.NoError(t, err)
require.Equal(t, expectedWikiPageRevisions, wikiPageRevisions)
}
func TestWikiService_RevisionsPage(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
blob, err := readFileContents("../testdata/wiki/revisions.json")
require.NoError(t, err)
mux.HandleFunc("/r/testsubreddit/wiki/revisions/testpage", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
form := url.Values{}
form.Set("limit", "10")
form.Set("after", "WikiRevision_wikiId1")
form.Set("before", "WikiRevision_wikiId2")
err := r.ParseForm()
require.NoError(t, err)
require.Equal(t, form, r.Form)
fmt.Fprint(w, blob)
})
wikiPageRevisions, _, err := client.Wiki.RevisionsPage(ctx, "testsubreddit", "testpage", &ListOptions{
Limit: 10,
After: "wikiId1",
Before: "wikiId2",
})
require.NoError(t, err)
require.Equal(t, expectedWikiPageRevisions, wikiPageRevisions)
}
func TestWikiService_Allow(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
@@ -200,20 +401,3 @@ func TestWikiService_Deny(t *testing.T) {
_, err := client.Wiki.Deny(ctx, "testsubreddit", "testpage", "testusername")
require.NoError(t, err)
}
func TestWikiService_Discussions(t *testing.T) {
client, mux, teardown := setup()
defer teardown()
blob, err := readFileContents("../testdata/wiki/discussions.json")
require.NoError(t, err)
mux.HandleFunc("/r/testsubreddit/wiki/discussions/testpage", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
fmt.Fprint(w, blob)
})
wikiPageDiscussions, _, err := client.Wiki.Discussions(ctx, "testsubreddit", "testpage", nil)
require.NoError(t, err)
require.Equal(t, expectedWikiPageDiscussions, wikiPageDiscussions)
}