Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions api_coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ API call | Status
`/upload_session/append` | alias?
`/upload_session/append_v2` | 🌕
`/upload_session/finish` | 🌕
`/upload_session/finish_batch` | 🌑
`/upload_session/finish_batch/check` | 🌑
`/upload_session/finish_batch` | 🌕
`/upload_session/finish_batch/check` | 🌕
`/upload_session/start` | 🌕
`/upload_session/start_batch` | 🌕

## Paper

Expand Down
7 changes: 7 additions & 0 deletions lib/dropbox_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@
require 'dropbox_api/results/shared_folder_members'
require 'dropbox_api/results/void_result'
require 'dropbox_api/results/upload_session_start'
require 'dropbox_api/results/upload_session_start_batch_result'
require 'dropbox_api/results/upload_session_finish_batch_result_entry'
require 'dropbox_api/results/upload_session_finish_batch_result'
require 'dropbox_api/results/upload_session_finish_batch_job_status'
require 'dropbox_api/results/delete_batch_result_entry'
require 'dropbox_api/results/delete_batch_result'

Expand Down Expand Up @@ -194,6 +198,9 @@
require 'dropbox_api/endpoints/files/upload_session_start'
require 'dropbox_api/endpoints/files/upload_session_append_v2'
require 'dropbox_api/endpoints/files/upload_session_finish'
require 'dropbox_api/endpoints/files/upload_session_start_batch'
require 'dropbox_api/endpoints/files/upload_session_finish_batch'
require 'dropbox_api/endpoints/files/upload_session_finish_batch_check'
require 'dropbox_api/endpoints/files/delete_batch_check'
require 'dropbox_api/endpoints/files/delete_batch'
require 'dropbox_api/endpoints/files/create_folder_batch_check'
Expand Down
76 changes: 76 additions & 0 deletions lib/dropbox_api/endpoints/files/upload_session_finish_batch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true
module DropboxApi::Endpoints::Files
class UploadSessionFinishBatch < DropboxApi::Endpoints::Rpc
Method = :post
Path = '/2/files/upload_session/finish_batch_v2'
ResultType = DropboxApi::Results::UploadSessionFinishBatchResult
ErrorType = nil

include DropboxApi::OptionsValidator

# This route helps you commit many files at once into a user's Dropbox.
# Use {Client#upload_session_start} and {Client#upload_session_append_v2} to
# upload file contents. We recommend uploading many files in parallel to
# increase throughput. Once the file contents have been uploaded, rather
# than calling {Client#upload_session_finish}, use this route to finish all
# your upload sessions in a single request.
#
# UploadSessionStartArg.close or UploadSessionAppendArg.close needs to be
# true for the last upload_session/start or upload_session/append:2 call
# of each upload session. The maximum size of a file one can upload to an
# upload session is 350 GiB. We allow up to 1000 entries in a single request.
#
# @param entries [Array<Hash>] Commit information for each file in the batch.
# Each entry should contain:
# - cursor: A DropboxApi::Metadata::UploadSessionCursor
# - commit: A DropboxApi::Metadata::CommitInfo
# @return [DropboxApi::Results::UploadSessionFinishBatchResult] Result containing
# either an async_job_id or the file metadata for each entry
# @example
# entries = [
# {
# cursor: DropboxApi::Metadata::UploadSessionCursor.new({
# session_id: "session123",
# offset: 1024
# }),
# commit: DropboxApi::Metadata::CommitInfo.new({
# path: "/file1.txt",
# mode: "add"
# })
# },
# {
# cursor: DropboxApi::Metadata::UploadSessionCursor.new({
# session_id: "session456",
# offset: 2048
# }),
# commit: DropboxApi::Metadata::CommitInfo.new({
# path: "/file2.txt",
# mode: "add"
# })
# }
# ]
# result = client.upload_session_finish_batch(entries)
add_endpoint :upload_session_finish_batch do |entries|
if !entries.is_a?(Array)
raise ArgumentError, "entries must be an array"
end

