class Object

Constants

APP_KEY

You must use your Dropbox App key and secret to use the API. Find this at www.dropbox.com/developers

APP_SECRET
STATE_FILE

Public Instance Methods

apply_delta(root, e) click to toggle source
# File examples/search_cache.rb, line 191
def apply_delta(root, e)
  path, metadata = e
  branch, leaf = split_path(path)

  if metadata != nil
    puts "+ #{path}"
    # Traverse down the tree until we find the parent folder of the entry
    # we want to add.  Create any missing folders along the way.
    children = root
    branch.each do |part|
      node = get_or_create_child(children, part)
      # If there's no folder here, make an empty one.
      if not node.folder?
        node.content = {}
      end
      children = node.content
    end

    # Create the file/folder.
    node = get_or_create_child(children, leaf)
    node.path = metadata['path']  # Save the un-lower-cased path.
    if metadata['is_dir']
      # Only create a folder if there isn't one there already.
      node.content = {} if not node.folder?
    else
      node.content = metadata['size'], metadata['modified']
    end
  else
    puts "- #{path}"
    # Traverse down the tree until we find the parent of the entry we
    # want to delete.
    children = root
    missing_parent = false
    branch.each do |part|
      node = children[part]
      # If one of the parent folders is missing, then we're done.
      if node == nil or not node.folder?
        missing_parent = true
        break
      end
      children = node.content
    end
    # If we made it all the way, delete the file/folder.
    if not missing_parent
      children.delete(leaf)
    end
  end
