aboutsummaryrefslogtreecommitdiffhomepage
path: root/integration
diff options
context:
space:
mode:
authorGravatar Frédéric Guillot <fred@miniflux.net>2018-05-20 15:29:14 -0700
committerGravatar Frédéric Guillot <fred@miniflux.net>2018-05-20 15:29:14 -0700
commit7f2fd1fdd85a62b187ad901d4917e561e39e37b2 (patch)
tree635fd7622cda67a0b9a422e093edee0b2bbc7399 /integration
parent0f3f5e442f81d37a03618d0df5ea8f0524a24029 (diff)
Add Pocket authorization flow in the user interface
Diffstat (limited to 'integration')
-rw-r--r--integration/pocket/connector.go103
-rw-r--r--integration/pocket/pocket.go27
2 files changed, 118 insertions, 12 deletions
diff --git a/integration/pocket/connector.go b/integration/pocket/connector.go
new file mode 100644
index 0000000..b3ed79d
--- /dev/null
+++ b/integration/pocket/connector.go
@@ -0,0 +1,103 @@
+// Copyright 2018 Frédéric Guillot. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+package pocket
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/url"
+
+ "github.com/miniflux/miniflux/http/client"
+)
+
+// Connector manages the authorization flow with Pocket to get a personal access token.
+type Connector struct {
+ consumerKey string
+}
+
+// RequestToken fetches a new request token from Pocket API.
+func (c *Connector) RequestToken(redirectURL string) (string, error) {
+ type req struct {
+ ConsumerKey string `json:"consumer_key"`
+ RedirectURI string `json:"redirect_uri"`
+ }
+
+ clt := client.New("https://getpocket.com/v3/oauth/request")
+ response, err := clt.PostJSON(&req{ConsumerKey: c.consumerKey, RedirectURI: redirectURL})
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to fetch request token: %v", err)
+ }
+
+ if response.HasServerFailure() {
+ return "", fmt.Errorf("pocket: unable to fetch request token, status=%d", response.StatusCode)
+ }
+
+ body, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to read response body: %v", err)
+ }
+
+ values, err := url.ParseQuery(string(body))
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to parse response: %v", err)
+ }
+
+ code := values.Get("code")
+ if code == "" {
+ return "", errors.New("pocket: code is empty")
+ }
+
+ return code, nil
+}
+
+// AccessToken fetches a new access token once the end-user authorized the application.
+func (c *Connector) AccessToken(requestToken string) (string, error) {
+ type req struct {
+ ConsumerKey string `json:"consumer_key"`
+ Code string `json:"code"`
+ }
+
+ clt := client.New("https://getpocket.com/v3/oauth/authorize")
+ response, err := clt.PostJSON(&req{ConsumerKey: c.consumerKey, Code: requestToken})
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to fetch access token: %v", err)
+ }
+
+ if response.HasServerFailure() {
+ return "", fmt.Errorf("pocket: unable to fetch access token, status=%d", response.StatusCode)
+ }
+
+ body, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to read response body: %v", err)
+ }
+
+ values, err := url.ParseQuery(string(body))
+ if err != nil {
+ return "", fmt.Errorf("pocket: unable to parse response: %v", err)
+ }
+
+ token := values.Get("access_token")
+ if token == "" {
+ return "", errors.New("pocket: access_token is empty")
+ }
+
+ return token, nil
+}
+
+// AuthorizationURL returns the authorization URL for the end-user.
+func (c *Connector) AuthorizationURL(requestToken, redirectURL string) string {
+ return fmt.Sprintf(
+ "https://getpocket.com/auth/authorize?request_token=%s&redirect_uri=%s",
+ requestToken,
+ redirectURL,
+ )
+}
+
+// NewConnector returns a new Pocket Connector.
+func NewConnector(consumerKey string) *Connector {
+ return &Connector{consumerKey}
+}
diff --git a/integration/pocket/pocket.go b/integration/pocket/pocket.go
index a46cd30..16a826c 100644
--- a/integration/pocket/pocket.go
+++ b/integration/pocket/pocket.go
@@ -1,4 +1,4 @@
-// Copyright 2017 Frédéric Guillot. All rights reserved.
+// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
@@ -16,21 +16,20 @@ type Client struct {
consumerKey string
}
-// Parameters for a Pocket add call.
-type Parameters struct {
- AccessToken string `json:"access_token"`
- ConsumerKey string `json:"consumer_key"`
- Title string `json:"title,omitempty"`
- URL string `json:"url,omitempty"`
-}
-
// AddURL sends a single link to Pocket.
func (c *Client) AddURL(link, title string) error {
if c.consumerKey == "" || c.accessToken == "" {
return fmt.Errorf("pocket: missing credentials")
}
- parameters := &Parameters{
+ type body struct {
+ AccessToken string `json:"access_token"`
+ ConsumerKey string `json:"consumer_key"`
+ Title string `json:"title,omitempty"`
+ URL string `json:"url"`
+ }
+
+ data := &body{
AccessToken: c.accessToken,
ConsumerKey: c.consumerKey,
Title: title,
@@ -38,12 +37,16 @@ func (c *Client) AddURL(link, title string) error {
}
clt := client.New("https://getpocket.com/v3/add")
- response, err := clt.PostJSON(parameters)
+ response, err := clt.PostJSON(data)
+ if err != nil {
+ return fmt.Errorf("pocket: unable to send url: %v", err)
+ }
+
if response.HasServerFailure() {
return fmt.Errorf("pocket: unable to send url, status=%d", response.StatusCode)
}
- return err
+ return nil
}
// NewClient returns a new Pocket client.