if entries.empty? || entries.size > 1000
raise ArgumentError, "entries must contain between 1 and 1000 items"
end

formatted_entries = entries.map do |entry|
unless entry[:cursor] && entry[:commit]
raise ArgumentError, "Each entry must have :cursor and :commit"
end

{
cursor: entry[:cursor].to_hash,
commit: entry[:commit].to_hash
}
end

perform_request(entries: formatted_entries)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true
module DropboxApi::Endpoints::Files
class UploadSessionFinishBatchCheck < DropboxApi::Endpoints::Rpc
Method = :post
Path = '/2/files/upload_session/finish_batch/check'
ResultType = DropboxApi::Results::UploadSessionFinishBatchJobStatus
ErrorType = DropboxApi::Errors::PollError

# Returns the status of an asynchronous job for {Client#upload_session_finish_batch}.
# If success, it returns list of result for each entry.
#
# @param async_job_id [String] Id of the asynchronous job.
# This is the value of a response returned from the method that
# launched the job.
# @return [:in_progress, Array] This could be either the `:in_progress`
# flag or a list of file metadata entries.
# @example
# # First, start a batch finish operation
# batch_result = client.upload_session_finish_batch(entries)
#
# # If async, check the status
# if batch_result.async_job_id
# job_status = client.upload_session_finish_batch_check(batch_result.async_job_id)
#
# if job_status == :in_progress
# # Job is still processing
# else
# # job_status is an array of file metadata
# job_status.each do |file_metadata|
# puts "Uploaded: #{file_metadata.path_display}"
# end
# end
# end
add_endpoint :upload_session_finish_batch_check do |async_job_id|
perform_request async_job_id: async_job_id
end
end
end
44 changes: 44 additions & 0 deletions lib/dropbox_api/endpoints/files/upload_session_start_batch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true
module DropboxApi::Endpoints::Files
class UploadSessionStartBatch < DropboxApi::Endpoints::Rpc
Method = :post
Path = '/2/files/upload_session/start_batch'
ResultType = DropboxApi::Results::UploadSessionStartBatchResult
ErrorType = nil

include DropboxApi::OptionsValidator

# This route starts batch of upload_sessions. Please refer to
# {Client#upload_session_start} usage.
#
# @param num_sessions [Integer] The number of upload sessions to start.
# Must be between 1 and 1000.
# @option options session_type [String] Type of upload session you want to
# start. If not specified, default is 'sequential'. Valid values are
# 'sequential' or 'concurrent'.
# @return [DropboxApi::Results::UploadSessionStartBatchResult] Result containing
# session IDs that can be used with upload_session/append and upload_session/finish
add_endpoint :upload_session_start_batch do |num_sessions, options = {}|
validate_options([
:session_type
], options)

if num_sessions < 1 || num_sessions > 1000
raise ArgumentError, "num_sessions must be between 1 and 1000"
end

params = {
num_sessions: num_sessions
}

if options[:session_type]
unless %w[sequential concurrent].include?(options[:session_type])
raise ArgumentError, "session_type must be 'sequential' or 'concurrent'"
end
params[:session_type] = options[:session_type]
end

