divshare 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{License.txt → LICENSE} +1 -1
- data/{README.txt → README} +0 -0
- data/Rakefile +33 -3
- data/VERSION +1 -0
- data/lib/divshare.rb +0 -3
- data/lib/divshare/client.rb +101 -77
- data/lib/divshare/divshare_file.rb +8 -11
- data/lib/divshare/encoder.rb +50 -0
- data/lib/divshare/multipart.rb +37 -0
- data/spec/client_spec.rb +97 -107
- data/spec/divshare_file_spec.rb +1 -1
- data/spec/encoder_spec.rb +100 -0
- data/spec/spec_helper.rb +9 -3
- data/spec/user_spec.rb +1 -3
- metadata +42 -45
- data/History.txt +0 -4
- data/Manifest.txt +0 -35
- data/config/hoe.rb +0 -72
- data/config/requirements.rb +0 -17
- data/lib/divshare/post_args.rb +0 -16
- data/lib/divshare/version.rb +0 -9
- data/log/debug.log +0 -0
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/test_run_client +0 -59
- data/script/txt2html +0 -74
- data/setup.rb +0 -1585
- data/spec/fixtures/divshare_mock_valid_audio.html +0 -299
- data/spec/fixtures/divshare_mock_valid_video.html +0 -294
- data/spec/post_args_spec.rb +0 -54
- data/tasks/deployment.rake +0 -34
- data/tasks/environment.rake +0 -7
- data/tasks/website.rake +0 -17
- data/website/index.html +0 -93
- data/website/index.txt +0 -39
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.rhtml +0 -48
data/{License.txt → LICENSE}
RENAMED
data/{README.txt → README}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -1,4 +1,34 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
begin
|
2
|
+
require "spec/rake/spectask"
|
3
|
+
desc "Run all specs"
|
4
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
5
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
6
|
+
t.libs = ['spec', 'lib']
|
7
|
+
t.spec_opts = ["-c", "-f s"]
|
8
|
+
t.ruby_opts = ["-r rubygems"] # If you want to use rubygems for requires
|
9
|
+
end
|
10
|
+
rescue LoadError
|
11
|
+
puts "RSpec not available. Can't run specs without it. Install with: sudo gem install rspec"
|
12
|
+
end
|
3
13
|
|
4
|
-
|
14
|
+
task :default => :spec
|
15
|
+
|
16
|
+
begin
|
17
|
+
require "jeweler"
|
18
|
+
Jeweler::Tasks.new do |gemspec|
|
19
|
+
gemspec.name = "divshare"
|
20
|
+
gemspec.description = "A Ruby interface to the DivShare file hosting service"
|
21
|
+
gemspec.summary = "A Ruby interface to the DivShare file hosting service"
|
22
|
+
gemspec.date = Time.now.strftime("%Y-%m-%d")
|
23
|
+
gemspec.files = ["README", "LICENSE", "VERSION", "Rakefile", Dir::glob("lib/**/**")].flatten
|
24
|
+
gemspec.authors = ["Eric Watson"]
|
25
|
+
gemspec.email = "wasnotrice@gmail.com"
|
26
|
+
gemspec.homepage = "http://github.com/wasnotrice/divshare"
|
27
|
+
gemspec.rubyforge_project = "divshare"
|
28
|
+
|
29
|
+
gemspec.add_dependency "hpricot"
|
30
|
+
gemspec.add_dependency "mime-types"
|
31
|
+
end
|
32
|
+
rescue LoadError
|
33
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
34
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/lib/divshare.rb
CHANGED
data/lib/divshare/client.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'cgi'
|
3
2
|
require 'net/http'
|
4
3
|
require 'hpricot'
|
5
4
|
require 'digest/md5'
|
6
|
-
require 'divshare/errors'
|
7
5
|
require 'divshare/divshare_file'
|
8
|
-
require 'divshare/
|
6
|
+
require 'divshare/encoder'
|
7
|
+
require 'divshare/errors'
|
8
|
+
require 'divshare/multipart'
|
9
9
|
require 'divshare/user'
|
10
10
|
|
11
11
|
module Divshare
|
@@ -18,19 +18,49 @@ module Divshare
|
|
18
18
|
# client.logout
|
19
19
|
#
|
20
20
|
class Client
|
21
|
+
|
22
|
+
API_URL = 'http://www.divshare.com/api/'
|
23
|
+
UPLOAD_URL = 'http://upload.divshare.com'
|
24
|
+
UPLOAD_PATH = '/api/upload'
|
25
|
+
|
21
26
|
SUCCESS = '1'
|
22
27
|
FAILURE = '0'
|
23
28
|
|
24
|
-
|
29
|
+
attr_accessor :debug # If true, extended debugging information is printed
|
30
|
+
|
31
|
+
def initialize(key, secret)
|
32
|
+
@encoder = Encoder.new(key, secret)
|
33
|
+
# @debug = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def key
|
37
|
+
@encoder.key
|
38
|
+
end
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def
|
31
|
-
@
|
32
|
-
|
33
|
-
|
40
|
+
def secret
|
41
|
+
@encoder.secret
|
42
|
+
end
|
43
|
+
|
44
|
+
def session_key
|
45
|
+
@encoder.session_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def login(email, password)
|
49
|
+
logout if @encoder.session_key
|
50
|
+
response = send_method(:login, {'user_email' => email, 'user_password' => password})
|
51
|
+
@encoder.session_key = response.at(:api_session_key).inner_html
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns true if logout is successful.
|
55
|
+
def logout
|
56
|
+
response = send_method(:logout)
|
57
|
+
debug response.to_html
|
58
|
+
if response[:status] == SUCCESS
|
59
|
+
@encoder.session_key = nil
|
60
|
+
true
|
61
|
+
else
|
62
|
+
false
|
63
|
+
end
|
34
64
|
end
|
35
65
|
|
36
66
|
# file_ids should be an array of file ids
|
@@ -45,8 +75,8 @@ module Divshare
|
|
45
75
|
# logged-in user.
|
46
76
|
def get_files(file_ids)
|
47
77
|
file_ids = [file_ids] unless file_ids.is_a? Array
|
78
|
+
debug "DivShare.get_files(): #{file_ids.class}"
|
48
79
|
files = get_user_files
|
49
|
-
puts file_ids.class
|
50
80
|
files.delete_if {|f| file_ids.include?(f.file_id) == false}
|
51
81
|
end
|
52
82
|
|
@@ -57,8 +87,9 @@ module Divshare
|
|
57
87
|
get_files(file_id).first
|
58
88
|
end
|
59
89
|
|
60
|
-
# Returns an array of Divshare::DivshareFile objects belonging to the
|
61
|
-
# <tt>offset</tt> to narrow things
|
90
|
+
# Returns an array of Divshare::DivshareFile objects belonging to the
|
91
|
+
# logged-in user. Use <tt>limit</tt> and <tt>offset</tt> to narrow things
|
92
|
+
# down.
|
62
93
|
def get_user_files(limit=nil, offset=nil)
|
63
94
|
args = {}
|
64
95
|
args['limit'] = limit unless limit.nil?
|
@@ -67,8 +98,8 @@ module Divshare
|
|
67
98
|
files_from response
|
68
99
|
end
|
69
100
|
|
70
|
-
# Returns an array of Divshare::DivshareFile objects in the specified
|
71
|
-
# <tt>offset</tt> to narrow things down.
|
101
|
+
# Returns an array of Divshare::DivshareFile objects in the specified
|
102
|
+
# folder. Use <tt>limit</tt> and <tt>offset</tt> to narrow things down.
|
72
103
|
def get_folder_files(folder_id, limit=nil, offset=nil)
|
73
104
|
args = {}
|
74
105
|
args['limit'] = limit unless limit.nil?
|
@@ -80,51 +111,63 @@ module Divshare
|
|
80
111
|
|
81
112
|
# Returns information about the logged-in user
|
82
113
|
def get_user_info
|
83
|
-
response = send_method
|
84
|
-
user_from
|
114
|
+
response = send_method(:get_user_info)
|
115
|
+
user_from(response)
|
85
116
|
end
|
86
117
|
|
87
118
|
# Returns an upload ticket string for use in uploading files. See
|
88
119
|
# http://www.divshare.com/integrate/api#uploading for more information on
|
89
120
|
# how to use the upload ticket once you've got it.
|
90
121
|
def get_upload_ticket
|
91
|
-
|
92
|
-
upload_ticket_from response
|
122
|
+
send_method(:get_upload_ticket).at(:upload_ticket).inner_html
|
93
123
|
end
|
94
124
|
|
95
|
-
#
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
125
|
+
# Uploads a file or files to the user's DivShare account, and returns the
|
126
|
+
# file id(s).
|
127
|
+
#
|
128
|
+
# The DivShare API is written for use with actual HTML forms, so the API
|
129
|
+
# method requires a 'response_url', and makes a GET request to that url,
|
130
|
+
# sending the file id(s) as query parameters.
|
131
|
+
#
|
132
|
+
# Here, we're simulating the form, so we parse DivShare's GET request and
|
133
|
+
# simply return the file id(s). In this case, response_url is just a
|
134
|
+
# filler so that the server doesn't complain.
|
135
|
+
def upload(ticket, file_path, response_url='www.divshare.com/upload_result')
|
136
|
+
location = nil
|
137
|
+
File.open(file_path, 'r') { |file|
|
138
|
+
uri = URI.parse(UPLOAD_URL)
|
139
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
140
|
+
# API methods can be SLOW. Timeout interval should be long.
|
141
|
+
http.read_timeout = 15*60
|
142
|
+
request = Net::HTTP::Post.new(UPLOAD_PATH)
|
143
|
+
fields = Hash.new
|
144
|
+
fields['upload_ticket'] = ticket
|
145
|
+
# API doesn't allow blank response_url. This is just filler.
|
146
|
+
fields['response_url'] = response_url
|
108
147
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
148
|
+
fields['file1'] = file
|
149
|
+
request.multipart_params = fields
|
150
|
+
# Until DivShare supports direct upload API, we deal with its response location field
|
151
|
+
location = http.request(request)['location']
|
152
|
+
}
|
153
|
+
|
154
|
+
# if error, throw, otherwise return file ID for caller to do whatever they like
|
155
|
+
resp = {}
|
156
|
+
location.split('?')[1].split('&').each { |param|
|
157
|
+
k, v = param.split('=', 2) # some params could contain two '=' for some reason
|
158
|
+
resp[k]=CGI.unescape(v)
|
159
|
+
}
|
160
|
+
if resp['error']
|
161
|
+
raise Divshare::APIError, resp['description']
|
115
162
|
else
|
116
|
-
|
163
|
+
resp['file1'] # return the file ID
|
117
164
|
end
|
118
|
-
true
|
119
165
|
end
|
120
166
|
|
121
|
-
|
122
|
-
# http://www.divshare.com/integrate/api#sig
|
123
|
-
def sign(method, args)
|
124
|
-
Digest::MD5.hexdigest(string_to_sign(args))
|
125
|
-
end
|
167
|
+
|
126
168
|
|
127
169
|
private
|
170
|
+
|
128
171
|
def files_from(xml)
|
129
172
|
xml = xml/:file
|
130
173
|
xml = [xml] unless xml.respond_to?(:each)
|
@@ -136,11 +179,6 @@ module Divshare
|
|
136
179
|
Divshare::User.new(xml)
|
137
180
|
end
|
138
181
|
|
139
|
-
def upload_ticket_from(xml)
|
140
|
-
xml = xml.at(:upload_ticket).inner_html
|
141
|
-
end
|
142
|
-
|
143
|
-
# Since login and logout aren't easily re-nameable to use method missing
|
144
182
|
def send_method(method_id, *params)
|
145
183
|
response = http_post(method_id, *params)
|
146
184
|
xml = Hpricot(response).at(:response)
|
@@ -149,44 +187,30 @@ module Divshare
|
|
149
187
|
raise Divshare::APIError, errors.join("\n")
|
150
188
|
end
|
151
189
|
xml
|
152
|
-
end
|
153
|
-
|
154
|
-
def post_args(method, args)
|
155
|
-
PostArgs.new(self, method, args)
|
156
190
|
end
|
157
|
-
|
191
|
+
|
158
192
|
def http_post(method, args={})
|
159
|
-
url = URI.parse(
|
193
|
+
url = URI.parse(API_URL)
|
160
194
|
tries = 3
|
161
195
|
response = ""
|
196
|
+
form_args = @encoder.encode(method, args)
|
162
197
|
begin
|
163
|
-
response = Net::HTTP.post_form(url,
|
198
|
+
response = Net::HTTP.post_form(url, form_args).body
|
164
199
|
rescue
|
165
200
|
tries -= 1
|
166
|
-
|
201
|
+
debug "DivShare\#http_post() failed: #{tries} tries remaining"
|
167
202
|
if tries > 0
|
168
203
|
retry
|
169
204
|
else
|
170
|
-
raise Divshare::ConnectionError, "Couldn't connect for '#{method}' using #{
|
205
|
+
raise Divshare::ConnectionError, "Couldn't connect to #{API_URL} for '#{method}' using #{form_args.inspect}"
|
171
206
|
end
|
172
207
|
end
|
173
208
|
response
|
174
209
|
end
|
175
|
-
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
# * Your session key is 456-session.
|
180
|
-
# * You are using the get_user_files method, and you're sending the
|
181
|
-
# parameters limit=5 and offset=10.
|
182
|
-
#
|
183
|
-
# The string used to create your signature will be:
|
184
|
-
# 123-secret456-sessionlimit5offset10. Note that the parameters must be in
|
185
|
-
# alphabetical order, so limit always comes before offset. Each parameter
|
186
|
-
# should be paired with its value as shown.
|
187
|
-
def string_to_sign(args)
|
188
|
-
args_for_string = args.dup.delete_if {|k,v| %w(api_key method api_sig api_session_key).include?(k) }
|
189
|
-
"#{@api_secret}#{@api_session_key}#{args_for_string.to_a.sort.flatten.join}"
|
210
|
+
|
211
|
+
# Outputs whatever is given to $stderr if debugging is enabled.
|
212
|
+
def debug(*args)
|
213
|
+
$stderr.puts(sprintf(*args)) if @debug
|
190
214
|
end
|
191
215
|
end
|
192
|
-
end
|
216
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'hpricot'
|
3
2
|
|
4
3
|
module Divshare
|
@@ -64,11 +63,10 @@ module Divshare
|
|
64
63
|
def find_medium
|
65
64
|
ext = @file_name ? File.extname(@file_name) : nil
|
66
65
|
medium = case
|
67
|
-
when AUDIO.match(ext)
|
68
|
-
when VIDEO.match(ext)
|
69
|
-
when DOCUMENT.match(ext)
|
70
|
-
when IMAGE.match(ext)
|
71
|
-
else nil
|
66
|
+
when AUDIO.match(ext) then "audio"
|
67
|
+
when VIDEO.match(ext) then "video"
|
68
|
+
when DOCUMENT.match(ext) then "document"
|
69
|
+
when IMAGE.match(ext) then "image"
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
@@ -102,11 +100,10 @@ module Divshare
|
|
102
100
|
|
103
101
|
def image_embed_tag_template(opts={:size=>:midsize})
|
104
102
|
size = case opts[:size]
|
105
|
-
when :midsize, :mid
|
106
|
-
when :thumb, :thumbnail
|
107
|
-
|
108
|
-
end
|
103
|
+
when :midsize, :mid then "midsize/"
|
104
|
+
when :thumb, :thumbnail then "thumb/"
|
105
|
+
end || ""
|
109
106
|
tag = "http://www.divshare.com/img/#{size}[FILE ID]"
|
110
107
|
end
|
111
108
|
end
|
112
|
-
end
|
109
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Divshare
|
2
|
+
|
3
|
+
# Manages the arguments send along with a POST to the DivShare API URL.
|
4
|
+
# Takes care of organizing arguments and generating API signatures for
|
5
|
+
# requests
|
6
|
+
class Encoder # :nodoc:
|
7
|
+
attr_reader :key, :secret
|
8
|
+
attr_accessor :session_key
|
9
|
+
|
10
|
+
def initialize(key, secret)
|
11
|
+
@key, @secret = key, secret
|
12
|
+
end
|
13
|
+
|
14
|
+
# Prepares arguments for a post using the given method and arguments.
|
15
|
+
# Returns a hash of arguments and values
|
16
|
+
def encode(method, args={})
|
17
|
+
# Stringifies incoming keys and values
|
18
|
+
post_args = Hash.new
|
19
|
+
args.each { |k, v| post_args[k.to_s] = v.to_s }
|
20
|
+
post_args.merge!({'method' => method.to_s, 'api_key' => @key.to_s})
|
21
|
+
if @session_key
|
22
|
+
sig = sign(post_args)
|
23
|
+
post_args.merge!({'api_session_key' => @session_key.to_s, 'api_sig' => sig})
|
24
|
+
end
|
25
|
+
post_args
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generates the required MD5 signature as described in
|
29
|
+
# http://www.divshare.com/integrate/api#sig
|
30
|
+
def sign(args)
|
31
|
+
Digest::MD5.hexdigest(string_to_sign(args))
|
32
|
+
end
|
33
|
+
|
34
|
+
# From http://www.divshare.com/integrate/api
|
35
|
+
#
|
36
|
+
# * Your secret key is 123-secret.
|
37
|
+
# * Your session key is 456-session.
|
38
|
+
# * You are using the get_user_files method, and you're sending the
|
39
|
+
# parameters limit=5 and offset=10.
|
40
|
+
#
|
41
|
+
# The string used to create your signature will be:
|
42
|
+
# 123-secret456-sessionlimit5offset10. Note that the parameters must be in
|
43
|
+
# alphabetical order, so limit always comes before offset. Each parameter
|
44
|
+
# should be paired with its value as shown.
|
45
|
+
def string_to_sign(args)
|
46
|
+
args_for_string = args.dup.delete_if {|k,v| %w(api_key method api_sig api_session_key).include?(k) }
|
47
|
+
"#{@secret}#{@session_key}#{args_for_string.to_a.sort.flatten.join}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This is based on this article from Pivot Labs:
|
2
|
+
# http://pivots.pivotallabs.com/users/damon/blog/articles/227-standup-04-27-07-testing-file-uploads
|
3
|
+
|
4
|
+
require 'net/https'
|
5
|
+
require "mime/types" # Requires gem install mime-types
|
6
|
+
|
7
|
+
module Net #:nodoc:all
|
8
|
+
class HTTP::Post
|
9
|
+
def multipart_params=(param_hash={})
|
10
|
+
boundary_token = [Array.new(8) {rand(256)}].join
|
11
|
+
self.content_type = "multipart/form-data; boundary=#{boundary_token}"
|
12
|
+
boundary_marker = "--#{boundary_token}\r\n"
|
13
|
+
self.body = param_hash.map { |param_name, param_value|
|
14
|
+
boundary_marker + case param_value
|
15
|
+
when File
|
16
|
+
file_to_multipart(param_name, param_value)
|
17
|
+
else
|
18
|
+
text_to_multipart(param_name, param_value.to_s)
|
19
|
+
end
|
20
|
+
}.join('') + "--#{boundary_token}--\r\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def file_to_multipart(key,file)
|
25
|
+
filename = File.basename(file.path)
|
26
|
+
mime_types = MIME::Types.of(filename)
|
27
|
+
mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
28
|
+
part = %Q|Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n|
|
29
|
+
part += "Content-Transfer-Encoding: binary\r\n"
|
30
|
+
part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}\r\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
def text_to_multipart(key,value)
|
34
|
+
"Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,175 +1,150 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'divshare/client'
|
3
3
|
include Divshare
|
4
4
|
|
5
5
|
module ClientSpecHelper
|
6
6
|
include DivshareMockXML
|
7
|
-
|
8
|
-
Client.new('api_key', 'api_secret')
|
9
|
-
end
|
10
|
-
|
11
|
-
def new_client_with_email_and_password
|
12
|
-
Client.new('api_key', 'api_secret', 'email', 'password')
|
13
|
-
end
|
14
|
-
|
15
|
-
def login(client, api_session_key='123-abcdefghijkl')
|
16
|
-
client.stub!(:login).and_return(api_session_key)
|
17
|
-
client.instance_variable_set(:@api_session_key, client.login)
|
18
|
-
api_session_key
|
19
|
-
end
|
20
|
-
|
7
|
+
|
21
8
|
# Each setup must declare what @mock_response will return
|
22
|
-
def common_setup(
|
23
|
-
|
24
|
-
@
|
25
|
-
@api_session_key =
|
9
|
+
def common_setup()
|
10
|
+
@api_key = 'api_key'
|
11
|
+
@api_secret = 'api_secret'
|
12
|
+
@api_session_key = '123-abcdefghijkl'
|
13
|
+
@user_email = 'fake_user_email'
|
14
|
+
@password = 'fake_password'
|
26
15
|
@files = ['2734485-1fc', '2735059-62d']
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
16
|
+
@api_url = URI.parse(Divshare::Client::API_URL)
|
17
|
+
end
|
18
|
+
|
19
|
+
def no_login_setup
|
31
20
|
@mock_response = mock('response')
|
32
|
-
Net::HTTP.
|
21
|
+
Net::HTTP.should_receive(:post_form).once.and_return(@mock_response)
|
22
|
+
@client = Client.new(@api_key, @api_secret)
|
33
23
|
end
|
34
24
|
|
35
|
-
def
|
36
|
-
|
25
|
+
def login_setup
|
26
|
+
@mock_response = mock('response')
|
27
|
+
@mock_login_response = mock('login_response')
|
28
|
+
Net::HTTP.should_receive(:post_form).twice.and_return(@mock_login_response, @mock_response)
|
29
|
+
@mock_login_response.should_receive(:body).and_return(successful_login_xml)
|
30
|
+
@client = Client.new(@api_key, @api_secret)
|
31
|
+
@client.login(@user_email, @password)
|
37
32
|
end
|
38
33
|
end
|
39
34
|
|
40
35
|
describe "A new Divshare Client" do
|
41
36
|
include ClientSpecHelper
|
42
|
-
|
43
|
-
|
44
|
-
new_client.should be_instance_of(Divshare::Client)
|
37
|
+
before :all do
|
38
|
+
common_setup
|
45
39
|
end
|
46
40
|
|
47
|
-
|
48
|
-
|
41
|
+
before :each do
|
42
|
+
@client = Client.new(@api_key, @api_secret)
|
49
43
|
end
|
50
|
-
|
51
|
-
it "should
|
52
|
-
client
|
53
|
-
[client.api_key, client.api_secret, client.email, client.password].should == ['api_key', 'api_secret', 'email', 'password']
|
44
|
+
|
45
|
+
it "should be created successfully" do
|
46
|
+
@client.should be_instance_of(Divshare::Client)
|
54
47
|
end
|
55
48
|
|
56
49
|
it "should know the proper post url" do
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
# Using string 'api_secret123-abcdefghijklfiles2734485-1fc'
|
61
|
-
it "should generate a correct signature" do
|
62
|
-
api_sig = '0e1c483506dd413808c80183333e1fc2'
|
63
|
-
common_setup(:stub_sign => false)
|
64
|
-
@client.sign("get_files", {"files" => @files.first}).should == api_sig
|
50
|
+
Divshare::Client::API_URL.should == "http://www.divshare.com/api/"
|
65
51
|
end
|
66
52
|
|
67
53
|
it "should raise Divshare::ConnectionError on timeout" do
|
68
|
-
|
69
|
-
|
70
|
-
lambda { new_client_with_email_and_password.login }.should raise_error(Divshare::ConnectionError)
|
54
|
+
pending 'Timeout code implementation'
|
55
|
+
lambda { @client.login('email', 'password') }.should raise_error(Divshare::ConnectionError)
|
71
56
|
end
|
72
57
|
|
73
58
|
end
|
74
59
|
|
60
|
+
describe Divshare::Client, "making a request to the API" do
|
61
|
+
# spec the request format. This should suffice for all requests.
|
62
|
+
|
63
|
+
end
|
64
|
+
|
75
65
|
describe "A Divshare Client getting one file" do
|
76
66
|
include ClientSpecHelper
|
77
|
-
before(:
|
67
|
+
before(:all) do
|
78
68
|
common_setup
|
79
69
|
end
|
80
|
-
|
81
|
-
# If it generates a PostArgs object, it's doing the right thing
|
82
|
-
it "should generate arguments for post" do
|
83
|
-
pending("Fix to API that allows correct get_files method")
|
84
|
-
@mock_response.should_receive(:body).and_return(get_one_file_xml)
|
85
|
-
PostArgs.should_receive(:new).with(@client,:get_files,{'files' => @files.first})
|
86
|
-
@client.get_files(@files.first)
|
87
|
-
end
|
88
70
|
|
89
71
|
it "should return an array of one DivshareFile when requesting a file through get_files" do
|
72
|
+
login_setup
|
90
73
|
@mock_response.should_receive(:body).and_return(get_one_file_xml)
|
91
74
|
@client.get_files('123456-abc').map {|f| f.class}.should == [DivshareFile]
|
92
75
|
end
|
93
76
|
|
94
77
|
it "should return a DivshareFile when requesting a file through get_file" do
|
78
|
+
login_setup
|
95
79
|
@mock_response.should_receive(:body).and_return(get_one_file_xml)
|
96
80
|
@client.get_file('123456-abc').class.should == DivshareFile
|
97
81
|
end
|
98
82
|
|
99
83
|
it "should raise ArgumentError if an array is passed to get_file" do
|
84
|
+
@client = Client.new(@api_key, @api_secret)
|
100
85
|
lambda {@client.get_file(['123456-abc'])}.should raise_error(ArgumentError)
|
101
86
|
end
|
102
87
|
end
|
103
88
|
|
104
89
|
describe "A Divshare Client getting two files" do
|
105
90
|
include ClientSpecHelper
|
106
|
-
before(:
|
91
|
+
before(:all) do
|
107
92
|
common_setup
|
108
93
|
end
|
109
94
|
|
95
|
+
before :each do
|
96
|
+
login_setup
|
97
|
+
@mock_response.should_receive(:body).and_return(get_two_files_xml)
|
98
|
+
end
|
99
|
+
|
110
100
|
it "should return an array of two DivshareFiles" do
|
111
|
-
mock_response = mock('response')
|
112
|
-
Net::HTTP.stub!(:post_form).and_return(mock_response)
|
113
|
-
mock_response.should_receive(:body).and_return(get_two_files_xml)
|
114
101
|
@client.get_files(['123456-abc', '456789-def']).map {|f| f.class}.should == [DivshareFile, DivshareFile]
|
115
102
|
end
|
116
103
|
end
|
117
104
|
|
118
105
|
describe "A Divshare Client getting user files" do
|
119
106
|
include ClientSpecHelper
|
120
|
-
before
|
107
|
+
before :all do
|
121
108
|
common_setup
|
122
|
-
|
109
|
+
end
|
110
|
+
|
111
|
+
before :each do
|
112
|
+
login_setup
|
113
|
+
@mock_response.should_receive(:body).and_return(get_two_files_xml)
|
123
114
|
end
|
124
115
|
|
125
116
|
it "should return an array of files" do
|
126
117
|
@client.get_user_files.map {|f| f.class }.should == [DivshareFile, DivshareFile]
|
127
118
|
end
|
128
|
-
|
129
|
-
# If it generates a PostArgs object, it's doing the right thing
|
130
|
-
it "should generate arguments for post" do
|
131
|
-
PostArgs.should_receive(:new).with(@client,:get_user_files, {})
|
132
|
-
@client.get_user_files
|
133
|
-
end
|
134
|
-
|
135
|
-
it "should generate arguments for post with limit and offset" do
|
136
|
-
PostArgs.should_receive(:new).with(@client, :get_user_files, {"limit" => 5, "offset" => 2})
|
137
|
-
@client.get_user_files(5, 2)
|
138
|
-
end
|
139
|
-
|
140
119
|
end
|
141
120
|
|
142
121
|
describe "A Divshare Client getting folder files" do
|
143
122
|
include ClientSpecHelper
|
144
|
-
before
|
123
|
+
before :all do
|
145
124
|
common_setup
|
146
|
-
@mock_response.should_receive(:body).and_return(get_two_files_xml)
|
147
125
|
end
|
148
126
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# If it generates a PostArgs object, it's doing the right thing
|
154
|
-
it "should generate arguments for post" do
|
155
|
-
PostArgs.should_receive(:new).with(@client,:get_folder_files, {'folder_id' => '12345'})
|
156
|
-
@client.get_folder_files('12345')
|
127
|
+
before :each do
|
128
|
+
login_setup
|
129
|
+
@mock_response.should_receive(:body).and_return(get_two_files_xml)
|
157
130
|
end
|
158
131
|
|
159
|
-
it "should
|
160
|
-
|
161
|
-
@client.get_folder_files('12345', 5, 2)
|
132
|
+
it "should return an array of files" do
|
133
|
+
@client.get_folder_files('12345').map {|f| f.class }.should == [DivshareFile, DivshareFile]
|
162
134
|
end
|
163
|
-
|
164
|
-
|
165
135
|
end
|
166
136
|
|
167
137
|
describe "A Divshare Client, creating an upload ticket" do
|
168
138
|
include ClientSpecHelper
|
169
|
-
before
|
139
|
+
before :all do
|
170
140
|
common_setup
|
141
|
+
end
|
142
|
+
|
143
|
+
before :each do
|
144
|
+
login_setup
|
171
145
|
@mock_response.should_receive(:body).and_return(get_upload_ticket_xml)
|
172
146
|
end
|
147
|
+
|
173
148
|
it "should return an upload ticket" do
|
174
149
|
@client.get_upload_ticket.should == '123-abcdefghijkl'
|
175
150
|
end
|
@@ -177,45 +152,60 @@ end
|
|
177
152
|
|
178
153
|
describe "A Divshare Client, logging in" do
|
179
154
|
include ClientSpecHelper
|
180
|
-
before
|
181
|
-
common_setup
|
182
|
-
@api_session_key = login(new_client)
|
183
|
-
@mock_response.should_receive(:body).and_return(successful_login_xml)
|
155
|
+
before :all do
|
156
|
+
common_setup
|
184
157
|
end
|
185
158
|
|
186
|
-
|
187
|
-
|
159
|
+
before :each do
|
160
|
+
no_login_setup
|
161
|
+
@mock_response.should_receive(:body).and_return(successful_login_xml)
|
188
162
|
end
|
189
|
-
|
163
|
+
|
190
164
|
it "should set api session key" do
|
191
|
-
@client.
|
192
|
-
@client.login
|
193
|
-
@client.
|
165
|
+
@client.session_key.should_not == @api_session_key
|
166
|
+
@client.login(@user_email, @password)
|
167
|
+
@client.session_key.should == @api_session_key
|
194
168
|
end
|
195
169
|
end
|
196
170
|
|
197
171
|
describe "A DivshareClient, unsuccessfully logging in" do
|
198
172
|
include ClientSpecHelper
|
199
173
|
it "should raise Divshare::APIError" do
|
200
|
-
common_setup
|
174
|
+
common_setup
|
175
|
+
no_login_setup
|
201
176
|
@mock_response.should_receive(:body).and_return(error_xml("Couldn't log in"))
|
202
|
-
lambda {@client.login}.should raise_error(Divshare::APIError)
|
177
|
+
lambda {@client.login(@user_email, @password)}.should raise_error(Divshare::APIError)
|
203
178
|
end
|
204
179
|
end
|
205
180
|
|
206
|
-
describe "A Divshare Client, logging out" do
|
181
|
+
describe "A Divshare Client, successfully logging out" do
|
207
182
|
include ClientSpecHelper
|
208
|
-
before
|
183
|
+
before :all do
|
209
184
|
common_setup
|
185
|
+
end
|
186
|
+
|
187
|
+
before :each do
|
188
|
+
login_setup
|
210
189
|
@mock_response.should_receive(:body).and_return(successful_logout_xml)
|
211
190
|
end
|
212
191
|
|
213
|
-
it "should
|
192
|
+
it "should return true" do
|
214
193
|
@client.logout.should be_true
|
215
194
|
end
|
216
|
-
|
217
|
-
it "should remove api session key
|
195
|
+
|
196
|
+
it "should remove api session key" do
|
218
197
|
@client.logout
|
219
|
-
@client.
|
198
|
+
@client.session_key.should be_nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "A Divshare Client, unsuccessfully logging out" do
|
203
|
+
include ClientSpecHelper
|
204
|
+
|
205
|
+
it "should return false" do
|
206
|
+
common_setup
|
207
|
+
login_setup
|
208
|
+
@mock_response.should_receive(:body).and_return(unsuccessful_logout_xml)
|
209
|
+
lambda {@client.logout}.should raise_error(Divshare::APIError)
|
220
210
|
end
|
221
211
|
end
|