medium_sdk 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|