divshare 0.1.0 → 0.3.0

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.
@@ -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