perform_request(params)
end
end
end
21 changes: 21 additions & 0 deletions lib/dropbox_api/results/upload_session_finish_batch_job_status.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
module DropboxApi::Results
# Result returned by {Client#upload_session_finish_batch_check} representing
# the status of an asynchronous batch upload session finish operation.
#
# The value will be either `:in_progress` or a list of file metadata entries.
class UploadSessionFinishBatchJobStatus < DropboxApi::Results::Base
def self.new(result_data)
case result_data['.tag']
when 'in_progress'
:in_progress
when 'complete'
result_data['entries'].map do |entry|
DropboxApi::Results::UploadSessionFinishBatchResultEntry.new(entry)
end
else
raise NotImplementedError, "Unknown result type: #{result_data['.tag']}"
end
end
end
end
30 changes: 30 additions & 0 deletions lib/dropbox_api/results/upload_session_finish_batch_result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true
module DropboxApi::Results
# Result returned by {Client#upload_session_finish_batch} that may
# either launch an asynchronous job or complete synchronously.
#
# The value will be either an async_job_id string or a list of file metadata entries.
class UploadSessionFinishBatchResult < DropboxApi::Results::Base
def self.new(result_data)
case result_data['.tag']
when 'async_job_id'
# Return a result object that has the async_job_id
super(result_data)
when 'complete'
# Return the array of entries directly
result_data['entries'].map do |entry|
DropboxApi::Results::UploadSessionFinishBatchResultEntry.new(entry)
end
else
raise NotImplementedError, "Unknown result type: #{result_data['.tag']}"
end
end

# Returns the async job ID if the operation is asynchronous
#
# @return [String, nil] The async job ID or nil if operation completed synchronously
def async_job_id
@data['async_job_id'] if @data
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true
module DropboxApi::Results
# Entry in the result returned by {Client#upload_session_finish_batch}
# representing the result for each file in the batch.
class UploadSessionFinishBatchResultEntry < DropboxApi::Results::Base
def self.new(result_data)
case result_data['.tag']
when 'success'
# Return file metadata
DropboxApi::Metadata::File.new(result_data)
when 'failure'
# Return error information
# The actual error is in result_data['failure']
DropboxApi::Errors::UploadSessionFinishError.build(
result_data['failure']['.tag'],
result_data['failure']
)
else
raise NotImplementedError, "Unknown result type: #{result_data['.tag']}"
end
end
end
end
12 changes: 12 additions & 0 deletions lib/dropbox_api/results/upload_session_start_batch_result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true
module DropboxApi::Results
class UploadSessionStartBatchResult < DropboxApi::Results::Base
# Returns a list of unique identifiers for the upload sessions.
# Pass each session_id to upload_session/append:2 and upload_session/finish.
#
# @return [Array<String>] List of session IDs
def session_ids
@data['session_ids']
end
end
end
49 changes: 49 additions & 0 deletions spec/endpoints/files/upload_session_finish_batch_check_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'spec_helper'

describe DropboxApi::Client, '#upload_session_finish_batch_check' do
before :each do
@client = DropboxApi::Client.new
end

it "returns in_progress for ongoing jobs", :cassette => "upload_session_finish_batch_check/in_progress" do
result = @client.upload_session_finish_batch_check("sample_async_job_id")

expect(result).to eq(:in_progress)
end

it "returns file metadata for completed jobs", :cassette => "upload_session_finish_batch_check/complete" do
result = @client.upload_session_finish_batch_check("completed_job_id")

expect(result).to be_a(Array)
result.each do |entry|
# Each entry should be either a File metadata or an error
expect(entry).to be_a(DropboxApi::Metadata::File).or be_a(DropboxApi::Errors::UploadSessionFinishError)
end
end

it "handles mixed success and failure results", :cassette => "upload_session_finish_batch_check/mixed" do
result = @client.upload_session_finish_batch_check("mixed_results_job_id")

expect(result).to be_a(Array)

# Check that we have both success and failure entries
successes = result.select { |r| r.is_a?(DropboxApi::Metadata::File) }
failures = result.select { |r| r.is_a?(DropboxApi::Errors::UploadSessionFinishError) }

expect(successes).not_to be_empty
expect(failures).not_to be_empty
end

it "raises PollError for invalid job id", :cassette => "upload_session_finish_batch_check/invalid_job_id" do
expect {
@client.upload_session_finish_batch_check("invalid_job_id")
}.to raise_error(DropboxApi::Errors::PollError)
end

it "handles internal errors", :cassette => "upload_session_finish_batch_check/internal_error" do
expect {
@client.upload_session_finish_batch_check("error_job_id")
}.to raise_error(DropboxApi::Errors::InternalError)
end
end
Loading