dropbox-api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -0,0 +1,17 @@
1
+ module Dropbox
2
+ module API
3
+
4
+ module Util
5
+
6
+ class << self
7
+
8
+ def query(data)
9
+ data.inject([]) { |memo, entry| memo.push(entry.join('=')); memo }.join('&')
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Dropbox
2
+ module API
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ app_key: # CONSUMER KEY
2
+ app_secret: # CONSUMER SECRET
3
+ token: # ACCESS TOKEN
4
+ secret: # ACCESS SECRET
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