From 07436f7b277564f9a55d8550b7576193164f3bee Mon Sep 17 00:00:00 2001 From: Csaba Okrona Date: Tue, 6 Oct 2020 14:25:51 +0200 Subject: [PATCH 1/2] Removed unused interfaces and renames services to '*Service' from '*ServiceOp' --- instapaper/bookmarks.go | 38 ++++++++++++------------------------ instapaper/bookmarks_test.go | 10 +++++----- instapaper/folders.go | 16 ++++++--------- 3 files changed, 23 insertions(+), 41 deletions(-) diff --git a/instapaper/bookmarks.go b/instapaper/bookmarks.go index e5bf561..aa6251e 100644 --- a/instapaper/bookmarks.go +++ b/instapaper/bookmarks.go @@ -60,28 +60,14 @@ type BookmarkAddRequestParams struct { PrivateSourceName string } -// BookmarkService defines the interface for all bookmark related API operations -type bookmarkService interface { - List(BookmarkListRequestParams) ([]Bookmark, error) - GetText(int) (string, error) - Star(int) error - UnStar(int) error - Archive(int) error - UnArchive(int) error - DeletePermanently(int) error - Move(int, string) error - UpdateReadProgress(int, float32, int64) - Add(BookmarkAddRequestParams) (Bookmark, error) -} - -// BookmarkServiceOp is the implementation of the bookmark related parts of the API client, conforming to the BookmarkService interface -type BookmarkServiceOp struct { +// BookmarkService is the implementation of the bookmark related parts of the API client, conforming to the BookmarkService interface +type BookmarkService struct { Client Client } // List returns the list of bookmarks. By default it returns (maximum) 500 of the unread bookmarks // see BookmarkListRequestParams for filtering options -func (svc *BookmarkServiceOp) List(p BookmarkListRequestParams) (*BookmarkListResponse, error) { +func (svc *BookmarkService) List(p BookmarkListRequestParams) (*BookmarkListResponse, error) { params := url.Values{} params.Set("limit", strconv.Itoa(p.Limit)) if p.CustomHaveParam != "" { @@ -127,7 +113,7 @@ func (svc *BookmarkServiceOp) List(p BookmarkListRequestParams) (*BookmarkListRe } // GetText returns the specified bookmark's processed text-view HTML, which is always text/html encoded as UTF-8. -func (svc *BookmarkServiceOp) GetText(bookmarkID int) (string, error) { +func (svc *BookmarkService) GetText(bookmarkID int) (string, error) { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) res, err := svc.Client.Call("/bookmarks/get_text", params) @@ -148,7 +134,7 @@ func (svc *BookmarkServiceOp) GetText(bookmarkID int) (string, error) { } // Star stars the specified bookmark -func (svc *BookmarkServiceOp) Star(bookmarkID int) error { +func (svc *BookmarkService) Star(bookmarkID int) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) _, err := svc.Client.Call("/bookmarks/star", params) @@ -156,7 +142,7 @@ func (svc *BookmarkServiceOp) Star(bookmarkID int) error { } // UnStar un-stars the specified bookmark -func (svc *BookmarkServiceOp) UnStar(bookmarkID int) error { +func (svc *BookmarkService) UnStar(bookmarkID int) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) _, err := svc.Client.Call("/bookmarks/unstar", params) @@ -164,7 +150,7 @@ func (svc *BookmarkServiceOp) UnStar(bookmarkID int) error { } // Archive archives the specified bookmark -func (svc *BookmarkServiceOp) Archive(bookmarkID int) error { +func (svc *BookmarkService) Archive(bookmarkID int) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) _, err := svc.Client.Call("/bookmarks/archive", params) @@ -172,7 +158,7 @@ func (svc *BookmarkServiceOp) Archive(bookmarkID int) error { } // UnArchive un-archives the specified bookmark -func (svc *BookmarkServiceOp) UnArchive(bookmarkID int) error { +func (svc *BookmarkService) UnArchive(bookmarkID int) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) _, err := svc.Client.Call("/bookmarks/unarchive", params) @@ -180,7 +166,7 @@ func (svc *BookmarkServiceOp) UnArchive(bookmarkID int) error { } // DeletePermanently PERMANENTLY deletes the specified bookmark -func (svc *BookmarkServiceOp) DeletePermanently(bookmarkID int) error { +func (svc *BookmarkService) DeletePermanently(bookmarkID int) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) _, err := svc.Client.Call("/bookmarks/delete", params) @@ -188,7 +174,7 @@ func (svc *BookmarkServiceOp) DeletePermanently(bookmarkID int) error { } // Move moves the specified bookmark to the specified folder -func (svc *BookmarkServiceOp) Move(bookmarkID int, folderID string) error { +func (svc *BookmarkService) Move(bookmarkID int, folderID string) error { params := url.Values{} params.Set("bookmark_id", strconv.Itoa(bookmarkID)) params.Set("folder_id", folderID) @@ -199,7 +185,7 @@ func (svc *BookmarkServiceOp) Move(bookmarkID int, folderID string) error { // UpdateReadProgress updates the read progress on the bookmark // progress is between 0.0 and 1.0 - a percentage // when - Unix timestamp - optionally specify when the update happened. If it's set to 0 the current timestamp is used. -func (svc *BookmarkServiceOp) UpdateReadProgress(bookmarkID int, progress float32, when int64) error { +func (svc *BookmarkService) UpdateReadProgress(bookmarkID int, progress float32, when int64) error { if when == 0 { when = time.Now().Unix() } @@ -212,7 +198,7 @@ func (svc *BookmarkServiceOp) UpdateReadProgress(bookmarkID int, progress float3 } // Add adds a new bookmark from the specified URL -func (svc *BookmarkServiceOp) Add(p BookmarkAddRequestParams) (*Bookmark, error) { +func (svc *BookmarkService) Add(p BookmarkAddRequestParams) (*Bookmark, error) { params := url.Values{} params.Set("url", p.URL) if p.Description != "" { diff --git a/instapaper/bookmarks_test.go b/instapaper/bookmarks_test.go index 9aeb049..8e13c78 100644 --- a/instapaper/bookmarks_test.go +++ b/instapaper/bookmarks_test.go @@ -40,7 +40,7 @@ func TestWithoutAuthentication(t *testing.T) { client.Credentials = nil mux.HandleFunc("/bookmarks/list", func(w http.ResponseWriter, r *http.Request) { }) - svc := BookmarkServiceOp{ + svc := BookmarkService{ Client: client, } _, err := svc.List(DefaultBookmarkListRequestParams) @@ -59,7 +59,7 @@ func TestBogusValidResponse(t *testing.T) { } fmt.Fprint(w, rawResponse) }) - svc := BookmarkServiceOp{ + svc := BookmarkService{ Client: client, } bookmarkList, err := svc.List(DefaultBookmarkListRequestParams) @@ -80,7 +80,7 @@ func TestInvalidResponse(t *testing.T) { mux.HandleFunc("/bookmarks/list", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, rawResponse) }) - svc := BookmarkServiceOp{ + svc := BookmarkService{ Client: client, } bookmarkList, err := svc.List(DefaultBookmarkListRequestParams) @@ -100,7 +100,7 @@ func TestNot200OKResponse(t *testing.T) { mux.HandleFunc("/bookmarks/list", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) }) - svc := BookmarkServiceOp{ + svc := BookmarkService{ Client: client, } bookmarkList, err := svc.List(DefaultBookmarkListRequestParams) @@ -185,7 +185,7 @@ func TestValidResponse(t *testing.T) { } fmt.Fprint(w, rawResponse) }) - svc := BookmarkServiceOp{ + svc := BookmarkService{ Client: client, } bookmarkList, err := svc.List(DefaultBookmarkListRequestParams) diff --git a/instapaper/folders.go b/instapaper/folders.go index 7a7beb9..7cc9d4f 100644 --- a/instapaper/folders.go +++ b/instapaper/folders.go @@ -26,17 +26,13 @@ const FolderIDStarred = "starred" // FolderIDArchive is a built-in folder for archived bookmarks const FolderIDArchive = "archive" -type folderService interface { - List() ([]Folder, error) -} - -// FolderServiceOp encapsulates all folder operations -type FolderServiceOp struct { +// FolderService encapsulates all folder operations +type FolderService struct { Client Client } // List returns the list of *custom created* folders. It does not return any of the built in ones! -func (svc *FolderServiceOp) List() ([]Folder, error) { +func (svc *FolderService) List() ([]Folder, error) { res, err := svc.Client.Call("/folders/list", nil) if err != nil { return nil, err @@ -65,7 +61,7 @@ func (svc *FolderServiceOp) List() ([]Folder, error) { } // Add creates a folder and returns with it if there wasn't already one with the same title - in that case it returns an error -func (svc *FolderServiceOp) Add(title string) (*Folder, error) { +func (svc *FolderService) Add(title string) (*Folder, error) { params := url.Values{} params.Set("title", title) res, err := svc.Client.Call("/folders/add", params) @@ -95,7 +91,7 @@ func (svc *FolderServiceOp) Add(title string) (*Folder, error) { } // Delete removes a folder and moves all of its bookmark entries to the archive -func (svc *FolderServiceOp) Delete(folderID string) error { +func (svc *FolderService) Delete(folderID string) error { params := url.Values{} params.Set("folder_id", folderID) _, err := svc.Client.Call("/folders/delete", params) @@ -111,7 +107,7 @@ func (svc *FolderServiceOp) Delete(folderID string) error { // the order of the pairs in the list does not matter. // You should include all folders for consistency. // !!!No errors returned for missing or invalid folders!!! -func (svc *FolderServiceOp) SetOrder(folderOrderlist string) ([]Folder, error) { +func (svc *FolderService) SetOrder(folderOrderlist string) ([]Folder, error) { params := url.Values{} params.Set("order", folderOrderlist) res, err := svc.Client.Call("/folders/set_order", params) From b14431895a13afa9ab79e05b64721751b72d7e83 Mon Sep 17 00:00:00 2001 From: Csaba Okrona Date: Tue, 6 Oct 2020 14:41:54 +0200 Subject: [PATCH 2/2] Some refactoring, and the full implementation of higlights. Fixes #17 , fixes #15 , fixes #16 --- instapaper/bookmarks.go | 42 +++++++++--------- instapaper/bookmarks_test.go | 2 +- instapaper/folders.go | 1 - instapaper/highlights.go | 85 +++++++++++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/instapaper/bookmarks.go b/instapaper/bookmarks.go index aa6251e..722616a 100644 --- a/instapaper/bookmarks.go +++ b/instapaper/bookmarks.go @@ -83,33 +83,31 @@ func (svc *BookmarkService) List(p BookmarkListRequestParams) (*BookmarkListResp res, err := svc.Client.Call("/bookmarks/list", params) if err != nil { return &BookmarkListResponse{}, err - } else { - var bookmarkList BookmarkListResponse - bodyBytes, err := ioutil.ReadAll(res.Body) - if err != nil { - return nil, &APIError{ + } + var bookmarkList BookmarkListResponse + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, &APIError{ + StatusCode: res.StatusCode, + Message: err.Error(), + ErrorCode: ErrHTTPError, + WrappedError: err, + } + } + bodyString := string(bodyBytes) + bookmarkList.RawResponse = bodyString + err = json.Unmarshal([]byte(bodyString), &bookmarkList) + if err != nil { + return &BookmarkListResponse{ + RawResponse: bodyString, + }, &APIError{ StatusCode: res.StatusCode, Message: err.Error(), - ErrorCode: ErrHTTPError, + ErrorCode: ErrUnmarshalError, WrappedError: err, } - } - bodyString := string(bodyBytes) - bookmarkList.RawResponse = bodyString - err = json.Unmarshal([]byte(bodyString), &bookmarkList) - if err != nil { - return &BookmarkListResponse{ - RawResponse: bodyString, - }, &APIError{ - StatusCode: res.StatusCode, - Message: err.Error(), - ErrorCode: ErrUnmarshalError, - WrappedError: err, - } - } - return &bookmarkList, nil } - + return &bookmarkList, nil } // GetText returns the specified bookmark's processed text-view HTML, which is always text/html encoded as UTF-8. diff --git a/instapaper/bookmarks_test.go b/instapaper/bookmarks_test.go index 8e13c78..0e7d260 100644 --- a/instapaper/bookmarks_test.go +++ b/instapaper/bookmarks_test.go @@ -173,7 +173,7 @@ func TestValidResponse(t *testing.T) { BookmarkID: 123456, Text: "That said, I do have some feelings on the matter.", Note: "", - Time: 1601797631, + Time: "1601797631", Position: 0, }, }, diff --git a/instapaper/folders.go b/instapaper/folders.go index 7cc9d4f..94d2556 100644 --- a/instapaper/folders.go +++ b/instapaper/folders.go @@ -56,7 +56,6 @@ func (svc *FolderService) List() ([]Folder, error) { WrappedError: err, } } - fmt.Println(string(bodyBytes)) return folderList, nil } diff --git a/instapaper/highlights.go b/instapaper/highlights.go index 14bd97c..adc596b 100644 --- a/instapaper/highlights.go +++ b/instapaper/highlights.go @@ -1,11 +1,94 @@ package instapaper +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/url" + "strconv" +) + // Highlight represents a highlight within a bookmark type Highlight struct { ID int `json:"highlight_id"` BookmarkID int `json:"bookmark_id"` Text string Note string - Time int + Time json.Number Position int } + +type HighlightService struct { + Client Client +} + +// List fetches all highlights for the specified bookmark +func (svc *HighlightService) List(bookmarkID int) ([]Highlight, error) { + path := fmt.Sprintf("/bookmarks/%d/highlights", bookmarkID) + res, err := svc.Client.Call(path, nil) + if err != nil { + return nil, err + } + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, &APIError{ + StatusCode: res.StatusCode, + Message: err.Error(), + ErrorCode: ErrHTTPError, + WrappedError: err, + } + } + var highlightList []Highlight + err = json.Unmarshal(bodyBytes, &highlightList) + if err != nil { + return nil, &APIError{ + StatusCode: res.StatusCode, + Message: err.Error(), + ErrorCode: ErrUnmarshalError, + WrappedError: err, + } + } + return highlightList, nil +} + +// Delete removes the specified highlight +func (svc *HighlightService) Delete(highlightID int) error { + path := fmt.Sprintf("/highlights/%d/delete", highlightID) + _, err := svc.Client.Call(path, nil) + if err != nil { + return err + } + return nil +} + +// Add adds a highlight for the specified bookmark +func (svc *HighlightService) Add(bookmarkID int, text string, position int) (*Highlight, error) { + path := fmt.Sprintf("/bookmarks/%d/highlight", bookmarkID) + params := url.Values{} + params.Set("text", text) + params.Set("position", strconv.Itoa(position)) + res, err := svc.Client.Call(path, params) + if err != nil { + return nil, err + } + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, &APIError{ + StatusCode: res.StatusCode, + Message: err.Error(), + ErrorCode: ErrHTTPError, + WrappedError: err, + } + } + var highlightList []Highlight + err = json.Unmarshal(bodyBytes, &highlightList) + if err != nil { + return nil, &APIError{ + StatusCode: res.StatusCode, + Message: err.Error(), + ErrorCode: ErrUnmarshalError, + WrappedError: err, + } + } + return &highlightList[0], nil +}