end
command_copy(args) click to toggle source
# File examples/copy_between_accounts.rb, line 92
def command_copy(args)
  if args.size != 3
    warn "ERROR: \"copy\" takes exactly two arguments"
    exit
  end

  state = load_state()

  if state.keys().length < 2
    warn "ERROR: You can't use the copy command until at least two users have linked"
    exit
  end

  from = args[1].gsub(/['"]/,'')
  to = args[2].gsub(/['"]/,'')

  if not to.index(':') or not from.index(':')
    warn "ERROR: Ill-formated paths. Run #{prog_name} without arugments to see documentation."
    exit
  end

  from_uid, from_path = from.split ":"
  to_uid, to_path = to.split ":"

  if not state.has_key?(to_uid) or not state.has_key?(from_uid)
    warn "ERROR: Those UIDs have not linked.  Run #{prog_name} list to see linked UIDs."
    exit
  end

  from_client = DropboxClient.new(state[from_uid]['access_token'])
  to_client = DropboxClient.new(state[to_uid]['access_token'])

  #Create a copy ref under the identity of the from user
  copy_ref = from_client.create_copy_ref(from_path)['copy_ref']

  metadata = to_client.add_copy_ref(to_path, copy_ref)

  puts "File successly copied from #{state[from_uid]['display_name']} to #{state[to_uid]['display_name']}!"
  puts "The file now exists at #{metadata['path']}"

end
command_find(args) click to toggle source
# File examples/search_cache.rb, line 254
def command_find(args)
  if args.size == 1
    term = ''
  elsif args.size == 2
    term = args[1]
  else
    warn("ERROR: \"find\" takes either zero or one arguments.")
    exit
  end

  state = load_state()
  results = []
  search_tree(results, state['tree'], term)
  for r in results
    puts("#{r}")
  end
  puts("[Matches: #{results.size}]")
end
command_list(args) click to toggle source
# File examples/copy_between_accounts.rb, line 76
def command_list(args)
  if args.size != 1
    warn "ERROR: \"list\" doesn't take any arguments"
    exit
  end

  state = load_state()
  for e in state.keys()
    if state[e]['team_name']
      puts "#{state[e]['display_name']} (#{state[e]['team_name']}) is uid #{e}"
    else
      puts "#{state[e]['display_name']} is uid #{e}"
    end
  end
end
command_reset(args) click to toggle source
# File examples/search_cache.rb, line 274
def command_reset(args)
  if args.size != 1
    warn("ERROR: \"reset\" takes no arguments.")
    exit
  end

  # Delete cursor, empty tree.
  state = load_state()
  if state.has_key?('cursor')
    state.delete('cursor')
  end
  state['tree'] = {}
  save_state(state)
end
command_update(args) click to toggle source
# File examples/search_cache.rb, line 94
def command_update(args)
  if args.size == 1
    page_limit = nil
  elsif args.size == 2
    page_limit = Integer(args[1])
  else
    warn "ERROR: \"update\" takes either zero or one argument."
    exit
  end

  # Load state
  state = load_state()
  access_token = state['access_token']
  cursor = state['cursor']
  tree = state['tree']

  # Connect to Dropbox
  c = DropboxClient.new(access_token)

  page = 0
  changed = false
  while (page_limit == nil) or (page < page_limit)
    # Get /delta results from Dropbox
    result = c.delta(cursor)
    page += 1
    if result['reset'] == true
      puts 'reset'
      changed = true
      tree = {}
    end
    cursor = result['cursor']
    # Apply the entries one by one to our cached tree.
    for delta_entry in result['entries']
      changed = true
      apply_delta(tree, delta_entry)
    end
    cursor = result['cursor']
    if not result['has_more']
      break
    end
  end

  # Save state
  if changed
    state['cursor'] = cursor
    state['tree'] = tree
    save_state(state)
  else
    puts "No updates."
  end

end
get_dropbox_client() click to toggle source

If we already have an authorized DropboxSession, returns a DropboxClient.

# File examples/web_file_browser.rb, line 75
def get_dropbox_client
  if session[:access_token]
    return DropboxClient.new(session[:access_token])
  end
end
get_or_create_child(children, name) click to toggle source
# File examples/search_cache.rb, line 240
def get_or_create_child(children, name)
  child = children[name]
  if child == nil
    children[name] = child = Node.new(nil, nil)
  end
  child
end
get_web_auth() click to toggle source

OAuth stuff

# File examples/web_file_browser.rb, line 31
def get_web_auth()
  return DropboxOAuth2Flow.new(APP_KEY, APP_SECRET, url('/dropbox-auth-finish'),
                 session, :dropbox_auth_csrf_token)
end
html_page(title, body='') click to toggle source

# File examples/web_file_browser.rb, line 171
def html_page(title, body='')
  "<html>" +
    "<head><title>#{h title}</title></head>" +
    "<body><h1>#{h title}</h1>#{body}</body>" +
  "</html>"
end
load_state() click to toggle source
# File examples/copy_between_accounts.rb, line 140
def load_state()
  if not FileTest.exists?(STATE_FILE)
    return {}
  end
  JSON.parse(File.read(STATE_FILE))
end
main() click to toggle source
# File examples/chunked_upload.rb, line 12
def main()
  if APP_KEY == '' or APP_SECRET == ''
    warn "ERROR: Set your APP_KEY and APP_SECRET at the top of search_cache.rb"
    exit
  end
  prog_name = __FILE__
  args = ARGV
  if args.size == 0
    warn("Usage:\n")
    warn("   #{prog_name} <local-file-path> <dropbox-target-path> <chunk-size-in-bytes>")
    exit
  end

  if args.size != 3
    warn "ERROR: expecting exactly three arguments.  Run with no arguments for help."
    exit(1)
  end

  web_auth = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET)
  authorize_url = web_auth.start()
  puts "1. Go to: #{authorize_url}"
  puts "2. Click \"Allow\" (you might have to log in first)."
  puts "3. Copy the authorization code."

  print "Enter the authorization code here: "
  STDOUT.flush
  auth_code = STDIN.gets.strip

  access_token, user_id = web_auth.finish(auth_code)

  c = DropboxClient.new(access_token)

  local_file_path = args[0]
  dropbox_target_path = args[1]
  chunk_size = args[2].to_i

  # Upload the file
  local_file_size = File.size(local_file_path)
  uploader = c.get_chunked_uploader(File.new(local_file_path, "r"), local_file_size)
  retries = 0
  puts "Uploading..."
  while uploader.offset < uploader.total_size
    begin
      uploader.upload(chunk_size)
    rescue DropboxError => e
      if retries > 10
        puts "- Error uploading, giving up."
        break
      end
      puts "- Error uploading, trying again..."
      retries += 1
    end
  end
  puts "Finishing upload..."
  uploader.finish(dropbox_target_path)
  puts "Done."

end
map_hash_values(h) { |v| ... } click to toggle source

Run a mapping function over every value in a Hash, returning a new Hash.

# File examples/search_cache.rb, line 184
def map_hash_values(h)
  new = {}
  h.each { |k,v| new[k] = yield v }
  new
end
render_file(client, entry) click to toggle source
# File examples/web_file_browser.rb, line 133
def render_file(client, entry)
  # Just dump out metadata hash
  html_page "File: #{entry['path']}", "<pre>#{h entry.pretty_inspect}</pre>"
end
render_folder(client, entry) click to toggle source
# File examples/web_file_browser.rb, line 115
def render_folder(client, entry)
  # Provide an upload form (so the user can add files to this folder)
  out = "<form action='/upload' method='post' enctype='multipart/form-data'>"
  out += "<label for='file'>Upload file:</label> <input name='file' type='file'/>"
  out += "<input type='submit' value='Upload'/>"
  out += "<input name='folder' type='hidden' value='#{h entry['path']}'/>"
  out += "</form>"  # TODO: Add a token to counter CSRF attacks.
  # List of folder contents
  entry['contents'].each do |child|
    cp = child['path']      # child path
    cn = File.basename(cp)  # child name
    if (child['is_dir']) then cn += '/' end
    out += "<div><a style='text-decoration: none' href='/?path=#{h cp}'>#{h cn}</a></div>"
  end

  html_page "Folder: #{entry['path']}", out
end
save_state(state) click to toggle source
# File examples/copy_between_accounts.rb, line 134
def save_state(state)
  File.open(STATE_FILE,"w") do |f|
    f.write(JSON.pretty_generate(state))
  end
end
search_tree(results, tree, term) click to toggle source

Recursively search 'tree' for files that contain the string in 'term'. Print out any matches.

# File examples/search_cache.rb, line 292
def search_tree(results, tree, term)
  tree.each do |name_lc, node|
    path = node.path
    if (path != nil) and path.include?(term)
      if node.folder?
        results.push("#{path}")
      else
        size, modified = node.content
        results.push("#{path}  (#{size}, #{modified})")
      end
    end
    if node.folder?
      search_tree(results, node.content, term)
    end
  end
end
split_path(path) click to toggle source
# File examples/search_cache.rb, line 248
def split_path(path)
  bad, *parts = path.split '/'
  [parts, parts.pop]
end