dropbox-sdk 1.6.3 → 1.6.4
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/CHANGELOG +5 -0
- data/README +2 -2
- data/examples/chunked_upload.rb +71 -0
- data/{cli_example.rb → examples/cli_example.rb} +3 -2
- data/examples/copy_between_accounts.rb +148 -0
- data/{dropbox_controller.rb → examples/dropbox_controller.rb} +11 -5
- data/examples/oauth1_upgrade.rb +40 -0
- data/examples/search_cache.rb +322 -0
- data/{web_file_browser.rb → examples/web_file_browser.rb} +6 -1
- data/lib/dropbox_sdk.rb +13 -5
- metadata +14 -15
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -7,9 +7,9 @@ A Ruby library that for Dropbox's HTTP-based Core API.
|
|
7
7
|
----------------------------------
|
8
8
|
Setup
|
9
9
|
|
10
|
-
You can install this package using '
|
10
|
+
You can install this package using 'gem':
|
11
11
|
|
12
|
-
#
|
12
|
+
# gem install dropbox-sdk
|
13
13
|
|
14
14
|
----------------------------------
|
15
15
|
Getting a Dropbox API key
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# An example use of the /chunked_upload API call.
|
2
|
+
|
3
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
4
|
+
|
5
|
+
# You must use your Dropbox App key and secret to use the API.
|
6
|
+
# Find this at https://www.dropbox.com/developers
|
7
|
+
APP_KEY = ''
|
8
|
+
APP_SECRET = ''
|
9
|
+
|
10
|
+
STATE_FILE = 'search_cache.json'
|
11
|
+
|
12
|
+
def main()
|
13
|
+
if APP_KEY == '' or APP_SECRET == ''
|
14
|
+
warn "ERROR: Set your APP_KEY and APP_SECRET at the top of search_cache.rb"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
prog_name = __FILE__
|
18
|
+
args = ARGV
|
19
|
+
if args.size == 0
|
20
|
+
warn("Usage:\n")
|
21
|
+
warn(" #{prog_name} <local-file-path> <dropbox-target-path> <chunk-size-in-bytes>")
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
if args.size != 3
|
26
|
+
warn "ERROR: expecting exactly three arguments. Run with no arguments for help."
|
27
|
+
exit(1)
|
28
|
+
end
|
29
|
+
|
30
|
+
web_auth = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET)
|
31
|
+
authorize_url = web_auth.start()
|
32
|
+
puts "1. Go to: #{authorize_url}"
|
33
|
+
puts "2. Click \"Allow\" (you might have to log in first)."
|
34
|
+
puts "3. Copy the authorization code."
|
35
|
+
|
36
|
+
print "Enter the authorization code here: "
|
37
|
+
STDOUT.flush
|
38
|
+
auth_code = STDIN.gets.strip
|
39
|
+
|
40
|
+
access_token, user_id = web_auth.finish(auth_code)
|
41
|
+
|
42
|
+
c = DropboxClient.new(access_token)
|
43
|
+
|
44
|
+
local_file_path = args[0]
|
45
|
+
dropbox_target_path = args[1]
|
46
|
+
chunk_size = args[2].to_i
|
47
|
+
|
48
|
+
# Upload the file
|
49
|
+
local_file_size = File.size(local_file_path)
|
50
|
+
uploader = c.get_chunked_uploader(File.new(local_file_path, "r"), local_file_size)
|
51
|
+
retries = 0
|
52
|
+
puts "Uploading..."
|
53
|
+
while uploader.offset < uploader.total_size
|
54
|
+
begin
|
55
|
+
uploader.upload(chunk_size)
|
56
|
+
rescue DropboxError => e
|
57
|
+
if retries > 10
|
58
|
+
puts "- Error uploading, giving up."
|
59
|
+
break
|
60
|
+
end
|
61
|
+
puts "- Error uploading, trying again..."
|
62
|
+
retries += 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
puts "Finishing upload..."
|
66
|
+
uploader.finish(dropbox_target_path)
|
67
|
+
puts "Done."
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
main()
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
2
2
|
require 'pp'
|
3
|
+
require 'shellwords'
|
3
4
|
|
4
5
|
####
|
5
6
|
# An example app using the Dropbox API Ruby Client
|
@@ -65,7 +66,7 @@ class DropboxCLI
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def execute_dropbox_command(cmd_line)
|
68
|
-
command = cmd_line
|
69
|
+
command = Shellwords.shellwords cmd_line
|
69
70
|
method = command.first
|
70
71
|
if LOGIN_REQUIRED.include? method
|
71
72
|
if @client
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# You must use your Dropbox App key and secret to use the API.
|
5
|
+
# Find this at https://www.dropbox.com/developers
|
6
|
+
APP_KEY = ''
|
7
|
+
APP_SECRET = ''
|
8
|
+
|
9
|
+
STATE_FILE = 'copy_between_accounts.json'
|
10
|
+
|
11
|
+
def main()
|
12
|
+
prog_name = __FILE__
|
13
|
+
if APP_KEY == '' or APP_SECRET == ''
|
14
|
+
warn "ERROR: Set your APP_KEY and APP_SECRET at the top of #{prog_name}"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
args = ARGV
|
18
|
+
if args.size == 0
|
19
|
+
warn("Usage:\n")
|
20
|
+
warn(" #{prog_name} link Link to a user's account. Also displays UID.")
|
21
|
+
warn(" #{prog_name} list List linked users including UID.")
|
22
|
+
warn(" #{prog_name} copy '<uid>:<path>' '<uid>:<path>' Copies a file from the first user's path, to the second user's path.")
|
23
|
+
warn("\n\n <uid> is the account UID shown when linked. <path> is a path to a file on that user's dropbox.")
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
command = args[0]
|
28
|
+
if command == 'link'
|
29
|
+
command_link(args)
|
30
|
+
elsif command == 'list'
|
31
|
+
command_list(args)
|
32
|
+
elsif command == 'copy'
|
33
|
+
command_copy(args)
|
34
|
+
else
|
35
|
+
warn "ERROR: Unknown command: #{command}"
|
36
|
+
warn "Run with no arguments for help."
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def command_link(args)
|
42
|
+
if args.size != 1
|
43
|
+
warn "ERROR: \"link\" doesn't take any arguments"
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
|
47
|
+
web_auth = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET)
|
48
|
+
authorize_url = web_auth.start()
|
49
|
+
puts "1. Go to: #{authorize_url}"
|
50
|
+
puts "2. Click \"Allow\" (you might have to log in first)."
|
51
|
+
puts "3. Copy the authorization code."
|
52
|
+
|
53
|
+
print "Enter the authorization code here: "
|
54
|
+
STDOUT.flush
|
55
|
+
auth_code = STDIN.gets.strip
|
56
|
+
|
57
|
+
access_token, user_id = web_auth.finish(auth_code)
|
58
|
+
|
59
|
+
c = DropboxClient.new(access_token)
|
60
|
+
account_info = c.account_info()
|
61
|
+
puts "Link successful. #{account_info['display_name']} is uid #{account_info['uid']} "
|
62
|
+
|
63
|
+
state = load_state()
|
64
|
+
state[account_info['uid']] = {
|
65
|
+
'access_token' => access_token,
|
66
|
+
'display_name' => account_info['display_name'],
|
67
|
+
}
|
68
|
+
|
69
|
+
if account_info['team']
|
70
|
+
state[account_info['uid']]['team_name'] = account_info['team']['name']
|
71
|
+
end
|
72
|
+
|
73
|
+
save_state(state)
|
74
|
+
end
|
75
|
+
|
76
|
+
def command_list(args)
|
77
|
+
if args.size != 1
|
78
|
+
warn "ERROR: \"list\" doesn't take any arguments"
|
79
|
+
exit
|
80
|
+
end
|
81
|
+
|
82
|
+
state = load_state()
|
83
|
+
for e in state.keys()
|
84
|
+
if state[e]['team_name']
|
85
|
+
puts "#{state[e]['display_name']} (#{state[e]['team_name']}) is uid #{e}"
|
86
|
+
else
|
87
|
+
puts "#{state[e]['display_name']} is uid #{e}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def command_copy(args)
|
93
|
+
if args.size != 3
|
94
|
+
warn "ERROR: \"copy\" takes exactly two arguments"
|
95
|
+
exit
|
96
|
+
end
|
97
|
+
|
98
|
+
state = load_state()
|
99
|
+
|
100
|
+
if state.keys().length < 2
|
101
|
+
warn "ERROR: You can't use the copy command until at least two users have linked"
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
|
105
|
+
from = args[1].gsub(/['"]/,'')
|
106
|
+
to = args[2].gsub(/['"]/,'')
|
107
|
+
|
108
|
+
if not to.index(':') or not from.index(':')
|
109
|
+
warn "ERROR: Ill-formated paths. Run #{prog_name} without arugments to see documentation."
|
110
|
+
exit
|
111
|
+
end
|
112
|
+
|
113
|
+
from_uid, from_path = from.split ":"
|
114
|
+
to_uid, to_path = to.split ":"
|
115
|
+
|
116
|
+
if not state.has_key?(to_uid) or not state.has_key?(from_uid)
|
117
|
+
warn "ERROR: Those UIDs have not linked. Run #{prog_name} list to see linked UIDs."
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
|
121
|
+
from_client = DropboxClient.new(state[from_uid]['access_token'])
|
122
|
+
to_client = DropboxClient.new(state[to_uid]['access_token'])
|
123
|
+
|
124
|
+
#Create a copy ref under the identity of the from user
|
125
|
+
copy_ref = from_client.create_copy_ref(from_path)['copy_ref']
|
126
|
+
|
127
|
+
metadata = to_client.add_copy_ref(to_path, copy_ref)
|
128
|
+
|
129
|
+
puts "File successly copied from #{state[from_uid]['display_name']} to #{state[to_uid]['display_name']}!"
|
130
|
+
puts "The file now exists at #{metadata['path']}"
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def save_state(state)
|
135
|
+
File.open(STATE_FILE,"w") do |f|
|
136
|
+
f.write(JSON.pretty_generate(state))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def load_state()
|
141
|
+
if not FileTest.exists?(STATE_FILE)
|
142
|
+
return {}
|
143
|
+
end
|
144
|
+
JSON.parse(File.read(STATE_FILE))
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
main()
|
@@ -3,18 +3,24 @@
|
|
3
3
|
# - Runs the through Dropbox's OAuth 2 flow, yielding a Dropbox API access token.
|
4
4
|
# - Makes a Dropbox API call to upload a file.
|
5
5
|
#
|
6
|
+
# To set up:
|
7
|
+
# 1. Create a Dropbox App key and secret to use the API. https://www.dropbox.com/developers
|
8
|
+
# 2. Add http://localhost:3000/dropbox/auth_finish as a Redirect URI for your Dropbox app.
|
9
|
+
# 3. Copy your App key and App secret into APP_KEY and APP_SECRET below.
|
10
|
+
#
|
6
11
|
# To run:
|
7
12
|
# 1. You need a Rails 3 project (to create one, run: rails new <folder-name>)
|
8
|
-
# 2. Copy
|
9
|
-
# 3.
|
13
|
+
# 2. Copy dropbox_sdk.rb into <folder-name>/vendor
|
14
|
+
# 3. Copy this file into <folder-name>/app/controllers/
|
15
|
+
# 4. Add the following lines to <folder-name>/config/routes.rb
|
10
16
|
# get "dropbox/main"
|
11
17
|
# post "dropbox/upload"
|
12
18
|
# get "dropbox/auth_start"
|
13
19
|
# get "dropbox/auth_finish"
|
14
|
-
#
|
15
|
-
#
|
20
|
+
# 5. Run: rails server
|
21
|
+
# 6. Point your browser at: https://localhost:3000/dropbox/main
|
16
22
|
|
17
|
-
require '
|
23
|
+
require 'dropbox_sdk'
|
18
24
|
require 'securerandom'
|
19
25
|
|
20
26
|
APP_KEY = ""
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
# You must use your Dropbox App key and secret to use the API.
|
5
|
+
# Find this at https://www.dropbox.com/developers
|
6
|
+
APP_KEY = ''
|
7
|
+
APP_SECRET = ''
|
8
|
+
|
9
|
+
def main
|
10
|
+
if APP_KEY == '' or APP_SECRET == ''
|
11
|
+
warn "ERROR: Set your APP_KEY and APP_SECRET at the top of search_cache.rb"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
prog_name = __FILE__
|
16
|
+
args = ARGV
|
17
|
+
if args.size != 2
|
18
|
+
warn "Usage: #{prog_name} <oauth1-access-token-key> <oauth1-access-token-secret>"
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
access_token_key = args[0]
|
23
|
+
access_token_secret = args[1]
|
24
|
+
|
25
|
+
sess = DropboxSession.new(APP_KEY, APP_SECRET)
|
26
|
+
sess.set_access_token(access_token_key, access_token_secret)
|
27
|
+
c = DropboxClient.new(sess)
|
28
|
+
|
29
|
+
print "Creating OAuth 2 access token...\n"
|
30
|
+
oauth2_access_token = c.create_oauth2_access_token
|
31
|
+
|
32
|
+
print "Using OAuth 2 access token to get account info...\n"
|
33
|
+
c2 = DropboxClient.new(oauth2_access_token)
|
34
|
+
pp c2.account_info
|
35
|
+
|
36
|
+
print "Disabling OAuth 1 access token...\n"
|
37
|
+
c.disable_access_token
|
38
|
+
end
|
39
|
+
|
40
|
+
main()
|
@@ -0,0 +1,322 @@
|
|
1
|
+
# An example use of the /delta API call. Maintains a local cache of
|
2
|
+
# the App Folder's contents. Use the 'update' sub-command to update
|
3
|
+
# the local cache. Use the 'find' sub-command to search the local
|
4
|
+
# cache.
|
5
|
+
#
|
6
|
+
# Example usage:
|
7
|
+
#
|
8
|
+
# 1. Link to your Dropbox account
|
9
|
+
# > ruby search_cache.rb link
|
10
|
+
#
|
11
|
+
# 2. Go to Dropbox and make changes to the contents.
|
12
|
+
#
|
13
|
+
# 3. Update the local cache to match what's on Dropbox.
|
14
|
+
# > ruby search_cache.rb update
|
15
|
+
#
|
16
|
+
# 4. Search the local cache.
|
17
|
+
# > ruby search_cache.rb find 'txt'
|
18
|
+
|
19
|
+
# Repeat steps 2-4 any number of times.
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
24
|
+
require 'json'
|
25
|
+
|
26
|
+
# You must use your Dropbox App key and secret to use the API.
|
27
|
+
# Find this at https://www.dropbox.com/developers
|
28
|
+
APP_KEY = ''
|
29
|
+
APP_SECRET = ''
|
30
|
+
|
31
|
+
STATE_FILE = 'search_cache.json'
|
32
|
+
|
33
|
+
def main()
|
34
|
+
if APP_KEY == '' or APP_SECRET == ''
|
35
|
+
warn "ERROR: Set your APP_KEY and APP_SECRET at the top of search_cache.rb"
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
prog_name = __FILE__
|
39
|
+
args = ARGV
|
40
|
+
if args.size == 0
|
41
|
+
warn("Usage:\n")
|
42
|
+
warn(" #{prog_name} link Link to a user's account.")
|
43
|
+
warn(" #{prog_name} update Update cache to the latest on Dropbox.")
|
44
|
+
warn(" #{prog_name} update <num> Update cache, limit to <num> pages of /delta.")
|
45
|
+
warn(" #{prog_name} find <term> Search cache for <term>.")
|
46
|
+
warn(" #{prog_name} find Display entire cache contents")
|
47
|
+
warn(" #{prog_name} reset Delete the cache.")
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
command = args[0]
|
52
|
+
if command == 'link'
|
53
|
+
command_link(args)
|
54
|
+
elsif command == 'update'
|
55
|
+
command_update(args)
|
56
|
+
elsif command == 'find'
|
57
|
+
command_find(args)
|
58
|
+
elsif command == 'reset'
|
59
|
+
command_reset(args)
|
60
|
+
else
|
61
|
+
warn "ERROR: Unknown command: #{command}"
|
62
|
+
warn "Run with no arguments for help."
|
63
|
+
exit(1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def command_link(args)
|
69
|
+
if args.size != 1
|
70
|
+
warn "ERROR: \"link\" doesn't take any arguments"
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
web_auth = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET)
|
75
|
+
authorize_url = web_auth.start()
|
76
|
+
puts "1. Go to: #{authorize_url}"
|
77
|
+
puts "2. Click \"Allow\" (you might have to log in first)."
|
78
|
+
puts "3. Copy the authorization code."
|
79
|
+
|
80
|
+
print "Enter the authorization code here: "
|
81
|
+
STDOUT.flush
|
82
|
+
auth_code = STDIN.gets.strip
|
83
|
+
|
84
|
+
access_token, user_id = web_auth.finish(auth_code)
|
85
|
+
puts "Link successful."
|
86
|
+
|
87
|
+
save_state({
|
88
|
+
'access_token' => access_token,
|
89
|
+
'tree' => {}
|
90
|
+
})
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def command_update(args)
|
95
|
+
if args.size == 1
|
96
|
+
page_limit = nil
|
97
|
+
elsif args.size == 2
|
98
|
+
page_limit = Integer(args[1])
|
99
|
+
else
|
100
|
+
warn "ERROR: \"update\" takes either zero or one argument."
|
101
|
+
exit
|
102
|
+
end
|
103
|
+
|
104
|
+
# Load state
|
105
|
+
state = load_state()
|
106
|
+
access_token = state['access_token']
|
107
|
+
cursor = state['cursor']
|
108
|
+
tree = state['tree']
|
109
|
+
|
110
|
+
# Connect to Dropbox
|
111
|
+
c = DropboxClient.new(access_token)
|
112
|
+
|
113
|
+
page = 0
|
114
|
+
changed = false
|
115
|
+
while (page_limit == nil) or (page < page_limit)
|
116
|
+
# Get /delta results from Dropbox
|
117
|
+
result = c.delta(cursor)
|
118
|
+
page += 1
|
119
|
+
if result['reset'] == true
|
120
|
+
puts 'reset'
|
121
|
+
changed = true
|
122
|
+
tree = {}
|
123
|
+
end
|
124
|
+
cursor = result['cursor']
|
125
|
+
# Apply the entries one by one to our cached tree.
|
126
|
+
for delta_entry in result['entries']
|
127
|
+
changed = true
|
128
|
+
apply_delta(tree, delta_entry)
|
129
|
+
end
|
130
|
+
cursor = result['cursor']
|
131
|
+
if not result['has_more']
|
132
|
+
break
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Save state
|
137
|
+
if changed
|
138
|
+
state['cursor'] = cursor
|
139
|
+
state['tree'] = tree
|
140
|
+
save_state(state)
|
141
|
+
else
|
142
|
+
puts "No updates."
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
# We track folder state as a tree of Node objects.
|
148
|
+
class Node
|
149
|
+
attr_accessor :path, :content
|
150
|
+
def initialize(path, content)
|
151
|
+
# The "original" page (i.e. not the lower-case path)
|
152
|
+
@path = path
|
153
|
+
# For files, content is a pair (size, modified)
|
154
|
+
# For folders, content is a hash of children Nodes, keyed by lower-case file names.
|
155
|
+
@content = content
|
156
|
+
end
|
157
|
+
def folder?()
|
158
|
+
@content.is_a? Hash
|
159
|
+
end
|
160
|
+
def to_json()
|
161
|
+
[@path, Node.to_json_content(@content)]
|
162
|
+
end
|
163
|
+
def self.from_json(jnode)
|
164
|
+
path, jcontent = jnode
|
165
|
+
Node.new(path, Node.from_json_content(jcontent))
|
166
|
+
end
|
167
|
+
def self.to_json_content(content)
|
168
|
+
if content.is_a? Hash
|
169
|
+
map_hash_values(content) { |child| child.to_json }
|
170
|
+
else
|
171
|
+
content
|
172
|
+
end
|
173
|
+
end
|
174
|
+
def self.from_json_content(jcontent)
|
175
|
+
if jcontent.is_a? Hash
|
176
|
+
map_hash_values(jcontent) { |jchild| Node.from_json jchild }
|
177
|
+
else
|
178
|
+
jcontent
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Run a mapping function over every value in a Hash, returning a new Hash.
|
184
|
+
def map_hash_values(h)
|
185
|
+
new = {}
|
186
|
+
h.each { |k,v| new[k] = yield v }
|
187
|
+
new
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
def apply_delta(root, e)
|
192
|
+
path, metadata = e
|
193
|
+
branch, leaf = split_path(path)
|
194
|
+
|
195
|
+
if metadata != nil
|
196
|
+
puts "+ #{path}"
|
197
|
+
# Traverse down the tree until we find the parent folder of the entry
|
198
|
+
# we want to add. Create any missing folders along the way.
|
199
|
+
children = root
|
200
|
+
branch.each do |part|
|
201
|
+
node = get_or_create_child(children, part)
|
202
|
+
# If there's no folder here, make an empty one.
|
203
|
+
if not node.folder?
|
204
|
+
node.content = {}
|
205
|
+
end
|
206
|
+
children = node.content
|
207
|
+
end
|
208
|
+
|
209
|
+
# Create the file/folder.
|
210
|
+
node = get_or_create_child(children, leaf)
|
211
|
+
node.path = metadata['path'] # Save the un-lower-cased path.
|
212
|
+
if metadata['is_dir']
|
213
|
+
# Only create a folder if there isn't one there already.
|
214
|
+
node.content = {} if not node.folder?
|
215
|
+
else
|
216
|
+
node.content = metadata['size'], metadata['modified']
|
217
|
+
end
|
218
|
+
else
|
219
|
+
puts "- #{path}"
|
220
|
+
# Traverse down the tree until we find the parent of the entry we
|
221
|
+
# want to delete.
|
222
|
+
children = root
|
223
|
+
missing_parent = false
|
224
|
+
branch.each do |part|
|
225
|
+
node = children[part]
|
226
|
+
# If one of the parent folders is missing, then we're done.
|
227
|
+
if node == nil or not node.folder?
|
228
|
+
missing_parent = true
|
229
|
+
break
|
230
|
+
end
|
231
|
+
children = node.content
|
232
|
+
end
|
233
|
+
# If we made it all the way, delete the file/folder.
|
234
|
+
if not missing_parent
|
235
|
+
children.delete(leaf)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def get_or_create_child(children, name)
|
241
|
+
child = children[name]
|
242
|
+
if child == nil
|
243
|
+
children[name] = child = Node.new(nil, nil)
|
244
|
+
end
|
245
|
+
child
|
246
|
+
end
|
247
|
+
|
248
|
+
def split_path(path)
|
249
|
+
bad, *parts = path.split '/'
|
250
|
+
[parts, parts.pop]
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
def command_find(args)
|
255
|
+
if args.size == 1
|
256
|
+
term = ''
|
257
|
+
elsif args.size == 2
|
258
|
+
term = args[1]
|
259
|
+
else
|
260
|
+
warn("ERROR: \"find\" takes either zero or one arguments.")
|
261
|
+
exit
|
262
|
+
end
|
263
|
+
|
264
|
+
state = load_state()
|
265
|
+
results = []
|
266
|
+
search_tree(results, state['tree'], term)
|
267
|
+
for r in results
|
268
|
+
puts("#{r}")
|
269
|
+
end
|
270
|
+
puts("[Matches: #{results.size}]")
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def command_reset(args)
|
275
|
+
if args.size != 1
|
276
|
+
warn("ERROR: \"reset\" takes no arguments.")
|
277
|
+
exit
|
278
|
+
end
|
279
|
+
|
280
|
+
# Delete cursor, empty tree.
|
281
|
+
state = load_state()
|
282
|
+
if state.has_key?('cursor')
|
283
|
+
state.delete('cursor')
|
284
|
+
end
|
285
|
+
state['tree'] = {}
|
286
|
+
save_state(state)
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
# Recursively search 'tree' for files that contain the string in 'term'.
|
291
|
+
# Print out any matches.
|
292
|
+
def search_tree(results, tree, term)
|
293
|
+
tree.each do |name_lc, node|
|
294
|
+
path = node.path
|
295
|
+
if (path != nil) and path.include?(term)
|
296
|
+
if node.folder?
|
297
|
+
results.push("#{path}")
|
298
|
+
else
|
299
|
+
size, modified = node.content
|
300
|
+
results.push("#{path} (#{size}, #{modified})")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
if node.folder?
|
304
|
+
search_tree(results, node.content, term)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def save_state(state)
|
310
|
+
state['tree'] = Node.to_json_content(state['tree'])
|
311
|
+
File.open(STATE_FILE,"w") do |f|
|
312
|
+
f.write(JSON.pretty_generate(state, :max_nesting => false))
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def load_state()
|
317
|
+
state = JSON.parse(File.read(STATE_FILE), :max_nesting => false)
|
318
|
+
state['tree'] = Node.from_json_content(state['tree'])
|
319
|
+
state
|
320
|
+
end
|
321
|
+
|
322
|
+
main()
|
@@ -4,6 +4,11 @@
|
|
4
4
|
# - The webapp OAuth process.
|
5
5
|
# - The metadata() and put_file() calls.
|
6
6
|
#
|
7
|
+
# To set up:
|
8
|
+
# 1. Create a Dropbox App key and secret to use the API. https://www.dropbox.com/developers
|
9
|
+
# 2. Add http://localhost:4567/dropbox-auth-finish as a Redirect URI for your Dropbox app.
|
10
|
+
# 3. Copy your App key and App secret into APP_KEY and APP_SECRET below.
|
11
|
+
#
|
7
12
|
# To run:
|
8
13
|
# 1. Install Sinatra $ gem install sinatra
|
9
14
|
# 2. Launch server $ ruby web_file_browser.rb
|
@@ -14,7 +19,7 @@ require 'rubygems'
|
|
14
19
|
require 'sinatra'
|
15
20
|
require 'pp'
|
16
21
|
require 'securerandom'
|
17
|
-
require '
|
22
|
+
require File.expand_path('../../lib/dropbox_sdk', __FILE__)
|
18
23
|
|
19
24
|
# Get your app's key and secret from https://www.dropbox.com/developers/
|
20
25
|
APP_KEY = ''
|
data/lib/dropbox_sdk.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'uri'
|
3
2
|
require 'net/https'
|
4
3
|
require 'cgi'
|
@@ -14,7 +13,7 @@ module Dropbox # :nodoc:
|
|
14
13
|
WEB_SERVER = "www.dropbox.com"
|
15
14
|
|
16
15
|
API_VERSION = 1
|
17
|
-
SDK_VERSION = "1.6.
|
16
|
+
SDK_VERSION = "1.6.4"
|
18
17
|
|
19
18
|
TRUSTED_CERT_FILE = File.join(File.dirname(__FILE__), 'trusted-certs.crt')
|
20
19
|
|
@@ -88,7 +87,7 @@ module Dropbox # :nodoc:
|
|
88
87
|
http.request(request)
|
89
88
|
rescue OpenSSL::SSL::SSLError => e
|
90
89
|
raise DropboxError.new("SSL error connecting to Dropbox. " +
|
91
|
-
"There may be a problem with the set of certificates in \"#{Dropbox::TRUSTED_CERT_FILE}\". #{e}")
|
90
|
+
"There may be a problem with the set of certificates in \"#{Dropbox::TRUSTED_CERT_FILE}\". #{e.message}")
|
92
91
|
end
|
93
92
|
end
|
94
93
|
|
@@ -861,9 +860,18 @@ class DropboxClient
|
|
861
860
|
begin
|
862
861
|
resp = Dropbox::parse_response(@client.partial_chunked_upload(last_chunk, @upload_id, @offset))
|
863
862
|
last_chunk = nil
|
863
|
+
rescue SocketError => e
|
864
|
+
raise e
|
865
|
+
rescue SystemCallError => e
|
866
|
+
raise e
|
864
867
|
rescue DropboxError => e
|
865
|
-
|
866
|
-
|
868
|
+
raise e if e.http_response.nil? or e.http_response.code[0] == '5'
|
869
|
+
begin
|
870
|
+
resp = JSON.parse(e.http_response.body)
|
871
|
+
raise DropboxError.new('server response does not have offset key') unless resp.has_key? 'offset'
|
872
|
+
rescue JSON::ParserError
|
873
|
+
raise DropboxError.new("Unable to parse JSON response: #{e.http_response.body}")
|
874
|
+
end
|
867
875
|
end
|
868
876
|
|
869
877
|
if resp.has_key? 'offset' and resp['offset'] > @offset
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dropbox-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
7
|
- 6
|
9
|
-
-
|
10
|
-
version: 1.6.
|
8
|
+
- 4
|
9
|
+
version: 1.6.4
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Dropbox, Inc.
|
@@ -15,17 +14,16 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date:
|
17
|
+
date: 2014-04-24 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: json
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
24
|
requirements:
|
26
25
|
- - ">="
|
27
26
|
- !ruby/object:Gem::Version
|
28
|
-
hash: 3
|
29
27
|
segments:
|
30
28
|
- 0
|
31
29
|
version: "0"
|
@@ -44,11 +42,16 @@ files:
|
|
44
42
|
- CHANGELOG
|
45
43
|
- LICENSE
|
46
44
|
- README
|
47
|
-
- cli_example.rb
|
48
|
-
- dropbox_controller.rb
|
49
|
-
- web_file_browser.rb
|
45
|
+
- examples/cli_example.rb
|
46
|
+
- examples/dropbox_controller.rb
|
47
|
+
- examples/web_file_browser.rb
|
48
|
+
- examples/copy_between_accounts.rb
|
49
|
+
- examples/chunked_upload.rb
|
50
|
+
- examples/oauth1_upgrade.rb
|
51
|
+
- examples/search_cache.rb
|
50
52
|
- lib/dropbox_sdk.rb
|
51
53
|
- lib/trusted-certs.crt
|
54
|
+
has_rdoc: true
|
52
55
|
homepage: http://www.dropbox.com/developers/
|
53
56
|
licenses:
|
54
57
|
- MIT
|
@@ -58,27 +61,23 @@ rdoc_options: []
|
|
58
61
|
require_paths:
|
59
62
|
- lib
|
60
63
|
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
64
|
requirements:
|
63
65
|
- - ">="
|
64
66
|
- !ruby/object:Gem::Version
|
65
|
-
hash: 3
|
66
67
|
segments:
|
67
68
|
- 0
|
68
69
|
version: "0"
|
69
70
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
-
none: false
|
71
71
|
requirements:
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
hash: 3
|
75
74
|
segments:
|
76
75
|
- 0
|
77
76
|
version: "0"
|
78
77
|
requirements: []
|
79
78
|
|
80
79
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.
|
80
|
+
rubygems_version: 1.3.6
|
82
81
|
signing_key:
|
83
82
|
specification_version: 3
|
84
83
|
summary: Dropbox REST API Client.
|