dropbox-api-petems 0.4.1

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.
@@ -0,0 +1,11 @@
1
+ module Dropbox
2
+ module API
3
+ class Delta
4
+ attr_reader :cursor, :entries
5
+ def initialize(cursor, entries)
6
+ @cursor = cursor
7
+ @entries = entries
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ class Dir < Dropbox::API::Object
5
+
6
+ include Dropbox::API::Fileops
7
+
8
+ def ls(path_to_list = '')
9
+ data = client.raw.metadata :path => path + path_to_list
10
+ if data['is_dir']
11
+ Dropbox::API::Object.convert(data.delete('contents') || [], client)
12
+ else
13
+ [Dropbox::API::Object.convert(data, client)]
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ class File < Dropbox::API::Object
5
+
6
+ include Dropbox::API::Fileops
7
+
8
+ def revisions(options = {})
9
+ response = client.raw.revisions({ :path => self.path }.merge(options))
10
+ Dropbox::API::Object.convert(response, client)
11
+ end
12
+
13
+ def restore(rev, options = {})
14
+ response = client.raw.restore({ :rev => rev, :path => self.path }.merge(options))
15
+ self.update response
16
+ end
17
+
18
+ def share_url(options = {})
19
+ response = client.raw.shares({ :path => self.path }.merge(options))
20
+ Dropbox::API::Object.init(response, client)
21
+ end
22
+
23
+ def direct_url(options = {})
24
+ response = client.raw.media({ :path => self.path }.merge(options))
25
+ Dropbox::API::Object.init(response, client)
26
+ end
27
+
28
+ def thumbnail(options = {})
29
+ client.raw.thumbnails({ :path => self.path }.merge(options))
30
+ end
31
+
32
+ def copy_ref(options = {})
33
+ response = client.raw.copy_ref({ :path => self.path }.merge(options))
34
+ Dropbox::API::Object.init(response, client)
35
+ end
36
+
37
+ def download
38
+ client.download(self.path)
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,28 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ module Fileops
5
+
6
+ def copy(to, options = {})
7
+ response = client.raw.copy({ :from_path => self.path, :to_path => to }.merge(options))
8
+ self.update response
9
+ end
10
+
11
+ def move(to, options = {})
12
+ response = client.raw.move({ :from_path => self.path, :to_path => to }.merge(options))
13
+ self.update response
14
+ end
15
+
16
+ def destroy(options = {})
17
+ response = client.raw.delete({ :path => self.path }.merge(options))
18
+ self.update response
19
+ end
20
+
21
+ def path
22
+ self['path'].sub(/^\//, '')
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ class Object < Hashie::Mash
5
+ attr_accessor :client
6
+
7
+ def self.init(response, client)
8
+ instance = self.new(response)
9
+ instance.client = client
10
+ instance
11
+ end
12
+
13
+ def self.resolve_class(hash)
14
+ hash['is_dir'] == true ? Dropbox::API::Dir : Dropbox::API::File
15
+ end
16
+
17
+ def self.convert(array_or_object, client)
18
+ if array_or_object.is_a?(Array)
19
+ array_or_object.collect do |item|
20
+ resolve_class(item).init(item, client)
21
+ end
22
+ else
23
+ resolve_class(array_or_object).init(array_or_object, client)
24
+ end
25
+ end
26
+
27
+ # Kill off the ability for recursive conversion
28
+ def deep_update(other_hash)
29
+ other_hash.each_pair do |k,v|
30
+ key = convert_key(k)
31
+ regular_writer(key, convert_value(v, true))
32
+ end
33
+ self
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,48 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ class Tasks
5
+
6
+ extend Rake::DSL if defined? Rake::DSL
7
+
8
+ def self.install
9
+
10
+ namespace :dropbox do
11
+ desc "Authorize wizard for Dropbox API"
12
+ task :authorize do
13
+ require "dropbox-api"
14
+ require "cgi"
15
+ print "Enter consumer key: "
16
+ consumer_key = $stdin.gets.chomp
17
+ print "Enter consumer secret: "
18
+ consumer_secret = $stdin.gets.chomp
19
+
20
+ Dropbox::API::Config.app_key = consumer_key
21
+ Dropbox::API::Config.app_secret = consumer_secret
22
+
23
+ consumer = Dropbox::API::OAuth.consumer(:authorize)
24
+ request_token = consumer.get_request_token
25
+ puts "\nGo to this url and click 'Authorize' to get the token:"
26
+ puts request_token.authorize_url
27
+ query = request_token.authorize_url.split('?').last
28
+ params = CGI.parse(query)
29
+ token = params['oauth_token'].first
30
+ print "\nOnce you authorize the app on Dropbox, press enter... "
31
+ $stdin.gets.chomp
32
+
33
+ access_token = request_token.get_access_token(:oauth_verifier => token)
34
+
35
+ puts "\nAuthorization complete!:\n\n"
36
+ puts " Dropbox::API::Config.app_key = '#{consumer.key}'"
37
+ puts " Dropbox::API::Config.app_secret = '#{consumer.secret}'"
38
+ puts " client = Dropbox::API::Client.new(:token => '#{access_token.token}', :secret => '#{access_token.secret}')"
39
+ puts "\n"
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ module Config
5
+
6
+ class << self
7
+ attr_accessor :endpoints
8
+ attr_accessor :prefix
9
+ attr_accessor :app_key
10
+ attr_accessor :app_secret
11
+ attr_accessor :mode
12
+ end
13
+
14
+ self.endpoints = {
15
+ :main => "https://api.dropbox.com",
16
+ :content => "https://api-content.dropbox.com",
17
+ :authorize => "https://www.dropbox.com"
18
+ }
19
+ self.prefix = "/1"
20
+ self.app_key = nil
21
+ self.app_secret = nil
22
+ self.mode = 'sandbox'
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ class Error < StandardError
5
+
6
+ class BadInput < Error; end
7
+ class ConnectionFailed < Error; end
8
+ class Config < Error; end
9
+ class Unauthorized < Error; end
10
+ class Forbidden < Error; end
11
+ class NotFound < Error; end
12
+ class Redirect < Error; end
13
+ class WrongMethod < Error; end
14
+ class RateLimit < Error; end
15
+ class StorageQuota < Error; end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ module OAuth
5
+
6
+ class << self
7
+
8
+ def consumer(endpoint)
9
+ if !Dropbox::API::Config.app_key or !Dropbox::API::Config.app_secret
10
+ raise Dropbox::API::Error::Config.new("app_key or app_secret not provided")
11
+ end
12
+ ::OAuth::Consumer.new(Dropbox::API::Config.app_key, Dropbox::API::Config.app_secret,
13
+ :site => Dropbox::API::Config.endpoints[endpoint],
14
+ :request_token_path => Dropbox::API::Config.prefix + "/oauth/request_token",
15
+ :authorize_path => Dropbox::API::Config.prefix + "/oauth/authorize",
16
+ :access_token_path => Dropbox::API::Config.prefix + "/oauth/access_token")
17
+ end
18
+
19
+ def access_token(consumer, options = {})
20
+ ::OAuth::AccessToken.new(consumer, options[:token], options[:secret])
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+
@@ -0,0 +1,27 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ module Util
5
+
6
+ class << self
7
+
8
+ def escape(string)
9
+ string.gsub(/([^ a-zA-Z0-9\.\\\-\/\_]+)/) do
10
+ '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
11
+ end.gsub(' ', '%20')
12
+ end
13
+
14
+ def query(data)
15
+ data.inject([]) { |memo, entry| memo.push(entry.join('=')); memo }.join('&')
16
+ end
17
+
18
+ def remove_double_slashes(path)
19
+ path.gsub('//', '/')
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module Dropbox
2
+ module API
3
+ VERSION = "0.4.1"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ require "oauth"
2
+ require "multi_json"
3
+ require "hashie"
4
+
5
+ module Dropbox
6
+ module API
7
+
8
+ end
9
+ end
10
+
11
+ require "dropbox-api/version"
12
+ require "dropbox-api/util/config"
13
+ require "dropbox-api/util/oauth"
14
+ require "dropbox-api/util/error"
15
+ require "dropbox-api/util/util"
16
+ require "dropbox-api/objects/object"
17
+ require "dropbox-api/objects/fileops"
18
+ require "dropbox-api/objects/file"
19
+ require "dropbox-api/objects/dir"
20
+ require "dropbox-api/objects/delta"
21
+ require "dropbox-api/connection"
22
+ require "dropbox-api/client"
@@ -0,0 +1,5 @@
1
+ app_key: # CONSUMER KEY
2
+ app_secret: # CONSUMER SECRET
3
+ token: # ACCESS TOKEN
4
+ secret: # ACCESS SECRET
5
+ mode: # 'sandbox' or 'dropbox'
Binary file
@@ -0,0 +1,201 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dropbox::API::Client do
5
+
6
+ before do
7
+ # pending
8
+ @client = Dropbox::Spec.instance
9
+ end
10
+
11
+ describe "#initialize" do
12
+
13
+ it "has a handle to the connection" do
14
+ @client.connection.should be_an_instance_of(Dropbox::API::Connection)
15
+ end
16
+
17
+ end
18
+
19
+ describe "#account" do
20
+
21
+ it "retrieves the account object" do
22
+ response = @client.account
23
+ response.should be_an_instance_of(Dropbox::API::Object)
24
+ end
25
+
26
+ end
27
+
28
+ describe "#find" do
29
+
30
+ before do
31
+ @filename = "#{Dropbox::Spec.test_dir}/spec-find-file-test-#{Time.now.to_i}.txt"
32
+ @file = @client.upload @filename, "spec file"
33
+
34
+ @dirname = "#{Dropbox::Spec.test_dir}/spec-find-dir-test-#{Time.now.to_i}"
35
+ @dir = @client.mkdir @dirname
36
+ end
37
+
38
+ it "returns a single file" do
39
+ response = @client.find(@filename)
40
+ response.path.should == @file.path
41
+ response.should be_an_instance_of(Dropbox::API::File)
42
+ end
43
+
44
+ it "returns a single directory" do
45
+ response = @client.find(@dirname)
46
+ response.path.should == @dir.path
47
+ response.should be_an_instance_of(Dropbox::API::Dir)
48
+ end
49
+
50
+ end
51
+
52
+ describe "#ls" do
53
+
54
+ it "returns an array of files and dirs" do
55
+ result = @client.ls
56
+ result.should be_an_instance_of(Array)
57
+ end
58
+
59
+ it "returns a single item array of if we ls a file" do
60
+ result = @client.ls(Dropbox::Spec.test_dir)
61
+ first_file = result.detect { |f| f.class == Dropbox::API::File }
62
+ result = @client.ls first_file.path
63
+ result.should be_an_instance_of(Array)
64
+ end
65
+
66
+ end
67
+
68
+ describe "#mkdir" do
69
+
70
+ it "returns an array of files and dirs" do
71
+ dirname = "#{Dropbox::Spec.test_dir}/test-dir-#{Dropbox::Spec.namespace}"
72
+ response = @client.mkdir dirname
73
+ response.path.should == dirname
74
+ response.should be_an_instance_of(Dropbox::API::Dir)
75
+ end
76
+
77
+ it "creates dirs with tricky characters" do
78
+ dirname = "#{Dropbox::Spec.test_dir}/test-dir |!@\#$%^&*{b}[].;'.,<>?: #{Dropbox::Spec.namespace}"
79
+ response = @client.mkdir dirname
80
+ response.path.should == dirname.gsub(/[\\\:\?\*\<\>\"\|]+/, '')
81
+ response.should be_an_instance_of(Dropbox::API::Dir)
82
+ end
83
+
84
+ it "creates dirs with utf8 characters" do
85
+ dirname = "#{Dropbox::Spec.test_dir}/test-dir łółą #{Dropbox::Spec.namespace}"
86
+ response = @client.mkdir dirname
87
+ response.path.should == dirname
88
+ response.should be_an_instance_of(Dropbox::API::Dir)
89
+ end
90
+
91
+ end
92
+
93
+ describe "#upload" do
94
+
95
+ it "puts the file in dropbox" do
96
+ filename = "#{Dropbox::Spec.test_dir}/test-#{Dropbox::Spec.namespace}.txt"
97
+ response = @client.upload filename, "Some file"
98
+ response.path.should == filename
99
+ response.bytes.should == 9
100
+ end
101
+
102
+ it "uploads the file with tricky characters" do
103
+ filename = "#{Dropbox::Spec.test_dir}/test ,|!@\#$%^&*{b}[].;'.,<>?:-#{Dropbox::Spec.namespace}.txt"
104
+ response = @client.upload filename, "Some file"
105
+ response.path.should == filename
106
+ response.bytes.should == 9
107
+ end
108
+
109
+ it "uploads the file with utf8" do
110
+ filename = "#{Dropbox::Spec.test_dir}/test łołąó-#{Dropbox::Spec.namespace}.txt"
111
+ response = @client.upload filename, "Some file"
112
+ response.path.should == filename
113
+ response.bytes.should == 9
114
+ end
115
+ end
116
+
117
+ describe "#search" do
118
+
119
+ let(:term) { "searchable-test-#{Dropbox::Spec.namespace}" }
120
+
121
+ before do
122
+ filename = "#{Dropbox::Spec.test_dir}/searchable-test-#{Dropbox::Spec.namespace}.txt"
123
+ @client.upload filename, "Some file"
124
+ end
125
+
126
+ after do
127
+ @response.size.should == 1
128
+ @response.first.class.should == Dropbox::API::File
129
+ end
130
+
131
+ it "finds a file" do
132
+ @response = @client.search term, :path => "#{Dropbox::Spec.test_dir}"
133
+ end
134
+
135
+ it "works if leading slash is present in path" do
136
+ @response = @client.search term, :path => "/#{Dropbox::Spec.test_dir}"
137
+ end
138
+
139
+ end
140
+
141
+ describe "#copy_from_copy_ref" do
142
+
143
+ it "copies a file from a copy_ref" do
144
+ filename = "test/searchable-test-#{Dropbox::Spec.namespace}.txt"
145
+ @client.upload filename, "Some file"
146
+ response = @client.search "searchable-test-#{Dropbox::Spec.namespace}", :path => 'test'
147
+ ref = response.first.copy_ref['copy_ref']
148
+ @client.copy_from_copy_ref ref, "#{filename}.copied"
149
+ response = @client.search "searchable-test-#{Dropbox::Spec.namespace}.txt.copied", :path => 'test'
150
+ response.size.should == 1
151
+ response.first.class.should == Dropbox::API::File
152
+ end
153
+
154
+ end
155
+
156
+ describe "#download" do
157
+
158
+ it "downloads a file from Dropbox" do
159
+ @client.upload "#{Dropbox::Spec.test_dir}/test.txt", "Some file"
160
+ file = @client.download "#{Dropbox::Spec.test_dir}/test.txt"
161
+ file.should == "Some file"
162
+ end
163
+
164
+ it "raises a 404 when a file is not found in Dropbox" do
165
+ lambda {
166
+ @client.download "#{Dropbox::Spec.test_dir}/no.txt"
167
+ }.should raise_error(Dropbox::API::Error::NotFound)
168
+ end
169
+
170
+ end
171
+
172
+ describe "#delta" do
173
+ it "returns a cursor and list of files" do
174
+ filename = "#{Dropbox::Spec.test_dir}/delta-test-#{Dropbox::Spec.namespace}.txt"
175
+ @client.upload filename, 'Some file'
176
+ response = @client.delta
177
+ cursor, files = response.cursor, response.entries
178
+ cursor.should be_an_instance_of(String)
179
+ files.should be_an_instance_of(Array)
180
+ files.last.should be_an_instance_of(Dropbox::API::File)
181
+ end
182
+
183
+ it "returns the files that have changed since the cursor was made" do
184
+ filename = "#{Dropbox::Spec.test_dir}/delta-test-#{Dropbox::Spec.namespace}.txt"
185
+ delete_filename = "#{Dropbox::Spec.test_dir}/delta-test-delete-#{Dropbox::Spec.namespace}.txt"
186
+ @client.upload delete_filename, 'Some file'
187
+ response = @client.delta
188
+ cursor, files = response.cursor, response.entries
189
+ files.last.path.should == delete_filename
190
+ files.last.destroy
191
+ @client.upload filename, 'Another file'
192
+ response = @client.delta(cursor)
193
+ cursor, files = response.cursor, response.entries
194
+ files.length.should == 2
195
+ files.first.is_deleted.should == true
196
+ files.first.path.should == delete_filename
197
+ files.last.path.should == filename
198
+ end
199
+ end
200
+
201
+ end
@@ -0,0 +1,129 @@
1
+ require "spec_helper"
2
+
3
+ describe Dropbox::API::Connection do
4
+
5
+ before do
6
+ @connection = Dropbox::API::Connection.new(:token => Dropbox::Spec.token,
7
+ :secret => Dropbox::Spec.secret)
8
+ end
9
+
10
+ describe "#request" do
11
+
12
+ it "returns a parsed response when the response is a 200" do
13
+ response = double :code => 200, :body => '{ "a":1}'
14
+ response = @connection.request { response }
15
+ response.should be_an_instance_of(Hash)
16
+ end
17
+
18
+ it "raises a Dropbox::API::Error::Unauthorized when the response is a 401" do
19
+ response = double :code => 401, :body => '{ "a":1}'
20
+ lambda do
21
+ @connection.request { response }
22
+ end.should raise_error(Dropbox::API::Error::Unauthorized, '401 - Bad or expired token')
23
+ end
24
+
25
+ it "raises a Dropbox::API::Error::Forbidden when the response is a 403" do
26
+ response = double :code => 403, :body => '{ "a":1}'
27
+ lambda do
28
+ @connection.request { response }
29
+ end.should raise_error(Dropbox::API::Error::Forbidden, '403 - Bad OAuth request')
30
+ end
31
+
32
+ it "raises a Dropbox::API::Error::NotFound when the response is a 404" do
33
+ response = double :code => 404, :body => '{ "a":1}'
34
+ lambda do
35
+ @connection.request { response }
36
+ end.should raise_error(Dropbox::API::Error::NotFound, '404 - Not found')
37
+ end
38
+
39
+ it "raises a Dropbox::API::Error::WrongMethod when the response is a 405" do
40
+ response = double :code => 405, :body => '{ "error": "The requested method GET is not allowed for the URL /foo/." }'
41
+ lambda do
42
+ @connection.request { response }
43
+ end.should raise_error(Dropbox::API::Error::WrongMethod, '405 - Request method not expected - The requested method GET is not allowed for the URL /foo/.')
44
+ end
45
+
46
+ it "raises a Dropbox::API::Error when the response is a 3xx" do
47
+ response = double :code => 301, :body => '{ "a":1}'
48
+ lambda do
49
+ @connection.request { response }
50
+ end.should raise_error(Dropbox::API::Error::Redirect, '301 - Redirect Error')
51
+ end
52
+
53
+ it "raises a Dropbox::API::Error when the response is a 5xx" do
54
+ response = double :code => 500, :body => '{ "a":1}'
55
+ lambda do
56
+ @connection.request { response }
57
+ end.should raise_error(Dropbox::API::Error, '500 - Server error. Check http://status.dropbox.com/')
58
+ end
59
+
60
+ it "raises a Dropbox::API::Error when the response is a 400" do
61
+ response = double :code => 400, :body => '{ "error": "bad request foo" }'
62
+ lambda do
63
+ @connection.request { response }
64
+ end.should raise_error(Dropbox::API::Error::BadInput, '400 - Bad input parameter - bad request foo')
65
+ end
66
+
67
+ it "raises a Dropbox::API::Error when the response is a 406" do
68
+ response = double :code => 406, :body => '{ "error": "bad request bar" }'
69
+ lambda do
70
+ @connection.request { response }
71
+ end.should raise_error(Dropbox::API::Error, '406 - bad request bar')
72
+ end
73
+
74
+ it "raises a Dropbox::API::Error when the response is a 406" do
75
+ response = double :code => 429, :body => '{ "error": "rate limited" }'
76
+ lambda do
77
+ @connection.request { response }
78
+ end.should raise_error(Dropbox::API::Error::RateLimit, '429 - Rate Limiting in affect')
79
+ end
80
+
81
+ it "raises a Dropbox::API::Error when the response is a 503" do
82
+ response = double :code => 503, :body => '{ "error": "rate limited" }'
83
+ lambda do
84
+ @connection.request { response }
85
+ end.should raise_error(Dropbox::API::Error, '503 - Possible Rate Limiting: rate limited')
86
+ end
87
+
88
+ it "raises a Dropbox::API::Error::StorageQuota when the response is a 507" do
89
+ response = double :code => 507, :body => '{ "error": "quote limit" }'
90
+ lambda do
91
+ @connection.request { response }
92
+ end.should raise_error(Dropbox::API::Error, '507 - Dropbox storage quota exceeded.')
93
+ end
94
+
95
+
96
+ it "returns the raw response if :raw => true is provided" do
97
+ response = double :code => 200, :body => '{ "something": "more" }'
98
+ response = @connection.request(:raw => true) { response }
99
+ response.should == '{ "something": "more" }'
100
+ end
101
+
102
+ end
103
+
104
+ describe "#consumer" do
105
+
106
+ it "returns an appropriate consumer object" do
107
+ @connection.consumer(:main).should be_a(::OAuth::Consumer)
108
+ end
109
+
110
+ end
111
+
112
+ describe "errors" do
113
+
114
+ it "recovers error with rescue statement modifier" do
115
+ expect { raise Dropbox::API::Error rescue nil }.to_not raise_error
116
+ end
117
+
118
+ it "recovers any kind of errors with the generic error" do
119
+ expect do
120
+ begin
121
+ raise Dropbox::API::Error::Forbidden
122
+ rescue Dropbox::API::Error
123
+ end
124
+ end.to_not raise_error
125
+ end
126
+
127
+ end
128
+
129
+ end