divshare 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 Eric Watson
1
+ Copyright (c) 2007-2009 Eric Watson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
File without changes
data/Rakefile CHANGED
@@ -1,4 +1,34 @@
1
- require 'config/requirements'
2
- require 'config/hoe' # setup Hoe + all gem configuration
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
- Dir['tasks/**/*.rake'].each { |rake| load rake }
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
@@ -1,4 +1 @@
1
1
  require 'divshare/client'
2
- require 'divshare/divshare_file'
3
- require 'divshare/post_args'
4
- require 'divshare/errors'
@@ -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/post_args'
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
- attr_reader :api_key, :api_secret, :post_url, :api_session_key, :email, :password
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
- # Creates a Divshare::Client. The <tt>api_key</tt> and <tt>api_secret</tt>
27
- # are required, but <tt>email</tt> and <tt>password</tt> are optional. If
28
- # you omit <tt>email</tt> and <tt>password</tt> here, you must send them
29
- # with link:login when you call it.
30
- def initialize(api_key, api_secret, email=nil, password=nil)
31
- @api_key, @api_secret, @email, @password = api_key, api_secret, email, password
32
- @api_session_key = nil
33
- @post_url = "http://www.divshare.com/api/"
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 logged-in user. Use <tt>limit</tt> and
61
- # <tt>offset</tt> to narrow things down.
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 folder. Use <tt>limit</tt> and
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 :get_user_info
84
- user_from response
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
- response = send_method :get_upload_ticket
92
- upload_ticket_from response
122
+ send_method(:get_upload_ticket).at(:upload_ticket).inner_html
93
123
  end
94
124
 
95
- # Login to the Divshare service. Raises Divshare::APIError if login is
96
- # unsuccessful.
97
- def login(email=nil, password=nil)
98
- logout if @api_session_key
99
- email ||= @email
100
- password ||= @password
101
- response = send_method(:login, {'user_email' => email, 'user_password' => password})
102
- if response.at(:api_session_key)
103
- @api_session_key = response.at(:api_session_key).inner_html
104
- else
105
- raise Divshare::APIError, "Couldn't log in. Received: \n" + response.to_s
106
- end
107
- end
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
- # Returns true if logout is successful. Raises Divshare::APIError if logout is
110
- # unsuccessful.
111
- def logout
112
- response = send_method(:logout)
113
- if response.at(:logged_out) && (%w(true 1).include? response.at(:logged_out).inner_html)
114
- @api_session_key = nil
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
- raise Divshare::APIError, "Couldn't log out. Received: \n" + response.to_s
163
+ resp['file1'] # return the file ID
117
164
  end
118
- true
119
165
  end
120
166
 
121
- # Generates the required MD5 signature as described in
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(@post_url)
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, post_args(method, args)).body
198
+ response = Net::HTTP.post_form(url, form_args).body
164
199
  rescue
165
200
  tries -= 1
166
- puts "Tries == '#{tries}'"
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 #{post_args(method, args)}"
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
- # From http://www.divshare.com/integrate/api
177
- #
178
- # * Your secret key is 123-secret.
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): "audio"
68
- when VIDEO.match(ext): "video"
69
- when DOCUMENT.match(ext): "document"
70
- when IMAGE.match(ext): "image"
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: "midsize/"
106
- when :thumb, :thumbnail: "thumb/"
107
- else ""
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
@@ -1,175 +1,150 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ require 'spec_helper'
2
2
  require 'divshare/client'
3
3
  include Divshare
4
4
 
5
5
  module ClientSpecHelper
6
6
  include DivshareMockXML
7
- def new_client
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(opts={})
23
- options = {:login => true, :stub_sign => true}.merge(opts)
24
- @client = new_client
25
- @api_session_key = login(@client) if options[:login]
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
- if opts[:stub_sign]
28
- @api_sig = 'api_sig'
29
- @client.stub!(:sign).and_return(@api_sig)
30
- end
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.stub!(:post_form).and_return(@mock_response)
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 basic_post_args(to_merge={})
36
- {'api_key' => 'api_key', "api_sig" => @api_sig, "api_session_key" => @api_session_key}.merge(to_merge)
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
- it "should be created with api key and secret only" do
44
- new_client.should be_instance_of(Divshare::Client)
37
+ before :all do
38
+ common_setup
45
39
  end
46
40
 
47
- it "should be created with api key, api_secret, email, and password" do
48
- new_client_with_email_and_password.should be_instance_of(Divshare::Client)
41
+ before :each do
42
+ @client = Client.new(@api_key, @api_secret)
49
43
  end
50
-
51
- it "should assign api key, api_secret, email, and password correctly" do
52
- client = new_client_with_email_and_password
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
- new_client.post_url.should == "http://www.divshare.com/api/"
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
- # Net::HTTP.should_receive(:post_form).once.and_raise
69
- Net::HTTP.stub!(:post_form).and_raise(Net::HTTPServerError)
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(:each) do
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(:each) do
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(:each) do
107
+ before :all do
121
108
  common_setup
122
- @mock_response.should_receive(:body).and_return(get_two_files_xml)
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(:each) do
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
- it "should return an array of files" do
150
- @client.get_folder_files('12345').map {|f| f.class }.should == [DivshareFile, DivshareFile]
151
- end
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 generate arguments for post with limit and offset" do
160
- PostArgs.should_receive(:new).with(@client, :get_folder_files, {'folder_id' => '12345', "limit" => 5, "offset" => 2})
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(:each) do
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(:each) do
181
- common_setup(:login => false)
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
- it "should login" do
187
- @client.login.should == @api_session_key
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.api_session_key.should be_nil
192
- @client.login
193
- @client.api_session_key.should == @api_session_key
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(:login => false)
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(:each) do
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 logout" do
192
+ it "should return true" do
214
193
  @client.logout.should be_true
215
194
  end
216
-
217
- it "should remove api session key on logout" do
195
+
196
+ it "should remove api session key" do
218
197
  @client.logout
219
- @client.api_session_key.should be_nil
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