mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-07-20 18:18:56 +00:00
1270 lines
54 KiB
CoffeeScript
1270 lines
54 KiB
CoffeeScript
# Represents a user accessing the application.
|
|
class Dropbox.Client
|
|
# Dropbox client representing an application.
|
|
#
|
|
# For an optimal user experience, applications should use a single client for
|
|
# all Dropbox interactions.
|
|
#
|
|
# @param {Object} options the application type and API key
|
|
# @option options {Boolean} sandbox true for applications that request
|
|
# sandbox access (access to a single folder exclusive to the app)
|
|
# @option options {String} key the Dropbox application's key; browser-side
|
|
# applications should use Dropbox.encodeKey to obtain an encoded
|
|
# key string, and pass it as the key option
|
|
# @option options {String} secret the Dropbox application's secret;
|
|
# browser-side applications should not use the secret option; instead,
|
|
# they should pass the result of Dropbox.encodeKey as the key option
|
|
# @option options {String} token if set, the user's access token
|
|
# @option options {String} tokenSecret if set, the secret for the user's
|
|
# access token
|
|
# @option options {String} uid if set, the user's Dropbox UID
|
|
# @option options {Number} authState if set, indicates that the token and
|
|
# tokenSecret are in an intermediate state in the authentication process;
|
|
# this option should never be set by hand, however it may be returned by
|
|
# calls to credentials()
|
|
constructor: (options) ->
|
|
@sandbox = options.sandbox or false
|
|
@apiServer = options.server or @defaultApiServer()
|
|
@authServer = options.authServer or @defaultAuthServer()
|
|
@fileServer = options.fileServer or @defaultFileServer()
|
|
@downloadServer = options.downloadServer or @defaultDownloadServer()
|
|
|
|
@onXhr = new Dropbox.EventSource cancelable: true
|
|
@onError = new Dropbox.EventSource
|
|
@onAuthStateChange = new Dropbox.EventSource
|
|
|
|
@oauth = new Dropbox.Oauth options
|
|
@driver = null
|
|
@filter = null
|
|
@uid = null
|
|
@authState = null
|
|
@authError = null
|
|
@_credentials = null
|
|
@setCredentials options
|
|
|
|
@setupUrls()
|
|
|
|
# Plugs in the OAuth / application integration code.
|
|
#
|
|
# @param {DropboxAuthDriver} driver provides the integration between the
|
|
# application and the Dropbox OAuth flow; most applications should be
|
|
# able to use instances of Dropbox.Driver.Redirect, Dropbox.Driver.Popup,
|
|
# or Dropbox.Driver.NodeServer
|
|
# @return {Dropbox.Client} this, for easy call chaining
|
|
authDriver: (driver) ->
|
|
@driver = driver
|
|
@
|
|
|
|
# @property {Dropbox.EventSource<Dropbox.Xhr>} cancelable event fired every
|
|
# time when a network request to the Dropbox API server is about to be
|
|
# sent; if the event is canceled by returning a falsey value from a
|
|
# listener, the network request is silently discarded; whenever possible,
|
|
# listeners should restrict themselves to using the xhr property of the
|
|
# Dropbox.Xhr instance passed to them; everything else in the Dropbox.Xhr
|
|
# API is in flux
|
|
onXhr: null
|
|
|
|
# @property {Dropbox.EventSource<Dropbox.ApiError>} non-cancelable event
|
|
# fired every time when a network request to the Dropbox API server results
|
|
# in an error
|
|
onError: null
|
|
|
|
# @property {Dropbox.EventSource<Dropbox.Client>} non-cancelable event fired
|
|
# every time the authState property changes; this can be used to update UI
|
|
# state
|
|
onAuthStateChange: null
|
|
|
|
# The authenticated user's Dropbx user ID.
|
|
#
|
|
# This user ID is guaranteed to be consistent across API calls from the same
|
|
# application (not across applications, though).
|
|
#
|
|
# @return {?String} a short ID that identifies the user, or null if no user
|
|
# is authenticated
|
|
dropboxUid: ->
|
|
@uid
|
|
|
|
# Get the client's OAuth credentials.
|
|
#
|
|
# @param {?Object} the result of a prior call to credentials()
|
|
# @return {Object} a plain object whose properties can be passed to the
|
|
# Dropbox.Client constructor to reuse this client's login credentials
|
|
credentials: () ->
|
|
@computeCredentials() unless @_credentials
|
|
@_credentials
|
|
|
|
# Authenticates the app's user to Dropbox' API server.
|
|
#
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Client)} callback called when
|
|
# the authentication completes; if successful, the second parameter is
|
|
# this client and the first parameter is null
|
|
# @return {Dropbox.Client} this, for easy call chaining
|
|
authenticate: (callback) ->
|
|
oldAuthState = null
|
|
|
|
unless @driver or @authState is DropboxClient.DONE
|
|
throw new Error "Call authDriver to set an authentication driver"
|
|
|
|
# Advances the authentication FSM by one step.
|
|
_fsmStep = =>
|
|
if oldAuthState isnt @authState
|
|
if oldAuthState isnt null
|
|
@onAuthStateChange.dispatch @
|
|
oldAuthState = @authState
|
|
if @driver and @driver.onAuthStateChange
|
|
return @driver.onAuthStateChange(@, _fsmStep)
|
|
|
|
switch @authState
|
|
when DropboxClient.RESET # No user credentials -> request token.
|
|
@requestToken (error, data) =>
|
|
if error
|
|
@authError = error
|
|
@authState = DropboxClient.ERROR
|
|
else
|
|
token = data.oauth_token
|
|
tokenSecret = data.oauth_token_secret
|
|
@oauth.setToken token, tokenSecret
|
|
@authState = DropboxClient.REQUEST
|
|
@_credentials = null
|
|
_fsmStep()
|
|
|
|
when DropboxClient.REQUEST # Have request token, get it authorized.
|
|
authUrl = @authorizeUrl @oauth.token
|
|
@driver.doAuthorize authUrl, @oauth.token, @oauth.tokenSecret, =>
|
|
@authState = DropboxClient.AUTHORIZED
|
|
@_credentials = null
|
|
_fsmStep()
|
|
|
|
when DropboxClient.AUTHORIZED
|
|
# Request token authorized, switch it for an access token.
|
|
@getAccessToken (error, data) =>
|
|
if error
|
|
@authError = error
|
|
@authState = DropboxClient.ERROR
|
|
else
|
|
@oauth.setToken data.oauth_token, data.oauth_token_secret
|
|
@uid = data.uid
|
|
@authState = DropboxClient.DONE
|
|
@_credentials = null
|
|
_fsmStep()
|
|
|
|
when DropboxClient.DONE # We have an access token.
|
|
callback null, @
|
|
|
|
when DropboxClient.SIGNED_OFF # The user signed off, restart the flow.
|
|
# The authState change makes reset() not trigger onAuthStateChange.
|
|
@authState = DropboxClient.RESET
|
|
@reset()
|
|
_fsmStep()
|
|
|
|
when DropboxClient.ERROR # An error occurred during authentication.
|
|
callback @authError
|
|
|
|
_fsmStep() # Start up the state machine.
|
|
@
|
|
|
|
# @return {Boolean} true if this client is authenticated, false otherwise
|
|
isAuthenticated: ->
|
|
@authState is DropboxClient.DONE
|
|
|
|
# Revokes the user's Dropbox credentials.
|
|
#
|
|
# This should be called when the user explictly signs off from your
|
|
# application, to meet the users' expectation that after they sign off, their
|
|
# access tokens will be persisted on the machine.
|
|
#
|
|
# @param {function(?Dropbox.ApiError)} callback called when
|
|
# the authentication completes; if successful, the error parameter is
|
|
# null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
signOut: (callback) ->
|
|
xhr = new Dropbox.Xhr 'POST', @urls.signOut
|
|
xhr.signWithOauth @oauth
|
|
@dispatchXhr xhr, (error) =>
|
|
return callback(error) if error
|
|
|
|
# The authState change makes reset() not trigger onAuthStateChange.
|
|
@authState = DropboxClient.RESET
|
|
@reset()
|
|
@authState = DropboxClient.SIGNED_OFF
|
|
@onAuthStateChange.dispatch @
|
|
if @driver.onAuthStateChange
|
|
@driver.onAuthStateChange @, ->
|
|
callback error
|
|
else
|
|
callback error
|
|
|
|
# Alias for signOut.
|
|
signOff: (callback) ->
|
|
@signOut callback
|
|
|
|
# Retrieves information about the logged in user.
|
|
#
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.UserInfo, ?Object)} callback
|
|
# called with the result of the /account/info HTTP request; if the call
|
|
# succeeds, the second parameter is a Dropbox.UserInfo instance, the
|
|
# third parameter is the parsed JSON data behind the Dropbox.UserInfo
|
|
# instance, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
getUserInfo: (options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
httpCache = false
|
|
if options and options.httpCache
|
|
httpCache = true
|
|
|
|
xhr = new Dropbox.Xhr 'GET', @urls.accountInfo
|
|
xhr.signWithOauth @oauth, httpCache
|
|
@dispatchXhr xhr, (error, userData) ->
|
|
callback error, Dropbox.UserInfo.parse(userData), userData
|
|
|
|
# Retrieves the contents of a file stored in Dropbox.
|
|
#
|
|
# Some options are silently ignored in Internet Explorer 9 and below, due to
|
|
# insufficient support in its proprietary XDomainRequest replacement for XHR.
|
|
# Currently, the options are: arrayBuffer, blob, length, start.
|
|
#
|
|
# @param {String} path the path of the file to be read, relative to the
|
|
# user's Dropbox or to the application's folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {String} versionTag the tag string for the desired version
|
|
# of the file contents; the most recent version is retrieved by default
|
|
# @option options {String} rev alias for "versionTag" that matches the HTTP
|
|
# API
|
|
# @option options {Boolean} arrayBuffer if true, the file's contents will be
|
|
# passed to the callback in an ArrayBuffer; this is the recommended method
|
|
# of reading non-UTF8 data such as images, as it is well supported across
|
|
# modern browsers; requires XHR Level 2 support, which is not available in
|
|
# IE <= 9
|
|
# @option options {Boolean} blob if true, the file's contents will be
|
|
# passed to the callback in a Blob; this is a good method of reading
|
|
# non-UTF8 data, such as images; requires XHR Level 2 support, which is not
|
|
# available in IE <= 9
|
|
# @option options {Boolean} binary if true, the file will be retrieved as a
|
|
# binary string; the default is an UTF-8 encoded string; this relies on
|
|
# hacks and should not be used if the environment supports XHR Level 2 API
|
|
# @option options {Number} length the number of bytes to be retrieved from
|
|
# the file; if the start option is not present, the last "length" bytes
|
|
# will be read (after issue #30 is closed); by default, the entire file is
|
|
# read
|
|
# @option options {Number} start the 0-based offset of the first byte to be
|
|
# retrieved; if the length option is not present, the bytes between
|
|
# "start" and the file's end will be read; by default, the entire
|
|
# file is read
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?String, ?Dropbox.Stat)} callback
|
|
# called with the result of the /files (GET) HTTP request; the second
|
|
# parameter is the contents of the file, the third parameter is a
|
|
# Dropbox.Stat instance describing the file, and the first parameter is
|
|
# null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
readFile: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = {}
|
|
responseType = null
|
|
rangeHeader = null
|
|
httpCache = false
|
|
if options
|
|
if options.versionTag
|
|
params.rev = options.versionTag
|
|
else if options.rev
|
|
params.rev = options.rev
|
|
|
|
if options.arrayBuffer
|
|
responseType = 'arraybuffer'
|
|
else if options.blob
|
|
responseType = 'blob'
|
|
else if options.binary
|
|
responseType = 'b' # See the Dropbox.Xhr.request2 docs
|
|
|
|
if options.length
|
|
if options.start?
|
|
rangeStart = options.start
|
|
rangeEnd = options.start + options.length - 1
|
|
else
|
|
rangeStart = ''
|
|
rangeEnd = options.length
|
|
rangeHeader = "bytes=#{rangeStart}-#{rangeEnd}"
|
|
else if options.start?
|
|
rangeHeader = "bytes=#{options.start}-"
|
|
|
|
httpCache = true if options.httpCache
|
|
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.getFile}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth(@oauth, httpCache)
|
|
xhr.setResponseType(responseType)
|
|
xhr.setHeader 'Range', rangeHeader if rangeHeader
|
|
@dispatchXhr xhr, (error, data, metadata) ->
|
|
callback error, data, Dropbox.Stat.parse(metadata)
|
|
|
|
# Store a file into a user's Dropbox.
|
|
#
|
|
# @param {String} path the path of the file to be created, relative to the
|
|
# user's Dropbox or to the application's folder
|
|
# @param {String, ArrayBuffer, ArrayBufferView, Blob, File} data the contents
|
|
# written to the file; if a File is passed, its name is ignored
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {String} lastVersionTag the identifier string for the
|
|
# version of the file's contents that was last read by this program, used
|
|
# for conflict resolution; for best results, use the versionTag attribute
|
|
# value from the Dropbox.Stat instance provided by readFile
|
|
# @option options {String} parentRev alias for "lastVersionTag" that matches
|
|
# the HTTP API
|
|
# @option options {Boolean} noOverwrite if set, the write will not overwrite
|
|
# a file with the same name that already exsits; instead the contents
|
|
# will be written to a similarly named file (e.g. "notes (1).txt"
|
|
# instead of "notes.txt")
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /files (POST) HTTP request; the second paramter is a
|
|
# Dropbox.Stat instance describing the newly created file, and the first
|
|
# parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
writeFile: (path, data, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
useForm = Dropbox.Xhr.canSendForms and typeof data is 'object'
|
|
if useForm
|
|
@writeFileUsingForm path, data, options, callback
|
|
else
|
|
@writeFileUsingPut path, data, options, callback
|
|
|
|
# writeFile implementation that uses the POST /files API.
|
|
#
|
|
# @private
|
|
# This method is more demanding in terms of CPU and browser support, but does
|
|
# not require CORS preflight, so it always completes in 1 HTTP request.
|
|
writeFileUsingForm: (path, data, options, callback) ->
|
|
# Break down the path into a file/folder name and the containing folder.
|
|
slashIndex = path.lastIndexOf '/'
|
|
if slashIndex is -1
|
|
fileName = path
|
|
path = ''
|
|
else
|
|
fileName = path.substring slashIndex
|
|
path = path.substring 0, slashIndex
|
|
|
|
params = { file: fileName }
|
|
if options
|
|
if options.noOverwrite
|
|
params.overwrite = 'false'
|
|
if options.lastVersionTag
|
|
params.parent_rev = options.lastVersionTag
|
|
else if options.parentRev or options.parent_rev
|
|
params.parent_rev = options.parentRev or options.parent_rev
|
|
# TODO: locale support would edit the params here
|
|
|
|
xhr = new Dropbox.Xhr 'POST', "#{@urls.postFile}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth(@oauth).setFileField('file', fileName,
|
|
data, 'application/octet-stream')
|
|
|
|
# NOTE: the Dropbox API docs ask us to replace the 'file' parameter after
|
|
# signing the request; the hack below works as intended
|
|
delete params.file
|
|
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# writeFile implementation that uses the /files_put API.
|
|
#
|
|
# @private
|
|
# This method is less demanding on CPU, and makes fewer assumptions about
|
|
# browser support, but it takes 2 HTTP requests for binary files, because it
|
|
# needs CORS preflight.
|
|
writeFileUsingPut: (path, data, options, callback) ->
|
|
params = {}
|
|
if options
|
|
if options.noOverwrite
|
|
params.overwrite = 'false'
|
|
if options.lastVersionTag
|
|
params.parent_rev = options.lastVersionTag
|
|
else if options.parentRev or options.parent_rev
|
|
params.parent_rev = options.parentRev or options.parent_rev
|
|
# TODO: locale support would edit the params here
|
|
xhr = new Dropbox.Xhr 'POST', "#{@urls.putFile}/#{@urlEncodePath(path)}"
|
|
xhr.setBody(data).setParams(params).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Atomic step in a resumable file upload.
|
|
#
|
|
# @param {String, ArrayBuffer, ArrayBufferView, Blob, File} data the file
|
|
# contents fragment to be uploaded; if a File is passed, its name is
|
|
# ignored
|
|
# @param {?Dropbox.UploadCursor} cursor the cursor that tracks the state of
|
|
# the resumable file upload; the cursor information will not be updated
|
|
# when the API call completes
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.UploadCursor)} callback called
|
|
# with the result of the /chunked_upload HTTP request; the second paramter
|
|
# is a Dropbox.UploadCursor instance describing the progress of the upload
|
|
# operation, and the first parameter is null if things go well
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
resumableUploadStep: (data, cursor, callback) ->
|
|
if cursor
|
|
params = { offset: cursor.offset }
|
|
params.upload_id = cursor.tag if cursor.tag
|
|
else
|
|
params = { offset: 0 }
|
|
|
|
xhr = new Dropbox.Xhr 'POST', @urls.chunkedUpload
|
|
xhr.setBody(data).setParams(params).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, cursor) ->
|
|
if error and error.status is 400 and
|
|
error.response.upload_id and error.response.offset
|
|
callback null, Dropbox.UploadCursor.parse(error.response)
|
|
else
|
|
callback error, Dropbox.UploadCursor.parse(cursor)
|
|
|
|
# Finishes a resumable file upload.
|
|
#
|
|
# @param {String} path the path of the file to be created, relative to the
|
|
# user's Dropbox or to the application's folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {String} lastVersionTag the identifier string for the
|
|
# version of the file's contents that was last read by this program, used
|
|
# for conflict resolution; for best results, use the versionTag attribute
|
|
# value from the Dropbox.Stat instance provided by readFile
|
|
# @option options {String} parentRev alias for "lastVersionTag" that matches
|
|
# the HTTP API
|
|
# @option options {Boolean} noOverwrite if set, the write will not overwrite
|
|
# a file with the same name that already exsits; instead the contents
|
|
# will be written to a similarly named file (e.g. "notes (1).txt"
|
|
# instead of "notes.txt")
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /files (POST) HTTP request; the second paramter is a
|
|
# Dropbox.Stat instance describing the newly created file, and the first
|
|
# parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
resumableUploadFinish: (path, cursor, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = { upload_id: cursor.tag }
|
|
|
|
if options
|
|
if options.lastVersionTag
|
|
params.parent_rev = options.lastVersionTag
|
|
else if options.parentRev or options.parent_rev
|
|
params.parent_rev = options.parentRev or options.parent_rev
|
|
if options.noOverwrite
|
|
params.autorename = true
|
|
|
|
# TODO: locale support would edit the params here
|
|
xhr = new Dropbox.Xhr 'POST',
|
|
"#{@urls.commitChunkedUpload}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Reads the metadata of a file or folder in a user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file or folder whose metadata will be
|
|
# read, relative to the user's Dropbox or to the application's folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Number} version if set, the call will return the metadata
|
|
# for the given revision of the file / folder; the latest version is used
|
|
# by default
|
|
# @option options {Boolean} removed if set to true, the results will include
|
|
# files and folders that were deleted from the user's Dropbox
|
|
# @option options {Boolean} deleted alias for "removed" that matches the HTTP
|
|
# API; using this alias is not recommended, because it may cause confusion
|
|
# with JavaScript's delete operation
|
|
# @option options {Boolean, Number} readDir only meaningful when stat-ing
|
|
# folders; if this is set, the API call will also retrieve the folder's
|
|
# contents, which is passed into the callback's third parameter; if this
|
|
# is a number, it specifies the maximum number of files and folders that
|
|
# should be returned; the default limit is 10,000 items; if the limit is
|
|
# exceeded, the call will fail with an error
|
|
# @option options {String} versionTag used for saving bandwidth when getting
|
|
# a folder's contents; if this value is specified and it matches the
|
|
# folder's contents, the call will fail with a 304 (Contents not changed)
|
|
# error code; a folder's version identifier can be obtained from the
|
|
# versionTag attribute of a Dropbox.Stat instance describing it
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat, ?Array<Dropbox.Stat>)}
|
|
# callback called with the result of the /metadata HTTP request; if the
|
|
# call succeeds, the second parameter is a Dropbox.Stat instance
|
|
# describing the file / folder, and the first parameter is null;
|
|
# if the readDir option is true and the call succeeds, the third
|
|
# parameter is an array of Dropbox.Stat instances describing the folder's
|
|
# entries
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
stat: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = {}
|
|
httpCache = false
|
|
if options
|
|
if options.version?
|
|
params.rev = options.version
|
|
if options.removed or options.deleted
|
|
params.include_deleted = 'true'
|
|
if options.readDir
|
|
params.list = 'true'
|
|
if options.readDir isnt true
|
|
params.file_limit = options.readDir.toString()
|
|
if options.cacheHash
|
|
params.hash = options.cacheHash
|
|
if options.httpCache
|
|
httpCache = true
|
|
params.include_deleted ||= 'false'
|
|
params.list ||= 'false'
|
|
# TODO: locale support would edit the params here
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.metadata}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth @oauth, httpCache
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
stat = Dropbox.Stat.parse metadata
|
|
if metadata?.contents
|
|
entries = (Dropbox.Stat.parse(entry) for entry in metadata.contents)
|
|
else
|
|
entries = undefined
|
|
callback error, stat, entries
|
|
|
|
# Lists the files and folders inside a folder in a user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the folder whose contents will be
|
|
# retrieved, relative to the user's Dropbox or to the application's
|
|
# folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Boolean} removed if set to true, the results will include
|
|
# files and folders that were deleted from the user's Dropbox
|
|
# @option options {Boolean} deleted alias for "removed" that matches the HTTP
|
|
# API; using this alias is not recommended, because it may cause confusion
|
|
# with JavaScript's delete operation
|
|
# @option options {Boolean, Number} limit the maximum number of files and
|
|
# folders that should be returned; the default limit is 10,000 items; if
|
|
# the limit is exceeded, the call will fail with an error
|
|
# @option options {String} versionTag used for saving bandwidth; if this
|
|
# option is specified, and its value matches the folder's version tag,
|
|
# the call will fail with a 304 (Contents not changed) error code
|
|
# instead of returning the contents; a folder's version identifier can be
|
|
# obtained from the versionTag attribute of a Dropbox.Stat instance
|
|
# describing it
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?Array<String>, ?Dropbox.Stat,
|
|
# ?Array<Dropbox.Stat>)} callback called with the result of the /metadata
|
|
# HTTP request; if the call succeeds, the second parameter is an array
|
|
# containing the names of the files and folders in the given folder, the
|
|
# third parameter is a Dropbox.Stat instance describing the folder, the
|
|
# fourth parameter is an array of Dropbox.Stat instances describing the
|
|
# folder's entries, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
readdir: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
statOptions = { readDir: true }
|
|
if options
|
|
if options.limit?
|
|
statOptions.readDir = options.limit
|
|
if options.versionTag
|
|
statOptions.versionTag = options.versionTag
|
|
if options.removed or options.deleted
|
|
statOptions.removed = options.removed or options.deleted
|
|
if options.httpCache
|
|
statOptions.httpCache = options.httpCache
|
|
@stat path, statOptions, (error, stat, entry_stats) ->
|
|
if entry_stats
|
|
entries = (entry_stat.name for entry_stat in entry_stats)
|
|
else
|
|
entries = null
|
|
callback error, entries, stat, entry_stats
|
|
|
|
# Alias for "stat" that matches the HTTP API.
|
|
metadata: (path, options, callback) ->
|
|
@stat path, options, callback
|
|
|
|
# Creates a publicly readable URL to a file or folder in the user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file or folder that will be linked to;
|
|
# the path is relative to the user's Dropbox or to the application's
|
|
# folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Boolean} download if set, the URL will be a direct
|
|
# download URL, instead of the usual Dropbox preview URLs; direct
|
|
# download URLs are short-lived (currently 4 hours), whereas regular URLs
|
|
# virtually have no expiration date (currently set to 2030); no direct
|
|
# download URLs can be generated for directories
|
|
# @option options {Boolean} downloadHack if set, a long-living download URL
|
|
# will be generated by asking for a preview URL and using the officially
|
|
# documented hack at https://www.dropbox.com/help/201 to turn the preview
|
|
# URL into a download URL
|
|
# @option options {Boolean} long if set, the URL will not be shortened using
|
|
# Dropbox's shortner; the download and downloadHack options imply long
|
|
# @option options {Boolean} longUrl synonym for long; makes life easy for
|
|
# RhinoJS users
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.PublicUrl)} callback called
|
|
# with the result of the /shares or /media HTTP request; if the call
|
|
# succeeds, the second parameter is a Dropbox.PublicUrl instance, and the
|
|
# first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
makeUrl: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
# NOTE: cannot use options.long; normally, the CoffeeScript compiler
|
|
# escapes keywords for us; although long isn't really a keyword, the
|
|
# Rhino VM thinks it is; this hack can be removed when the bug below
|
|
# is fixed:
|
|
# https://github.com/mozilla/rhino/issues/93
|
|
if options and (options['long'] or options.longUrl or options.downloadHack)
|
|
params = { short_url: 'false' }
|
|
else
|
|
params = {}
|
|
|
|
path = @urlEncodePath path
|
|
url = "#{@urls.shares}/#{path}"
|
|
isDirect = false
|
|
useDownloadHack = false
|
|
if options
|
|
if options.downloadHack
|
|
isDirect = true
|
|
useDownloadHack = true
|
|
else if options.download
|
|
isDirect = true
|
|
url = "#{@urls.media}/#{path}"
|
|
|
|
# TODO: locale support would edit the params here
|
|
xhr = new Dropbox.Xhr('POST', url).setParams(params).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, urlData) ->
|
|
if useDownloadHack and urlData and urlData.url
|
|
urlData.url = urlData.url.replace(@authServer, @downloadServer)
|
|
callback error, Dropbox.PublicUrl.parse(urlData, isDirect)
|
|
|
|
# Retrieves the revision history of a file in a user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file whose revision history will be
|
|
# retrieved, relative to the user's Dropbox or to the application's
|
|
# folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Number} limit if specified, the call will return at most
|
|
# this many versions
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?Array<Dropbox.Stat>)} callback called
|
|
# with the result of the /revisions HTTP request; if the call succeeds,
|
|
# the second parameter is an array with one Dropbox.Stat instance per
|
|
# file version, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
history: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = {}
|
|
httpCache = false
|
|
if options
|
|
if options.limit?
|
|
params.rev_limit = options.limit
|
|
if options.httpCache
|
|
httpCache = true
|
|
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.revisions}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth @oauth, httpCache
|
|
@dispatchXhr xhr, (error, versions) ->
|
|
if versions
|
|
stats = (Dropbox.Stat.parse(metadata) for metadata in versions)
|
|
else
|
|
stats = undefined
|
|
callback error, stats
|
|
|
|
# Alias for "history" that matches the HTTP API.
|
|
revisions: (path, options, callback) ->
|
|
@history path, options, callback
|
|
|
|
# Computes a URL that generates a thumbnail for a file in the user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file whose thumbnail image URL will be
|
|
# computed, relative to the user's Dropbox or to the application's
|
|
# folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Boolean} png if true, the thumbnail's image will be a PNG
|
|
# file; the default thumbnail format is JPEG
|
|
# @option options {String} format value that gets passed directly to the API;
|
|
# this is intended for newly added formats that the API may not support;
|
|
# use options such as "png" when applicable
|
|
# @option options {String} sizeCode specifies the image's dimensions; this
|
|
# gets passed directly to the API; currently, the following values are
|
|
# supported: 'small' (32x32), 'medium' (64x64), 'large' (128x128),
|
|
# 's' (64x64), 'm' (128x128), 'l' (640x480), 'xl' (1024x768); the default
|
|
# value is "small"
|
|
# @return {String} a URL to an image that can be used as the thumbnail for
|
|
# the given file
|
|
thumbnailUrl: (path, options) ->
|
|
xhr = @thumbnailXhr path, options
|
|
xhr.paramsToUrl().url
|
|
|
|
# Retrieves the image data of a thumbnail for a file in the user's Dropbox.
|
|
#
|
|
# This method is intended to be used with low-level painting APIs. Whenever
|
|
# possible, it is easier to place the result of thumbnailUrl in a DOM
|
|
# element, and rely on the browser to fetch the file.
|
|
#
|
|
# @param {String} path the path to the file whose thumbnail image URL will be
|
|
# computed, relative to the user's Dropbox or to the application's
|
|
# folder
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Boolean} png if true, the thumbnail's image will be a PNG
|
|
# file; the default thumbnail format is JPEG
|
|
# @option options {String} format value that gets passed directly to the API;
|
|
# this is intended for newly added formats that the API may not support;
|
|
# use options such as "png" when applicable
|
|
# @option options {String} sizeCode specifies the image's dimensions; this
|
|
# gets passed directly to the API; currently, the following values are
|
|
# supported: 'small' (32x32), 'medium' (64x64), 'large' (128x128),
|
|
# 's' (64x64), 'm' (128x128), 'l' (640x480), 'xl' (1024x768); the default
|
|
# value is "small"
|
|
# @option options {Boolean} blob if true, the file will be retrieved as a
|
|
# Blob, instead of a String; this requires XHR Level 2 support, which is
|
|
# not available in IE <= 9
|
|
# @param {function(?Dropbox.ApiError, ?Object, ?Dropbox.Stat)} callback
|
|
# called with the result of the /thumbnails HTTP request; if the call
|
|
# succeeds, the second parameter is the image data as a String or Blob,
|
|
# the third parameter is a Dropbox.Stat instance describing the
|
|
# thumbnailed file, and the first argument is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
readThumbnail: (path, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
responseType = 'b'
|
|
if options
|
|
responseType = 'blob' if options.blob
|
|
|
|
xhr = @thumbnailXhr path, options
|
|
xhr.setResponseType responseType
|
|
@dispatchXhr xhr, (error, data, metadata) ->
|
|
callback error, data, Dropbox.Stat.parse(metadata)
|
|
|
|
# Sets up an XHR for reading a thumbnail for a file in the user's Dropbox.
|
|
#
|
|
# @see Dropbox.Client#thumbnailUrl
|
|
# @return {Dropbox.Xhr} an XHR request configured for fetching the thumbnail
|
|
thumbnailXhr: (path, options) ->
|
|
params = {}
|
|
if options
|
|
if options.format
|
|
params.format = options.format
|
|
else if options.png
|
|
params.format = 'png'
|
|
if options.size
|
|
# Can we do something nicer here?
|
|
params.size = options.size
|
|
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.thumbnails}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth(@oauth)
|
|
|
|
# Reverts a file's contents to a previous version.
|
|
#
|
|
# This is an atomic, bandwidth-optimized equivalent of reading the file
|
|
# contents at the given file version (readFile), and then using it to
|
|
# overwrite the file (writeFile).
|
|
#
|
|
# @param {String} path the path to the file whose contents will be reverted
|
|
# to a previous version, relative to the user's Dropbox or to the
|
|
# application's folder
|
|
# @param {String} versionTag the tag of the version that the file will be
|
|
# reverted to; maps to the "rev" parameter in the HTTP API
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /restore HTTP request; if the call succeeds, the
|
|
# second parameter is a Dropbox.Stat instance describing the file after
|
|
# the revert operation, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
revertFile: (path, versionTag, callback) ->
|
|
xhr = new Dropbox.Xhr 'POST', "#{@urls.restore}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(rev: versionTag).signWithOauth @oauth
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Alias for "revertFile" that matches the HTTP API.
|
|
restore: (path, versionTag, callback) ->
|
|
@revertFile path, versionTag, callback
|
|
|
|
# Finds files / folders whose name match a pattern, in the user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file whose contents will be reverted
|
|
# to a previous version, relative to the user's Dropbox or to the
|
|
# application's folder
|
|
# @param {String} namePattern the string that file / folder names must
|
|
# contain in order to match the search criteria;
|
|
# @param {?Object} options the advanced settings below; for the default
|
|
# settings, skip the argument or pass null
|
|
# @option options {Number} limit if specified, the call will return at most
|
|
# this many versions
|
|
# @option options {Boolean} removed if set to true, the results will include
|
|
# files and folders that were deleted from the user's Dropbox; the default
|
|
# limit is the maximum value of 1,000
|
|
# @option options {Boolean} deleted alias for "removed" that matches the HTTP
|
|
# API; using this alias is not recommended, because it may cause confusion
|
|
# with JavaScript's delete operation
|
|
# @option options {Boolean} httpCache if true, the API request will be set to
|
|
# allow HTTP caching to work; by default, requests are set up to avoid
|
|
# CORS preflights; setting this option can make sense when making the same
|
|
# request repeatedly (polling?)
|
|
# @param {function(?Dropbox.ApiError, ?Array<Dropbox.Stat>)} callback called
|
|
# with the result of the /search HTTP request; if the call succeeds, the
|
|
# second parameter is an array with one Dropbox.Stat instance per search
|
|
# result, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
findByName: (path, namePattern, options, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = { query: namePattern }
|
|
httpCache = false
|
|
if options
|
|
if options.limit?
|
|
params.file_limit = options.limit
|
|
if options.removed or options.deleted
|
|
params.include_deleted = true
|
|
if options.httpCache
|
|
httpCache = true
|
|
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.search}/#{@urlEncodePath(path)}"
|
|
xhr.setParams(params).signWithOauth @oauth, httpCache
|
|
@dispatchXhr xhr, (error, results) ->
|
|
if results
|
|
stats = (Dropbox.Stat.parse(metadata) for metadata in results)
|
|
else
|
|
stats = undefined
|
|
callback error, stats
|
|
|
|
# Alias for "findByName" that matches the HTTP API.
|
|
search: (path, namePattern, options, callback) ->
|
|
@findByName path, namePattern, options, callback
|
|
|
|
# Creates a reference used to copy a file to another user's Dropbox.
|
|
#
|
|
# @param {String} path the path to the file whose contents will be
|
|
# referenced, relative to the uesr's Dropbox or to the application's
|
|
# folder
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.CopyReference)} callback
|
|
# called with the result of the /copy_ref HTTP request; if the call
|
|
# succeeds, the second parameter is a Dropbox.CopyReference instance, and
|
|
# the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
makeCopyReference: (path, callback) ->
|
|
xhr = new Dropbox.Xhr 'GET', "#{@urls.copyRef}/#{@urlEncodePath(path)}"
|
|
xhr.signWithOauth @oauth
|
|
@dispatchXhr xhr, (error, refData) ->
|
|
callback error, Dropbox.CopyReference.parse(refData)
|
|
|
|
# Alias for "makeCopyReference" that matches the HTTP API.
|
|
copyRef: (path, callback) ->
|
|
@makeCopyReference path, callback
|
|
|
|
# Fetches a list of changes in the user's Dropbox since the last call.
|
|
#
|
|
# This method is intended to make full sync implementations easier and more
|
|
# performant. Each call returns a cursor that can be used in a future call
|
|
# to obtain all the changes that happened in the user's Dropbox (or
|
|
# application directory) between the two calls.
|
|
#
|
|
# @param {Dropbox.PulledChanges, String} cursor the result of a previous
|
|
# call to pullChanges, or a string containing a tag representing the
|
|
# Dropbox state that is used as the baseline for the change list; this
|
|
# should either be the Dropbox.PulledChanges obtained from a previous call
|
|
# to pullChanges, the return value of Dropbox.PulledChanges#cursor, or null
|
|
# / ommitted on the first call to pullChanges
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.PulledChanges)} callback
|
|
# called with the result of the /delta HTTP request; if the call
|
|
# succeeds, the second parameter is a Dropbox.PulledChanges describing
|
|
# the changes to the user's Dropbox since the pullChanges call that
|
|
# produced the given cursor, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
pullChanges: (cursor, callback) ->
|
|
if (not callback) and (typeof cursor is 'function')
|
|
callback = cursor
|
|
cursor = null
|
|
|
|
if cursor
|
|
if cursor.cursorTag
|
|
params = { cursor: cursor.cursorTag }
|
|
else
|
|
params = { cursor: cursor }
|
|
else
|
|
params = {}
|
|
|
|
xhr = new Dropbox.Xhr 'POST', @urls.delta
|
|
xhr.setParams(params).signWithOauth @oauth
|
|
@dispatchXhr xhr, (error, deltaInfo) ->
|
|
callback error, Dropbox.PulledChanges.parse(deltaInfo)
|
|
|
|
# Alias for "pullChanges" that matches the HTTP API.
|
|
delta: (cursor, callback) ->
|
|
@pullChanges cursor, callback
|
|
|
|
# Creates a folder in a user's Dropbox.
|
|
#
|
|
# @param {String} path the path of the folder that will be created, relative
|
|
# to the user's Dropbox or to the application's folder
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /fileops/create_folder HTTP request; if the call
|
|
# succeeds, the second parameter is a Dropbox.Stat instance describing
|
|
# the newly created folder, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
mkdir: (path, callback) ->
|
|
xhr = new Dropbox.Xhr 'POST', @urls.fileopsCreateFolder
|
|
xhr.setParams(root: @fileRoot, path: @normalizePath(path)).
|
|
signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Removes a file or diretory from a user's Dropbox.
|
|
#
|
|
# @param {String} path the path of the file to be read, relative to the
|
|
# user's Dropbox or to the application's folder
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /fileops/delete HTTP request; if the call succeeds,
|
|
# the second parameter is a Dropbox.Stat instance describing the removed
|
|
# file or folder, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
remove: (path, callback) ->
|
|
xhr = new Dropbox.Xhr 'POST', @urls.fileopsDelete
|
|
xhr.setParams(root: @fileRoot, path: @normalizePath(path)).
|
|
signWithOauth(@oauth)
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# node.js-friendly alias for "remove".
|
|
unlink: (path, callback) ->
|
|
@remove path, callback
|
|
|
|
# Alias for "remove" that matches the HTTP API.
|
|
delete: (path, callback) ->
|
|
@remove path, callback
|
|
|
|
# Copies a file or folder in the user's Dropbox.
|
|
#
|
|
# This method's "from" parameter can be either a path or a copy reference
|
|
# obtained by a previous call to makeCopyRef. The method uses a crude
|
|
# heuristic to interpret the "from" string -- if it doesn't contain any
|
|
# slash (/) or dot (.) character, it is assumed to be a copy reference. The
|
|
# easiest way to work with it is to prepend "/" to every path passed to the
|
|
# method. The method will process paths that start with multiple /s
|
|
# correctly.
|
|
#
|
|
# @param {String, Dropbox.CopyReference} from the path of the file or folder
|
|
# that will be copied, or a Dropbox.CopyReference instance obtained by
|
|
# calling makeCopyRef or Dropbox.CopyReference.parse; if this is a path, it
|
|
# is relative to the user's Dropbox or to the application's folder
|
|
# @param {String} toPath the path that the file or folder will have after the
|
|
# method call; the path is relative to the user's Dropbox or to the
|
|
# application folder
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /fileops/copy HTTP request; if the call succeeds, the
|
|
# second parameter is a Dropbox.Stat instance describing the file or folder
|
|
# created by the copy operation, and the first parameter is null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
copy: (from, toPath, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
params = { root: @fileRoot, to_path: @normalizePath(toPath) }
|
|
if from instanceof Dropbox.CopyReference
|
|
params.from_copy_ref = from.tag
|
|
else
|
|
params.from_path = @normalizePath from
|
|
# TODO: locale support would edit the params here
|
|
|
|
xhr = new Dropbox.Xhr 'POST', @urls.fileopsCopy
|
|
xhr.setParams(params).signWithOauth @oauth
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Moves a file or folder to a different location in a user's Dropbox.
|
|
#
|
|
# @param {String} fromPath the path of the file or folder that will be moved,
|
|
# relative to the user's Dropbox or to the application's folder
|
|
# @param {String} toPath the path that the file or folder will have after
|
|
# the method call; the path is relative to the user's Dropbox or to the
|
|
# application's folder
|
|
# @param {function(?Dropbox.ApiError, ?Dropbox.Stat)} callback called with
|
|
# the result of the /fileops/move HTTP request; if the call succeeds, the
|
|
# second parameter is a Dropbox.Stat instance describing the moved
|
|
# file or folder at its new location, and the first parameter is
|
|
# null
|
|
# @return {XMLHttpRequest} the XHR object used for this API call
|
|
move: (fromPath, toPath, callback) ->
|
|
if (not callback) and (typeof options is 'function')
|
|
callback = options
|
|
options = null
|
|
|
|
xhr = new Dropbox.Xhr 'POST', @urls.fileopsMove
|
|
xhr.setParams(
|
|
root: @fileRoot, from_path: @normalizePath(fromPath),
|
|
to_path: @normalizePath(toPath)).signWithOauth @oauth
|
|
@dispatchXhr xhr, (error, metadata) ->
|
|
callback error, Dropbox.Stat.parse(metadata)
|
|
|
|
# Removes all login information.
|
|
#
|
|
# @return {Dropbox.Client} this, for easy call chaining
|
|
reset: ->
|
|
@uid = null
|
|
@oauth.setToken null, ''
|
|
oldAuthState = @authState
|
|
@authState = DropboxClient.RESET
|
|
if oldAuthState isnt @authState
|
|
@onAuthStateChange.dispatch @
|
|
@authError = null
|
|
@_credentials = null
|
|
@
|
|
|
|
# Change the client's OAuth credentials.
|
|
#
|
|
# @param {?Object} the result of a prior call to credentials()
|
|
# @return {Dropbox.Client} this, for easy call chaining
|
|
setCredentials: (credentials) ->
|
|
oldAuthState = @authState
|
|
@oauth.reset credentials
|
|
@uid = credentials.uid or null
|
|
if credentials.authState
|
|
@authState = credentials.authState
|
|
else
|
|
if credentials.token
|
|
@authState = DropboxClient.DONE
|
|
else
|
|
@authState = DropboxClient.RESET
|
|
@authError = null
|
|
@_credentials = null
|
|
if oldAuthState isnt @authState
|
|
@onAuthStateChange.dispatch @
|
|
@
|
|
|
|
# @return {String} a string that uniquely identifies the Dropbox application
|
|
# of this client
|
|
appHash: ->
|
|
@oauth.appHash()
|
|
|
|
# Computes the URLs of all the Dropbox API calls.
|
|
#
|
|
# @private
|
|
# This is called by the constructor, and used by the other methods. It should
|
|
# not be used directly.
|
|
setupUrls: ->
|
|
@fileRoot = if @sandbox then 'sandbox' else 'dropbox'
|
|
|
|
@urls =
|
|
# Authentication.
|
|
requestToken: "#{@apiServer}/1/oauth/request_token"
|
|
authorize: "#{@authServer}/1/oauth/authorize"
|
|
accessToken: "#{@apiServer}/1/oauth/access_token"
|
|
signOut: "#{@apiServer}/1/unlink_access_token"
|
|
|
|
# Accounts.
|
|
accountInfo: "#{@apiServer}/1/account/info"
|
|
|
|
# Files and metadata.
|
|
getFile: "#{@fileServer}/1/files/#{@fileRoot}"
|
|
postFile: "#{@fileServer}/1/files/#{@fileRoot}"
|
|
putFile: "#{@fileServer}/1/files_put/#{@fileRoot}"
|
|
metadata: "#{@apiServer}/1/metadata/#{@fileRoot}"
|
|
delta: "#{@apiServer}/1/delta"
|
|
revisions: "#{@apiServer}/1/revisions/#{@fileRoot}"
|
|
restore: "#{@apiServer}/1/restore/#{@fileRoot}"
|
|
search: "#{@apiServer}/1/search/#{@fileRoot}"
|
|
shares: "#{@apiServer}/1/shares/#{@fileRoot}"
|
|
media: "#{@apiServer}/1/media/#{@fileRoot}"
|
|
copyRef: "#{@apiServer}/1/copy_ref/#{@fileRoot}"
|
|
thumbnails: "#{@fileServer}/1/thumbnails/#{@fileRoot}"
|
|
chunkedUpload: "#{@fileServer}/1/chunked_upload"
|
|
commitChunkedUpload:
|
|
"#{@fileServer}/1/commit_chunked_upload/#{@fileRoot}"
|
|
|
|
# File operations.
|
|
fileopsCopy: "#{@apiServer}/1/fileops/copy"
|
|
fileopsCreateFolder: "#{@apiServer}/1/fileops/create_folder"
|
|
fileopsDelete: "#{@apiServer}/1/fileops/delete"
|
|
fileopsMove: "#{@apiServer}/1/fileops/move"
|
|
|
|
# @property {Number} the client's progress in the authentication process;
|
|
# Dropbox.Client#isAuthenticated should be called instead whenever
|
|
# possible; this attribute was intended to be used by OAuth drivers
|
|
authState: null
|
|
|
|
# authState value for a client that experienced an authentication error
|
|
@ERROR: 0
|
|
|
|
# authState value for a properly initialized client with no user credentials
|
|
@RESET: 1
|
|
|
|
# authState value for a client with a request token that must be authorized
|
|
@REQUEST: 2
|
|
|
|
# authState value for a client whose request token was authorized
|
|
@AUTHORIZED: 3
|
|
|
|
# authState value for a client that has an access token
|
|
@DONE: 4
|
|
|
|
# authState value for a client that voluntarily invalidated its access token
|
|
@SIGNED_OFF: 5
|
|
|
|
# Normalizes a Dropobx path and encodes it for inclusion in a request URL.
|
|
#
|
|
# @private
|
|
# This is called internally by the other client functions, and should not be
|
|
# used outside the {Dropbox.Client} class.
|
|
urlEncodePath: (path) ->
|
|
Dropbox.Xhr.urlEncodeValue(@normalizePath(path)).replace /%2F/gi, '/'
|
|
|
|
# Normalizes a Dropbox path for API requests.
|
|
#
|
|
# @private
|
|
# This is an internal method. It is used by all the client methods that take
|
|
# paths as arguments.
|
|
#
|
|
# @param {String} path a path
|
|
normalizePath: (path) ->
|
|
if path.substring(0, 1) is '/'
|
|
i = 1
|
|
while path.substring(i, i + 1) is '/'
|
|
i += 1
|
|
path.substring i
|
|
else
|
|
path
|
|
|
|
# Generates an OAuth request token.
|
|
#
|
|
# @private
|
|
# This a low-level method called by authorize. Users should call authorize.
|
|
#
|
|
# @param {function(error, data)} callback called with the result of the
|
|
# /oauth/request_token HTTP request
|
|
requestToken: (callback) ->
|
|
xhr = new Dropbox.Xhr('POST', @urls.requestToken).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, callback
|
|
|
|
# The URL for /oauth/authorize, embedding the user's token.
|
|
#
|
|
# @private
|
|
# This a low-level method called by authorize. Users should call authorize.
|
|
#
|
|
# @param {String} token the oauth_token obtained from an /oauth/request_token
|
|
# call
|
|
# @return {String} the URL that the user's browser should be redirected to in
|
|
# order to perform an /oauth/authorize request
|
|
authorizeUrl: (token) ->
|
|
params = { oauth_token: token, oauth_callback: @driver.url() }
|
|
"#{@urls.authorize}?" + Dropbox.Xhr.urlEncode(params)
|
|
|
|
# Exchanges an OAuth request token with an access token.
|
|
#
|
|
# @private
|
|
# This a low-level method called by authorize. Users should call authorize.
|
|
#
|
|
# @param {function(error, data)} callback called with the result of the
|
|
# /oauth/access_token HTTP request
|
|
getAccessToken: (callback) ->
|
|
xhr = new Dropbox.Xhr('POST', @urls.accessToken).signWithOauth(@oauth)
|
|
@dispatchXhr xhr, callback
|
|
|
|
# Prepares and sends an XHR to the Dropbox API server.
|
|
#
|
|
# @private
|
|
# This is a low-level method called by other client methods.
|
|
#
|
|
# @param {Dropbox.Xhr} xhr wrapper for the XHR to be sent
|
|
# @param {function(?Dropbox.ApiError, ?Object)} callback called with the
|
|
# outcome of the XHR
|
|
# @return {XMLHttpRequest} the native XHR object used to make the request
|
|
dispatchXhr: (xhr, callback) ->
|
|
xhr.setCallback callback
|
|
xhr.onError = @onError
|
|
xhr.prepare()
|
|
nativeXhr = xhr.xhr
|
|
if @onXhr.dispatch xhr
|
|
xhr.send()
|
|
nativeXhr
|
|
|
|
# @private
|
|
# @return {String} the URL to the default value for the "server" option
|
|
defaultApiServer: ->
|
|
'https://api.dropbox.com'
|
|
|
|
# @private
|
|
# @return {String} the URL to the default value for the "authServer" option
|
|
defaultAuthServer: ->
|
|
@apiServer.replace 'api.', 'www.'
|
|
|
|
# @private
|
|
# @return {String} the URL to the default value for the "fileServer" option
|
|
defaultFileServer: ->
|
|
@apiServer.replace 'api.', 'api-content.'
|
|
|
|
# @private
|
|
# @return {String} the URL to the default value for the "downloadServer"
|
|
# option
|
|
defaultDownloadServer: ->
|
|
@apiServer.replace 'api.', 'dl.'
|
|
|
|
# Computes the cached value returned by credentials.
|
|
#
|
|
# @private
|
|
# @see Dropbox.Client#computeCredentials
|
|
computeCredentials: ->
|
|
value =
|
|
key: @oauth.key
|
|
sandbox: @sandbox
|
|
value.secret = @oauth.secret if @oauth.secret
|
|
if @oauth.token
|
|
value.token = @oauth.token
|
|
value.tokenSecret = @oauth.tokenSecret
|
|
value.uid = @uid if @uid
|
|
if @authState isnt DropboxClient.ERROR and
|
|
@authState isnt DropboxClient.RESET and
|
|
@authState isnt DropboxClient.DONE and
|
|
@authState isnt DropboxClient.SIGNED_OFF
|
|
value.authState = @authState
|
|
if @apiServer isnt @defaultApiServer()
|
|
value.server = @apiServer
|
|
if @authServer isnt @defaultAuthServer()
|
|
value.authServer = @authServer
|
|
if @fileServer isnt @defaultFileServer()
|
|
value.fileServer = @fileServer
|
|
if @downloadServer isnt @defaultDownloadServer()
|
|
value.downloadServer = @downloadServer
|
|
@_credentials = value
|
|
|
|
DropboxClient = Dropbox.Client
|