medium_sdk 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +55 -9
- data/lib/medium_sdk.rb +1 -1
- data/lib/medium_sdk/client.rb +23 -16
- data/lib/medium_sdk/connection/auth_code.rb +24 -17
- data/test/test_api_me_stub.rb +151 -0
- data/test/test_api_me_unk.rb +22 -0
- data/test/test_oauth_stub.rb +42 -0
- data/test/test_setup_oauth.rb +53 -0
- data/test/test_setup_token.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afab6a1385d13e4a793053d8f316d0b833965c00
|
4
|
+
data.tar.gz: f5103cf9ef2728c0eee21fee3ebcedac80c706c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbc6d536ea192bdd2e1fe99dfbaaa709411b3af6363316f2c7d66c12b07724747d41cae24eb73cebcb11882d26169ea05300cd98a28a40f8ab9620c78227b830
|
7
|
+
data.tar.gz: fb92b3958cb66cf4a3562c270ea72ba6f4961fcb932f9cc41b437fc327e0a9c7d7a0c8af9d4d1afc0da45c9b7dfd50f29e8f82e50fb7ef1e10b1d1ab2c88c58e
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -15,9 +15,10 @@ Medium SDK for Ruby
|
|
15
15
|
|
16
16
|
A Ruby SDK for the [Medium.com API](https://github.com/Medium/medium-api-docs) including:
|
17
17
|
|
18
|
-
1. Auth via OAuth 2.0 with token refresh and demo app
|
19
|
-
1. Auth via integration token
|
20
|
-
1. Get and Post APIs
|
18
|
+
1. Auth via OAuth 2.0 with [automatic token refresh](https://github.com/grokify/faraday_middleware-oauth2_refresh) and [demo app](https://github.com/grokify/medium-sdk-ruby/tree/master/scripts/sinatra). This is necessary to request the `listPublications` or `uploadImage` access scopes.
|
19
|
+
1. Auth via integration token with [demo app](https://github.com/grokify/medium-sdk-ruby/blob/master/scripts)
|
20
|
+
1. Get and Post convenience APIs
|
21
|
+
1. Raw APIs via Faraday HTTP client
|
21
22
|
|
22
23
|
## Installation
|
23
24
|
|
@@ -42,9 +43,10 @@ $ gem install medium_sdk
|
|
42
43
|
|
43
44
|
#### Authorization Code Grant
|
44
45
|
|
45
|
-
The OAuth 2.0 authorization code grant is designed for where authorization needs to be granted by a 3rd party resource owner.
|
46
|
+
The OAuth 2.0 authorization code grant is designed for where authorization needs to be granted by a 3rd party resource owner. This is required if your app wishes to request the `listPublications` or `uploadImage` scopes.
|
46
47
|
|
47
|
-
|
48
|
+
* Initializing the SDK with the `client_id` parameter will use `MediumSdk::Connection::AuthCode` to manage the connection
|
49
|
+
* Token refresh is automatically / transparently handled by `FaradayMiddleware::OAuth2Refresh`
|
48
50
|
|
49
51
|
```ruby
|
50
52
|
require 'medium_sdk'
|
@@ -58,7 +60,7 @@ client = MediumSdk.new(
|
|
58
60
|
|
59
61
|
# Retrieve OAuth authorize url using default redirect URL
|
60
62
|
auth_url = client.connection.authorize_uri(
|
61
|
-
scope: 'basicProfile,publishPost',
|
63
|
+
scope: 'basicProfile,listPublications,publishPost',
|
62
64
|
state: 'myState'
|
63
65
|
)
|
64
66
|
```
|
@@ -70,22 +72,43 @@ code = params['code'] # e.g. using Sinatra to retrieve code param in Redirect U
|
|
70
72
|
client.connection.authorize_code(code)
|
71
73
|
```
|
72
74
|
|
75
|
+
You can also save and load tokens for use across SDK instances:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# Access `OAuth2::AccessToken` object as hash including `access_token`, `refresh_token`, etc.
|
79
|
+
token_hash = client.connection.token.to_hash
|
80
|
+
|
81
|
+
# set_token() accepts a hash or OAuth2::AccessToken object
|
82
|
+
client.connection.set_token(token_hash)
|
83
|
+
```
|
84
|
+
|
73
85
|
#### Integration Token
|
74
86
|
|
87
|
+
Initializing the SDK with the `integration_token` and not the `client_id` parameter will use `MediumSdk::Connection::IntegrationToken` to manage the connection.
|
88
|
+
|
75
89
|
```ruby
|
76
90
|
require 'medium_sdk'
|
77
91
|
|
92
|
+
# Initialize SDK with integration token
|
78
93
|
client = MediumSdk.new integration_token: token
|
94
|
+
|
95
|
+
# Set integration token after initialization
|
96
|
+
client.connection.token = token
|
79
97
|
```
|
80
98
|
|
81
99
|
### API Requests
|
82
100
|
|
101
|
+
#### Convenience Methods
|
102
|
+
|
103
|
+
Convenience methods are provided which return the `data` property of the response body.
|
104
|
+
|
83
105
|
```ruby
|
84
106
|
# Getting the authenticated user’s details
|
85
107
|
data = client.me
|
86
108
|
|
87
109
|
# Listing the user’s publications
|
88
|
-
data = client.user_publications '
|
110
|
+
data = client.user_publications # uses authorized user's userId
|
111
|
+
data = client.user_publications 'user_id' # uses explicit userId
|
89
112
|
|
90
113
|
# Fetching contributors for a publication
|
91
114
|
data = client.publication_contributors 'publication_id'
|
@@ -99,17 +122,40 @@ data = client.post, {
|
|
99
122
|
publishStatus: "draft"
|
100
123
|
}
|
101
124
|
|
102
|
-
# Creating a
|
125
|
+
# Creating a backdated user post using `publishedAt` and `notifyFollowers`
|
126
|
+
data = client.post, {
|
127
|
+
title: "Hard things in software development",
|
128
|
+
contentFormat: "html",
|
129
|
+
content: "<p>Cache invalidation</p><p>Naming things</p>",
|
130
|
+
tags: ["development", "design"],
|
131
|
+
publishStatus: "public",
|
132
|
+
publishedAt: "2016-08-12T00:00:00+00:00",
|
133
|
+
notifyFollowers: false
|
134
|
+
}
|
135
|
+
|
136
|
+
# Creating a publication post using `publicationId`
|
103
137
|
data = client.post, {
|
104
138
|
title: "Hard things in software development",
|
105
139
|
contentFormat: "html",
|
106
140
|
content: "<p>Cache invalidation</p><p>Naming things</p>",
|
107
141
|
tags: ["development", "design"],
|
108
|
-
publishStatus: "
|
142
|
+
publishStatus: "public",
|
109
143
|
publicationId: "deadbeef"
|
110
144
|
}
|
111
145
|
```
|
112
146
|
|
147
|
+
#### Raw Methods
|
148
|
+
|
149
|
+
The SDK's Faraday client can be accessed for sending raw requests:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
response = client.connection.http.get 'me'
|
153
|
+
|
154
|
+
response = client.connection.http do |req|
|
155
|
+
req.url 'me'
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
113
159
|
## Demos
|
114
160
|
|
115
161
|
Demos are in the `scripts` directory and use `.env` files for configuration.
|
data/lib/medium_sdk.rb
CHANGED
data/lib/medium_sdk/client.rb
CHANGED
@@ -2,13 +2,11 @@ module MediumSdk
|
|
2
2
|
class Client
|
3
3
|
attr_accessor :connection
|
4
4
|
|
5
|
-
attr_reader :me
|
6
|
-
|
7
5
|
def initialize(opts = {})
|
8
|
-
if opts.key? :
|
9
|
-
@connection = MediumSdk::Connection::IntegrationToken.new opts
|
10
|
-
elsif opts.key? :client_id
|
6
|
+
if opts.key? :client_id
|
11
7
|
@connection = MediumSdk::Connection::AuthCode.new opts
|
8
|
+
elsif opts.key? :integration_token
|
9
|
+
@connection = MediumSdk::Connection::IntegrationToken.new opts
|
12
10
|
end
|
13
11
|
end
|
14
12
|
|
@@ -19,16 +17,30 @@ module MediumSdk
|
|
19
17
|
end
|
20
18
|
|
21
19
|
def body_key(res, key)
|
20
|
+
if res.status >= 400
|
21
|
+
raise "HTTP Error #{res.status} " + res.pretty_inspect
|
22
|
+
end
|
22
23
|
return res.body.key?(key) ? res.body[key] : nil
|
23
24
|
end
|
24
25
|
|
25
|
-
def me()
|
26
|
-
@
|
27
|
-
|
26
|
+
def me(reload = nil)
|
27
|
+
if @_me.nil? || reload
|
28
|
+
@_me = body_key get_url('me'), 'data'
|
29
|
+
end
|
30
|
+
return @_me
|
31
|
+
end
|
32
|
+
|
33
|
+
def me_id
|
34
|
+
me unless @_me
|
35
|
+
unless @_me.is_a?(Hash) && @_me.key?('id') && @_me['id'].to_s.length>0
|
36
|
+
raise 'Authorized User Id is unknown'
|
37
|
+
end
|
38
|
+
return @_me['id']
|
28
39
|
end
|
29
40
|
|
30
|
-
def user_publications(user_id)
|
31
|
-
|
41
|
+
def user_publications(user_id = nil)
|
42
|
+
user_id = me_id if user_id.nil?
|
43
|
+
res = get_url File.join 'users', user_id.to_s, 'publications'
|
32
44
|
return body_key(res, 'data')
|
33
45
|
end
|
34
46
|
|
@@ -39,12 +51,7 @@ module MediumSdk
|
|
39
51
|
post.delete :publicationId
|
40
52
|
url = File.join 'publications', publication_id, 'posts'
|
41
53
|
else
|
42
|
-
|
43
|
-
unless @me.is_a?(Hash) && @me.key?('id') && @me['id'].to_s.length>0
|
44
|
-
raise 'Authorized User Id is unknown'
|
45
|
-
end
|
46
|
-
id = @me['id']
|
47
|
-
url = File.join 'users', id, 'posts'
|
54
|
+
url = File.join 'users', me_id(), 'posts'
|
48
55
|
end
|
49
56
|
res = @connection.http.post do |req|
|
50
57
|
req.url url
|
@@ -13,6 +13,7 @@ module MediumSdk::Connection
|
|
13
13
|
|
14
14
|
attr_reader :client_id
|
15
15
|
|
16
|
+
attr_accessor :authcode_client
|
16
17
|
attr_accessor :oauth2client
|
17
18
|
attr_accessor :oauth_redirect_uri
|
18
19
|
attr_accessor :http
|
@@ -24,7 +25,9 @@ module MediumSdk::Connection
|
|
24
25
|
@client_secret = opts[:client_secret] if opts.key? :client_secret
|
25
26
|
@oauth_redirect_uri = opts[:redirect_uri] if opts.key? :redirect_uri
|
26
27
|
@scope = opts[:scope] if opts.key? :scope
|
27
|
-
@
|
28
|
+
@instance_headers = opts[:instance_headers] if opts.key? :instance_headers
|
29
|
+
@oauth2client = new_oauth2_client
|
30
|
+
@authcode_client = new_auth_code_client
|
28
31
|
end
|
29
32
|
|
30
33
|
def init_attributes()
|
@@ -35,14 +38,14 @@ module MediumSdk::Connection
|
|
35
38
|
|
36
39
|
def set_token(token)
|
37
40
|
if token.is_a? Hash
|
38
|
-
token = OAuth2::AccessToken::from_hash
|
41
|
+
token = OAuth2::AccessToken::from_hash @oauth2client, token
|
39
42
|
elsif token.is_a? String
|
40
43
|
if token =~ /^\s*{.+}\s*$/
|
41
44
|
token_hash = MultiJson.decode(token)
|
42
|
-
token = OAuth2::AccessToken::from_hash
|
45
|
+
token = OAuth2::AccessToken::from_hash @oauth2client, token_hash
|
43
46
|
else
|
44
47
|
token = { 'access_token' => token }
|
45
|
-
token = OAuth2::AccessToken::from_hash
|
48
|
+
token = OAuth2::AccessToken::from_hash @oauth2client, token
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
@@ -52,7 +55,7 @@ module MediumSdk::Connection
|
|
52
55
|
|
53
56
|
@token = token
|
54
57
|
|
55
|
-
@http = Faraday.new(url:
|
58
|
+
@http = Faraday.new(url: api_version_uri()) do |conn|
|
56
59
|
conn.request :oauth2_refresh, @token
|
57
60
|
conn.request :json
|
58
61
|
if @instance_headers.is_a? Hash
|
@@ -66,7 +69,7 @@ module MediumSdk::Connection
|
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
69
|
-
def
|
72
|
+
def api_version_uri()
|
70
73
|
return File.join API_HOST, API_VERSION
|
71
74
|
end
|
72
75
|
|
@@ -74,8 +77,10 @@ module MediumSdk::Connection
|
|
74
77
|
@oauth2client = new_oauth2_client() unless @oauth2client
|
75
78
|
opts.merge!({
|
76
79
|
'client_id' => @client_id,
|
77
|
-
'response_type' => 'code'
|
78
|
-
|
80
|
+
'response_type' => 'code'})
|
81
|
+
if ! opts.key(:scope) && ! opts.key('scope') && @scope
|
82
|
+
opts.merge!({ 'scope' => @scope })
|
83
|
+
end
|
79
84
|
@oauth2client.auth_code.authorize_url _add_redirect_uri(opts)
|
80
85
|
end
|
81
86
|
|
@@ -88,13 +93,6 @@ module MediumSdk::Connection
|
|
88
93
|
|
89
94
|
def authorize_code(code, opts = {})
|
90
95
|
#token = @oauth2client.auth_code.get_token(code, _add_redirect_uri(opts))
|
91
|
-
|
92
|
-
conn = Faraday.new(:url => API_HOST) do |faraday|
|
93
|
-
faraday.request :url_encoded # form-encode POST params
|
94
|
-
faraday.response :json, content_type: /\bjson$/
|
95
|
-
faraday.response :logger # log requests to STDOUT
|
96
|
-
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
97
|
-
end
|
98
96
|
params = {
|
99
97
|
code: code,
|
100
98
|
client_id: @client_id,
|
@@ -102,12 +100,21 @@ module MediumSdk::Connection
|
|
102
100
|
redirect_uri: @oauth_redirect_uri,
|
103
101
|
grant_type: 'authorization_code'
|
104
102
|
}
|
105
|
-
res =
|
103
|
+
res = @authcode_client.post '/v1/tokens', params
|
106
104
|
set_token res.body
|
107
105
|
return @token
|
108
106
|
end
|
109
107
|
|
110
|
-
def
|
108
|
+
def new_auth_code_client
|
109
|
+
return Faraday.new(url: API_HOST) do |faraday|
|
110
|
+
faraday.request :url_encoded # form-encode POST params
|
111
|
+
faraday.response :json, content_type: /\bjson$/
|
112
|
+
faraday.response :logger # log requests to STDOUT
|
113
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def new_oauth2_client
|
111
118
|
return OAuth2::Client.new(@client_id, @client_secret,
|
112
119
|
site: OAUTH_HOST,
|
113
120
|
authorize_url: OAUTH_AUTHZ_ENDPOINT,
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require './test/test_base.rb'
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'multi_json'
|
5
|
+
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
class MediumSdkApiMeTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
body_me = MultiJson.decode('{
|
11
|
+
"data": {
|
12
|
+
"id": "5303d74c64f66366f00cb9b2a94f3251bf5",
|
13
|
+
"username": "majelbstoat",
|
14
|
+
"name": "Jamie Talbot",
|
15
|
+
"url": "https://medium.com/@majelbstoat",
|
16
|
+
"imageUrl": "https://images.medium.com/0*fkfQiTzT7TlUGGyI.png"
|
17
|
+
}
|
18
|
+
}')
|
19
|
+
body_user_publications = MultiJson.decode('{
|
20
|
+
"data": [
|
21
|
+
{
|
22
|
+
"id": "b969ac62a46b",
|
23
|
+
"name": "About Medium",
|
24
|
+
"description": "What is this thing and how does it work?",
|
25
|
+
"url": "https://medium.com/about",
|
26
|
+
"imageUrl": "https://cdn-images-1.medium.com/fit/c/200/200/0*ae1jbP_od0W6EulE.jpeg"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"id": "b45573563f5a",
|
30
|
+
"name": "Developers",
|
31
|
+
"description": "Medium’s Developer resources",
|
32
|
+
"url": "https://medium.com/developers",
|
33
|
+
"imageUrl": "https://cdn-images-1.medium.com/fit/c/200/200/1*ccokMT4VXmDDO1EoQQHkzg@2x.png"
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}')
|
37
|
+
body_publication_contributors = MultiJson.decode('{
|
38
|
+
"data": [
|
39
|
+
{
|
40
|
+
"publicationId": "b45573563f5a",
|
41
|
+
"userId": "13a06af8f81849c64dafbce822cbafbfab7ed7cecf82135bca946807ea351290d",
|
42
|
+
"role": "editor"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"publicationId": "b45573563f5a",
|
46
|
+
"userId": "1c9c63b15b874d3e354340b7d7458d55e1dda0f6470074df1cc99608a372866ac",
|
47
|
+
"role": "editor"
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"publicationId": "b45573563f5a",
|
51
|
+
"userId": "1cc07499453463518b77d31650c0b53609dc973ad8ebd33690c7be9236e9384ad",
|
52
|
+
"role": "editor"
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"publicationId": "b45573563f5a",
|
56
|
+
"userId": "196f70942410555f4b3030debc4f199a0d5a0309a7b9df96c57b8ec6e4b5f11d7",
|
57
|
+
"role": "writer"
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"publicationId": "b45573563f5a",
|
61
|
+
"userId": "14d4a581f21ff537d245461b8ff2ae9b271b57d9554e25d863e3df6ef03ddd480",
|
62
|
+
"role": "writer"
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}')
|
66
|
+
@post_request = MultiJson.decode('{
|
67
|
+
"title": "Liverpool FC",
|
68
|
+
"contentFormat": "html",
|
69
|
+
"content": "<h1>Liverpool FC</h1><p>You’ll never walk alone.</p>",
|
70
|
+
"canonicalUrl": "http://jamietalbot.com/posts/liverpool-fc",
|
71
|
+
"tags": ["football", "sport", "Liverpool"],
|
72
|
+
"publishStatus": "public"
|
73
|
+
}')
|
74
|
+
body_post = MultiJson.decode('{
|
75
|
+
"data": {
|
76
|
+
"id": "e6f36a",
|
77
|
+
"title": "Liverpool FC",
|
78
|
+
"authorId": "5303d74c64f66366f00cb9b2a94f3251bf5",
|
79
|
+
"tags": ["football", "sport", "Liverpool"],
|
80
|
+
"url": "https://medium.com/@majelbstoat/liverpool-fc-e6f36a",
|
81
|
+
"canonicalUrl": "http://jamietalbot.com/posts/liverpool-fc",
|
82
|
+
"publishStatus": "public",
|
83
|
+
"publishedAt": 1442286338435,
|
84
|
+
"license": "all-rights-reserved",
|
85
|
+
"licenseUrl": "https://medium.com/policy/9db0094a1e0f"
|
86
|
+
}
|
87
|
+
}')
|
88
|
+
body_post_publication = MultiJson.decode('{
|
89
|
+
"data": {
|
90
|
+
"id": "e6f36a",
|
91
|
+
"title": "Liverpool FC",
|
92
|
+
"authorId": "5303d74c64f66366f00cb9b2a94f3251bf5",
|
93
|
+
"tags": ["football", "sport", "Liverpool"],
|
94
|
+
"url": "https://medium.com/@majelbstoat/liverpool-fc-e6f36a",
|
95
|
+
"canonicalUrl": "http://jamietalbot.com/posts/liverpool-fc",
|
96
|
+
"publishStatus": "public",
|
97
|
+
"publishedAt": 1442286338435000,
|
98
|
+
"license": "all-rights-reserved",
|
99
|
+
"licenseUrl": "https://medium.com/policy/9db0094a1e0f"
|
100
|
+
}
|
101
|
+
}')
|
102
|
+
|
103
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
104
|
+
stub.get('me') { |env| [200, {}, body_me] }
|
105
|
+
stub.get('users/5303d74c64f66366f00cb9b2a94f3251bf5/publications') { |env| [200, {}, body_user_publications] }
|
106
|
+
stub.get('publications/b45573563f5a/contributors') { |env| [ 200, {}, body_publication_contributors ]}
|
107
|
+
stub.post('users/5303d74c64f66366f00cb9b2a94f3251bf5/posts') { |env| [ 200, {}, body_post ]}
|
108
|
+
stub.post('publications/b45573563f5a/posts') { |env| [ 200, {}, body_post_publication ]}
|
109
|
+
end
|
110
|
+
@client = Faraday.new do |builder|
|
111
|
+
builder.adapter :test, stubs do |stub|
|
112
|
+
stub.get('me') { |env| [ 200, {}, body_me ]}
|
113
|
+
stub.get('users/5303d74c64f66366f00cb9b2a94f3251bf5/publications') { |env| [200, {}, body_user_publications] }
|
114
|
+
stub.get('publications/b45573563f5a/contributors') { |env| [ 200, {}, body_publication_contributors ]}
|
115
|
+
stub.post('users/5303d74c64f66366f00cb9b2a94f3251bf5/posts') { |env| [ 200, {}, body_post ]}
|
116
|
+
stub.post('publications/b45573563f5a/posts') { |env| [ 200, {}, body_post_publication ]}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
stubs.get('users/5303d74c64f66366f00cb9b2a94f3251bf5/publications') { |env| [ 200, {}, body_user_publications ]}
|
121
|
+
stubs.get('publications/b45573563f5a/contributors') { |env| [ 200, {}, body_publication_contributors ]}
|
122
|
+
stubs.post('users/5303d74c64f66366f00cb9b2a94f3251bf5/posts') { |env| [ 200, {}, body_post ]}
|
123
|
+
stubs.post('publications/b45573563f5a/posts') { |env| [ 200, {}, body_post_publication ]}
|
124
|
+
|
125
|
+
@token = 'deadbeef'
|
126
|
+
@sdk = MediumSdk.new integration_token: @token
|
127
|
+
@sdk.connection.http = @client
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_main
|
131
|
+
data = @sdk.me
|
132
|
+
assert_equal 'majelbstoat', data['username']
|
133
|
+
id = '5303d74c64f66366f00cb9b2a94f3251bf5'
|
134
|
+
assert_equal id, data['id']
|
135
|
+
|
136
|
+
data2 = @sdk.user_publications
|
137
|
+
assert_equal 'b969ac62a46b', data2[0]['id']
|
138
|
+
|
139
|
+
data2 = @sdk.user_publications '5303d74c64f66366f00cb9b2a94f3251bf5'
|
140
|
+
assert_equal 'b969ac62a46b', data2[0]['id']
|
141
|
+
|
142
|
+
data3 = @sdk.publication_contributors 'b45573563f5a'
|
143
|
+
assert_equal '1c9c63b15b874d3e354340b7d7458d55e1dda0f6470074df1cc99608a372866ac', data3[1]['userId']
|
144
|
+
|
145
|
+
data4 = @sdk.post @post_request
|
146
|
+
assert_equal 1442286338435, data4['publishedAt']
|
147
|
+
|
148
|
+
data4 = @sdk.post @post_request.merge({publicationId: 'b45573563f5a'})
|
149
|
+
assert_equal 1442286338435000, data4['publishedAt']
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require './test/test_base.rb'
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'multi_json'
|
5
|
+
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
class MediumSdkApiMeRaiseTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@token = 'deadbeef'
|
11
|
+
@sdk = MediumSdk.new integration_token: @token
|
12
|
+
|
13
|
+
@sdk.connection.http = @client
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_main
|
18
|
+
assert_raise do
|
19
|
+
@sdk.md_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require './test/test_base.rb'
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'multi_json'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
class MediumSdkOAuthStubTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@string = 'deadbeef'
|
10
|
+
@redirect_uri = 'https://example.com/callback'
|
11
|
+
@sdk = MediumSdk.new client_id: 'dead', client_secret: 'beef', redirect_uri: @redirect_uri
|
12
|
+
|
13
|
+
@body_token = MultiJson.decode('{
|
14
|
+
"token_type": "Bearer",
|
15
|
+
"access_token": "dead",
|
16
|
+
"refresh_token": "beef",
|
17
|
+
"scope": "listPublications",
|
18
|
+
"expires_at": 12345
|
19
|
+
}')
|
20
|
+
|
21
|
+
url = '/v1/tokens'
|
22
|
+
#url = '/m/oauth/authorize'
|
23
|
+
#url = 'tokens'
|
24
|
+
#url = 'v1/tokens'
|
25
|
+
|
26
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
27
|
+
stub.post(url) { |env| [200, {}, @body_token] }
|
28
|
+
end
|
29
|
+
@client = Faraday.new do |builder|
|
30
|
+
builder.adapter :test, stubs do |stub|
|
31
|
+
stub.post(url) { |env| [ 200, {}, @body_token ]}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
stubs.post(url) { |env| [ 200, {}, @body_token ]}
|
35
|
+
@sdk.connection.authcode_client = @client
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_main
|
39
|
+
token = @sdk.connection.authorize_code 'myTestAuthCode'
|
40
|
+
assert_equal 12345, token.to_hash[:expires_at]
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require './test/test_base.rb'
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'multi_json'
|
5
|
+
require 'oauth2'
|
6
|
+
|
7
|
+
class MediumSdkSetupOAuthTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@string = 'deadbeef'
|
10
|
+
@redirect_uri = 'https://example.com/callback'
|
11
|
+
@sdk = MediumSdk.new client_id: 'dead', client_secret: 'beef', redirect_uri: @redirect_uri
|
12
|
+
@sdk2 = MediumSdk.new client_id: 'dead', client_secret: 'beef', redirect_uri: @redirect_uri, scope: 'listPublications'
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_main
|
16
|
+
assert_equal 'dead', @sdk.connection.client_id
|
17
|
+
assert_equal @redirect_uri, @sdk.connection.oauth_redirect_uri
|
18
|
+
assert_equal 'https://api.medium.com/v1', @sdk.connection.api_version_uri
|
19
|
+
|
20
|
+
token = {
|
21
|
+
'access_token' => @string
|
22
|
+
}
|
23
|
+
@sdk.connection.set_token token
|
24
|
+
token2 = @sdk.connection.token.to_hash
|
25
|
+
assert_equal @string, token2[:access_token]
|
26
|
+
|
27
|
+
token = {
|
28
|
+
'access_token' => @string + @string
|
29
|
+
}
|
30
|
+
token2 = MultiJson.encode token
|
31
|
+
@sdk.connection.set_token token2
|
32
|
+
token3 = @sdk.connection.token.to_hash
|
33
|
+
assert_equal (@string + @string), token3[:access_token]
|
34
|
+
|
35
|
+
@sdk.connection.set_token @string
|
36
|
+
token = @sdk.connection.token.to_hash
|
37
|
+
assert_equal @string, token[:access_token]
|
38
|
+
|
39
|
+
opts = {}
|
40
|
+
opts = @sdk.connection._add_redirect_uri opts
|
41
|
+
assert_equal @redirect_uri, opts[:redirect_uri]
|
42
|
+
|
43
|
+
auth_uri = @sdk.connection.authorize_uri
|
44
|
+
assert_equal 'https://medium.com/m/oauth/authorize?client_id=dead&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&response_type=code', auth_uri
|
45
|
+
|
46
|
+
auth_uri = @sdk2.connection.authorize_uri
|
47
|
+
assert_equal 'https://medium.com/m/oauth/authorize?client_id=dead&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&response_type=code&scope=listPublications', auth_uri
|
48
|
+
|
49
|
+
assert_raise do
|
50
|
+
@sdk2.connection.set_token(['fail'])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/test/test_setup_token.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: medium_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -185,7 +185,11 @@ files:
|
|
185
185
|
- lib/medium_sdk/connection.rb
|
186
186
|
- lib/medium_sdk/connection/auth_code.rb
|
187
187
|
- lib/medium_sdk/connection/integration_token.rb
|
188
|
+
- test/test_api_me_stub.rb
|
189
|
+
- test/test_api_me_unk.rb
|
188
190
|
- test/test_base.rb
|
191
|
+
- test/test_oauth_stub.rb
|
192
|
+
- test/test_setup_oauth.rb
|
189
193
|
- test/test_setup_token.rb
|
190
194
|
homepage: https://github.com/grokify/
|
191
195
|
licenses:
|