dropbox 0.0.10 → 1.0.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/.document +5 -0
- data/.gitignore +23 -3
- data/LICENSE +20 -0
- data/README.rdoc +84 -17
- data/Rakefile +39 -20
- data/VERSION +1 -1
- data/lib/dropbox.rb +41 -12
- data/lib/dropbox/api.rb +530 -0
- data/lib/dropbox/entry.rb +96 -0
- data/lib/dropbox/event.rb +109 -0
- data/lib/dropbox/memoization.rb +98 -0
- data/lib/dropbox/revision.rb +197 -0
- data/lib/dropbox/session.rb +160 -0
- data/lib/extensions/array.rb +9 -0
- data/lib/extensions/hash.rb +61 -0
- data/lib/extensions/module.rb +22 -0
- data/lib/extensions/object.rb +5 -0
- data/lib/extensions/string.rb +9 -0
- data/lib/extensions/to_bool.rb +17 -0
- data/spec/dropbox/api_spec.rb +778 -0
- data/spec/dropbox/entry_spec.rb +144 -0
- data/spec/dropbox/event_spec.rb +122 -0
- data/spec/dropbox/revision_spec.rb +367 -0
- data/spec/dropbox/session_spec.rb +148 -0
- data/spec/dropbox_spec.rb +57 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +64 -27
- data/ChangeLog.rdoc +0 -17
- data/examples/dropbox_spec.rb +0 -99
- data/lib/dropbox/dropbox.rb +0 -213
data/lib/dropbox/dropbox.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'nokogiri'
|
3
|
-
require 'mechanize'
|
4
|
-
|
5
|
-
Mechanize.html_parser = Nokogiri::HTML
|
6
|
-
|
7
|
-
# TODO: Tests (mock out expected DropBox output)
|
8
|
-
# TODO: Directory object, File object
|
9
|
-
|
10
|
-
class DropBox
|
11
|
-
#before_filter :login_filter, :except => [:login]
|
12
|
-
|
13
|
-
def initialize(email, password, folder_namespace = "")
|
14
|
-
@email = email
|
15
|
-
@password = password
|
16
|
-
@agent = Mechanize.new
|
17
|
-
@folder_namespace = folder_namespace.gsub(/^\//,"")
|
18
|
-
@logged_in = false
|
19
|
-
end
|
20
|
-
|
21
|
-
def agent
|
22
|
-
@agent
|
23
|
-
end
|
24
|
-
|
25
|
-
# Lists all the files and folders in a given directory
|
26
|
-
def index(path = "/")
|
27
|
-
login_filter
|
28
|
-
path = namespace_path(path)
|
29
|
-
|
30
|
-
list = @agent.post("/browse2#{path}?ajax=yes", {"d"=> 1, "t" => @token })
|
31
|
-
|
32
|
-
listing = list.search('div.browse-file-box-details').collect do |file|
|
33
|
-
details = {}
|
34
|
-
details['name'] = file.at('div.details-filename a').content.strip
|
35
|
-
details['url'] = file.at('div.details-filename a')["href"]
|
36
|
-
#details['size'] = file.at('div.details-size a').try(:content).try(:strip)
|
37
|
-
#details['modified'] = file.at('div.details-modified a').try(:content).try(:strip)
|
38
|
-
|
39
|
-
if match_data = details['url'].match(/^\/browse_plain(.*)$/)
|
40
|
-
details['directory'] = true
|
41
|
-
details['path'] = normalize_namespace(match_data[1])
|
42
|
-
elsif match_data = details['url'].match(%r{^https?://[^/]*/get(.*)$})
|
43
|
-
details['directory'] = false
|
44
|
-
details['path'] = normalize_namespace(match_data[1])
|
45
|
-
elsif match_data = details['url'].match(%r{^https?://[^/]*/u/\d*/(.*)$})
|
46
|
-
details['directory'] = false
|
47
|
-
details['path'] = "Public/#{match_data[1]}"
|
48
|
-
else
|
49
|
-
raise "could not parse path from Dropbox URL: #{details['url'] }"
|
50
|
-
end
|
51
|
-
|
52
|
-
details
|
53
|
-
end
|
54
|
-
|
55
|
-
return listing
|
56
|
-
end
|
57
|
-
|
58
|
-
alias :list :index
|
59
|
-
|
60
|
-
# Lists the full history for a file on DropBox
|
61
|
-
def list_history(path)
|
62
|
-
login_filter
|
63
|
-
|
64
|
-
path = namespace_path(path)
|
65
|
-
|
66
|
-
history = @agent.get("/revisions#{path}")
|
67
|
-
listing = history.search("table.filebrowser > tr").select{|r| r.search("td").count > 1 }.collect do |r|
|
68
|
-
|
69
|
-
# warning, this is very brittle!
|
70
|
-
details = {}
|
71
|
-
details["version"] = r.search("td a").first.content.strip
|
72
|
-
details["url"] = r.search("td a").first["href"]
|
73
|
-
details["size"] = r.search("td").last.content.strip
|
74
|
-
details["modified"] = r.search("td")[2].content.strip
|
75
|
-
details["version_id"] = details["url"].match(/^.*sjid=([\d]*)$/)[1]
|
76
|
-
details['path'] = normalize_namespace(details['url'][33..-1])
|
77
|
-
|
78
|
-
details
|
79
|
-
end
|
80
|
-
|
81
|
-
return listing
|
82
|
-
end
|
83
|
-
|
84
|
-
# Downloads the specified file from DropBox
|
85
|
-
def show(path)
|
86
|
-
require 'pathname'
|
87
|
-
# change to before filter
|
88
|
-
login_filter
|
89
|
-
|
90
|
-
# round about way of getting the secure url we need
|
91
|
-
# path = namespace_path(path)
|
92
|
-
pathname = Pathname.new(path)
|
93
|
-
url = self.list(pathname.dirname.to_s).detect{ |f| f["name"] == pathname.basename.to_s }["url"]
|
94
|
-
|
95
|
-
#https://dl-web.dropbox.com/get/testing.txt?w=0ff80d5d&sjid=125987568
|
96
|
-
@agent.get(url).content
|
97
|
-
end
|
98
|
-
|
99
|
-
alias :get :show
|
100
|
-
|
101
|
-
# Creates a directory
|
102
|
-
def create_directory(new_path, destination = "/" )
|
103
|
-
# change to before filter
|
104
|
-
login unless @logged_in
|
105
|
-
destination = namespace_path(destination)
|
106
|
-
@agent.post("/cmd/new#{destination}",{"to_path"=>new_path, "folder"=>"yes", "t" => @token }).code == "200"
|
107
|
-
end
|
108
|
-
|
109
|
-
# Uploads a file to DropBox under the given filename
|
110
|
-
def create(file, destination = "/")
|
111
|
-
# change to before filter
|
112
|
-
if @logged_in
|
113
|
-
home_page = @agent.get('https://www.dropbox.com/home')
|
114
|
-
else
|
115
|
-
home_page = login
|
116
|
-
end
|
117
|
-
|
118
|
-
upload_form = home_page.forms.detect{ |f| f.action == "https://dl-web.dropbox.com/upload" }
|
119
|
-
upload_form.dest = namespace_path(destination)
|
120
|
-
upload_form.file_uploads.first.file_name = file if file
|
121
|
-
|
122
|
-
@agent.submit(upload_form).code == "200"
|
123
|
-
end
|
124
|
-
|
125
|
-
alias :update :create
|
126
|
-
|
127
|
-
# Renames a file or folder in the DropBox
|
128
|
-
def rename(file, destination)
|
129
|
-
login_filter
|
130
|
-
file = namespace_path(file)
|
131
|
-
destination = namespace_path(destination)
|
132
|
-
@agent.post("/cmd/rename#{file}", {"to_path"=> destination, "t" => @token }).code == "200"
|
133
|
-
end
|
134
|
-
|
135
|
-
# Deletes a file/folder from the DropBox (accepts string path or an array of string paths)
|
136
|
-
def destroy(paths)
|
137
|
-
login_filter
|
138
|
-
paths = [paths].flatten
|
139
|
-
paths = paths.collect { |path| namespace_path(path) }
|
140
|
-
@agent.post("/cmd/delete", {"files"=> paths, "t" => @token }).code == "200"
|
141
|
-
end
|
142
|
-
|
143
|
-
# Permanently deletes a file from the DropBox (no history!) accepts arrays, as #destroy does
|
144
|
-
def purge(paths)
|
145
|
-
login_filter
|
146
|
-
paths = [paths].flatten
|
147
|
-
paths = paths.collect { |path| namespace_path(path) }
|
148
|
-
@agent.post("/cmd/purge", {"files"=> paths, "t" => @token }).code == "200"
|
149
|
-
end
|
150
|
-
|
151
|
-
# Will give a hash of the amount of space left on the DropBox, the amound used, the calculated amount free (all as a 1 d.p. rounded GB value) and the percentage used (scraped)
|
152
|
-
def usage_stats
|
153
|
-
login_filter
|
154
|
-
|
155
|
-
stats_page = @agent.get("/account")
|
156
|
-
|
157
|
-
stats = stats_page.at('#usage-percent').content.scan(/(\d+(?:\.\d+)?)%\ used\ \((\d+(?:\.\d+)?)([MG])B of (\d+(?:\.\d+)?)GB\)/).collect{ |d|
|
158
|
-
{ :used => d[1].to_f * ((d[2] == "G") ? 1024 : 1),
|
159
|
-
:total => d[3].to_f * 1024,
|
160
|
-
:free => (d[3].to_f * 1024 - d[1].to_f * ((d[2] == "G") ? 1024 : 1)),
|
161
|
-
:percent => Percentage.new(d[0].to_f/100)
|
162
|
-
}
|
163
|
-
}[0]
|
164
|
-
|
165
|
-
regular_data = stats_page.at('span.bar-graph-legend.bar-graph-normal').next.content.scan(/\((\d+(?:\.\d+)?)([MG])B/)[0]
|
166
|
-
stats[:regular_used] = regular_data[0].to_f * ((regular_data[1] == "G") ? 1024 : 1) unless regular_data.nil?
|
167
|
-
|
168
|
-
shared_data = stats_page.at('span.bar-graph-legend.bar-graph-shared').next.content.scan(/\((\d+(?:\.\d+)?)([MG])B/)[0]
|
169
|
-
stats[:shared_used] = shared_data[0].to_f * ((shared_data[1] == "G") ? 1024 : 1) unless shared_data.nil?
|
170
|
-
|
171
|
-
return stats
|
172
|
-
end
|
173
|
-
|
174
|
-
private
|
175
|
-
def namespace_path(path)
|
176
|
-
# remove the start slash if we have one
|
177
|
-
path.gsub(/^\//,"")
|
178
|
-
new_path = if @folder_namespace.empty?
|
179
|
-
"/#{path}"
|
180
|
-
else
|
181
|
-
"/#{@folder_namespace}/#{path}"
|
182
|
-
end
|
183
|
-
new_path.gsub("//","/")
|
184
|
-
end
|
185
|
-
|
186
|
-
def normalize_namespace(file)
|
187
|
-
file.gsub(/^\/#{@folder_namespace}/,"")
|
188
|
-
end
|
189
|
-
|
190
|
-
def login
|
191
|
-
page = @agent.get('https://www.dropbox.com/login')
|
192
|
-
login_form = page.forms.detect { |f| f.action == "/login" }
|
193
|
-
login_form.login_email = @email
|
194
|
-
login_form.login_password = @password
|
195
|
-
|
196
|
-
home_page = @agent.submit(login_form)
|
197
|
-
# todo check if we are logged in! (ie search for email and "Log out"
|
198
|
-
@logged_in = true
|
199
|
-
@token = home_page.at('//script[contains(text(), "TOKEN")]').content.match("TOKEN: '(.*)',$")[1]
|
200
|
-
|
201
|
-
# check if we have our namespace
|
202
|
-
|
203
|
-
home_page
|
204
|
-
end
|
205
|
-
|
206
|
-
def login_filter
|
207
|
-
login unless @logged_in
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# this file doesn't use the standard ruby indent settings, so the following
|
212
|
-
# modeline will make sure that the whitespace stays consistent.
|
213
|
-
# vim:noexpandtab tabstop=4 shiftwidth=4
|