Skip to content

Commit

Permalink
Document all exported types and methods
Browse files Browse the repository at this point in the history
  • Loading branch information
drags committed Nov 10, 2019
1 parent 1990120 commit aaef2c7
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 3 deletions.
5 changes: 5 additions & 0 deletions encoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package pinboard
import "strings"
import "time"

// postTags is a type for parsing tags returned by the Pinboard API. The API returns
// tags as a space delimeted list, however we want to return them to the user as a
// slice of []string
type postTags []string

func (t postTags) MarshalText() ([]byte, error) {
Expand All @@ -19,6 +22,7 @@ func (t *postTags) UnmarshalText(text []byte) error {
return nil
}

// utcDate is a type for parsing _some_ of the dates returned by the Pinboard API.
type utcDate struct {
time.Time
}
Expand All @@ -34,6 +38,7 @@ func (u *utcDate) UnmarshalText(text []byte) error {
return err
}

// notesDate is a type for parsing the datetime stamps in the notes list
type notesDate struct {
time.Time
}
Expand Down
6 changes: 6 additions & 0 deletions notes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type notes struct {
Notes []Note `xml:"note"`
}

// A Note can represent either a note in the NotesList, or a single note. Depending
// on which type of note is called for different fields will be populated (ex: Created
// and Updated are only returned in the NotesList. Text is only returned by NotesGet).
// Text may be contain newlines.
type Note struct {
XMLName xml.Name `xml:"note"`
ID string `xml:"id,attr"`
Expand All @@ -23,6 +27,7 @@ type Note struct {
Text string `xml:"text"`
}

// NotesList returns a list of the user's notes.
func (p *Pinboard) NotesList() ([]Note, error) {
u, err := url.Parse(apiBase + "notes/list")
if err != nil {
Expand All @@ -42,6 +47,7 @@ func (p *Pinboard) NotesList() ([]Note, error) {
return no.Notes, err
}

// NotesGet returns a single Note.
func (p *Pinboard) NotesGet(noteID string) (Note, error) {
if m, _ := regexp.Match("[a-z0-9]{20}", []byte(noteID)); !m {
return Note{}, fmt.Errorf("Note ID must be a 20 character sha1 hash")
Expand Down
8 changes: 6 additions & 2 deletions pinboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (

var apiBase = "https://api.pinboard.in/v1/"

// A Pinboard represents a client for the Pinboard V1 API. Authentication can use passwords
// or tokens. Token auth is recommended for good password hygiene.
// A Pinboard represents a client for the Pinboard V1 API. Authentication can use
// passwords or tokens. Token auth is recommended for good password hygiene.
type Pinboard struct {
User string
Password string
Expand All @@ -41,6 +41,7 @@ func (p *Pinboard) authQuery(u *url.URL) error {
return nil
}

// Retrieve an API response for the given URL. Auth is added to the URL object here
func (p *Pinboard) get(u *url.URL) (*http.Response, error) {
err := p.authQuery(u)
if err != nil {
Expand All @@ -65,6 +66,9 @@ func (p *Pinboard) get(u *url.URL) (*http.Response, error) {
return resp, err
}

// parseResponse is a helper for parsing XML into different types. The use of the
// empty interface and type assertions may be too clever for our own good. Feel free
// to report bugs if you get panics from this
func parseResponse(resp *http.Response, to interface{}) (interface{}, error) {
resp_body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
Expand Down
29 changes: 28 additions & 1 deletion posts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"
)

// Pinboard only accepts URLs with the following schemes
var validSchemes = []string{
"http",
"https",
Expand All @@ -25,6 +26,8 @@ type posts struct {
Posts []Post `xml:"post"`
}

// Posts returned by the Pinboard API. Methods will return a slice of []Post, there
// are no single post read endpoint(s).
type Post struct {
XMLName xml.Name `xml:"post"`
Url string `xml:"href,attr"`
Expand All @@ -42,18 +45,25 @@ type postsLastUpdate struct {
UpdateTime time.Time `xml:"time,attr"`
}

// PostsFilter is used for PostsGet to filter posts returned. If no Date is given
// then only posts from the date of the most recent post will be returned. If a Url
// is given only that post will be returned. Posts can be filtered by up to 3 tags
// (a post must have *ALL* given tags in order to match)
type PostsFilter struct {
Tags []string
Date time.Time
Url string
Meta bool
}

// PostsRecentFilter is used for PostsRecent to filter the posts returned. If no
// Count is given then 15 posts are returned.
type PostsRecentFilter struct {
Tags []string
Count int
}

// PostsUpdated returns that datetime of the most recent post update.
func (p *Pinboard) PostsUpdated() (time.Time, error) {
u, err := url.Parse(apiBase + "posts/update")

Expand All @@ -71,6 +81,10 @@ func (p *Pinboard) PostsUpdated() (time.Time, error) {
return up.UpdateTime, err
}

// PostsAdd adds a new post. The 'keep' argument decides whether a post should be
// updated or rejected if the Url has already been saved before. The 'read' argument
// sets the read-indicator within Pinboard (highlighting the post until "Mark as read"
// has been clicked)
func (p *Pinboard) PostsAdd(pp Post, keep bool, toread bool) error {
u, err := url.Parse(apiBase + "posts/add")
q := u.Query()
Expand Down Expand Up @@ -147,6 +161,9 @@ func (p *Pinboard) PostsAdd(pp Post, keep bool, toread bool) error {
return nil
}

// PostsDelete deletes a post via a given URL. The API does not distinguish whether
// a post with the given URL actually exists within an account, so an error is only
// returned if something happens at the HTTP/application server level.
func (p *Pinboard) PostsDelete(du string) error {
u, err := url.Parse(apiBase + "posts/delete")
if err != nil {
Expand All @@ -165,6 +182,7 @@ func (p *Pinboard) PostsDelete(du string) error {
return nil
}

// PostsGet retrieves all posts from a given day or the single post for a given URL.
func (p *Pinboard) PostsGet(pf PostsFilter) ([]Post, error) {
u, _ := url.Parse(apiBase + "posts/get")
q := u.Query()
Expand Down Expand Up @@ -214,13 +232,14 @@ type postDates struct {
PostDates []PostDate `xml:"date"`
}

// A PostDate represents the number of posts per date within a user's account.
type PostDate struct {
XMLName xml.Name `xml:"date"`
Date utcDate `xml:"date,attr"`
Count int `xml:"count,attr"`
}

// PostDates returns an array of posts-per-day optionally filtered by a
// PostsDates returns an array of posts-per-day optionally filtered by a
// given tag. Contrary to Pinboard's API documentation only a single tag is
// accepted for filtering.
func (p *Pinboard) PostsDates(tag string) ([]PostDate, error) {
Expand All @@ -246,6 +265,7 @@ func (p *Pinboard) PostsDates(tag string) ([]PostDate, error) {
return pd.PostDates, err
}

// PostsRecent returns up to the 100 most recent posts from a user's account.
func (p *Pinboard) PostsRecent(rpf PostsRecentFilter) ([]Post, error) {
u, err := url.Parse(apiBase + "posts/recent")

Expand Down Expand Up @@ -283,6 +303,12 @@ func (p *Pinboard) PostsRecent(rpf PostsRecentFilter) ([]Post, error) {
return pd.Posts, err
}

// PostsAllFilter is used by PostsAll to filter posts returned. If none of the
// filters are set *ALL* posts from the users account will be returned.
// Alternatively results can be sliced by date (using From and To) or paginated
// using Start and Results. Results should be called "Count" but is named Result
// to match the API. Posts can also be filtered by up to 3 tags (posts must be
// tagged with *ALL* given tags in order to match).
type PostsAllFilter struct {
Tags []string
Start int
Expand All @@ -292,6 +318,7 @@ type PostsAllFilter struct {
Meta bool
}

// PostsAll returns all posts in a user's account filtered by a PostsAllFilter.
func (p *Pinboard) PostsAll(apf PostsAllFilter) ([]Post, error) {
u, _ := url.Parse(apiBase + "posts/all")
q := u.Query()
Expand Down
10 changes: 10 additions & 0 deletions tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ type tags struct {
Tags []Tag `xml:"tag"`
}

// A Tag in Pinboard is a simple string applied to posts for organizational purposes.
// Users can create Private Tags (tags only visible to the posting user) by prepending
// the tag with a period (.). Tags returned from the Tags endpoints contain a count of
// how often they're used.
type Tag struct {
XMLName xml.Name `xml:"tag"`
Count int `xml:"count,attr"`
Tag string `xml:"tag,attr"`
}

// TagsGet returns a list of []Tag corresponding to the tags in the user's account.
func (p *Pinboard) TagsGet() ([]Tag, error) {
u, err := url.Parse(apiBase + "tags/get")
if err != nil {
Expand Down Expand Up @@ -64,6 +69,7 @@ func (p *Pinboard) TagsDelete(tag string) error {
return nil
}

// TagsRename renames a tag by changing that tag on every post in the user's account.
func (p *Pinboard) TagsRename(old, new string) error {
u, err := url.Parse(apiBase + "tags/rename")
if err != nil {
Expand All @@ -88,12 +94,16 @@ func (p *Pinboard) TagsRename(old, new string) error {
return nil
}

// Pinboard returns two types of tag suggestions, popular tags are tags from the community.
// Recommended tags are based on the user's existing tags
type TagSuggestions struct {
XMLName xml.Name `xml:"suggested"`
Popular []string `xml:"popular"`
Recommended []string `xml:"recommended"`
}

// TagsSuggestions returns tag suggestions for the given URL. Note: Currently only recommended
// tags are actually returned from the Pinboard API
func (p *Pinboard) TagsSuggestions(postUrl string) (TagSuggestions, error) {
u, _ := url.Parse(apiBase + "posts/suggest")
q := u.Query()
Expand Down
2 changes: 2 additions & 0 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/url"
)

// UserSecret returns the user's secret RSS key for viewing private feeds.
func (p *Pinboard) UserSecret() (string, error) {
u, err := url.Parse(apiBase + "user/secret")
if err != nil {
Expand All @@ -24,6 +25,7 @@ func (p *Pinboard) UserSecret() (string, error) {
return res.Result, err
}

// UserApitoken returns the user's API token.
func (p *Pinboard) UserApiToken() (string, error) {
u, err := url.Parse(apiBase + "user/api_token")
if err != nil {
Expand Down

0 comments on commit aaef2c7

Please sign in to comment.