diff --git a/archivesspace-client.gemspec b/archivesspace-client.gemspec index 7d6bf66..0275720 100644 --- a/archivesspace-client.gemspec +++ b/archivesspace-client.gemspec @@ -30,7 +30,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "webmock", "~> 3.24" spec.add_dependency "dry-cli", "< 2.0" - spec.add_dependency "httparty", "~> 0.14" + spec.add_dependency "httparty", "~> 0.16" spec.add_dependency "json", "~> 2.0" spec.add_dependency "jbuilder", "~> 2.12" end diff --git a/examples/upload_ead.rb b/examples/upload_ead.rb new file mode 100644 index 0000000..ac7bbcf --- /dev/null +++ b/examples/upload_ead.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "archivesspace/client" + +# usage: ruby examples/upload_ead.rb path/to/ead.xml +path = ARGV.fetch(0) { abort "usage: ruby #{$PROGRAM_NAME} path/to/ead.xml" } + +# official sandbox, config boilerplate +config = ArchivesSpace::Configuration.new( + { + base_uri: "https://test.archivesspace.org/staff/api", + username: "admin", + password: "admin", + page_size: 50, + throttle: 0, + verify_ssl: false + } +) + +client = ArchivesSpace::Client.new(config).login + +job = { + jsonmodel_type: "job", + job: { + jsonmodel_type: "import_job", + import_type: "ead_xml", + filenames: [File.basename(path)] + } +} + +client.repository 2 do + response = File.open(path) do |file| + client.post_multipart("jobs_with_files", {job: job.to_json, files: [file]}) + end + abort "upload failed (#{response.status_code}): #{response.body}" unless + response.status_code == 200 + + job_id = response.parsed["id"] + puts "created import job #{job_id}" + + # poll until the import finishes, but not for more than ~60s + status = nil + 30.times do + status = client.get("jobs/#{job_id}").parsed["status"] + puts "status: #{status}" + break if %w[completed failed canceled].include?(status) + + sleep 2 + end + + puts client.get("jobs/#{job_id}/log").body +end diff --git a/lib/archivesspace/client/client.rb b/lib/archivesspace/client/client.rb index 97c6928..e14a106 100644 --- a/lib/archivesspace/client/client.rb +++ b/lib/archivesspace/client/client.rb @@ -33,6 +33,12 @@ def post(path, payload, params = {}) request "POST", path, {body: payload.to_json, query: params} end + # Allow passing a file object (multipart = true) + def post_multipart(path, payload, params = {}) + body = payload.transform_values { |v| v.is_a?(Hash) ? v.to_json : v } + request "POST", path, {body: body, query: params, multipart: true} + end + def put(path, payload, params = {}) request "PUT", path, {body: payload.to_json, query: params} end @@ -76,7 +82,7 @@ def use_global_repository def request(method, path, options = {}) sleep config.throttle options = options.dup - options[:headers] = {TOKEN => token} if token + options[:headers] = options.fetch(:headers, {}).merge(TOKEN => token) if token Request.new(context, config, method, path, options).execute end end diff --git a/lib/archivesspace/client/request.rb b/lib/archivesspace/client/request.rb index 2ef1405..779c784 100644 --- a/lib/archivesspace/client/request.rb +++ b/lib/archivesspace/client/request.rb @@ -17,6 +17,7 @@ def initialize(context, config, method = "GET", path = "", options = {}) @options = options.dup @options[:headers] = DEFAULT_HEADERS.merge(@options.fetch(:headers, {})) + @options[:headers].delete("Content-Type") if @options[:multipart] @options[:headers]["User-Agent"] = "#{Client::NAME}/#{Client::VERSION}" @options[:verify] = config.verify_ssl diff --git a/spec/archivesspace/client_spec.rb b/spec/archivesspace/client_spec.rb index 1ea0e44..93dffcf 100644 --- a/spec/archivesspace/client_spec.rb +++ b/spec/archivesspace/client_spec.rb @@ -209,6 +209,24 @@ client.get("resources", opts) expect(opts).to eq(caller_opts) end + + it "posts a file (as multipart form data) with session token" do + client.token = "abc123" + stub = stub_request(:post, "#{DEFAULT_BASE_URI}/repositories/2/jobs_with_files") + .with { |req| + req.headers["Content-Type"].start_with?("multipart/form-data; boundary=") && + req.headers["X-Archivesspace-Session"] == "abc123" && + req.body.include?('name="files[]"; filename="client_spec.rb"') && + req.body.include?('name="job"') + } + .to_return(status: 200, body: "{}", headers: {"Content-Type" => "application/json"}) + File.open(__FILE__) do |file| + client.repository(2) do + client.post_multipart("jobs_with_files", {job: {jsonmodel_type: "job"}, files: [file]}) + end + end + expect(stub).to have_been_requested + end end describe "URL construction" do