dbox 0.7.6 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,25 +0,0 @@
1
- # Build with: gem build gemspec.rb
2
- Gem::Specification.new do |s|
3
- s.name = "dropbox-sdk"
4
-
5
- s.version = "1.3.1"
6
- s.license = 'MIT'
7
-
8
- s.authors = ["Dropbox, Inc."]
9
- s.email = ["support-api@dropbox.com"]
10
-
11
- s.add_dependency "json"
12
-
13
- s.homepage = "http://www.dropbox.com/developers/"
14
- s.summary = "Dropbox REST API Client."
15
- s.description = <<-EOF
16
- A library that provides a plain function-call interface to the
17
- Dropbox API web endpoints.
18
- EOF
19
-
20
- s.files = [
21
- "CHANGELOG", "LICENSE", "README",
22
- "cli_example.rb", "dropbox_controller.rb", "web_file_browser.rb",
23
- "lib/dropbox_sdk.rb", "lib/trusted-certs.crt",
24
- ]
25
- end
@@ -1,883 +0,0 @@
1
- require 'rubygems'
2
- require 'uri'
3
- require 'net/https'
4
- require 'cgi'
5
- require 'json'
6
- require 'yaml'
7
-
8
- module Dropbox # :nodoc:
9
- API_SERVER = "api.dropbox.com"
10
- API_CONTENT_SERVER = "api-content.dropbox.com"
11
- WEB_SERVER = "www.dropbox.com"
12
-
13
- API_VERSION = 1
14
- SDK_VERSION = "1.3.1"
15
-
16
- TRUSTED_CERT_FILE = File.join(File.dirname(__FILE__), 'trusted-certs.crt')
17
- end
18
-
19
- # DropboxSession is responsible for holding OAuth information. It knows how to take your consumer key and secret
20
- # and request an access token, an authorize url, and get an access token. You just need to pass it to
21
- # DropboxClient after its been authorized.
22
- class DropboxSession
23
-
24
- # * consumer_key - Your Dropbox application's "app key".
25
- # * consumer_secret - Your Dropbox application's "app secret".
26
- def initialize(consumer_key, consumer_secret)
27
- @consumer_key = consumer_key
28
- @consumer_secret = consumer_secret
29
- @request_token = nil
30
- @access_token = nil
31
- end
32
-
33
- private
34
-
35
- def do_http(uri, auth_token, request) # :nodoc:
36
- http = Net::HTTP.new(uri.host, uri.port)
37
-
38
- http.use_ssl = true
39
- enable_cert_checking(http)
40
- http.ca_file = Dropbox::TRUSTED_CERT_FILE
41
-
42
- request.add_field('Authorization', build_auth_header(auth_token))
43
-
44
- #We use this to better understand how developers are using our SDKs.
45
- request['User-Agent'] = "OfficialDropboxRubySDK/#{Dropbox::SDK_VERSION}"
46
-
47
- begin
48
- http.request(request)
49
- rescue OpenSSL::SSL::SSLError => e
50
- raise DropboxError.new("SSL error connecting to Dropbox. " +
51
- "There may be a problem with the set of certificates in \"#{Dropbox::TRUSTED_CERT_FILE}\". " +
52
- e)
53
- end
54
- end
55
-
56
- def enable_cert_checking(http)
57
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
58
- end
59
-
60
- def build_auth_header(token) # :nodoc:
61
- header = "OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", " +
62
- "oauth_consumer_key=\"#{URI.escape(@consumer_key)}\", "
63
- if token
64
- key = URI.escape(token.key)
65
- secret = URI.escape(token.secret)
66
- header += "oauth_token=\"#{key}\", oauth_signature=\"#{URI.escape(@consumer_secret)}&#{secret}\""
67
- else
68
- header += "oauth_signature=\"#{URI.escape(@consumer_secret)}&\""
69
- end
70
- header
71
- end
72
-
73
- def do_get_with_token(url, token, headers=nil) # :nodoc:
74
- uri = URI.parse(url)
75
- do_http(uri, token, Net::HTTP::Get.new(uri.request_uri))
76
- end
77
-
78
- public
79
-
80
- def do_get(url, headers=nil) # :nodoc:
81
- assert_authorized
82
- do_get_with_token(url, @access_token)
83
- end
84
-
85
- def do_http_with_body(uri, request, body)
86
- if body != nil
87
- if body.is_a?(Hash)
88
- form_data = {}
89
- body.each {|k,v| form_data[k.to_s] = v if !v.nil?}
90
- request.set_form_data(form_data)
91
- elsif body.respond_to?(:read)
92
- if body.respond_to?(:length)
93
- request["Content-Length"] = body.length.to_s
94
- elsif body.respond_to?(:stat) && body.stat.respond_to?(:size)
95
- request["Content-Length"] = body.stat.size.to_s
96
- else
97
- raise ArgumentError, "Don't know how to handle 'body' (responds to 'read' but not to 'length' or 'stat.size')."
98
- end
99
- request.body_stream = body
100
- else
101
- s = body.to_s
102
- request["Content-Length"] = s.length
103
- request.body = s
104
- end
105
- end
106
- do_http(uri, @access_token, request)
107
- end
108
-
109
- def do_post(url, headers=nil, body=nil) # :nodoc:
110
- assert_authorized
111
- uri = URI.parse(url)
112
- do_http_with_body(uri, Net::HTTP::Post.new(uri.request_uri, headers), body)
113
- end
114
-
115
- def do_put(url, headers=nil, body=nil) # :nodoc:
116
- assert_authorized
117
- uri = URI.parse(url)
118
- do_http_with_body(uri, Net::HTTP::Put.new(uri.request_uri, headers), body)
119
- end
120
-
121
-
122
- def get_token(url_end, input_token, error_message_prefix) #: nodoc:
123
- response = do_get_with_token("https://#{Dropbox::API_SERVER}:443/#{Dropbox::API_VERSION}/oauth#{url_end}", input_token)
124
- if not response.kind_of?(Net::HTTPSuccess) # it must be a 200
125
- raise DropboxAuthError.new("#{error_message_prefix} Server returned #{response.code}: #{response.message}.", response)
126
- end
127
- parts = CGI.parse(response.body)
128
-
129
- if !parts.has_key? "oauth_token" and parts["oauth_token"].length != 1
130
- raise DropboxAuthError.new("Invalid response from #{url_end}: missing \"oauth_token\" parameter: #{response.body}", response)
131
- end
132
- if !parts.has_key? "oauth_token_secret" and parts["oauth_token_secret"].length != 1
133
- raise DropboxAuthError.new("Invalid response from #{url_end}: missing \"oauth_token\" parameter: #{response.body}", response)
134
- end
135
-
136
- OAuthToken.new(parts["oauth_token"][0], parts["oauth_token_secret"][0])
137
- end
138
-
139
- # This returns a request token. Requests one from the dropbox server using the provided application key and secret if nessecary.
140
- def get_request_token()
141
- @request_token ||= get_token("/request_token", nil, "Error getting request token. Is your app key and secret correctly set?")
142
- end
143
-
144
- # This returns a URL that your user must visit to grant
145
- # permissions to this application.
146
- def get_authorize_url(callback=nil)
147
- get_request_token()
148
-
149
- url = "/#{Dropbox::API_VERSION}/oauth/authorize?oauth_token=#{URI.escape(@request_token.key)}"
150
- if callback
151
- url += "&oauth_callback=#{URI.escape(callback)}"
152
- end
153
- if @locale
154
- url += "&locale=#{URI.escape(@locale)}"
155
- end
156
-
157
- "https://#{Dropbox::WEB_SERVER}#{url}"
158
- end
159
-
160
- # Clears the access_token
161
- def clear_access_token
162
- @access_token = nil
163
- end
164
-
165
- # Returns the request token, or nil if one hasn't been acquired yet.
166
- def request_token
167
- @request_token
168
- end
169
-
170
- # Returns the access token, or nil if one hasn't been acquired yet.
171
- def access_token
172
- @access_token
173
- end
174
-
175
- # Given a saved request token and secret, set this location's token and secret
176
- # * token - this is the request token
177
- # * secret - this is the request token secret
178
- def set_request_token(key, secret)
179
- @request_token = OAuthToken.new(key, secret)
180
- end
181
-
182
- # Given a saved access token and secret, you set this Session to use that token and secret
183
- # * token - this is the access token
184
- # * secret - this is the access token secret
185
- def set_access_token(key, secret)
186
- @access_token = OAuthToken.new(key, secret)
187
- end
188
-
189
- # Returns the access token. If this DropboxSession doesn't yet have an access_token, it requests one
190
- # using the request_token generate from your app's token and secret. This request will fail unless
191
- # your user has gone to the authorize_url and approved your request
192
- def get_access_token
193
- return @access_token if authorized?
194
-
195
- if @request_token.nil?
196
- raise DropboxAuthError.new("No request token. You must set this or get an authorize url first.")
197
- end
198
-
199
- @access_token = get_token("/access_token", @request_token, "Couldn't get access token.")
200
- end
201
-
202
- # If we have an access token, then do nothing. If not, throw a RuntimeError.
203
- def assert_authorized
204
- unless authorized?
205
- raise RuntimeError.new('Session does not yet have a request token')
206
- end
207
- end
208
-
209
- # Returns true if this Session has been authorized and has an access_token.
210
- def authorized?
211
- !!@access_token
212
- end
213
-
214
- # serialize the DropboxSession.
215
- # At DropboxSession's state is capture in three key/secret pairs. Consumer, request, and access.
216
- # Serialize returns these in a YAML string, generated from a converted array of the form:
217
- # [consumer_key, consumer_secret, request_token.token, request_token.secret, access_token.token, access_token.secret]
218
- # access_token is only included if it already exists in the DropboxSesssion
219
- def serialize
220
- toreturn = []
221
- if @access_token
222
- toreturn.push @access_token.secret, @access_token.key
223
- end
224
-
225
- get_request_token
226
-
227
- toreturn.push @request_token.secret, @request_token.key
228
- toreturn.push @consumer_secret, @consumer_key
229
-
230
- toreturn.to_yaml
231
- end
232
-
233
- # Takes a serialized DropboxSession YAML String and returns a new DropboxSession object
234
- def self.deserialize(ser)
235
- ser = YAML::load(ser)
236
- session = DropboxSession.new(ser.pop, ser.pop)
237
- session.set_request_token(ser.pop, ser.pop)
238
-
239
- if ser.length > 0
240
- session.set_access_token(ser.pop, ser.pop)
241
- end
242
- session
243
- end
244
- end
245
-
246
-
247
- # A class that represents either an OAuth request token or an OAuth access token.
248
- class OAuthToken # :nodoc:
249
- def initialize(key, secret)
250
- @key = key
251
- @secret = secret
252
- end
253
-
254
- def key
255
- @key
256
- end
257
-
258
- def secret
259
- @secret
260
- end
261
- end
262
-
263
-
264
- # This is the usual error raised on any Dropbox related Errors
265
- class DropboxError < RuntimeError
266
- attr_accessor :http_response, :error, :user_error
267
- def initialize(error, http_response=nil, user_error=nil)
268
- @error = error
269
- @http_response = http_response
270
- @user_error = user_error
271
- end
272
-
273
- def to_s
274
- return "#{user_error} (#{error})" if user_error
275
- "#{error}"
276
- end
277
- end
278
-
279
- # This is the error raised on Authentication failures. Usually this means
280
- # one of three things
281
- # * Your user failed to go to the authorize url and approve your application
282
- # * You set an invalid or expired token and secret on your Session
283
- # * Your user deauthorized the application after you stored a valid token and secret
284
- class DropboxAuthError < DropboxError
285
- end
286
-
287
- # This is raised when you call metadata with a hash and that hash matches
288
- # See documentation in metadata function
289
- class DropboxNotModified < DropboxError
290
- end
291
-
292
- # This is the Dropbox Client API you'll be working with most often. You need to give it
293
- # a DropboxSession which has already been authorized, or which it can authorize.
294
- class DropboxClient
295
-
296
- # Initialize a new DropboxClient. You need to give it a session which has been authorized. See
297
- # documentation on DropboxSession for how to authorize it.
298
- def initialize(session, root="app_folder", locale=nil)
299
- session.get_access_token
300
-
301
- @root = root.to_s # If they passed in a symbol, make it a string
302
-
303
- if not ["dropbox","app_folder"].include?(@root)
304
- raise DropboxError.new("root must be :dropbox or :app_folder")
305
- end
306
- if @root == "app_folder"
307
- #App Folder is the name of the access type, but for historical reasons
308
- #sandbox is the URL root component that indicates this
309
- @root = "sandbox"
310
- end
311
-
312
- @locale = locale
313
- @session = session
314
- end
315
-
316
- # Parse response. You probably shouldn't be calling this directly. This takes responses from the server
317
- # and parses them. It also checks for errors and raises exceptions with the appropriate messages.
318
- def parse_response(response, raw=false) # :nodoc:
319
- if response.kind_of?(Net::HTTPServerError)
320
- raise DropboxError.new("Dropbox Server Error: #{response} - #{response.body}", response)
321
- elsif response.kind_of?(Net::HTTPUnauthorized)
322
- raise DropboxAuthError.new(response, "User is not authenticated.")
323
- elsif not response.kind_of?(Net::HTTPSuccess)
324
- begin
325
- d = JSON.parse(response.body)
326
- rescue
327
- raise DropboxError.new("Dropbox Server Error: body=#{response.body}", response)
328
- end
329
- if d['user_error'] and d['error']
330
- raise DropboxError.new(d['error'], response, d['user_error']) #user_error is translated
331
- elsif d['error']
332
- raise DropboxError.new(d['error'], response)
333
- else
334
- raise DropboxError.new(response.body, response)
335
- end
336
- end
337
-
338
- return response.body if raw
339
-
340
- begin
341
- return JSON.parse(response.body)
342
- rescue JSON::ParserError
343
- raise DropboxError.new("Unable to parse JSON response: #{response.body}", response)
344
- end
345
- end
346
-
347
- # Returns account info in a Hash object
348
- #
349
- # For a detailed description of what this call returns, visit:
350
- # https://www.dropbox.com/developers/reference/api#account-info
351
- def account_info()
352
- response = @session.do_get build_url("/account/info")
353
- parse_response(response)
354
- end
355
-
356
- # Uploads a file to a server. This uses the HTTP PUT upload method for simplicity
357
- #
358
- # Arguments:
359
- # * to_path: The directory path to upload the file to. If the destination
360
- # directory does not yet exist, it will be created.
361
- # * file_obj: A file-like object to upload. If you would like, you can
362
- # pass a string as file_obj.
363
- # * overwrite: Whether to overwrite an existing file at the given path. [default is False]
364
- # If overwrite is False and a file already exists there, Dropbox
365
- # will rename the upload to make sure it doesn't overwrite anything.
366
- # You must check the returned metadata to know what this new name is.
367
- # This field should only be True if your intent is to potentially
368
- # clobber changes to a file that you don't know about.
369
- # * parent_rev: The rev field from the 'parent' of this upload. [optional]
370
- # If your intent is to update the file at the given path, you should
371
- # pass the parent_rev parameter set to the rev value from the most recent
372
- # metadata you have of the existing file at that path. If the server
373
- # has a more recent version of the file at the specified path, it will
374
- # automatically rename your uploaded file, spinning off a conflict.
375
- # Using this parameter effectively causes the overwrite parameter to be ignored.
376
- # The file will always be overwritten if you send the most-recent parent_rev,
377
- # and it will never be overwritten you send a less-recent one.
378
- # Returns:
379
- # * a Hash containing the metadata of the newly uploaded file. The file may have a different name if it conflicted.
380
- #
381
- # Simple Example
382
- # client = DropboxClient(session, :app_folder)
383
- # #session is a DropboxSession I've already authorized
384
- # client.put_file('/test_file_on_dropbox', open('/tmp/test_file'))
385
- # This will upload the "/tmp/test_file" from my computer into the root of my App's app folder
386
- # and call it "test_file_on_dropbox".
387
- # The file will not overwrite any pre-existing file.
388
- def put_file(to_path, file_obj, overwrite=false, parent_rev=nil)
389
- path = "/files_put/#{@root}#{format_path(to_path)}"
390
-
391
- params = {
392
- 'overwrite' => overwrite.to_s
393
- }
394
-
395
- params['parent_rev'] = parent_rev unless parent_rev.nil?
396
-
397
- response = @session.do_put(build_url(path, params, content_server=true),
398
- {"Content-Type" => "application/octet-stream"},
399
- file_obj)
400
-
401
- parse_response(response)
402
- end
403
-
404
- # Download a file
405
- #
406
- # Args:
407
- # * from_path: The path to the file to be downloaded
408
- # * rev: A previous revision value of the file to be downloaded
409
- #
410
- # Returns:
411
- # * The file contents.
412
- def get_file(from_path, rev=nil)
413
- response = get_file_impl(from_path, rev)
414
- parse_response(response, raw=true)
415
- end
416
-
417
- # Download a file and get its metadata.
418
- #
419
- # Args:
420
- # * from_path: The path to the file to be downloaded
421
- # * rev: A previous revision value of the file to be downloaded
422
- #
423
- # Returns:
424
- # * The file contents.
425
- # * The file metadata as a hash.
426
- def get_file_and_metadata(from_path, rev=nil)
427
- response = get_file_impl(from_path, rev)
428
- parsed_response = parse_response(response, raw=true)
429
- metadata = parse_metadata(response)
430
- return parsed_response, metadata
431
- end
432
-
433
- # Download a file (helper method - don't call this directly).
434
- #
435
- # Args:
436
- # * from_path: The path to the file to be downloaded
437
- # * rev: A previous revision value of the file to be downloaded
438
- #
439
- # Returns:
440
- # * The HTTPResponse for the file download request.
441
- def get_file_impl(from_path, rev=nil) # :nodoc:
442
- params = {}
443
- params['rev'] = rev.to_s if rev
444
-
445
- path = "/files/#{@root}#{format_path(from_path)}"
446
- @session.do_get build_url(path, params, content_server=true)
447
- end
448
- private :get_file_impl
449
-
450
- # Parses out file metadata from a raw dropbox HTTP response.
451
- #
452
- # Args:
453
- # * dropbox_raw_response: The raw, unparsed HTTPResponse from Dropbox.
454
- #
455
- # Returns:
456
- # * The metadata of the file as a hash.
457
- def parse_metadata(dropbox_raw_response) # :nodoc:
458
- begin
459
- raw_metadata = dropbox_raw_response['x-dropbox-metadata']
460
- metadata = JSON.parse(raw_metadata)
461
- rescue
462
- raise DropboxError.new("Dropbox Server Error: x-dropbox-metadata=#{raw_metadata}",
463
- dropbox_raw_response)
464
- end
465
- return metadata
466
- end
467
- private :parse_metadata
468
-
469
- # Copy a file or folder to a new location.
470
- #
471
- # Arguments:
472
- # * from_path: The path to the file or folder to be copied.
473
- # * to_path: The destination path of the file or folder to be copied.
474
- # This parameter should include the destination filename (e.g.
475
- # from_path: '/test.txt', to_path: '/dir/test.txt'). If there's
476
- # already a file at the to_path, this copy will be renamed to
477
- # be unique.
478
- #
479
- # Returns:
480
- # * A hash with the metadata of the new copy of the file or folder.
481
- # For a detailed description of what this call returns, visit:
482
- # https://www.dropbox.com/developers/reference/api#fileops-copy
483
- def file_copy(from_path, to_path)
484
- params = {
485
- "root" => @root,
486
- "from_path" => format_path(from_path, false),
487
- "to_path" => format_path(to_path, false),
488
- }
489
- response = @session.do_post build_url("/fileops/copy", params)
490
- parse_response(response)
491
- end
492
-
493
- # Create a folder.
494
- #
495
- # Arguments:
496
- # * path: The path of the new folder.
497
- #
498
- # Returns:
499
- # * A hash with the metadata of the newly created folder.
500
- # For a detailed description of what this call returns, visit:
501
- # https://www.dropbox.com/developers/reference/api#fileops-create-folder
502
- def file_create_folder(path)
503
- params = {
504
- "root" => @root,
505
- "path" => format_path(path, false),
506
- }
507
- response = @session.do_post build_url("/fileops/create_folder", params)
508
-
509
- parse_response(response)
510
- end
511
-
512
- # Deletes a file
513
- #
514
- # Arguments:
515
- # * path: The path of the file to delete
516
- #
517
- # Returns:
518
- # * A Hash with the metadata of file just deleted.
519
- # For a detailed description of what this call returns, visit:
520
- # https://www.dropbox.com/developers/reference/api#fileops-delete
521
- def file_delete(path)
522
- params = {
523
- "root" => @root,
524
- "path" => format_path(path, false),
525
- }
526
- response = @session.do_post build_url("/fileops/delete", params)
527
- parse_response(response)
528
- end
529
-
530
- # Moves a file
531
- #
532
- # Arguments:
533
- # * from_path: The path of the file to be moved
534
- # * to_path: The destination path of the file or folder to be moved
535
- # If the file or folder already exists, it will be renamed to be unique.
536
- #
537
- # Returns:
538
- # * A Hash with the metadata of file or folder just moved.
539
- # For a detailed description of what this call returns, visit:
540
- # https://www.dropbox.com/developers/reference/api#fileops-delete
541
- def file_move(from_path, to_path)
542
- params = {
543
- "root" => @root,
544
- "from_path" => format_path(from_path, false),
545
- "to_path" => format_path(to_path, false),
546
- }
547
- response = @session.do_post build_url("/fileops/move", params)
548
- parse_response(response)
549
- end
550
-
551
- # Retrives metadata for a file or folder
552
- #
553
- # Arguments:
554
- # * path: The path to the file or folder.
555
- # * list: Whether to list all contained files (only applies when
556
- # path refers to a folder).
557
- # * file_limit: The maximum number of file entries to return within
558
- # a folder. If the number of files in the directory exceeds this
559
- # limit, an exception is raised. The server will return at max
560
- # 25,000 files within a folder.
561
- # * hash: Every directory listing has a hash parameter attached that
562
- # can then be passed back into this function later to save on
563
- # bandwidth. Rather than returning an unchanged folder's contents, if
564
- # the hash matches a DropboxNotModified exception is raised.
565
- # * rev: Optional. The revision of the file to retrieve the metadata for.
566
- # This parameter only applies for files. If omitted, you'll receive
567
- # the most recent revision metadata.
568
- # * include_deleted: Specifies whether to include deleted files in metadata results.
569
- #
570
- # Returns:
571
- # * A Hash object with the metadata of the file or folder (and contained files if
572
- # appropriate). For a detailed description of what this call returns, visit:
573
- # https://www.dropbox.com/developers/reference/api#metadata
574
- def metadata(path, file_limit=25000, list=true, hash=nil, rev=nil, include_deleted=false)
575
- params = {
576
- "file_limit" => file_limit.to_s,
577
- "list" => list.to_s,
578
- "include_deleted" => include_deleted.to_s
579
- }
580
-
581
- params["hash"] = hash if hash
582
- params["rev"] = rev if rev
583
-
584
- response = @session.do_get build_url("/metadata/#{@root}#{format_path(path)}", params=params)
585
- if response.kind_of? Net::HTTPRedirection
586
- raise DropboxNotModified.new("metadata not modified")
587
- end
588
- parse_response(response)
589
- end
590
-
591
- # Search directory for filenames matching query
592
- #
593
- # Arguments:
594
- # * path: The directory to search within
595
- # * query: The query to search on (3 character minimum)
596
- # * file_limit: The maximum number of file entries to return/
597
- # If the number of files exceeds this
598
- # limit, an exception is raised. The server will return at max 1,000
599
- # * include_deleted: Whether to include deleted files in search results
600
- #
601
- # Returns:
602
- # * A Hash object with a list the metadata of the file or folders matching query
603
- # inside path. For a detailed description of what this call returns, visit:
604
- # https://www.dropbox.com/developers/reference/api#search
605
- def search(path, query, file_limit=1000, include_deleted=false)
606
- params = {
607
- 'query' => query,
608
- 'file_limit' => file_limit.to_s,
609
- 'include_deleted' => include_deleted.to_s
610
- }
611
-
612
- response = @session.do_get build_url("/search/#{@root}#{format_path(path)}", params)
613
- parse_response(response)
614
- end
615
-
616
- # Retrive revisions of a file
617
- #
618
- # Arguments:
619
- # * path: The file to fetch revisions for. Note that revisions
620
- # are not available for folders.
621
- # * rev_limit: The maximum number of file entries to return within
622
- # a folder. The server will return at max 1,000 revisions.
623
- #
624
- # Returns:
625
- # * A Hash object with a list of the metadata of the all the revisions of
626
- # all matches files (up to rev_limit entries)
627
- # For a detailed description of what this call returns, visit:
628
- # https://www.dropbox.com/developers/reference/api#revisions
629
- def revisions(path, rev_limit=1000)
630
-
631
- params = {
632
- 'rev_limit' => rev_limit.to_s
633
- }
634
-
635
- response = @session.do_get build_url("/revisions/#{@root}#{format_path(path)}", params)
636
- parse_response(response)
637
-
638
- end
639
-
640
- # Restore a file to a previous revision.
641
- #
642
- # Arguments:
643
- # * path: The file to restore. Note that folders can't be restored.
644
- # * rev: A previous rev value of the file to be restored to.
645
- #
646
- # Returns:
647
- # * A Hash object with a list the metadata of the file or folders restored
648
- # For a detailed description of what this call returns, visit:
649
- # https://www.dropbox.com/developers/reference/api#search
650
- def restore(path, rev)
651
- params = {
652
- 'rev' => rev.to_s
653
- }
654
-
655
- response = @session.do_post build_url("/restore/#{@root}#{format_path(path)}", params)
656
- parse_response(response)
657
- end
658
-
659
- # Returns a direct link to a media file
660
- # All of Dropbox's API methods require OAuth, which may cause problems in
661
- # situations where an application expects to be able to hit a URL multiple times
662
- # (for example, a media player seeking around a video file). This method
663
- # creates a time-limited URL that can be accessed without any authentication.
664
- #
665
- # Arguments:
666
- # * path: The file to stream.
667
- #
668
- # Returns:
669
- # * A Hash object that looks like the following:
670
- # {'url': 'https://dl.dropbox.com/0/view/wvxv1fw6on24qw7/file.mov', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'}
671
- def media(path)
672
- response = @session.do_get build_url("/media/#{@root}#{format_path(path)}")
673
- parse_response(response)
674
- end
675
-
676
- # Get a URL to share a media file
677
- # Shareable links created on Dropbox are time-limited, but don't require any
678
- # authentication, so they can be given out freely. The time limit should allow
679
- # at least a day of shareability, though users have the ability to disable
680
- # a link from their account if they like.
681
- #
682
- # Arguments:
683
- # * path: The file to share.
684
- #
685
- # Returns:
686
- # * A Hash object that looks like the following example:
687
- # {'url': 'http://www.dropbox.com/s/m/a2mbDa2', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'}
688
- # For a detailed description of what this call returns, visit:
689
- # https://www.dropbox.com/developers/reference/api#shares
690
- def shares(path)
691
- response = @session.do_get build_url("/shares/#{@root}#{format_path(path)}")
692
- parse_response(response)
693
- end
694
-
695
- # Download a thumbnail for an image.
696
- #
697
- # Arguments:
698
- # * from_path: The path to the file to be thumbnailed.
699
- # * size: A string describing the desired thumbnail size. At this time,
700
- # 'small', 'medium', and 'large' are officially supported sizes
701
- # (32x32, 64x64, and 128x128 respectively), though others may
702
- # be available. Check https://www.dropbox.com/developers/reference/api#thumbnails
703
- # for more details. [defaults to large]
704
- # Returns:
705
- # * The thumbnail data
706
- def thumbnail(from_path, size='large')
707
- response = thumbnail_impl(from_path, size)
708
- parse_response(response, raw=true)
709
- end
710
-
711
- # Download a thumbnail for an image alongwith the image's metadata.
712
- #
713
- # Arguments:
714
- # * from_path: The path to the file to be thumbnailed.
715
- # * size: A string describing the desired thumbnail size. See thumbnail()
716
- # for details.
717
- # Returns:
718
- # * The thumbnail data
719
- # * The metadata for the image as a hash
720
- def thumbnail_and_metadata(from_path, size='large')
721
- response = thumbnail_impl(from_path, size)
722
- parsed_response = parse_response(response, raw=true)
723
- metadata = parse_metadata(response)
724
- return parsed_response, metadata
725
- end
726
-
727
- # A way of letting you keep a local representation of the Dropbox folder
728
- # heirarchy. You can periodically call delta() to get a list of "delta
729
- # entries", which are instructions on how to update your local state to
730
- # match the server's state.
731
- #
732
- # Arguments:
733
- # * +cursor+: On the first call, omit this argument (or pass in +nil+). On
734
- # subsequent calls, pass in the +cursor+ string returned by the previous
735
- # call.
736
- #
737
- # Returns: A hash with three fields.
738
- # * +entries+: A list of "delta entries" (described below)
739
- # * +reset+: If +true+, you should reset local state to be an empty folder
740
- # before processing the list of delta entries. This is only +true+ only
741
- # in rare situations.
742
- # * +cursor+: A string that is used to keep track of your current state.
743
- # On the next call to delta(), pass in this value to return entries
744
- # that were recorded since the cursor was returned.
745
- # * +has_more+: If +true+, then there are more entries available; you can
746
- # call delta() again immediately to retrieve those entries. If +false+,
747
- # then wait at least 5 minutes (preferably longer) before checking again.
748
- #
749
- # Delta Entries: Each entry is a 2-item list of one of following forms:
750
- # * [_path_, _metadata_]: Indicates that there is a file/folder at the given
751
- # path. You should add the entry to your local state. (The _metadata_
752
- # value is the same as what would be returned by the #metadata() call.)
753
- # * If the path refers to parent folders that don't yet exist in your
754
- # local state, create those parent folders in your local state. You
755
- # will eventually get entries for those parent folders.
756
- # * If the new entry is a file, replace whatever your local state has at
757
- # _path_ with the new entry.
758
- # * If the new entry is a folder, check what your local state has at
759
- # _path_. If it's a file, replace it with the new entry. If it's a
760
- # folder, apply the new _metadata_ to the folder, but do not modify
761
- # the folder's children.
762
- # * [path, +nil+]: Indicates that there is no file/folder at the _path_ on
763
- # Dropbox. To update your local state to match, delete whatever is at
764
- # _path_, including any children (you will sometimes also get separate
765
- # delta entries for each child, but this is not guaranteed). If your
766
- # local state doesn't have anything at _path_, ignore this entry.
767
- #
768
- # Remember: Dropbox treats file names in a case-insensitive but case-preserving
769
- # way. To facilitate this, the _path_ strings above are lower-cased versions of
770
- # the actual path. The _metadata_ dicts have the original, case-preserved path.
771
- def delta(cursor=nil)
772
- params = {}
773
- if cursor
774
- params['cursor'] = cursor
775
- end
776
-
777
- response = @session.do_post build_url("/delta", params)
778
- parse_response(response)
779
- end
780
-
781
- # Download a thumbnail (helper method - don't call this directly).
782
- #
783
- # Args:
784
- # * from_path: The path to the file to be thumbnailed.
785
- # * size: A string describing the desired thumbnail size. See thumbnail()
786
- # for details.
787
- #
788
- # Returns:
789
- # * The HTTPResponse for the thumbnail request.
790
- def thumbnail_impl(from_path, size='large') # :nodoc:
791
- from_path = format_path(from_path, false)
792
-
793
- raise DropboxError.new("size must be small medium or large. (not '#{size})") unless ['small','medium','large'].include?(size)
794
-
795
- params = {
796
- "size" => size
797
- }
798
-
799
- url = build_url("/thumbnails/#{@root}#{from_path}", params, content_server=true)
800
-
801
- @session.do_get url
802
- end
803
- private :thumbnail_impl
804
-
805
-
806
- # Creates and returns a copy ref for a specific file. The copy ref can be
807
- # used to instantly copy that file to the Dropbox of another account.
808
- #
809
- # Args:
810
- # * path: The path to the file for a copy ref to be created on.
811
- #
812
- # Returns:
813
- # * A Hash object that looks like the following example:
814
- # {"expires"=>"Fri, 31 Jan 2042 21:01:05 +0000", "copy_ref"=>"z1X6ATl6aWtzOGq0c3g5Ng"}
815
- def create_copy_ref(path)
816
- path = "/copy_ref/#{@root}#{format_path(path)}"
817
-
818
- response = @session.do_get(build_url(path, {}))
819
-
820
- parse_response(response)
821
- end
822
-
823
- # Adds the file referenced by the copy ref to the specified path
824
- #
825
- # Args:
826
- # * copy_ref: A copy ref string that was returned from a create_copy_ref call.
827
- # The copy_ref can be created from any other Dropbox account, or from the same account.
828
- # * to_path: The path to where the file will be created.
829
- #
830
- # Returns:
831
- # * A hash with the metadata of the new file.
832
- def add_copy_ref(to_path, copy_ref)
833
- path = "/fileops/copy"
834
-
835
- params = {'from_copy_ref' => copy_ref,
836
- 'to_path' => "#{format_path(to_path)}",
837
- 'root' => @root}
838
-
839
- response = @session.do_post(build_url(path, params))
840
-
841
- parse_response(response)
842
- end
843
-
844
- def build_url(url, params=nil, content_server=false) # :nodoc:
845
- port = 443
846
- host = content_server ? Dropbox::API_CONTENT_SERVER : Dropbox::API_SERVER
847
- versioned_url = "/#{Dropbox::API_VERSION}#{url}"
848
-
849
- target = URI::Generic.new("https", nil, host, port, nil, versioned_url, nil, nil, nil)
850
-
851
- #add a locale param if we have one
852
- #initialize a params object is we don't have one
853
- if @locale
854
- (params ||= {})['locale']=@locale
855
- end
856
-
857
- if params
858
- target.query = params.collect {|k,v|
859
- CGI.escape(k) + "=" + CGI.escape(v)
860
- }.join("&")
861
- end
862
-
863
- target.to_s
864
- end
865
-
866
- #From the oauth spec plus "/". Slash should not be ecsaped
867
- RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~\/]/
868
-
869
- def format_path(path, escape=true) # :nodoc:
870
- path = path.gsub(/\/+/,"/")
871
- # replace multiple slashes with a single one
872
-
873
- path = path.gsub(/^\/?/,"/")
874
- # ensure the path starts with a slash
875
-
876
- path.gsub(/\/?$/,"")
877
- # ensure the path doesn't end with a slash
878
-
879
- return URI.escape(path, RESERVED_CHARACTERS) if escape
880
- path
881
- end
882
-
883
- end