diff --git a/app/controllers/concerns/bulkrax/datatables_behavior.rb b/app/controllers/concerns/bulkrax/datatables_behavior.rb
index 570ac18db..cbe50bfe6 100644
--- a/app/controllers/concerns/bulkrax/datatables_behavior.rb
+++ b/app/controllers/concerns/bulkrax/datatables_behavior.rb
@@ -143,6 +143,26 @@ def format_entries(entries, item)
}
end
+ def format_statuses(statuses, item)
+ result = statuses.map do |status|
+ {
+ identifier: view_context.link_to(status.id, importer_status_path(item, status)),
+ id: status.id,
+ status_message: status.status_message,
+ error_class: status.error_class,
+ created_at: status.created_at,
+ updated_at: status.updated_at,
+ runnable_id: view_context.link_to(status.runnable_id, importer_path(item)),
+ actions: status_util_links(status, item)
+ }
+ end
+ {
+ data: result,
+ recordsTotal: statuses.size,
+ recordsFiltered: statuses.size
+ }
+ end
+
def entry_util_links(e, item)
links = []
links << view_context.link_to(view_context.raw(''), view_context.item_entry_path(item, e))
@@ -151,6 +171,13 @@ def entry_util_links(e, item)
links.join(" ")
end
+ def status_util_links(status, item)
+ links = []
+ links << view_context.link_to(view_context.raw(''), importer_status_path(item, status))
+ links << "" if view_context.an_importer?(item)
+ links.join(" ")
+ end
+
def status_message_for(e)
if e.status_message == "Complete"
"
#{e.status_message} | "
diff --git a/app/models/bulkrax/csv_entry.rb b/app/models/bulkrax/csv_entry.rb
index c51a64d99..b56f391bf 100644
--- a/app/models/bulkrax/csv_entry.rb
+++ b/app/models/bulkrax/csv_entry.rb
@@ -83,6 +83,10 @@ def build_metadata
add_local
self.parsed_metadata
+ rescue => e
+ self.save!
+ self.set_status_info(e, self)
+ raise e
end
# limited metadata is needed for delete jobs
diff --git a/config/routes.rb b/config/routes.rb
index c4dfc4c6b..286ea5343 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,6 +8,7 @@
get :exporter_table
end
resources :entries, only: %i[show update destroy]
+ resources :statuses, only: :show
end
resources :importers do
put :continue
@@ -19,6 +20,7 @@
post :external_sets
end
resources :entries, only: %i[show update destroy]
+ resources :statuses, only: :show
get :upload_corrected_entries
post :upload_corrected_entries_file
end
diff --git a/spec/controllers/concerns/bulkrax/datatables_behavior_spec.rb b/spec/controllers/concerns/bulkrax/datatables_behavior_spec.rb
index abfca8849..843d3c5f5 100644
--- a/spec/controllers/concerns/bulkrax/datatables_behavior_spec.rb
+++ b/spec/controllers/concerns/bulkrax/datatables_behavior_spec.rb
@@ -95,6 +95,33 @@ def current_user
end
end
+ describe '#format_statuses' do
+ let(:item) { FactoryBot.create(:bulkrax_importer) }
+ let(:entry_1) { FactoryBot.create(:bulkrax_entry, importerexporter: item) }
+ let(:entry_2) { FactoryBot.create(:bulkrax_entry, importerexporter: item) }
+ let(:entries) { [entry_1, entry_2] }
+ let(:status_1) { FactoryBot.create(:bulkrax_status) }
+ let(:status_2) { FactoryBot.create(:bulkrax_status) }
+ let(:status_3) { FactoryBot.create(:bulkrax_status) }
+ let(:statuses) { [status_1, status_2, status_3] }
+
+ it 'returns a hash with the correct structure' do
+ get :index
+ result = controller.format_statuses(statuses, item)
+ expect(result).to be_a(Hash)
+ expect(result.keys).to contain_exactly(:data, :recordsTotal, :recordsFiltered)
+ expect(result[:data]).to be_a(Array)
+ expect(result[:data].first.keys).to contain_exactly(:identifier, :id, :status_message, :updated_at, :error_class, :actions, :created_at, :runnable_id)
+ end
+
+ it 'returns the correct number of statuses' do
+ get :index
+ result = controller.format_statuses(statuses, item)
+ expect(result[:recordsTotal]).to eq(statuses.size)
+ expect(result[:recordsFiltered]).to eq(statuses.size)
+ end
+ end
+
describe '#entry_util_links' do
include Bulkrax::Engine.routes.url_helpers
@@ -124,6 +151,28 @@ def current_user
end
end
+ describe '#status_util_links' do
+ include Bulkrax::Engine.routes.url_helpers
+
+ let(:item) { FactoryBot.create(:bulkrax_importer) }
+ let(:entry) { FactoryBot.create(:bulkrax_entry, importerexporter: item) }
+ let(:status) { FactoryBot.create(:bulkrax_status) }
+
+ it 'returns a string of HTML links' do
+ get :index
+ result = controller.status_util_links(status, item)
+ expect(result).to be_a(String)
+ expect(result).to include('fa-info-circle')
+ expect(result).to include('fa-repeat')
+ end
+
+ it 'includes a link to the status' do
+ get :index
+ result = controller.status_util_links(status, item)
+ expect(result).to include(importer_status_path(item, status))
+ end
+ end
+
describe '#status_message_for' do
let(:item) { FactoryBot.create(:bulkrax_importer) }
diff --git a/spec/models/bulkrax/csv_entry_spec.rb b/spec/models/bulkrax/csv_entry_spec.rb
index 70331a5e7..b345a80d2 100644
--- a/spec/models/bulkrax/csv_entry_spec.rb
+++ b/spec/models/bulkrax/csv_entry_spec.rb
@@ -118,7 +118,14 @@ class ::Avocado < Work
end
it 'fails and stores an error' do
+ expect(subject.status_message).to eq 'Pending'
+ expect(subject.error_class).to eq nil
expect { subject.build_metadata }.to raise_error(StandardError)
+ expect(subject.status_message).to eq 'Failed'
+ expect(subject.statuses[0].status_message).to eq 'Failed'
+ expect(subject.statuses[0].error_message).to eq 'Missing required elements, missing element(s) are: title'
+ expect(subject.statuses[0].error_backtrace.nil?).to eq false
+ expect(subject.error_class).to eq 'StandardError'
end
end
@@ -227,8 +234,12 @@ class ::Avocado < Work
end
it 'raises a StandardError' do
+ expect(subject.status_message).to eq 'Pending'
+ expect(subject.error_class).to eq nil
expect { subject.build_metadata }
.to raise_error(StandardError, %("hello world" is not a valid and/or active authority ID for the :rights_statement field))
+ expect(subject.status_message).to eq 'Failed'
+ expect(subject.error_class).to eq 'StandardError'
end
end
end
@@ -282,8 +293,12 @@ class ::Avocado < Work
end
it 'raises a StandardError' do
+ expect(subject.status_message).to eq 'Pending'
+ expect(subject.error_class).to eq nil
expect { subject.build_metadata }
.to raise_error(StandardError, %("hello world" is not a valid and/or active authority ID for the :license field))
+ expect(subject.status_message).to eq 'Failed'
+ expect(subject.error_class).to eq 'StandardError'
end
end
end
diff --git a/spec/models/bulkrax/status_spec.rb b/spec/models/bulkrax/status_spec.rb
index f4dff9655..a306845b7 100644
--- a/spec/models/bulkrax/status_spec.rb
+++ b/spec/models/bulkrax/status_spec.rb
@@ -4,6 +4,99 @@
module Bulkrax
RSpec.describe Status, type: :model do
- pending "add some examples to (or delete) #{__FILE__}"
+ context 'for exporters' do
+ context 'without errors' do
+ let(:exporter_without_errors) { FactoryBot.create(:bulkrax_exporter) }
+ it 'can display the current status' do
+ exporter_without_errors.save
+ expect(exporter_without_errors.statuses.count).to eq 0
+ expect(exporter_without_errors.last_error_at).to eq nil
+ expect(exporter_without_errors.error_class).to eq nil
+ expect(exporter_without_errors.status).to eq 'Pending'
+ end
+ end
+ context 'with errors' do
+ end
+ end
+ context 'for importers' do
+ context 'without errors' do
+ let(:importer_without_errors) { FactoryBot.create(:bulkrax_importer) }
+ it 'can display the current status' do
+ importer_without_errors.save
+ expect(importer_without_errors.statuses.count).to eq 0
+ expect(importer_without_errors.last_error_at).to eq nil
+ expect(importer_without_errors.error_class).to eq nil
+ expect(importer_without_errors.status).to eq 'Pending'
+ end
+ end
+ context 'with errors' do
+ end
+ end
+ context 'for csv entries' do
+ let(:importer) { FactoryBot.create(:bulkrax_importer_csv) }
+ let(:entry_without_errors) { FactoryBot.create(:bulkrax_csv_entry) }
+ let(:entry_with_errors) { Bulkrax::CsvEntry.new(importerexporter: importer) }
+ let(:collection) { FactoryBot.build(:collection) }
+ let(:hyrax_record) do
+ OpenStruct.new(
+ file_sets: [],
+ member_of_collections: [],
+ member_of_work_ids: [],
+ in_work_ids: [],
+ member_work_ids: []
+ )
+ end
+ before do
+ allow(entry_with_errors).to receive(:hyrax_record).and_return(hyrax_record)
+ end
+ context 'without errors' do
+ it 'can display the current status' do
+ entry_without_errors.save
+ expect(entry_without_errors.statuses.count).to eq 0
+ expect(entry_without_errors.last_error_at).to eq nil
+ expect(entry_without_errors.error_class).to eq nil
+ expect(entry_without_errors.status).to eq 'Pending'
+ end
+ end
+ context 'with errors' do
+ context 'for missing metadata' do
+ before do
+ allow_any_instance_of(Bulkrax::CsvEntry).to receive(:collections_created?).and_return(true)
+ allow_any_instance_of(Bulkrax::CsvEntry).to receive(:find_collection).and_return(collection)
+ allow(entry_with_errors).to receive(:raw_metadata).and_return('source_identifier' => '1', 'some_field' => 'some data')
+ end
+ it 'can display a history' do
+ expect { entry_with_errors.build_metadata }.to raise_error(StandardError)
+ expect(entry_with_errors.statuses.count).to eq 1
+ expect(entry_with_errors.status_message).to eq 'Failed'
+ expect(entry_with_errors.statuses[0].status_message).to eq 'Failed'
+ expect(entry_with_errors.statuses[0].error_message).to eq 'Missing required elements, missing element(s) are: title'
+ expect(entry_with_errors.statuses[0].error_backtrace.nil?).to eq false
+ expect(entry_with_errors.error_class).to eq 'StandardError'
+ expect { entry_with_errors.build_metadata }.to raise_error(StandardError)
+ expect(entry_with_errors.statuses.count).to eq 2
+ end
+ end
+ context 'for missing collection' do
+ before do
+ allow_any_instance_of(Bulkrax::CsvEntry).to receive(:collections_created?).and_return(false)
+ allow_any_instance_of(Bulkrax::CsvEntry).to receive(:find_collection).and_return(nil)
+ allow(entry_with_errors).to receive(:raw_metadata).and_return('source_identifier' => '1', 'some_field' => 'some data', 'title' => 'Missing Collection Example')
+ end
+ it 'can display a history' do
+ pending("Making this test make sense")
+ expect { entry_with_errors.build_metadata }.to raise_error(CollectionsCreatedError)
+ expect(entry_with_errors.statuses.count).to eq 1
+ expect(entry_with_errors.status_message).to eq 'Failed'
+ expect(entry_with_errors.statuses[0].status_message).to eq 'Failed'
+ expect(entry_with_errors.statuses[0].error_message).to eq 'Missing required elements, missing element(s) are: title'
+ expect(entry_with_errors.statuses[0].error_backtrace.nil?).to eq false
+ expect(entry_with_errors.error_class).to eq 'StandardError'
+ expect { entry_with_errors.build_metadata }.to raise_error(StandardError)
+ expect(entry_with_errors.statuses.count).to eq 2
+ end
+ end
+ end
+ end
end
end