dropbox-api 0.1.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.
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/LICENSE +22 -0
- data/README.markdown +289 -0
- data/Rakefile +4 -0
- data/dropbox-api.gemspec +24 -0
- data/lib/dropbox-api.rb +21 -0
- data/lib/dropbox-api/client.rb +46 -0
- data/lib/dropbox-api/client/files.rb +31 -0
- data/lib/dropbox-api/client/raw.rb +48 -0
- data/lib/dropbox-api/connection.rb +34 -0
- data/lib/dropbox-api/connection/requests.rb +63 -0
- data/lib/dropbox-api/objects/dir.rb +20 -0
- data/lib/dropbox-api/objects/file.rb +39 -0
- data/lib/dropbox-api/objects/fileops.rb +28 -0
- data/lib/dropbox-api/objects/object.rb +39 -0
- data/lib/dropbox-api/tasks.rb +48 -0
- data/lib/dropbox-api/util/config.rb +27 -0
- data/lib/dropbox-api/util/error.rb +16 -0
- data/lib/dropbox-api/util/oauth.rb +29 -0
- data/lib/dropbox-api/util/util.rb +17 -0
- data/lib/dropbox-api/version.rb +5 -0
- data/spec/connection.sample.yml +4 -0
- data/spec/fixtures/dropbox.jpg +0 -0
- data/spec/lib/dropbox-api/client_spec.rb +92 -0
- data/spec/lib/dropbox-api/connection_spec.rb +82 -0
- data/spec/lib/dropbox-api/dir_spec.rb +44 -0
- data/spec/lib/dropbox-api/file_spec.rb +114 -0
- data/spec/lib/dropbox-api/oauth_spec.rb +17 -0
- data/spec/lib/dropbox-api/thumbnail_spec.rb +29 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/config.rb +13 -0
- data/spec/support/jpeg.rb +39 -0
- metadata +129 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Dropbox
|
2
|
+
module API
|
3
|
+
|
4
|
+
class Raw
|
5
|
+
|
6
|
+
attr_accessor :connection
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@connection = options[:connection]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.add_method(method, action, options = {})
|
13
|
+
# Add the default root bit, but allow it to be disabled by a config option
|
14
|
+
root = options[:root] == false ? '' : "options[:root] ||= '#{Dropbox::API::Config.mode}'"
|
15
|
+
self.class_eval <<-STR
|
16
|
+
def #{options[:as] || action}(options = {})
|
17
|
+
#{root}
|
18
|
+
request(:#{options[:endpoint] || 'main'}, :#{method}, "#{action}", options)
|
19
|
+
end
|
20
|
+
STR
|
21
|
+
end
|
22
|
+
|
23
|
+
def request(endpoint, method, action, data = {})
|
24
|
+
action.sub! ':root', data.delete(:root) if action.match ':root'
|
25
|
+
action.sub! ':path', data.delete(:path) if action.match ':path'
|
26
|
+
connection.send(method, endpoint, action, data)
|
27
|
+
end
|
28
|
+
|
29
|
+
add_method :get, "/account/info", :as => 'account', :root => false
|
30
|
+
|
31
|
+
add_method :get, "/metadata/:root/:path", :as => 'metadata'
|
32
|
+
add_method :get, "/revisions/:root/:path", :as => 'revisions'
|
33
|
+
add_method :post, "/restore/:root/:path", :as => 'restore'
|
34
|
+
add_method :get, "/search/:root/:path", :as => 'search'
|
35
|
+
add_method :post, "/shares/:root/:path", :as => 'shares'
|
36
|
+
add_method :post, "/media/:root/:path", :as => 'media'
|
37
|
+
|
38
|
+
add_method :get_raw, "/thumbnails/:root/:path", :as => 'thumbnails', :endpoint => :content
|
39
|
+
|
40
|
+
add_method :post, "/fileops/copy", :as => "copy"
|
41
|
+
add_method :post, "/fileops/create_folder", :as => "create_folder"
|
42
|
+
add_method :post, "/fileops/delete", :as => "delete"
|
43
|
+
add_method :post, "/fileops/move", :as => "move"
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "dropbox-api/connection/requests"
|
2
|
+
|
3
|
+
module Dropbox
|
4
|
+
module API
|
5
|
+
|
6
|
+
class Connection
|
7
|
+
|
8
|
+
include Dropbox::API::Connection::Requests
|
9
|
+
|
10
|
+
attr_accessor :consumers
|
11
|
+
attr_accessor :tokens
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@options = options
|
15
|
+
@consumers = {}
|
16
|
+
@tokens = {}
|
17
|
+
Dropbox::API::Config.endpoints.each do |endpoint, url|
|
18
|
+
@consumers[endpoint] = Dropbox::API::OAuth.consumer(endpoint)
|
19
|
+
@tokens[endpoint] = Dropbox::API::OAuth.access_token(@consumers[endpoint], options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def consumer(endpoint = :main)
|
24
|
+
@consumers[endpoint]
|
25
|
+
end
|
26
|
+
|
27
|
+
def token(endpoint = :main)
|
28
|
+
@tokens[endpoint]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Dropbox
|
2
|
+
module API
|
3
|
+
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
module Requests
|
7
|
+
|
8
|
+
def request(options = {})
|
9
|
+
response = yield
|
10
|
+
raise Dropbox::API::Error::ConnectionFailed if !response
|
11
|
+
status = response.code.to_i
|
12
|
+
case status
|
13
|
+
when 401
|
14
|
+
raise Dropbox::API::Error::Unauthorized
|
15
|
+
when 403
|
16
|
+
parsed = Yajl::Parser.parse(response.body)
|
17
|
+
raise Dropbox::API::Error::Forbidden.new(parsed["error"])
|
18
|
+
when 404
|
19
|
+
raise Dropbox::API::Error::NotFound
|
20
|
+
when 400, 406
|
21
|
+
parsed = Yajl::Parser.parse(response.body)
|
22
|
+
raise Dropbox::API::Error.new(parsed["error"])
|
23
|
+
when 300..399
|
24
|
+
raise Dropbox::API::Error::Redirect
|
25
|
+
when 500..599
|
26
|
+
raise Dropbox::API::Error
|
27
|
+
else
|
28
|
+
options[:raw] ? response.body : Yajl::Parser.parse(response.body)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_raw(endpoint, path, data = {}, headers = {})
|
33
|
+
query = Dropbox::API::Util.query(data)
|
34
|
+
request(:raw => true) do
|
35
|
+
token(endpoint).get "#{Dropbox::API::Config.prefix}#{URI.parse(URI.encode(path))}?#{URI.parse(URI.encode(query))}", headers
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def get(endpoint, path, data = {}, headers = {})
|
40
|
+
query = Dropbox::API::Util.query(data)
|
41
|
+
request do
|
42
|
+
token(endpoint).get "#{Dropbox::API::Config.prefix}#{URI.parse(URI.encode(path))}?#{URI.parse(URI.encode(query))}", headers
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def post(endpoint, path, data = {}, headers = {})
|
47
|
+
request do
|
48
|
+
token(endpoint).post "#{Dropbox::API::Config.prefix}#{URI.parse(URI.encode(path))}", data, headers
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def put(endpoint, path, data = {}, headers = {})
|
53
|
+
request do
|
54
|
+
token(endpoint).put "#{Dropbox::API::Config.prefix}#{URI.parse(URI.encode(path))}", data, headers
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
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,39 @@
|
|
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 download
|
33
|
+
client.download(self.path)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
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 delete(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,16 @@
|
|
1
|
+
module Dropbox
|
2
|
+
module API
|
3
|
+
|
4
|
+
class Error < Exception
|
5
|
+
|
6
|
+
class ConnectionFailed < Exception; end
|
7
|
+
class Config < Exception; end
|
8
|
+
class Unauthorized < Exception; end
|
9
|
+
class Forbidden < Exception; end
|
10
|
+
class NotFound < Exception; end
|
11
|
+
class Redirect < Exception; end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
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
|
+
|
Binary file
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dropbox::API::Client do
|
4
|
+
|
5
|
+
before do
|
6
|
+
# pending
|
7
|
+
@client = Dropbox::Spec.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
|
12
|
+
it "has a handle to the connection" do
|
13
|
+
@client.connection.should be_an_instance_of(Dropbox::API::Connection)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#account" do
|
19
|
+
|
20
|
+
it "retrieves the account object" do
|
21
|
+
response = @client.account
|
22
|
+
response.should be_an_instance_of(Dropbox::API::Object)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#ls" do
|
28
|
+
|
29
|
+
it "returns an array of files and dirs" do
|
30
|
+
result = @client.ls
|
31
|
+
result.should be_an_instance_of(Array)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns a single item array of if we ls a file" do
|
35
|
+
result = @client.ls
|
36
|
+
first_file = result.detect { |f| f.class == Dropbox::API::File }
|
37
|
+
result = @client.ls first_file.path
|
38
|
+
result.should be_an_instance_of(Array)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#mkdir" do
|
44
|
+
|
45
|
+
it "returns an array of files and dirs" do
|
46
|
+
dirname = "test/test-dir-#{Dropbox::Spec.namespace}"
|
47
|
+
response = @client.mkdir dirname
|
48
|
+
response.path.should == dirname
|
49
|
+
response.should be_an_instance_of(Dropbox::API::Dir)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#upload" do
|
55
|
+
|
56
|
+
it "puts the file in dropbox" do
|
57
|
+
filename = "test/test-#{Dropbox::Spec.namespace}.txt"
|
58
|
+
response = @client.upload filename, "Some file"
|
59
|
+
response.path.should == filename
|
60
|
+
response.bytes.should == 9
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#search" do
|
66
|
+
|
67
|
+
it "finds a file" do
|
68
|
+
filename = "test/searchable-test-#{Dropbox::Spec.namespace}.txt"
|
69
|
+
@client.upload filename, "Some file"
|
70
|
+
response = @client.search "searchable-test-#{Dropbox::Spec.namespace}", :path => 'test'
|
71
|
+
response.size.should == 1
|
72
|
+
response.first.class.should == Dropbox::API::File
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#download" do
|
78
|
+
|
79
|
+
it "downloads a file from Dropbox" do
|
80
|
+
file = @client.download 'test/test.txt'
|
81
|
+
file.should == "Some file"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "raises a 404 when a file is not found in Dropbox" do
|
85
|
+
lambda {
|
86
|
+
@client.download 'test/no.txt'
|
87
|
+
}.should raise_error(Dropbox::API::Error::NotFound)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|