diandian-oauth 0.0.3 → 0.1.1
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.
- data/Gemfile +1 -0
- data/Gemfile.lock +8 -2
- data/diandian-oauth.gemspec +1 -1
- data/lib/diandian_oauth.rb +4 -3
- data/lib/diandian_oauth/api.rb +8 -1
- data/lib/diandian_oauth/api/interface.rb +232 -29
- data/lib/diandian_oauth/client.rb +39 -11
- data/lib/diandian_oauth/client/callbacks.rb +49 -0
- data/lib/diandian_oauth/exceptions.rb +223 -6
- data/lib/diandian_oauth/models/response.rb +77 -0
- data/lib/diandian_oauth/models/response_meta.rb +61 -0
- data/test/diandian_oauth/authorize_test.rb +5 -4
- data/test/diandian_oauth/interface_test.rb +51 -10
- metadata +4 -1
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/secretworry/faraday.git
|
3
|
+
revision: b34ecbb6cd4d0b2280cdb19a15f1d39a9b0eb309
|
4
|
+
specs:
|
5
|
+
faraday (0.8.0)
|
6
|
+
multipart-post (~> 1.1)
|
7
|
+
|
1
8
|
GEM
|
2
9
|
remote: http://rubygems.org/
|
3
10
|
specs:
|
@@ -8,8 +15,6 @@ GEM
|
|
8
15
|
i18n (~> 0.6)
|
9
16
|
multi_json (~> 1.0)
|
10
17
|
builder (3.0.0)
|
11
|
-
faraday (0.8.1)
|
12
|
-
multipart-post (~> 1.1)
|
13
18
|
httpauth (0.1)
|
14
19
|
i18n (0.6.0)
|
15
20
|
jwt (0.1.5)
|
@@ -30,4 +35,5 @@ PLATFORMS
|
|
30
35
|
DEPENDENCIES
|
31
36
|
activemodel (~> 3.2.6)
|
32
37
|
activesupport (~> 3.2.1)
|
38
|
+
faraday!
|
33
39
|
oauth2 (~> 0.8.0)
|
data/diandian-oauth.gemspec
CHANGED
data/lib/diandian_oauth.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
require 'active_support/core_ext'
|
1
2
|
require 'diandian_oauth/api'
|
2
3
|
require 'diandian_oauth/client'
|
3
4
|
require 'diandian_oauth/exceptions'
|
4
|
-
require '
|
5
|
+
require 'diandian_oauth/models/response'
|
5
6
|
require 'logger'
|
6
7
|
module DiandianOAuth
|
7
|
-
VERSION = '0.
|
8
|
+
VERSION = '0.1.1'
|
8
9
|
module Logger
|
9
10
|
def logger *args
|
10
11
|
if args.empty?
|
@@ -16,4 +17,4 @@ module DiandianOAuth
|
|
16
17
|
end
|
17
18
|
extend Logger
|
18
19
|
logger STDOUT
|
19
|
-
end
|
20
|
+
end
|
data/lib/diandian_oauth/api.rb
CHANGED
@@ -18,15 +18,22 @@ module DiandianOAuth
|
|
18
18
|
interface :user_likes, Interface::UserLikes
|
19
19
|
interface :user_followings, Interface::UserFollowings
|
20
20
|
interface :my_tags, Interface::MyTags
|
21
|
-
interface :blog, Interface::Blog
|
22
21
|
interface :blog_info, Interface::BlogInfo
|
23
22
|
interface :blog_avatar, Interface::BlogAvatar
|
24
23
|
interface :blog_followers, Interface::BlogFollowers
|
25
24
|
interface :posts, Interface::Posts
|
25
|
+
interface :post_info, Interface::PostInfo
|
26
|
+
interface :create_post, Interface::CreatePost
|
27
|
+
interface :delete_post, Interface::DeletePost
|
28
|
+
interface :reblog_post, Interface::ReblogPost
|
26
29
|
interface :home_feeds, Interface::HomeFeeds
|
27
30
|
interface :tag_feeds, Interface::TagFeeds
|
28
31
|
interface :follow, Interface::Follow
|
29
32
|
interface :unfollow, Interface::Unfollow
|
33
|
+
interface :watch_tag, Interface::WatchTag
|
34
|
+
interface :unwatch_tag, Interface::UnwatchTag
|
30
35
|
interface :submissions, Interface::Submissions
|
36
|
+
interface :submit, Interface::Submit
|
37
|
+
interface :reject_submission, Interface::RejectSubmission
|
31
38
|
end
|
32
39
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module DiandianOAuth
|
3
2
|
class API
|
4
3
|
module Interface
|
@@ -40,20 +39,43 @@ module DiandianOAuth
|
|
40
39
|
end
|
41
40
|
end #Param
|
42
41
|
|
42
|
+
class Params
|
43
|
+
def initialize(params = {})
|
44
|
+
@params = params.symbolize_keys!
|
45
|
+
end
|
46
|
+
def [] key
|
47
|
+
@params[key.to_sym]
|
48
|
+
end
|
49
|
+
|
50
|
+
def []= key, value
|
51
|
+
@params[key.to_sym] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_a
|
55
|
+
@params.reduce([]) do |all, (key, value)|
|
56
|
+
case value
|
57
|
+
when Array
|
58
|
+
value.each{|v| all << [key, v]}
|
59
|
+
else
|
60
|
+
all << [key, value]
|
61
|
+
end
|
62
|
+
all
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_h
|
67
|
+
@params
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
43
71
|
class Base
|
44
72
|
def request_url params = {}
|
45
73
|
raise 'subclasses must implement this method'
|
46
74
|
end
|
47
75
|
|
48
|
-
# when the access_token is out-of-date, refresh it automatically
|
49
|
-
def apply! access_token, params, &block
|
50
|
-
access_token.refresh! if access_token.expired?
|
51
|
-
self.apply access_token, params, &block
|
52
|
-
end
|
53
|
-
|
54
76
|
def apply access_token, params, &block
|
55
|
-
raise
|
56
|
-
params
|
77
|
+
raise TokenExpiredError if access_token.expired?
|
78
|
+
params = Params.new( params || {})
|
57
79
|
action = case request_verb
|
58
80
|
when /get/ then :get
|
59
81
|
when /post/ then :post
|
@@ -62,30 +84,27 @@ module DiandianOAuth
|
|
62
84
|
else raise "unrecognized verb '#{request_verb}'"
|
63
85
|
end # case
|
64
86
|
options = {
|
65
|
-
:
|
87
|
+
:body => extract_params(params).to_a,
|
66
88
|
:raise_errors => false,
|
67
89
|
:parse => :json
|
68
90
|
}
|
69
91
|
request_url = self.request_url(params)
|
70
92
|
if DiandianOAuth.logger.debug?
|
71
|
-
DiandianOAuth.logger.debug("request with action:'#{action}', request_url:'#{request_url}'")
|
93
|
+
DiandianOAuth.logger.debug("request with action:'#{action}', request_url:'#{request_url}', options:'#{options}'")
|
72
94
|
end
|
73
|
-
access_token.request( action, request_url, options, &block)
|
95
|
+
DiandianOAuth::Response.from_response access_token.request( action, request_url, options, &block)
|
74
96
|
end
|
75
97
|
protected
|
76
98
|
def request_verb
|
77
99
|
self.class.verb
|
78
100
|
end
|
79
101
|
def extract_params params
|
80
|
-
params.
|
81
|
-
self.class.params.each_pair.reduce({}) do |result, ele|
|
82
|
-
key = ele[0]
|
83
|
-
param = ele[1]
|
102
|
+
self.class.params.reduce(Params.new) do |result, (key, value)|
|
84
103
|
param_value = params[key]
|
85
|
-
if param_value
|
104
|
+
if param_value
|
86
105
|
result[key] = param_value
|
87
|
-
elsif
|
88
|
-
raise
|
106
|
+
elsif value.required
|
107
|
+
raise ParamIsRequiredError.new( "'#{key}' is required")
|
89
108
|
end
|
90
109
|
result
|
91
110
|
end
|
@@ -137,8 +156,9 @@ module DiandianOAuth
|
|
137
156
|
protected
|
138
157
|
def blog_request_url params
|
139
158
|
blog_cname = params[:blogCName]
|
140
|
-
|
141
|
-
|
159
|
+
blog_uuid = params[:blogUuid]
|
160
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
161
|
+
API.url_for "/blog/#{blog_cname||blog_uuid}"
|
142
162
|
end
|
143
163
|
end #BlogInterface
|
144
164
|
|
@@ -155,7 +175,7 @@ module DiandianOAuth
|
|
155
175
|
size = params[:size]
|
156
176
|
if size
|
157
177
|
unless BlogAvatar.is_valid_size size
|
158
|
-
raise
|
178
|
+
raise IllegalParamError.new("'#{size}' is illegal")
|
159
179
|
end
|
160
180
|
end # if
|
161
181
|
end
|
@@ -166,13 +186,24 @@ module DiandianOAuth
|
|
166
186
|
|
167
187
|
end #BlogAvatar
|
168
188
|
|
189
|
+
class PostInfo < Base
|
190
|
+
param :id, :required => true
|
191
|
+
def request_url params={}
|
192
|
+
blog_cname = params[:blogCName]
|
193
|
+
blog_uuid = params[:blogUuid]
|
194
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
195
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/posts"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
169
199
|
class BlogFollowers < Base
|
170
200
|
param :limit, :required => false
|
171
201
|
param :offset, :required => false
|
172
202
|
def request_url params={}
|
173
203
|
blog_cname = params[:blogCName]
|
174
|
-
|
175
|
-
|
204
|
+
blog_uuid = params[:blogUuid]
|
205
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
206
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/info"
|
176
207
|
end
|
177
208
|
end #BlogFollowers
|
178
209
|
|
@@ -186,8 +217,9 @@ module DiandianOAuth
|
|
186
217
|
param :filter, :required => false
|
187
218
|
def request_url params={}
|
188
219
|
blog_cname = params[:blogCName]
|
189
|
-
|
190
|
-
|
220
|
+
blog_uuid = params[:blogUuid]
|
221
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
222
|
+
path = "/blog/#{blog_cname||blog_uuid}/posts"
|
191
223
|
if params[:type]
|
192
224
|
path = path + "/#{type}"
|
193
225
|
end
|
@@ -195,6 +227,107 @@ module DiandianOAuth
|
|
195
227
|
end
|
196
228
|
end # Posts
|
197
229
|
|
230
|
+
class CreatePost < Base
|
231
|
+
verb :post
|
232
|
+
param :type, :required => true
|
233
|
+
param :state, :required => true
|
234
|
+
param :tag, :required => false
|
235
|
+
param :slug, :required => false
|
236
|
+
#text
|
237
|
+
param :title, :required => false
|
238
|
+
param :body, :required => false
|
239
|
+
#photo
|
240
|
+
param :caption, :required => false
|
241
|
+
param :layout, :required => false
|
242
|
+
param :data, :required => false
|
243
|
+
param :itemDesc, :required => false
|
244
|
+
#link
|
245
|
+
param :title, :required => false
|
246
|
+
param :url, :required => false
|
247
|
+
param :description, :required => false
|
248
|
+
|
249
|
+
#audio
|
250
|
+
param :caption, :required => false
|
251
|
+
param :data, :required => false
|
252
|
+
param :musicName, :required => false
|
253
|
+
param :musicSinger, :required => false
|
254
|
+
param :albumName, :required => false
|
255
|
+
|
256
|
+
#video
|
257
|
+
param :caption, :required => false
|
258
|
+
param :sourceUrl, :required => false
|
259
|
+
|
260
|
+
def request_url params={}
|
261
|
+
blog_cname = params[:blogCName]
|
262
|
+
blog_uuid = params[:blogUuid]
|
263
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
264
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/post"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
class EditPost < Base
|
269
|
+
verb :post
|
270
|
+
param :id, :required => true
|
271
|
+
param :tag, :required => false
|
272
|
+
param :slug, :required => false
|
273
|
+
#text
|
274
|
+
param :title, :required => false
|
275
|
+
param :body, :required => false
|
276
|
+
#photo
|
277
|
+
param :caption, :required => false
|
278
|
+
param :layout, :required => false
|
279
|
+
param :data, :required => false
|
280
|
+
param :itemDesc, :required => false
|
281
|
+
#link
|
282
|
+
param :title, :required => false
|
283
|
+
param :url, :required => false
|
284
|
+
param :description, :required => false
|
285
|
+
|
286
|
+
#audio
|
287
|
+
param :caption, :required => false
|
288
|
+
param :data, :required => false
|
289
|
+
param :musicName, :required => false
|
290
|
+
param :musicSinger, :required => false
|
291
|
+
param :albumName, :required => false
|
292
|
+
|
293
|
+
#video
|
294
|
+
param :caption, :required => false
|
295
|
+
param :sourceUrl, :required => false
|
296
|
+
|
297
|
+
def request_url params={}
|
298
|
+
blog_cname = params[:blogCName]
|
299
|
+
blog_uuid = params[:blogUuid]
|
300
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
301
|
+
type = params[:type]
|
302
|
+
raise ParamIsRequiredError.new("type is required for interface #{self.class.name}") unless type
|
303
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/post/edit"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class DeletePost < Base
|
308
|
+
verb :post
|
309
|
+
param :id, :required => true
|
310
|
+
def request_url params={}
|
311
|
+
blog_cname = params[:blogCName]
|
312
|
+
blog_uuid = params[:blogUuid]
|
313
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
314
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/post/delete"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
class ReblogPost < Base
|
319
|
+
verb :post
|
320
|
+
param :id, :required => true
|
321
|
+
param :tag, :required => false
|
322
|
+
param :comment, :required => false
|
323
|
+
def request_url params={}
|
324
|
+
blog_cname = params[:blogCName]
|
325
|
+
blog_uuid = params[:blogUuid]
|
326
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
327
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/post/reblog"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
198
331
|
class HomeFeeds < Base
|
199
332
|
param :limit, :required => false
|
200
333
|
param :offset, :required => false
|
@@ -218,7 +351,7 @@ module DiandianOAuth
|
|
218
351
|
|
219
352
|
def request_url params={}
|
220
353
|
tag = params[:tag]
|
221
|
-
raise
|
354
|
+
raise ParamIsRequiredError.new("tag is required for interface #{self.class.name}") unless tag
|
222
355
|
API.url_for "/tag/posts/#{tag}"
|
223
356
|
end
|
224
357
|
end #TagFeeds
|
@@ -239,11 +372,81 @@ module DiandianOAuth
|
|
239
372
|
end
|
240
373
|
end # Unfollow
|
241
374
|
|
375
|
+
class WatchTag < Base
|
376
|
+
verb :post
|
377
|
+
def request_url params={}
|
378
|
+
tag = params[:tag]
|
379
|
+
raise ParamIsRequiredError.new("tag is required for interface #{self.class.name}") unless tag
|
380
|
+
API.url_for '/tag/watch/#{tag}'
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
class UnwatchTag < Base
|
385
|
+
verb :post
|
386
|
+
def request_url params={}
|
387
|
+
tag = params[:tag]
|
388
|
+
raise ParamIsRequiredError.new("tag is required for interface #{self.class.name}") unless tag
|
389
|
+
API.url_for '/tag/watch/#{tag}'
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
242
393
|
class Submissions < Base
|
243
394
|
def request_url params={}
|
244
395
|
blog_cname = params[:blogCName]
|
245
|
-
|
246
|
-
|
396
|
+
blog_uuid = params[:blogUuid]
|
397
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
398
|
+
API.url_for "/blog/#{blog_cname||blog_uuid}/submission"
|
399
|
+
end
|
400
|
+
end #Submissions
|
401
|
+
|
402
|
+
class Submit < Base
|
403
|
+
verb :post
|
404
|
+
param :tag, :required => false
|
405
|
+
param :slug, :required => false
|
406
|
+
#text
|
407
|
+
param :title, :required => false
|
408
|
+
param :body, :required => false
|
409
|
+
#photo
|
410
|
+
param :caption, :required => false
|
411
|
+
param :layout, :required => false
|
412
|
+
param :data, :required => false
|
413
|
+
param :itemDesc, :required => false
|
414
|
+
#link
|
415
|
+
param :title, :required => false
|
416
|
+
param :url, :required => false
|
417
|
+
param :description, :required => false
|
418
|
+
|
419
|
+
#audio
|
420
|
+
param :caption, :required => false
|
421
|
+
param :data, :required => false
|
422
|
+
param :musicName, :required => false
|
423
|
+
param :musicSinger, :required => false
|
424
|
+
param :albumName, :required => false
|
425
|
+
|
426
|
+
#video
|
427
|
+
param :caption, :required => false
|
428
|
+
param :sourceUrl, :required => false
|
429
|
+
|
430
|
+
def request_url params={}
|
431
|
+
blog_cname = params[:blogCName]
|
432
|
+
blog_uuid = params[:blogUuid]
|
433
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
434
|
+
type = params[:type]
|
435
|
+
raise ParamIsRequiredError.new("type is required for interface #{self.class.name}") unless type
|
436
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/submission/#{type}"
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
class RejectSubmission < Base
|
441
|
+
verb :post
|
442
|
+
param :reason, :required => false
|
443
|
+
def request_url params={}
|
444
|
+
blog_cname = params[:blogCName]
|
445
|
+
blog_uuid = params[:blogUuid]
|
446
|
+
raise ParamIsRequiredError.new("blogCName or blogUuid is required for interface #{self.class.name}") unless blog_cname || blog_uuid
|
447
|
+
id = params[:id]
|
448
|
+
raise ParamIsRequiredError.new("id is required for interface #{self.class.name}") unless id
|
449
|
+
API.url_for "/blog/#{blog_cname || blog_uuid}/submission/reject/#{id}"
|
247
450
|
end
|
248
451
|
end
|
249
452
|
end # Interface
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'oauth2'
|
2
|
+
require 'diandian_oauth/client/callbacks'
|
2
3
|
module DiandianOAuth
|
3
4
|
class Client
|
4
|
-
|
5
|
+
include DiandianOAuth::Client::Callbacks
|
6
|
+
attr_accessor :api, :client
|
5
7
|
def initialize client_id, client_secret, options={}
|
6
8
|
@api = options[:api] || DiandianOAuth::API.new
|
7
9
|
@redirect_uri = options[:redirect_uri]
|
@@ -9,7 +11,16 @@ module DiandianOAuth
|
|
9
11
|
:authorize_url => @api.authorize_url,
|
10
12
|
:token_url => @api.token_url
|
11
13
|
}
|
12
|
-
|
14
|
+
self.config_client_middleware(@client)
|
15
|
+
end
|
16
|
+
|
17
|
+
def config_client_middleware client
|
18
|
+
client.options[:connection_build] = Proc.new do |builder|
|
19
|
+
builder.request :multipart
|
20
|
+
builder.request :url_encoded
|
21
|
+
builder.adapter :net_http
|
22
|
+
end
|
23
|
+
end
|
13
24
|
|
14
25
|
def authorize_url response_type='code', scope=[]
|
15
26
|
if response_type.is_a? Array
|
@@ -38,13 +49,14 @@ module DiandianOAuth
|
|
38
49
|
else
|
39
50
|
begin
|
40
51
|
DiandianOAuth.logger.warn('redirect_url is required for authorization_code grant type') unless @redirect_uri
|
41
|
-
@access_token = @client.get_token(
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
52
|
+
@access_token = @client.auth_code.get_token(code_or_hash, {:redirect_uri => @redirect_uri})
|
53
|
+
#@access_token = @client.get_token(
|
54
|
+
# :client_id => @client.id,
|
55
|
+
# :client_secret => @client.secret,
|
56
|
+
# :grant_type => 'authorization_code',
|
57
|
+
# :code => code_or_hash,
|
58
|
+
# :redirect_uri => @redirect_uri
|
59
|
+
#)
|
48
60
|
rescue OAuth2::Error => e
|
49
61
|
DiandianOAuth.logger.error e.to_s
|
50
62
|
raise e
|
@@ -60,8 +72,24 @@ module DiandianOAuth
|
|
60
72
|
if interface
|
61
73
|
access_token = self.access_token
|
62
74
|
raise 'access_token is required' unless access_token
|
63
|
-
if force
|
64
|
-
|
75
|
+
response = if force
|
76
|
+
begin
|
77
|
+
token_expired = false
|
78
|
+
response = interface.apply access_token, args[0], &block
|
79
|
+
response.validate!
|
80
|
+
rescue TokenExpiredError => e
|
81
|
+
if DiandianOAuth.logger.debug?
|
82
|
+
DiandianOAuth.logger.debug("token '#{access_token.inspect}' expired")
|
83
|
+
end
|
84
|
+
new_access_token = access_token.refresh!
|
85
|
+
self.token_refreshed new_access_token
|
86
|
+
if DiandianOAuth.logger.debug?
|
87
|
+
DiandianOAuth.logger.debug("refreshed '#{access_token.inspect}' with '#{new_access_token}'")
|
88
|
+
end
|
89
|
+
self.access_token = access_token = new_access_token
|
90
|
+
token_expired = true
|
91
|
+
end while token_expired
|
92
|
+
response
|
65
93
|
else
|
66
94
|
interface.apply access_token, args[0], &block
|
67
95
|
end # force
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module DiandianOAuth
|
2
|
+
class Client
|
3
|
+
module Callbacks
|
4
|
+
class Callback
|
5
|
+
attr_accessor :executor
|
6
|
+
def initialize proc_or_method
|
7
|
+
self.executor = proc_or_method
|
8
|
+
end
|
9
|
+
def apply client, *args, &block
|
10
|
+
case executor
|
11
|
+
when Symbol then client.send(executor, *args, &block)
|
12
|
+
when Proc then executor.call( client, *args, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def self.included base
|
17
|
+
base.extend ClassMethods
|
18
|
+
base.send :include, InstanceMethods
|
19
|
+
base.class_eval do
|
20
|
+
self.callbacks = {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def callbacks name=nil
|
26
|
+
if name
|
27
|
+
@callbacks[name] ||= []
|
28
|
+
else
|
29
|
+
@callbacks
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def callbacks= callbacks
|
33
|
+
@callbacks = callbacks
|
34
|
+
end
|
35
|
+
def token_refreshed proc_or_method
|
36
|
+
self.callbacks(:token_refreshed) << Callback.new( proc_or_method)
|
37
|
+
end
|
38
|
+
private
|
39
|
+
end
|
40
|
+
module InstanceMethods
|
41
|
+
def token_refreshed access_token
|
42
|
+
self.class.callbacks[:token_refreshed].each do |callback|
|
43
|
+
callback.apply(self, access_token)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,19 +1,236 @@
|
|
1
1
|
module DiandianOAuth
|
2
2
|
|
3
|
-
class
|
3
|
+
class Error < ::StandardError
|
4
4
|
end
|
5
5
|
|
6
|
-
class
|
6
|
+
class TokenExpiredError < Error
|
7
7
|
end
|
8
8
|
|
9
|
-
class
|
9
|
+
class RefreshTokenExpireError < Error
|
10
10
|
end
|
11
11
|
# APIException
|
12
|
-
class
|
12
|
+
class APIError < Error
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
|
+
class ResponseError < APIError
|
16
|
+
end
|
17
|
+
|
18
|
+
class InvalidateRequestError < ResponseError
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class UnauthorizedClientError < ResponseError
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class AccessDeniedError < ResponseError
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class UnsupportedResponseTypeError < ResponseError
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class InvalidScopeError < ResponseError
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class TemporarilyUnavailableError < ResponseError
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class ParamIsRequiredError < APIError
|
43
|
+
end
|
44
|
+
class IllegalParamError < APIError
|
45
|
+
end
|
46
|
+
## 400000
|
47
|
+
class ClientError < APIError
|
48
|
+
end
|
49
|
+
|
50
|
+
## 400001
|
51
|
+
class ParameterError < APIError
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
## 400010
|
56
|
+
class EmailError < APIError
|
57
|
+
end
|
58
|
+
|
59
|
+
## 400011
|
60
|
+
class PasswordError < APIError
|
61
|
+
end
|
62
|
+
|
63
|
+
## 400012
|
64
|
+
class EccentricAccountError < APIError
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
## 400013
|
69
|
+
class EmailFormatError < APIError
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
## 400014
|
74
|
+
class PasswordFormatError < APIError
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
## 400015
|
79
|
+
class EmailExistsError < APIError
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
## 400020
|
86
|
+
class BindingFailError < APIError
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
## 40003x
|
91
|
+
class RelationError < APIError
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
## 400030
|
96
|
+
class FollowError < RelationError
|
97
|
+
|
98
|
+
end
|
99
|
+
## 400031
|
100
|
+
class UnfollowError < RelationError
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
## 400040
|
105
|
+
class IllegalContentError < APIError
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
## 40005x
|
110
|
+
class InboxError < APIError
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
## 400050
|
115
|
+
class InboxContentCannotBeEmptyError < APIError
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
## 400051
|
120
|
+
class InboxContentTooLongError < APIError
|
121
|
+
|
15
122
|
end
|
16
|
-
|
123
|
+
|
124
|
+
## 400052
|
125
|
+
class InboxClosedError < APIError
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
## 400053
|
130
|
+
class CannotSendToOwnBlogError < APIError
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
## 400060
|
135
|
+
class OperationTooFastError < APIError
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
## 400070
|
140
|
+
class BlogClosedError < APIError
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
## 40008x
|
146
|
+
class VerifyCodeError < APIError
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
## 400080
|
151
|
+
class VerifyCodeExpiredError < VerifyCodeError
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
## 400081
|
157
|
+
class VerifyCodeWrongError < VerifyCodeError
|
158
|
+
|
17
159
|
end
|
160
|
+
|
161
|
+
## 401xxx
|
162
|
+
class AuthorizationError < APIError
|
163
|
+
end
|
164
|
+
|
165
|
+
## 401000
|
166
|
+
class UnauthorizedError < AuthorizationError
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
## 403xxx
|
171
|
+
class ForbiddenError < APIError
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
## 403000
|
176
|
+
class VisitForbiddenError < ForbiddenError
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
## 403001
|
181
|
+
class BlogManagerRequiredError < ForbiddenError
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
## 404xxx
|
186
|
+
class NotFoundError < APIError
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
## 404000
|
191
|
+
class UrlNotFoundError < NotFoundError
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
## 404002
|
196
|
+
class BlogNotFoundError < NotFoundError
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
## 404003
|
201
|
+
class ContentNotFoundError < NotFoundError
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
## 404004
|
206
|
+
class UserNotFoundError < NotFoundError
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
## 500xxx
|
211
|
+
class ServerError < APIError
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
## 500000
|
216
|
+
class InternalServerError < APIError
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
## 500001
|
221
|
+
class PostTypeError < APIError
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
## 500002
|
226
|
+
class InboxError < APIError
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
## 503001
|
231
|
+
class UpgradingError < APIError
|
232
|
+
|
233
|
+
end
|
234
|
+
|
18
235
|
# End APIException
|
19
236
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module DiandianOAuth
|
2
|
+
class Response
|
3
|
+
attr_accessor :error, :meta, :response, :internal
|
4
|
+
def self.from_response response
|
5
|
+
response_json = response.parsed
|
6
|
+
result = Response.new
|
7
|
+
result.internal = response
|
8
|
+
result.error = response_json['error']
|
9
|
+
return result if result.error
|
10
|
+
result.meta = response_json['meta']
|
11
|
+
result.response = response_json['response']
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
!error && meta['status'] == 200
|
17
|
+
end
|
18
|
+
alias_method :success?, :validate
|
19
|
+
|
20
|
+
# throw exception when an error occurs
|
21
|
+
def validate!
|
22
|
+
puts "error: '#{self.inspect}'"
|
23
|
+
unless self.validate
|
24
|
+
if error
|
25
|
+
exception =
|
26
|
+
case error[:error]
|
27
|
+
when 'invalid_request' then DiandianOAuth::InvalidateRequestError
|
28
|
+
when 'unauthorized_client' then DiandianOAuth::UnauthorizedClientError
|
29
|
+
when 'access_denied' then DiandianOAuth::AccessDeniedError
|
30
|
+
when 'unsupported_response_type' then DiandianOAuth::UnsupportedResponseTypeError
|
31
|
+
when 'invalid_scope' then DiandianOAuth::InvalidScopeError
|
32
|
+
when 'server_error' then DiandianOAuth::ServerError
|
33
|
+
else APIError
|
34
|
+
end
|
35
|
+
raise exception
|
36
|
+
else
|
37
|
+
exception =
|
38
|
+
case meta[:status]
|
39
|
+
when 400000 then DiandianOAuth::ClientError
|
40
|
+
when 400001 then DiandianOAuth::ParameterError
|
41
|
+
when 400010 then DiandianOAuth::EmailError
|
42
|
+
when 400011 then DiandianOAuth::PasswordError
|
43
|
+
when 400012 then DiandianOAuth::EccentricAccountError
|
44
|
+
when 400013 then DiandianOAuth::EmailFormatError
|
45
|
+
when 400014 then DiandianOAuth::PasswordFormatError
|
46
|
+
when 400015 then DiandianOAuth::EmailExistsError
|
47
|
+
when 400020 then DiandianOAuth::BindingFailError
|
48
|
+
when 400030 then DiandianOAuth::FollowError
|
49
|
+
when 400031 then DiandianOAuth::UnfollowError
|
50
|
+
when 400040 then DiandianOAuth::IllegalContentError
|
51
|
+
when 400050 then DiandianOAuth::InboxContentCannotBeEmptyError
|
52
|
+
when 400051 then DiandianOAuth::InboxContentTooLongError
|
53
|
+
when 400052 then DiandianOAuth::InboxClosedError
|
54
|
+
when 400053 then DiandianOAuth::CannotSendToOwnBlogError
|
55
|
+
when 400060 then DiandianOAuth::OperationTooFastError
|
56
|
+
when 400070 then DiandianOAuth::BlogClosedError
|
57
|
+
when 400080 then DiandianOAuth::VerifyCodeExpiredError
|
58
|
+
when 400081 then DiandianOAuth::VerifyCodeWrongError
|
59
|
+
when 401000 then DiandianOAuth::UnauthorizedError
|
60
|
+
when 403000 then DiandianOAuth::VisitForbiddenError
|
61
|
+
when 403001 then DiandianOAuth::BlogManagerRequiredError
|
62
|
+
when 404002 then DiandianOAuth::BlogNotFoundError
|
63
|
+
when 404003 then DiandianOAuth::ContentNotFoundError
|
64
|
+
when 404004 then DiandianOAuth::UserNotFoundError
|
65
|
+
when 500000 then DiandianOAuth::InternalServerError
|
66
|
+
when 500001 then DiandianOAuth::PostTypeError
|
67
|
+
when 500002 then DiandianOAuth::InboxError
|
68
|
+
when 503001 then DiandianOAuth::UpgradingError
|
69
|
+
else DiandianOAuth::APIError
|
70
|
+
end
|
71
|
+
raise exception
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module DiandianOAuth
|
2
|
+
class ResponseMeta
|
3
|
+
attr_accessor :status, :message
|
4
|
+
def self.from_response response_json
|
5
|
+
meta = response_json['meta']
|
6
|
+
response_meta = ResponseMeta.new
|
7
|
+
response_meta.status = meta['status']
|
8
|
+
response_meta.message = meta['msg']
|
9
|
+
response_meta
|
10
|
+
end
|
11
|
+
|
12
|
+
def success?
|
13
|
+
self.validate
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate
|
17
|
+
self.status == 200
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate!
|
21
|
+
if !self.validate
|
22
|
+
exception =
|
23
|
+
case self.status
|
24
|
+
when 400000 then DiandianOAuth::ClientError
|
25
|
+
when 400001 then DiandianOAuth::ParameterError
|
26
|
+
when 400010 then DiandianOAuth::EmailError
|
27
|
+
when 400011 then DiandianOAuth::PasswordError
|
28
|
+
when 400012 then DiandianOAuth::EccentricAccountError
|
29
|
+
when 400013 then DiandianOAuth::EmailFormatError
|
30
|
+
when 400014 then DiandianOAuth::PasswordFormatError
|
31
|
+
when 400015 then DiandianOAuth::EmailExistsError
|
32
|
+
when 400020 then DiandianOAuth::BindingFailError
|
33
|
+
when 400030 then DiandianOAuth::FollowError
|
34
|
+
when 400031 then DiandianOAuth::UnfollowError
|
35
|
+
when 400040 then DiandianOAuth::IllegalContentError
|
36
|
+
when 400050 then DiandianOAuth::InboxContentCannotBeEmptyError
|
37
|
+
when 400051 then DiandianOAuth::InboxContentTooLongError
|
38
|
+
when 400052 then DiandianOAuth::InboxClosedError
|
39
|
+
when 400053 then DiandianOAuth::CannotSendToOwnBlogError
|
40
|
+
when 400060 then DiandianOAuth::OperationTooFastError
|
41
|
+
when 400070 then DiandianOAuth::BlogClosedError
|
42
|
+
when 400080 then DiandianOAuth::VerifyCodeExpiredError
|
43
|
+
when 400081 then DiandianOAuth::VerifyCodeWrongError
|
44
|
+
when 401000 then DiandianOAuth::UnauthorizedError
|
45
|
+
when 403000 then DiandianOAuth::VisitForbiddenError
|
46
|
+
when 403001 then DiandianOAuth::BlogManagerRequiredError
|
47
|
+
when 404002 then DiandianOAuth::BlogNotFoundError
|
48
|
+
when 404003 then DiandianOAuth::ContentNotFoundError
|
49
|
+
when 404004 then DiandianOAuth::UserNotFoundError
|
50
|
+
when 500000 then DiandianOAuth::InternalServerError
|
51
|
+
when 500001 then DiandianOAuth::PostTypeError
|
52
|
+
when 500002 then DiandianOAuth::InboxError
|
53
|
+
when 503001 then DiandianOAuth::UpgradingError
|
54
|
+
else DiandianOAuth::APIError
|
55
|
+
end
|
56
|
+
raise exception, self.message
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.join( File.dirname(__FILE__), 'test_helper')
|
2
2
|
|
3
3
|
class AuthorizeTest < ActiveSupport::TestCase
|
4
|
-
CLIENT_ID="
|
5
|
-
CLIENT_SECRET="
|
4
|
+
CLIENT_ID="fr2ejCbPrO"
|
5
|
+
CLIENT_SECRET="C5Cgprqe3DC674vdnaQlujko9ItuSAOB24qa"
|
6
6
|
|
7
7
|
test 'authorize_url' do
|
8
8
|
assert_nothing_raised do
|
@@ -12,11 +12,12 @@ class AuthorizeTest < ActiveSupport::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
test 'access_token' do
|
15
|
-
code = '
|
15
|
+
code = 'dJGgxE'
|
16
16
|
unless code.empty?
|
17
17
|
assert_nothing_raised do
|
18
|
-
client = DiandianOAuth::Client.new CLIENT_ID, CLIENT_SECRET, :redirect_uri => 'http://example.com/callback'
|
18
|
+
client = DiandianOAuth::Client.new CLIENT_ID, CLIENT_SECRET, :redirect_uri => 'http://example.com/users/auth/diandian/callback'
|
19
19
|
access_token = client.access_token code
|
20
|
+
p access_token
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
require File.join( File.dirname(__FILE__), 'test_helper')
|
2
2
|
|
3
|
+
require 'faraday/request/diandian_multipart'
|
4
|
+
|
3
5
|
class InterfaceTest < ActiveSupport::TestCase
|
4
|
-
CLIENT_ID="
|
5
|
-
CLIENT_SECRET="
|
6
|
+
CLIENT_ID="fr2ejCbPrO"
|
7
|
+
CLIENT_SECRET="C5Cgprqe3DC674vdnaQlujko9ItuSAOB24qa"
|
6
8
|
ACCESS_TOKEN = {
|
7
|
-
:access_token => '
|
8
|
-
:refresh_token => "
|
9
|
+
:access_token => '92eb54ba-4be0-4a75-ae2a-d185d0a0f751',
|
10
|
+
:refresh_token => "fa522c29-fc69-4d45-ab59-b9e26b9e5ed5",
|
9
11
|
:token_type => "bearer",
|
10
|
-
:expires_in =>
|
11
|
-
:expires_at =>
|
12
|
+
:expires_in => 3406,
|
13
|
+
:expires_at => 1344410022,
|
12
14
|
:scope => "write read",
|
13
15
|
:uid => "11449"
|
14
16
|
}
|
@@ -22,10 +24,46 @@ class InterfaceTest < ActiveSupport::TestCase
|
|
22
24
|
test 'user_info' do
|
23
25
|
client = self.client
|
24
26
|
client.access_token= ACCESS_TOKEN
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
p client.user_info
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'user_info!' do
|
31
|
+
client = self.client
|
32
|
+
client.access_token = ACCESS_TOKEN.merge(:expires_at => Time.now.to_i - 1.day.to_i)
|
33
|
+
puts "expired?: '#{client.access_token.expired?}'"
|
34
|
+
p client.user_info!
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'create_post' do
|
38
|
+
client = self.client
|
39
|
+
client.access_token = ACCESS_TOKEN
|
40
|
+
p client.create_post :blogCName => 'secretworry.diandian.com',
|
41
|
+
:type => 'text',
|
42
|
+
:state => 'published',
|
43
|
+
:title => 'Hello from diandian ruby client'
|
44
|
+
end
|
45
|
+
|
46
|
+
test 'create_photo_post' do
|
47
|
+
client = self.client
|
48
|
+
client.access_token = ACCESS_TOKEN
|
49
|
+
Faraday::Request.register_middleware :diandian_multipart => Faraday::Request::DiandianMultipart
|
50
|
+
p client.user_info!
|
51
|
+
p client.create_post! :blogCName => 'tree-hollow.diandian.com',
|
52
|
+
:type => 'photo',
|
53
|
+
:state => 'published',
|
54
|
+
:data => [Faraday::UploadIO.new('/Users/siyudu/Pictures/test/blue_700_342.jpg', 'image/jpeg'), Faraday::UploadIO.new('/Users/siyudu/Pictures/test/white_700_342.jpg', 'image/jpeg')]
|
55
|
+
end
|
56
|
+
|
57
|
+
test 'submissions' do
|
58
|
+
client = self.client
|
59
|
+
client.access_token = ACCESS_TOKEN
|
60
|
+
p client.submissions :blogCName => 'secretworry.diandian.com'
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'delete_post' do
|
64
|
+
client = self.client
|
65
|
+
client.access_token = ACCESS_TOKEN
|
66
|
+
p client.delete_post :blogCName => 'secretworry.diandian.com', :id => '3fdc4740-dcce-11e1-a2d7-782bcb43b268'
|
29
67
|
end
|
30
68
|
|
31
69
|
test 'posts' do
|
@@ -35,6 +73,9 @@ class InterfaceTest < ActiveSupport::TestCase
|
|
35
73
|
end
|
36
74
|
|
37
75
|
def client
|
76
|
+
DiandianOAuth::Client.token_refreshed (lambda{|client, token|
|
77
|
+
p "token_refreshed: '#{token}'"
|
78
|
+
})
|
38
79
|
@client ||= DiandianOAuth::Client.new CLIENT_ID, CLIENT_SECRET, :redirect_uri => 'http://example.com/callback'
|
39
80
|
end
|
40
81
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: diandian-oauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.1.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Rainer Du
|
@@ -69,7 +69,10 @@ files:
|
|
69
69
|
- lib/diandian_oauth/api.rb
|
70
70
|
- lib/diandian_oauth/api/interface.rb
|
71
71
|
- lib/diandian_oauth/client.rb
|
72
|
+
- lib/diandian_oauth/client/callbacks.rb
|
72
73
|
- lib/diandian_oauth/exceptions.rb
|
74
|
+
- lib/diandian_oauth/models/response.rb
|
75
|
+
- lib/diandian_oauth/models/response_meta.rb
|
73
76
|
- test/diandian_oauth/api_test.rb
|
74
77
|
- test/diandian_oauth/authorize_test.rb
|
75
78
|
- test/diandian_oauth/interface_test.rb
|