kuaipan 0.0.3
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 +6 -0
- data/Gemfile.lock +16 -0
- data/README.rdoc +33 -0
- data/Rakefile +9 -0
- data/kuaipan.gemspec +35 -0
- data/lib/kuaipan.rb +44 -0
- data/lib/kuaipan/base.rb +132 -0
- data/lib/kuaipan/config.rb +37 -0
- data/lib/kuaipan/errors.rb +46 -0
- data/lib/kuaipan/kauth/consumer.rb +169 -0
- data/lib/kuaipan/session.rb +54 -0
- data/test/kuaipan/test_base.rb +16 -0
- data/test/kuaipan/test_config.rb +12 -0
- data/test/kuaipan/test_session.rb +12 -0
- data/test/test_client.rb +99 -0
- metadata +91 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
= kuaipan.gem - the third part SDK of kuaipan@kingsoft.com
|
2
|
+
To install the gem simply enter:
|
3
|
+
gem install kuaipan --pre
|
4
|
+
To see an example of how it works enter the following into your terminal:
|
5
|
+
git clone git://github.com/tiemei/kuaipan-example.git
|
6
|
+
cd kuaipan-example
|
7
|
+
ruby example.rb
|
8
|
+
|
9
|
+
-----------
|
10
|
+
= how to use ?
|
11
|
+
require 'kuaipan'
|
12
|
+
class YourAPI
|
13
|
+
include Kuaipan::OpenAPI
|
14
|
+
def your_method
|
15
|
+
# 1 config
|
16
|
+
consumer_key = 'YourConsumerKey'
|
17
|
+
consumer_secret = 'YourConsumerSecret'
|
18
|
+
input_config(consumer_key, consumer_secret)
|
19
|
+
|
20
|
+
# 2 authorize + get_access_token
|
21
|
+
# k_session = g_session() # ok!
|
22
|
+
# k_session = g_session(:oauth_callback => 'Your callbake url') # ok!
|
23
|
+
# authorize_url = k_session[:authorize_url]
|
24
|
+
# user input their username+pwd
|
25
|
+
# then you should parse oauth_verifier
|
26
|
+
k_session.set_atoken oauth_verifier
|
27
|
+
|
28
|
+
# 3 use Kuaipan API(such as download file, upload file...)
|
29
|
+
# please refer to test/test_client.rb
|
30
|
+
k_session.account_info['user_id'] # get user_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/Rakefile
ADDED
data/kuaipan.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'kuaipan'
|
3
|
+
s.version = '0.0.3'
|
4
|
+
s.date = '2012-05-01'
|
5
|
+
s.summary = "Kuaipan openapi ruby-sdk"
|
6
|
+
s.description = "Kuaipan openAPI! With it , you can develop apps which connect to kuaipan@kingsoft"
|
7
|
+
s.authors = ["tiemei"]
|
8
|
+
s.email = 'jiadongkai@gmail.com'
|
9
|
+
s.files = [
|
10
|
+
"lib/kuaipan.rb",
|
11
|
+
"lib/kuaipan/base.rb",
|
12
|
+
"lib/kuaipan/config.rb",
|
13
|
+
"lib/kuaipan/session.rb",
|
14
|
+
"lib/kuaipan/errors.rb",
|
15
|
+
"lib/kuaipan/kauth/consumer.rb",
|
16
|
+
"Rakefile",
|
17
|
+
"README.rdoc",
|
18
|
+
"Gemfile",
|
19
|
+
"Gemfile.lock",
|
20
|
+
"kuaipan.gemspec",
|
21
|
+
"test/test_client.rb",
|
22
|
+
"test/kuaipan/test_base.rb",
|
23
|
+
"test/kuaipan/test_config.rb",
|
24
|
+
"test/kuaipan/test_session.rb"
|
25
|
+
]
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
#s.executables << 'hola_tiemei'
|
28
|
+
s.homepage = 'http://rubygems.org/gems/kuaipan'
|
29
|
+
s.required_ruby_version = '>= 1.9.3'
|
30
|
+
s.required_rubygems_version = ">= 1.3.6"
|
31
|
+
|
32
|
+
s.add_runtime_dependency 'json', '~> 1.6.6'
|
33
|
+
s.add_runtime_dependency 'rest-client'
|
34
|
+
|
35
|
+
end
|
data/lib/kuaipan.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
require 'forwardable'
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
require 'kuaipan/config'
|
7
|
+
require 'kuaipan/session'
|
8
|
+
require 'kuaipan/base'
|
9
|
+
require 'kuaipan/errors'
|
10
|
+
|
11
|
+
# kauth-kuaipan oauth implement by myself
|
12
|
+
require 'kuaipan/kauth/consumer'
|
13
|
+
|
14
|
+
module Kuaipan
|
15
|
+
module OpenAPI
|
16
|
+
|
17
|
+
def input_config(consumer_token, consumer_secret, p={})
|
18
|
+
Kuaipan::Config.opts(consumer_token, consumer_secret, p)
|
19
|
+
end
|
20
|
+
|
21
|
+
def g_session(opt={})
|
22
|
+
Kuaipan::Session.new(opt)
|
23
|
+
end
|
24
|
+
|
25
|
+
def g_session_skip_oauth(oauth_token, oauth_token_secret, user_id, opts={})
|
26
|
+
Kuaipan::Session.skip_oauth_session(oauth_token, oauth_token_secret, user_id, opts={})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class InnerLogicalError < KpErrors; end # 202
|
32
|
+
class BadRequest < KpErrors; end # 400
|
33
|
+
class Unauthorized < KpErrors; end # 401
|
34
|
+
class Forbidden < KpErrors; end # 403
|
35
|
+
class NotFound < KpErrors; end # 404
|
36
|
+
class NotAcceptable < KpErrors; end # 406
|
37
|
+
class RequestEntityTooLarge < KpErrors; end # 413
|
38
|
+
class InternalServerError < KpErrors; end # 500
|
39
|
+
class OverSpace < KpErrors; end # 507
|
40
|
+
class ServerError < KpErrors; end # 500..505
|
41
|
+
class UnknownError < KpErrors; end # other
|
42
|
+
class NoTypeError < KpErrors; end # documentView no type
|
43
|
+
class NoViewError < KpErrors; end # documentView no view
|
44
|
+
end
|
data/lib/kuaipan/base.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
require 'uri'
|
3
|
+
module Kuaipan
|
4
|
+
class Base
|
5
|
+
attr_reader :oauth_token
|
6
|
+
|
7
|
+
def initialize(consumer)
|
8
|
+
@consumer = consumer
|
9
|
+
end
|
10
|
+
|
11
|
+
def account_info
|
12
|
+
res = @consumer.get_no_ssl('account_info')
|
13
|
+
parse_response(res)
|
14
|
+
end
|
15
|
+
|
16
|
+
def metadata(path ,opts={})
|
17
|
+
root = opts[:root] ? opts[:root].to_s : 'app_folder'
|
18
|
+
res = @consumer.get_no_ssl(urlencode("metadata/#{ root }#{ path }"),opts)
|
19
|
+
parse_response(res)
|
20
|
+
end
|
21
|
+
|
22
|
+
def shares(path, opts={})
|
23
|
+
root = opts[:root] ? opts[:root].to_s : 'app_folder'
|
24
|
+
res = @consumer.get_no_ssl(urlencode("shares/#{ root }#{ path }"),opts)
|
25
|
+
parse_response(res)
|
26
|
+
end
|
27
|
+
|
28
|
+
def move(from_path, to_path, opts={})
|
29
|
+
res = @consumer.get_no_ssl('fileops/move',
|
30
|
+
{from_path: from_path,
|
31
|
+
to_path: to_path,
|
32
|
+
root: 'app_folder'}.merge(opts))
|
33
|
+
parse_response(res)
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy(from_path, to_path, opts={})
|
37
|
+
res = @consumer.get_no_ssl('fileops/copy',
|
38
|
+
{from_path: from_path,
|
39
|
+
to_path: to_path,
|
40
|
+
root: 'app_folder'}.merge(opts))
|
41
|
+
parse_response(res)
|
42
|
+
end
|
43
|
+
|
44
|
+
def download_file(path, opts={}, &block)
|
45
|
+
res = @consumer.get_no_ssl('fileops/download_file',
|
46
|
+
{root: 'app_folder',
|
47
|
+
path: path,
|
48
|
+
site: Config[:up_down_file_stie]}.merge(opts))
|
49
|
+
parse_response(res, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def thumbnail(width, height, path, opts={}, &block)
|
53
|
+
res = @consumer.get_no_ssl('fileops/thumbnail',
|
54
|
+
{width: width,
|
55
|
+
height: height,
|
56
|
+
path: path,
|
57
|
+
root: 'app_folder',
|
58
|
+
site: Config[:thum_doc_site]}.merge(opts))
|
59
|
+
parse_response(res, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def document_view(type, path, opts={}, &block)
|
64
|
+
raise NoTypeError.new("No type:#{ type }") if Config[:types].index(type.to_s) == nil
|
65
|
+
raise NoViewError("No view:#{ opts[:view] }") if (opts[:views] and (Config[:view].index(opts[:view].to_s) == nil))
|
66
|
+
res = @consumer.get_no_ssl('fileops/documentView',
|
67
|
+
{view: 'normal',
|
68
|
+
zip: 0,
|
69
|
+
root: 'app_folder',
|
70
|
+
path: path,
|
71
|
+
type: type,
|
72
|
+
site: Config[:thum_doc_site]
|
73
|
+
}.merge(opts))
|
74
|
+
parse_response(res, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def upload_locate
|
78
|
+
res = @consumer.get_no_ssl('/fileops/upload_locate',
|
79
|
+
{site: Config[:up_down_file_stie]})
|
80
|
+
parse_response(res)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def upload_file(file, opts={})
|
85
|
+
folder = opts[:path]
|
86
|
+
opts[:path] = opts[:path] ? "/#{ opts[:path] }/#{ File.basename(file.path) }"
|
87
|
+
: File.basename(file.path)
|
88
|
+
opts[:root] = 'app_folder' unless opts[:root]
|
89
|
+
create_folder((folder ||= ''), :root => opts[:root])
|
90
|
+
body = @consumer.post('fileops/upload_file',
|
91
|
+
file,
|
92
|
+
{overwrite: 'True',
|
93
|
+
site: upload_locate['url'],}.merge(opts))
|
94
|
+
JSON.parse(body)
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_folder(folder, opts={})
|
98
|
+
folder = folder.encode('UTF-8')
|
99
|
+
return nil if folder.size > 255
|
100
|
+
res = @consumer.get_no_ssl('fileops/create_folder',
|
101
|
+
{root: 'app_folder',
|
102
|
+
path: folder}.merge(opts))
|
103
|
+
parse_response(res)
|
104
|
+
end
|
105
|
+
|
106
|
+
def delete(path, opts={})
|
107
|
+
res = @consumer.get_no_ssl('fileops/delete',
|
108
|
+
{root: 'app_folder',
|
109
|
+
path: path,
|
110
|
+
to_recycle: 'True'}.merge(opts))
|
111
|
+
parse_response(res)
|
112
|
+
end
|
113
|
+
|
114
|
+
# .......
|
115
|
+
|
116
|
+
private
|
117
|
+
def urlencode(str)
|
118
|
+
URI.escape(str, /([^A-Za-z0-9\-._~])/)
|
119
|
+
end
|
120
|
+
def parse_response(res, &block)
|
121
|
+
if res.is_a?(Net::HTTPSuccess)
|
122
|
+
if block
|
123
|
+
block.call(res)
|
124
|
+
else
|
125
|
+
JSON.parse(res.body)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
KpErrors.raise_errors(res)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
module Kuaipan
|
3
|
+
module Config
|
4
|
+
class << self
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators :options, :[]
|
7
|
+
attr_accessor :options
|
8
|
+
|
9
|
+
def opts(consumer_key, consumer_secret, p={})
|
10
|
+
Config.options = {oauth_consumer_secret: consumer_secret,
|
11
|
+
oauth_consumer_key: consumer_key,
|
12
|
+
root: 'app_folder',
|
13
|
+
oauth_signature_method: 'HMAC-SHA1',
|
14
|
+
oauth_version: '1.0',
|
15
|
+
|
16
|
+
site: 'openapi.kuaipan.cn',
|
17
|
+
thum_doc_site: 'conv.kuaipan.cn',
|
18
|
+
up_down_file_stie: 'api-content.dfs.kuaipan.cn',
|
19
|
+
rtoken_path: '/open/requestToken',
|
20
|
+
atoken_path: '/open/accessToken',
|
21
|
+
authorize_url: 'https://www.kuaipan.cn/api.php?ac=open&op=authorise',
|
22
|
+
types: %w(pdf doc wps csv prn xls et ppt dps txt rtf),
|
23
|
+
views: %w(normal android iPad iphone)
|
24
|
+
}.merge(p)
|
25
|
+
end
|
26
|
+
|
27
|
+
def options_base
|
28
|
+
{oauth_signature_method: Config.options[:oauth_signature_method],
|
29
|
+
oauth_version: Config.options[:oauth_version],
|
30
|
+
oauth_consumer_key: Config.options[:oauth_consumer_key],
|
31
|
+
rtoken_path: Config.options[:rtoken_path],
|
32
|
+
atoken_path: Config.options[:atoken_path],
|
33
|
+
site: Config.options[:site]}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
module Kuaipan
|
3
|
+
class KpErrors < StandardError
|
4
|
+
def initialize(data)
|
5
|
+
@data = data
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.raise_errors(res)
|
10
|
+
data = parse(res)
|
11
|
+
case res.code.to_i
|
12
|
+
when 202
|
13
|
+
raise InnerLogicalError.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
14
|
+
when 400
|
15
|
+
raise BadRequest.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
16
|
+
when 401
|
17
|
+
raise Unauthorized.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
18
|
+
when 403
|
19
|
+
raise Forbidden.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
20
|
+
when 404
|
21
|
+
raise NotFound.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
22
|
+
when 406
|
23
|
+
raise NotAcceptable.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
24
|
+
when 413
|
25
|
+
raise RequestEntityTooLarge.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
26
|
+
when 500
|
27
|
+
raise InternalServerError.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
28
|
+
when 507
|
29
|
+
raise OverSpace.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
30
|
+
when 500..505
|
31
|
+
raise ServerError.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
32
|
+
else
|
33
|
+
raise UnknownError.new(data['msg']), "(#{ res.code }): #{ res.message } - #{ data['msg'] }"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def self.parse(res)
|
39
|
+
if res.body
|
40
|
+
JSON.parse(res.body)
|
41
|
+
else
|
42
|
+
{'msg' => ''}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'json'
|
3
|
+
require 'rest_client'
|
4
|
+
# std-lib
|
5
|
+
require 'base64'
|
6
|
+
require 'openssl'
|
7
|
+
require 'rest_client'
|
8
|
+
require 'net/http'
|
9
|
+
|
10
|
+
module KAuth
|
11
|
+
class Consumer
|
12
|
+
attr_accessor :oauth_token, :oauth_token_secret, :user_id
|
13
|
+
|
14
|
+
# determine the certificate authority path to verify SSL certs
|
15
|
+
CA_FILES = %w(/etc/ssl/certs/ca-certificates.crt /usr/share/curl/curl-ca-bundle.crt /etc/ssl/certs/ca-bundle.trust.crt)
|
16
|
+
CA_FILES.each do |ca_file|
|
17
|
+
if File.exists?(ca_file)
|
18
|
+
CA_FILE = ca_file
|
19
|
+
break
|
20
|
+
end
|
21
|
+
end
|
22
|
+
CA_FILE = nil unless defined?(CA_FILE)
|
23
|
+
|
24
|
+
def initialize(ctoken, csecret, opts={})
|
25
|
+
@oauth_consumer_secret = csecret
|
26
|
+
@base_url = opts.delete(:site)
|
27
|
+
@rtoken_path = opts.delete(:rtoken_path)
|
28
|
+
@atoken_path = opts.delete(:atoken_path)
|
29
|
+
@options = {oauth_signature_method: 'HMAC-SHA1',
|
30
|
+
oauth_version: '1.0',
|
31
|
+
oauth_consumer_key: ctoken}.merge(opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_request_token(oauth_callback=nil)
|
35
|
+
opts = {}
|
36
|
+
if oauth_callback
|
37
|
+
opts[:oauth_callback] = oauth_callback
|
38
|
+
end
|
39
|
+
res = get('https://', @rtoken_path, opts)
|
40
|
+
body = res.body
|
41
|
+
hash = JSON.parse(body)
|
42
|
+
|
43
|
+
hash.each do |pair|
|
44
|
+
instance_variable_set('@' + pair[0], pair[1])
|
45
|
+
end
|
46
|
+
hash['oauth_token']
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_atoken(oauth_verifier)
|
50
|
+
res = get('https://',
|
51
|
+
@atoken_path,
|
52
|
+
{oauth_token: @oauth_token,
|
53
|
+
oauth_verifier: oauth_verifier})
|
54
|
+
body = res.body
|
55
|
+
hash = JSON.parse(body)
|
56
|
+
hash.each do |pair|
|
57
|
+
instance_variable_set("@#{ pair[0] }" , pair[1])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_ssl(path, opts={})
|
62
|
+
opts.merge!({oauth_token: @oauth_token})
|
63
|
+
get('https://', "/#{ @options[:oauth_version].to_i.to_s }/#{ path }", opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_no_ssl(path, opts={})
|
67
|
+
opts.merge!({oauth_token: @oauth_token})
|
68
|
+
get('http://', "/#{ @options[:oauth_version].to_i.to_s }/#{ path }", opts)
|
69
|
+
end
|
70
|
+
|
71
|
+
def post(path, file, opts={})
|
72
|
+
opts.merge!({oauth_token: @oauth_token})
|
73
|
+
base_url_str = opts[:site] ? opts.delete(:site) : @base_url
|
74
|
+
url = "#{ base_url_str }#{ @options[:oauth_version].to_i.to_s }/#{ path }"
|
75
|
+
params = get_params('POST', url, opts)
|
76
|
+
uri = URI(url)
|
77
|
+
uri.query = URI.encode_www_form(params)
|
78
|
+
RestClient.post(uri.to_s, :my_file => file)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
private
|
83
|
+
def get_params(http_method, url, opts={})
|
84
|
+
params = {oauth_nonce: Consumer.get_oauth_nonce,
|
85
|
+
oauth_timestamp: "#{Time.new.to_i}"
|
86
|
+
}.merge(@options).merge(opts)
|
87
|
+
params[:oauth_signature] = get_oath_signature(Consumer.get_base_string(params, url, http_method))
|
88
|
+
params
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.get_oauth_nonce
|
92
|
+
a = [(1..9),('a'..'z'),('A'..'Z')].map{|r|r.to_a}.flatten
|
93
|
+
a << '_'
|
94
|
+
(1...32).map{a[rand(a.size)]}.join
|
95
|
+
end
|
96
|
+
|
97
|
+
# 生成签名算法
|
98
|
+
def get_oath_signature(base_str)
|
99
|
+
key = @oauth_consumer_secret + '&'
|
100
|
+
key += @oauth_token_secret if base_str.include?('oauth_token')
|
101
|
+
Base64.encode64("#{OpenSSL::HMAC.digest('sha1', key, base_str)}").chomp
|
102
|
+
end
|
103
|
+
|
104
|
+
def get(pre, path, opts={})
|
105
|
+
base_url_str = opts[:site] ? opts.delete(:site) : @base_url
|
106
|
+
url = "#{ pre }#{ base_url_str }#{ path }"
|
107
|
+
params = get_params('GET', url, opts)
|
108
|
+
fetch(url, params)
|
109
|
+
#fetch(url, 'GET', opts)
|
110
|
+
end
|
111
|
+
|
112
|
+
def fetch(url, params, limit=10)
|
113
|
+
#params = get_params(http_method, url, opts)
|
114
|
+
raise TooManyRedirect, 'too many redirect!' if limit == 0
|
115
|
+
|
116
|
+
uri = URI(url)
|
117
|
+
uri.query = URI.encode_www_form(params)
|
118
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
119
|
+
http.use_ssl = uri.scheme == 'https'
|
120
|
+
http.ca_file = CA_FILE
|
121
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
122
|
+
|
123
|
+
response = http.request(request)
|
124
|
+
case response
|
125
|
+
when Net::HTTPRedirection
|
126
|
+
location = response['location']
|
127
|
+
uri = URI(location)
|
128
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
129
|
+
req['Cookie'] = response['set-cookie']
|
130
|
+
res = Net::HTTP.start(uri.hostname, uri.port) {|http|
|
131
|
+
http.request(req)
|
132
|
+
}
|
133
|
+
#response = Net::HTTP.get_response(uri, {'Cookie' => response['set-cookie']})
|
134
|
+
#fetch(location, cookie)
|
135
|
+
#fetch(location, http_method, opts, limit - 1)
|
136
|
+
else
|
137
|
+
response
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.get_base_string(params, url, http_method)
|
142
|
+
param_str_arr = []
|
143
|
+
params.sort.each do |pair|
|
144
|
+
param_str_arr << "#{ urlencode(pair[0].to_s) }=#{ urlencode(pair[1].to_s) }"
|
145
|
+
end
|
146
|
+
"#{http_method}&#{urlencode url}&#{urlencode param_str_arr.join('&')}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.urlencode(str)
|
150
|
+
# 下面两种方式均可
|
151
|
+
#str.gsub(/([^A-Za-z0-9\-._~])/)do |s|
|
152
|
+
#a = []
|
153
|
+
#s.bytes.to_a.each{|i| a << ("%%%02X" % i)}
|
154
|
+
#a.join
|
155
|
+
#end
|
156
|
+
URI.escape(str, /([^A-Za-z0-9\-._~])/)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
class KAuthError < StandardError
|
162
|
+
attr_reader :res
|
163
|
+
def initialize(res)
|
164
|
+
@res = res
|
165
|
+
super
|
166
|
+
end
|
167
|
+
end
|
168
|
+
class TooManyRedirect < StandardError; end
|
169
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
module Kuaipan
|
3
|
+
class Session
|
4
|
+
extend Forwardable
|
5
|
+
attr_reader :authorize_url,:base, :consumer
|
6
|
+
def_delegators :base, :account_info, :upload_file,
|
7
|
+
:create_folder, :delete, :metadata,
|
8
|
+
:copy, :download_file, :thumbnail,
|
9
|
+
:shares, :move, :document_view
|
10
|
+
def_delegators :authorize_url, :[]
|
11
|
+
|
12
|
+
def initialize(opt={})
|
13
|
+
oauth_callback = opt.delete(:oauth_callback)
|
14
|
+
@consumer = KAuth::Consumer.new(Config[:oauth_consumer_key],
|
15
|
+
Config[:oauth_consumer_secret],
|
16
|
+
Config.options_base)
|
17
|
+
# get rtoken
|
18
|
+
begin
|
19
|
+
rtoken = @consumer.get_request_token(oauth_callback)
|
20
|
+
@base = Base.new(@consumer)
|
21
|
+
# set authorize_url
|
22
|
+
@authorize_url = {authorize_url: "#{ Config[:authorize_url] }&oauth_token=#{ rtoken }"}
|
23
|
+
rescue KAuth::KAuthError => myKauthError
|
24
|
+
KpErrors.raise_errors(myKauthError.res)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_atoken(oauth_verifier)
|
29
|
+
# set accesstoken
|
30
|
+
begin
|
31
|
+
@consumer.set_atoken(oauth_verifier)
|
32
|
+
{oauth_token: @consumer.oauth_token,
|
33
|
+
oauth_token_secret: @consumer.oauth_token_secret,
|
34
|
+
user_id: @consumer.user_id}
|
35
|
+
rescue KAuth::KAuthError => myKauthError
|
36
|
+
KpErrors.raise_errors(myKauthError.res)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_oauth_result
|
41
|
+
{oauth_token: @consumer.oauth_token,
|
42
|
+
oauth_token_secret: @consumer.oauth_token_secret,
|
43
|
+
user_id: @consumer.user_id}
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.skip_oauth_session(oauth_token, oauth_token_secret, user_id, opts={})
|
47
|
+
session = Session.new(opts)
|
48
|
+
session.consumer.oauth_token = oauth_token
|
49
|
+
session.consumer.oauth_token_secret = oauth_token_secret
|
50
|
+
session.consumer.user_id = user_id
|
51
|
+
session
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kuaipan'
|
3
|
+
|
4
|
+
class BaseTest < Test::Unit::TestCase
|
5
|
+
def test_usr_info
|
6
|
+
#File.open("../../usr.json", 'r'){ |f|
|
7
|
+
#json = f.read
|
8
|
+
#hash = JSON.parse json
|
9
|
+
#hash.each do |pair|
|
10
|
+
#instance_variable_set pair[0], pair[1]
|
11
|
+
#end
|
12
|
+
#consumer =
|
13
|
+
#base = Kuaipan::Base.new consumer
|
14
|
+
#base.usr_info['user_id']
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'kuaipan'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class ConfigTest < Test::Unit::TestCase
|
5
|
+
def test_attrs
|
6
|
+
ckey,csecret,p = '123', '321!', {:root => 'kuaipan'}
|
7
|
+
Kuaipan::Config.opts ckey, csecret, p
|
8
|
+
assert_equal csecret, Kuaipan::Config[:oauth_consumer_secret]
|
9
|
+
assert_equal ckey, Kuaipan::Config[:oauth_consumer_key]
|
10
|
+
assert_equal 'kuaipan', Kuaipan::Config[:root]
|
11
|
+
end
|
12
|
+
end
|
data/test/test_client.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# conding: utf-8
|
2
|
+
require 'kuaipan'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class ClientTest < Test::Unit::TestCase
|
6
|
+
include Kuaipan::OpenAPI
|
7
|
+
|
8
|
+
def test_open_api
|
9
|
+
ct, cs = 'xcWcZhCNKFJz1H8p', '8RvkM0aGYiQF5kJF'
|
10
|
+
input_config ct, cs
|
11
|
+
k_session = nil
|
12
|
+
oauth_result_file = 'oauth_result.json'
|
13
|
+
if File.exist?(oauth_result_file)
|
14
|
+
File.open(oauth_result_file, 'r')do |f|
|
15
|
+
oauth_result = JSON.parse(f.read)
|
16
|
+
k_session = g_session_skip_oauth(oauth_result['oauth_token'],
|
17
|
+
oauth_result['oauth_token_secret'],
|
18
|
+
oauth_result['user_id'])
|
19
|
+
end
|
20
|
+
else
|
21
|
+
k_session = g_session
|
22
|
+
authorize_url = k_session[:authorize_url]
|
23
|
+
p 'please input this url to your browser,then copy authorization code here:'
|
24
|
+
p authorize_url
|
25
|
+
oauth_verifier = gets
|
26
|
+
oauth_result = k_session.set_atoken oauth_verifier
|
27
|
+
File.open(oauth_result_file,'w+')do |f|
|
28
|
+
f.write(JSON.generate(oauth_result))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# get account info
|
34
|
+
assert_not_nil k_session.account_info['user_id']
|
35
|
+
|
36
|
+
# 1 create folder
|
37
|
+
# 2 get metadata of folder
|
38
|
+
# 3 create repeated folder
|
39
|
+
# 4 delete folder
|
40
|
+
folder = '/tiemei_kuaipan_test/test'
|
41
|
+
begin
|
42
|
+
assert_equal 'ok', k_session.create_folder(folder)['msg']
|
43
|
+
assert_not_nil k_session.metadata('/tiemei_kuaipan_test')['root']
|
44
|
+
assert_equal 'ok', k_session.create_folder(folder)['msg']
|
45
|
+
ensure
|
46
|
+
k_session.delete('/tiemei_kuaipan_test')
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# upload one file to a folder
|
51
|
+
# delete folder
|
52
|
+
# download file
|
53
|
+
# delete file
|
54
|
+
folder = 'kuaipan_testfolder'
|
55
|
+
file_name = '.kuaipan_test_file_123'
|
56
|
+
rename = 'renameFile'
|
57
|
+
copyname = 'copyfil.txt'
|
58
|
+
dir = 'demo_tiemei'
|
59
|
+
file = File.open("#{ file_name }",'w+b')do |f|
|
60
|
+
f.write('test content!You can delete it')
|
61
|
+
f.flush
|
62
|
+
end
|
63
|
+
file = File.open("#{ file_name }", 'rb')
|
64
|
+
begin
|
65
|
+
assert_not_nil k_session.upload_file(file, {:path => "/#{ folder }"})['file_id']
|
66
|
+
p k_session.shares("/#{ folder }/#{ file_name }").to_s
|
67
|
+
k_session.move("/#{ folder }/#{ file_name }",
|
68
|
+
"/#{ folder }/#{ rename }")
|
69
|
+
assert_not_nil k_session.copy("/#{ folder }/#{ rename }",
|
70
|
+
"/#{ folder }/#{ copyname }")['file_id']
|
71
|
+
k_session.download_file("/#{ folder }/#{ copyname }")do |res|
|
72
|
+
Dir.mkdir(dir) unless Dir.exist?(dir)
|
73
|
+
file = File.open("#{ dir }/#{ copyname }", 'wb')do |f|
|
74
|
+
f.write(res.body)
|
75
|
+
f.flush
|
76
|
+
end
|
77
|
+
end
|
78
|
+
# document_view
|
79
|
+
k_session.document_view('txt', "#{ folder }/#{ copyname }")do |res|
|
80
|
+
p res.body
|
81
|
+
end
|
82
|
+
|
83
|
+
ensure
|
84
|
+
k_session.delete(folder)
|
85
|
+
File.delete(file)
|
86
|
+
end
|
87
|
+
|
88
|
+
# get thumbnail
|
89
|
+
k_session.thumbnail(100, 100, '08.jpg')do |res|
|
90
|
+
Dir.mkdir(dir) unless Dir.exist?(dir)
|
91
|
+
file = File.open("#{ dir }/#{ '08.jpg' }", 'wb')do |f|
|
92
|
+
f.write(res.body)
|
93
|
+
f.flush
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kuaipan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- tiemei
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.6.6
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rest-client
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: Kuaipan openAPI! With it , you can develop apps which connect to kuaipan@kingsoft
|
47
|
+
email: jiadongkai@gmail.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- lib/kuaipan.rb
|
53
|
+
- lib/kuaipan/base.rb
|
54
|
+
- lib/kuaipan/config.rb
|
55
|
+
- lib/kuaipan/session.rb
|
56
|
+
- lib/kuaipan/errors.rb
|
57
|
+
- lib/kuaipan/kauth/consumer.rb
|
58
|
+
- Rakefile
|
59
|
+
- README.rdoc
|
60
|
+
- Gemfile
|
61
|
+
- Gemfile.lock
|
62
|
+
- kuaipan.gemspec
|
63
|
+
- test/test_client.rb
|
64
|
+
- test/kuaipan/test_base.rb
|
65
|
+
- test/kuaipan/test_config.rb
|
66
|
+
- test/kuaipan/test_session.rb
|
67
|
+
homepage: http://rubygems.org/gems/kuaipan
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.9.3
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 1.3.6
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.22
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Kuaipan openapi ruby-sdk
|
91
|
+
test_files: []
|