kuaipan 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|