lib/dropbox_sdk.rb in dropbox-sdk-1.6.1 vs lib/dropbox_sdk.rb in dropbox-sdk-1.6.2

- old
+ new

@@ -12,14 +12,28 @@ API_SERVER = "api.dropbox.com" API_CONTENT_SERVER = "api-content.dropbox.com" WEB_SERVER = "www.dropbox.com" API_VERSION = 1 - SDK_VERSION = "1.6.1" + SDK_VERSION = "1.6.2" TRUSTED_CERT_FILE = File.join(File.dirname(__FILE__), 'trusted-certs.crt') + def self.clean_params(params) + r = {} + params.each do |k,v| + r[k] = v.to_s if not v.nil? + end + r + end + + def self.make_query_string(params) + clean_params(params).collect {|k,v| + CGI.escape(k) + "=" + CGI.escape(v) + }.join("&") + end + def self.do_http(uri, request) # :nodoc: http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -79,32 +93,52 @@ end end class DropboxSessionBase # :nodoc: + attr_writer :locale + + def initialize(locale) + @locale = locale + end + + private + + def build_url(path, content_server) + port = 443 + host = content_server ? Dropbox::API_CONTENT_SERVER : Dropbox::API_SERVER + full_path = "/#{Dropbox::API_VERSION}#{path}" + return URI::HTTPS.build({:host => host, :path => full_path}) + end + + def build_url_with_params(path, params, content_server) # :nodoc: + target = build_url(path, content_server) + params['locale'] = @locale + target.query = Dropbox::make_query_string(params) + return target + end + protected def do_http(uri, request) # :nodoc: sign_request(request) Dropbox::do_http(uri, request) end public - def do_get(url, headers=nil) # :nodoc: + def do_get(path, params=nil, headers=nil, content_server=false) # :nodoc: + params ||= {} assert_authorized - uri = URI.parse(url) - request = Net::HTTP::Get.new(uri.request_uri) - do_http(uri, request) + uri = build_url_with_params(path, params, content_server) + do_http(uri, Net::HTTP::Get.new(uri.request_uri)) end def do_http_with_body(uri, request, body) if body != nil if body.is_a?(Hash) - form_data = {} - body.each {|k,v| form_data[k.to_s] = v if !v.nil?} - request.set_form_data(form_data) + request.set_form_data(Dropbox::clean_params(body)) elsif body.respond_to?(:read) if body.respond_to?(:length) request["Content-Length"] = body.length.to_s elsif body.respond_to?(:stat) && body.stat.respond_to?(:size) request["Content-Length"] = body.stat.size.to_s @@ -119,19 +153,22 @@ end end do_http(uri, request) end - def do_post(url, headers=nil, body=nil) # :nodoc: + def do_post(path, params=nil, headers=nil, content_server=false) # :nodoc: + params ||= {} assert_authorized - uri = URI.parse(url) - do_http_with_body(uri, Net::HTTP::Post.new(uri.request_uri, headers), body) + uri = build_url(path, content_server) + params['locale'] = @locale + do_http_with_body(uri, Net::HTTP::Post.new(uri.request_uri, headers), params) end - def do_put(url, headers=nil, body=nil) # :nodoc: + def do_put(path, params=nil, headers=nil, body=nil, content_server=false) # :nodoc: + params ||= {} assert_authorized - uri = URI.parse(url) + uri = build_url_with_params(path, params, content_server) do_http_with_body(uri, Net::HTTP::Put.new(uri.request_uri, headers), body) end end # DropboxSession is responsible for holding OAuth 1 information. It knows how to take your consumer key and secret @@ -139,11 +176,12 @@ # DropboxClient after its been authorized. class DropboxSession < DropboxSessionBase # :nodoc: # * consumer_key - Your Dropbox application's "app key". # * consumer_secret - Your Dropbox application's "app secret". - def initialize(consumer_key, consumer_secret) + def initialize(consumer_key, consumer_secret, locale=nil) + super(locale) @consumer_key = consumer_key @consumer_secret = consumer_secret @request_token = nil @access_token = nil end @@ -302,11 +340,13 @@ end end class DropboxOAuth2Session < DropboxSessionBase # :nodoc: - def initialize(oauth2_access_token) + + def initialize(oauth2_access_token, locale=nil) + super(locale) if not oauth2_access_token.is_a?(String) raise "bad type for oauth2_access_token (expecting String)" end @access_token = oauth2_access_token end @@ -338,30 +378,24 @@ @consumer_secret = consumer_secret @locale = locale end def _get_authorize_url(redirect_uri, state) - params = {"client_id" => @consumer_key, "response_type" => "code"} - if not redirect_uri.nil? - params["redirect_uri"] = redirect_uri - end - if not state.nil? - params["state"] = state - end - if not @locale.nil? - params['locale'] = @locale - end + params = { + "client_id" => @consumer_key, + "response_type" => "code", + "redirect_uri" => redirect_uri, + "state" => state, + "locale" => @locale, + } host = Dropbox::WEB_SERVER path = "/#{Dropbox::API_VERSION}/oauth2/authorize" target = URI::Generic.new("https", nil, host, nil, nil, path, nil, nil, nil) + target.query = Dropbox::make_query_string(params) - target.query = params.collect {|k,v| - CGI.escape(k) + "=" + CGI.escape(v) - }.join("&") - target.to_s end # Finish the OAuth 2 authorization process. If you used a redirect_uri, pass that in. # Will return an access token string that you can use with DropboxClient. @@ -376,23 +410,16 @@ request.add_field('Authorization', 'Basic ' + Base64.encode64(client_credentials).chomp("\n")) params = { "grant_type" => "authorization_code", "code" => code, + "redirect_uri" => original_redirect_uri, + "locale" => @locale, } - if not @locale.nil? - params['locale'] = @locale - end - if not original_redirect_uri.nil? - params['redirect_uri'] = original_redirect_uri - end + request.set_form_data(Dropbox::clean_params(params)) - form_data = {} - params.each {|k,v| form_data[k.to_s] = v if !v.nil?} - request.set_form_data(form_data) - response = Dropbox::do_http(uri, request) j = Dropbox::parse_response(response) ["token_type", "access_token", "uid"].each { |k| if not j.has_key?(k) @@ -651,14 +678,17 @@ # Args: # * +oauth2_access_token+: Obtained via DropboxOAuth2Flow or DropboxOAuth2FlowNoRedirect. # * +locale+: The user's current locale (used to localize error messages). def initialize(oauth2_access_token, root="auto", locale=nil) if oauth2_access_token.is_a?(String) - @session = DropboxOAuth2Session.new(oauth2_access_token) + @session = DropboxOAuth2Session.new(oauth2_access_token, locale) elsif oauth2_access_token.is_a?(DropboxSession) @session = oauth2_access_token @session.get_access_token + if not locale.nil? + @session.locale = locale + end else raise ArgumentError.new("oauth2_access_token doesn't have a valid type") end @root = root.to_s # If they passed in a symbol, make it a string @@ -669,21 +699,19 @@ if @root == "app_folder" #App Folder is the name of the access type, but for historical reasons #sandbox is the URL root component that indicates this @root = "sandbox" end - - @locale = locale end # Returns some information about the current user's Dropbox account (the "current user" # is the user associated with the access token you're using). # # For a detailed description of what this call returns, visit: # https://www.dropbox.com/developers/reference/api#account-info def account_info() - response = @session.do_get build_url("/account/info") + response = @session.do_get "/account/info" Dropbox::parse_response(response) end # Uploads a file to a server. This uses the HTTP PUT upload method for simplicity # @@ -718,21 +746,19 @@ # This will upload the "/tmp/test_file" from my computer into the root of my App's app folder # and call it "test_file_on_dropbox". # The file will not overwrite any pre-existing file. def put_file(to_path, file_obj, overwrite=false, parent_rev=nil) path = "/files_put/#{@root}#{format_path(to_path)}" - params = { - 'overwrite' => overwrite.to_s + 'overwrite' => overwrite.to_s, + 'parent_rev' => parent_rev, } - params['parent_rev'] = parent_rev unless parent_rev.nil? + headers = {"Content-Type" => "application/octet-stream"} + content_server = true + response = @session.do_put path, params, headers, file_obj, content_server - response = @session.do_put(build_url(path, params, content_server=true), - {"Content-Type" => "application/octet-stream"}, - file_obj) - Dropbox::parse_response(response) end # Returns a ChunkedUploader object. # @@ -817,24 +843,28 @@ Dropbox::parse_response(response) end end def commit_chunked_upload(to_path, upload_id, overwrite=false, parent_rev=nil) #:nodoc + path = "/commit_chunked_upload/#{@root}#{format_path(to_path)}" params = {'overwrite' => overwrite.to_s, 'upload_id' => upload_id, - 'parent_rev' => parent_rev.to_s, + 'parent_rev' => parent_rev, } - @session.do_post(build_url("/commit_chunked_upload/#{@root}#{format_path(to_path)}", params, content_server=true)) + headers = nil + content_server = true + @session.do_post path, params, headers, content_server end def partial_chunked_upload(data, upload_id=nil, offset=nil) #:nodoc - params = {} - params['upload_id'] = upload_id.to_s if upload_id - params['offset'] = offset.to_s if offset - @session.do_put(build_url('/chunked_upload', params, content_server=true), - {'Content-Type' => "application/octet-stream"}, - data) + params = { + 'upload_id' => upload_id, + 'offset' => offset, + } + headers = {'Content-Type' => "application/octet-stream"} + content_server = true + @session.do_put '/chunked_upload', params, headers, data, content_server end # Download a file # # Args: @@ -871,15 +901,17 @@ # * +rev+: A previous revision value of the file to be downloaded # # Returns: # * The HTTPResponse for the file download request. def get_file_impl(from_path, rev=nil) # :nodoc: - params = {} - params['rev'] = rev.to_s if rev - path = "/files/#{@root}#{format_path(from_path)}" - @session.do_get build_url(path, params, content_server=true) + params = { + 'rev' => rev, + } + headers = nil + content_server = true + @session.do_get path, params, headers, content_server end private :get_file_impl # Parses out file metadata from a raw dropbox HTTP response. # @@ -918,11 +950,11 @@ params = { "root" => @root, "from_path" => format_path(from_path, false), "to_path" => format_path(to_path, false), } - response = @session.do_post build_url("/fileops/copy", params) + response = @session.do_post "/fileops/copy", params Dropbox::parse_response(response) end # Create a folder. # @@ -936,11 +968,11 @@ def file_create_folder(path) params = { "root" => @root, "path" => format_path(path, false), } - response = @session.do_post build_url("/fileops/create_folder", params) + response = @session.do_post "/fileops/create_folder", params Dropbox::parse_response(response) end # Deletes a file @@ -955,11 +987,11 @@ def file_delete(path) params = { "root" => @root, "path" => format_path(path, false), } - response = @session.do_post build_url("/fileops/delete", params) + response = @session.do_post "/fileops/delete", params Dropbox::parse_response(response) end # Moves a file # @@ -976,11 +1008,11 @@ params = { "root" => @root, "from_path" => format_path(from_path, false), "to_path" => format_path(to_path, false), } - response = @session.do_post build_url("/fileops/move", params) + response = @session.do_post "/fileops/move", params Dropbox::parse_response(response) end # Retrives metadata for a file or folder # @@ -1007,19 +1039,18 @@ # https://www.dropbox.com/developers/reference/api#metadata def metadata(path, file_limit=25000, list=true, hash=nil, rev=nil, include_deleted=false) params = { "file_limit" => file_limit.to_s, "list" => list.to_s, - "include_deleted" => include_deleted.to_s + "include_deleted" => include_deleted.to_s, + "hash" => hash, + "rev" => rev, } - params["hash"] = hash if hash - params["rev"] = rev if rev - - response = @session.do_get build_url("/metadata/#{@root}#{format_path(path)}", params=params) + response = @session.do_get "/metadata/#{@root}#{format_path(path)}", params if response.kind_of? Net::HTTPRedirection - raise DropboxNotModified.new("metadata not modified") + raise DropboxNotModified.new("metadata not modified") end Dropbox::parse_response(response) end # Search directory for filenames matching query @@ -1041,11 +1072,11 @@ 'query' => query, 'file_limit' => file_limit.to_s, 'include_deleted' => include_deleted.to_s } - response = @session.do_get build_url("/search/#{@root}#{format_path(path)}", params) + response = @session.do_get "/search/#{@root}#{format_path(path)}", params Dropbox::parse_response(response) end # Retrive revisions of a file # @@ -1059,18 +1090,16 @@ # * A Hash object with a list of the metadata of the all the revisions of # all matches files (up to rev_limit entries) # For a detailed description of what this call returns, visit: # https://www.dropbox.com/developers/reference/api#revisions def revisions(path, rev_limit=1000) - params = { 'rev_limit' => rev_limit.to_s } - response = @session.do_get build_url("/revisions/#{@root}#{format_path(path)}", params) + response = @session.do_get "/revisions/#{@root}#{format_path(path)}", params Dropbox::parse_response(response) - end # Restore a file to a previous revision. # # Arguments: @@ -1084,11 +1113,11 @@ def restore(path, rev) params = { 'rev' => rev.to_s } - response = @session.do_post build_url("/restore/#{@root}#{format_path(path)}", params) + response = @session.do_post "/restore/#{@root}#{format_path(path)}", params Dropbox::parse_response(response) end # Returns a direct link to a media file # All of Dropbox's API methods require OAuth, which may cause problems in @@ -1099,13 +1128,13 @@ # Arguments: # * path: The file to stream. # # Returns: # * A Hash object that looks like the following: - # {'url': 'https://dl.dropbox.com/0/view/wvxv1fw6on24qw7/file.mov', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'} + # {'url': 'https://dl.dropboxusercontent.com/1/view/abcdefghijk/example', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'} def media(path) - response = @session.do_get build_url("/media/#{@root}#{format_path(path)}") + response = @session.do_get "/media/#{@root}#{format_path(path)}" Dropbox::parse_response(response) end # Get a URL to share a media file # Shareable links created on Dropbox are time-limited, but don't require any @@ -1116,15 +1145,15 @@ # Arguments: # * path: The file to share. # # Returns: # * A Hash object that looks like the following example: - # {'url': 'http://www.dropbox.com/s/m/a2mbDa2', 'expires': 'Thu, 16 Sep 2011 01:01:25 +0000'} + # {'url': 'https://db.tt/c0mFuu1Y', 'expires': 'Tue, 01 Jan 2030 00:00:00 +0000'} # For a detailed description of what this call returns, visit: # https://www.dropbox.com/developers/reference/api#shares def shares(path) - response = @session.do_get build_url("/shares/#{@root}#{format_path(path)}") + response = @session.do_get "/shares/#{@root}#{format_path(path)}" Dropbox::parse_response(response) end # Download a thumbnail for an image. # @@ -1201,16 +1230,15 @@ # # Remember: Dropbox treats file names in a case-insensitive but case-preserving # way. To facilitate this, the _path_ strings above are lower-cased versions of # the actual path. The _metadata_ dicts have the original, case-preserved path. def delta(cursor=nil) - params = {} - if cursor - params['cursor'] = cursor - end + params = { + 'cursor' => cursor, + } - response = @session.do_post build_url("/delta", params) + response = @session.do_post "/delta", params Dropbox::parse_response(response) end # Download a thumbnail (helper method - don't call this directly). # @@ -1220,19 +1248,17 @@ # for details. # # Returns: # * The HTTPResponse for the thumbnail request. def thumbnail_impl(from_path, size='large') # :nodoc: - from_path = format_path(from_path, true) - + path = "/thumbnails/#{@root}#{format_path(from_path, true)}" params = { "size" => size } - - url = build_url("/thumbnails/#{@root}#{from_path}", params, content_server=true) - - @session.do_get url + headers = nil + content_server = true + @session.do_get path, params, headers, content_server end private :thumbnail_impl # Creates and returns a copy ref for a specific file. The copy ref can be @@ -1244,13 +1270,11 @@ # Returns: # * A Hash object that looks like the following example: # {"expires"=>"Fri, 31 Jan 2042 21:01:05 +0000", "copy_ref"=>"z1X6ATl6aWtzOGq0c3g5Ng"} def create_copy_ref(path) path = "/copy_ref/#{@root}#{format_path(path)}" - - response = @session.do_get(build_url(path, {})) - + response = @session.do_get path Dropbox::parse_response(response) end # Adds the file referenced by the copy ref to the specified path # @@ -1260,40 +1284,15 @@ # * +to_path+: The path to where the file will be created. # # Returns: # * A hash with the metadata of the new file. def add_copy_ref(to_path, copy_ref) - path = "/fileops/copy" - params = {'from_copy_ref' => copy_ref, 'to_path' => "#{to_path}", 'root' => @root} - response = @session.do_post(build_url(path, params)) - + response = @session.do_post "/fileops/copy", params Dropbox::parse_response(response) - end - - def build_url(url, params=nil, content_server=false) # :nodoc: - port = 443 - host = content_server ? Dropbox::API_CONTENT_SERVER : Dropbox::API_SERVER - versioned_url = "/#{Dropbox::API_VERSION}#{url}" - - target = URI::Generic.new("https", nil, host, port, nil, versioned_url, nil, nil, nil) - - #add a locale param if we have one - #initialize a params object is we don't have one - if @locale - (params ||= {})['locale']=@locale - end - - if params - target.query = params.collect {|k,v| - CGI.escape(k) + "=" + CGI.escape(v) - }.join("&") - end - - target.to_s end #From the oauth spec plus "/". Slash should not be ecsaped RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~\/]/ # :nodoc: