bulkrax 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/bulkrax/importers_controller.rb +3 -4
  3. data/app/helpers/bulkrax/validation_helper.rb +4 -4
  4. data/app/jobs/bulkrax/create_relationships_job.rb +3 -0
  5. data/app/jobs/bulkrax/import_work_job.rb +20 -7
  6. data/app/jobs/bulkrax/importer_job.rb +1 -1
  7. data/app/jobs/bulkrax/schedule_relationships_job.rb +2 -1
  8. data/app/matchers/bulkrax/application_matcher.rb +1 -0
  9. data/app/models/bulkrax/csv_entry.rb +93 -24
  10. data/app/models/bulkrax/exporter.rb +3 -12
  11. data/app/models/bulkrax/importer.rb +1 -1
  12. data/app/models/bulkrax/pending_relationship.rb +1 -1
  13. data/app/models/concerns/bulkrax/dynamic_record_lookup.rb +1 -1
  14. data/app/models/concerns/bulkrax/export_behavior.rb +6 -4
  15. data/app/models/concerns/bulkrax/has_matchers.rb +1 -0
  16. data/app/models/concerns/bulkrax/import_behavior.rb +6 -3
  17. data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +9 -1
  18. data/app/parsers/bulkrax/application_parser.rb +14 -16
  19. data/app/parsers/bulkrax/bagit_parser.rb +5 -16
  20. data/app/parsers/bulkrax/csv_parser.rb +43 -111
  21. data/app/parsers/bulkrax/oai_dc_parser.rb +2 -2
  22. data/app/parsers/bulkrax/parser_export_record_set.rb +281 -0
  23. data/app/parsers/bulkrax/xml_parser.rb +9 -5
  24. data/app/services/bulkrax/remove_relationships_for_importer.rb +4 -2
  25. data/app/views/bulkrax/entries/show.html.erb +1 -1
  26. data/app/views/bulkrax/exporters/_form.html.erb +32 -33
  27. data/app/views/bulkrax/exporters/index.html.erb +2 -2
  28. data/app/views/bulkrax/exporters/show.html.erb +3 -3
  29. data/app/views/bulkrax/importers/_bagit_fields.html.erb +13 -12
  30. data/app/views/bulkrax/importers/_csv_fields.html.erb +13 -12
  31. data/app/views/bulkrax/importers/_oai_fields.html.erb +12 -10
  32. data/app/views/bulkrax/importers/_xml_fields.html.erb +12 -11
  33. data/app/views/bulkrax/importers/show.html.erb +18 -16
  34. data/app/views/bulkrax/shared/_collection_entries_tab.html.erb +6 -6
  35. data/app/views/bulkrax/shared/_file_set_entries_tab.html.erb +6 -6
  36. data/app/views/bulkrax/shared/_work_entries_tab.html.erb +6 -6
  37. data/config/locales/bulkrax.en.yml +26 -0
  38. data/lib/bulkrax/entry_spec_helper.rb +17 -0
  39. data/lib/bulkrax/version.rb +1 -1
  40. data/lib/bulkrax.rb +119 -46
  41. data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +1 -1
  42. data/lib/tasks/reset.rake +1 -1
  43. metadata +7 -6
@@ -1,7 +1,7 @@
1
1
  <% provide :page_header do %>
2
2
  <h1><span class="fa fa-cloud-download" aria-hidden="true"></span> Exporters</h1>
3
3
  <div class="pull-right">
4
- <%= link_to new_exporter_path, class: 'btn btn-primary' do %>
4
+ <%= link_to new_exporter_path, class: 'btn btn-primary', data: { turbolinks: false } do %>
5
5
  <span class="fa fa-edit" aria-hidden="true"></span> <%= t(:'helpers.action.exporter.new') %>
6
6
  <% end %>
7
7
  </div>
@@ -42,7 +42,7 @@
42
42
  <% end%>
43
43
  </td>
44
44
  <td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), exporter_path(exporter) %></td>
45
- <td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_exporter_path(exporter) %></td>
45
+ <td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_exporter_path(exporter), data: { turbolinks: false } %></td>
46
46
  <td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), exporter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
47
47
  </tr>
48
48
  <% end %>
@@ -96,9 +96,9 @@
96
96
  <div class="bulkrax-nav-tab-bottom-margin">
97
97
  <!-- Nav tabs -->
98
98
  <ul class="bulkrax-nav-tab-top-margin tab-nav nav nav-tabs" role="tablist">
99
- <li role="presentation" class='active'><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab">Work Entries</a></li>
100
- <li role="presentation"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab">Collection Entries</a></li>
101
- <li role="presentation"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab">File Set Entries</a></li>
99
+ <li role="presentation" class='active'><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.work_entries') %></a></li>
100
+ <li role="presentation"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.collection_entries') %></a></li>
101
+ <li role="presentation"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.file_set_entries') %></a></li>
102
102
  </ul>
103
103
  <!-- Tab panes -->
104
104
  <div class="tab-content outline">
@@ -24,17 +24,18 @@
24
24
  input_html: { class: 'form-control' }
25
25
  %>
26
26
 
27
- <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
28
- <%= fi.input :rights_statement,
29
- collection: rights_statements.select_active_options,
30
- selected: importer.parser_fields['rights_statement'],
31
- include_blank: true,
32
- item_helper: rights_statements.method(:include_current_value),
33
- input_html: { class: 'form-control' } ,
34
- required: false
35
- %>
36
- <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
37
-
27
+ <% if defined?(::Hyrax) %>
28
+ <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
29
+ <%= fi.input :rights_statement,
30
+ collection: rights_statements.select_active_options,
31
+ selected: importer.parser_fields['rights_statement'],
32
+ include_blank: true,
33
+ item_helper: rights_statements.method(:include_current_value),
34
+ input_html: { class: 'form-control' } ,
35
+ required: false
36
+ %>
37
+ <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
38
+ <% end %>
38
39
  <h4>Bag or Bags to Import:</h4>
39
40
  <p>File upload and Cloud File upload must be a Zip file containing a single BagIt Bag, or a folder containing multiple BagIt Bags.</p>
40
41
  <p>The Server Path can point to a BagIt Bag, a folder containing BagIt Bags, or a zip file containing either.</p>
@@ -47,7 +48,7 @@
47
48
  <%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
48
49
  </div>
49
50
  <div id='cloud'>
50
- <% if Hyrax.config.browse_everything? %>
51
+ <% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
51
52
  <%= render 'browse_everything', form: form %>
52
53
  <% end %>
53
54
  </div>
@@ -9,17 +9,18 @@
9
9
  input_html: { class: 'form-control' }
10
10
  %>
11
11
 
12
- <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
13
- <%= fi.input :rights_statement,
14
- collection: rights_statements.select_active_options,
15
- selected: importer.parser_fields['rights_statement'],
16
- include_blank: true,
17
- item_helper: rights_statements.method(:include_current_value),
18
- input_html: { class: 'form-control' },
19
- required: false
20
- %>
21
- <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
22
-
12
+ <% if defined?(::Hyrax) %>
13
+ <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
14
+ <%= fi.input :rights_statement,
15
+ collection: rights_statements.select_active_options,
16
+ selected: importer.parser_fields['rights_statement'],
17
+ include_blank: true,
18
+ item_helper: rights_statements.method(:include_current_value),
19
+ input_html: { class: 'form-control' },
20
+ required: false
21
+ %>
22
+ <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
23
+ <% end %>
23
24
  <h4>Add CSV File to Import:</h4>
24
25
  <%# accept a single file upload; data files and bags will need to be added another way %>
25
26
 
@@ -30,7 +31,7 @@
30
31
  <div id='file_path'>
31
32
  <%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
32
33
  </div>
33
- <% if Hyrax.config.browse_everything? %>
34
+ <% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
34
35
  <h4>Add Files to Import:</h4>
35
36
  <p>Choose files to upload. The filenames must be unique, and the filenames must be referenced in a column called 'file' in the accompanying CSV file.</p>
36
37
  <%= render 'browse_everything', form: form %>
@@ -15,16 +15,18 @@
15
15
  input_html: { class: 'form-control' }
16
16
  %>
17
17
 
18
- <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
19
- <%= fi.input :rights_statement,
20
- collection: rights_statements.select_active_options,
21
- selected: importer.parser_fields['rights_statement'],
22
- include_blank: true,
23
- item_helper: rights_statements.method(:include_current_value),
24
- input_html: { class: 'form-control' },
25
- required: false
26
- %>
27
- <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use dc:rights from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
18
+ <% if defined?(::Hyrax) %>
19
+ <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
20
+ <%= fi.input :rights_statement,
21
+ collection: rights_statements.select_active_options,
22
+ selected: importer.parser_fields['rights_statement'],
23
+ include_blank: true,
24
+ item_helper: rights_statements.method(:include_current_value),
25
+ input_html: { class: 'form-control' },
26
+ required: false
27
+ %>
28
+ <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use dc:rights from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
29
+ <% end %>
28
30
  <%= fi.input :thumbnail_url, required: false, as: :string, input_html: { value: importer.parser_fields['thumbnail_url'] } %>
29
31
  <div class="help-block well well-sm">
30
32
  <p>
@@ -31,16 +31,17 @@
31
31
  input_html: { class: 'form-control' }
32
32
  %>
33
33
 
34
- <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
35
- <%= fi.input :rights_statement,
36
- collection: rights_statements.select_active_options,
37
- selected: importer.parser_fields['rights_statement'],
38
- include_blank: true,
39
- item_helper: rights_statements.method(:include_current_value),
40
- input_html: { class: 'form-control' },
41
- required: false %>
42
- <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
43
-
34
+ <% if defined?(::Hyrax) %>
35
+ <% rights_statements = Hyrax.config.rights_statement_service_class.new %>
36
+ <%= fi.input :rights_statement,
37
+ collection: rights_statements.select_active_options,
38
+ selected: importer.parser_fields['rights_statement'],
39
+ include_blank: true,
40
+ item_helper: rights_statements.method(:include_current_value),
41
+ input_html: { class: 'form-control' },
42
+ required: false %>
43
+ <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %>
44
+ <% end %>
44
45
  <h4>XML and files to Import:</h4>
45
46
  <p>File upload and Cloud File upload MUST be a either a single XML file (for metadata only import) OR a Zip file containing the XML files and data files, each in a separate folder.</p>
46
47
  <p>The Server Path can point to a folder containing XML files and data files to import, or direct to the XML file itself.</p>
@@ -53,7 +54,7 @@
53
54
  <%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
54
55
  </div>
55
56
  <div id='cloud'>
56
- <% if Hyrax.config.browse_everything? %>
57
+ <% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
57
58
  <%= render 'browse_everything', form: form %>
58
59
  <% end %>
59
60
  </div>
@@ -1,6 +1,6 @@
1
1
  <div class="col-xs-12 main-header">
2
2
  <h1><span class="fa fa-cloud-upload" aria-hidden="true"></span> Importer: <%= @importer.name %></h1>
3
- <% if @importer.parser_klass == 'Bulkrax::CsvParser' && @work_entries.map { |e| e.status == 'failed' }.any? %>
3
+ <% if @importer.parser_klass == 'Bulkrax::CsvParser' && @work_entries.map(&:failed?).any? %>
4
4
  <div class="pull-right">
5
5
  <%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary' %>
6
6
  <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' %>
@@ -10,27 +10,29 @@
10
10
  <div class="panel panel-default bulkrax-align-text">
11
11
  <div class="panel-body">
12
12
  <p class="bulkrax-p-align">
13
- <strong>Name:</strong>
13
+ <strong><%= t('bulkrax.importer.labels.name') %>:</strong>
14
14
  <%= @importer.name %>
15
15
  </p>
16
+ <% if defined?(::Hyrax) %>
17
+ <p class="bulkrax-p-align">
18
+ <strong><%= t('bulkrax.importer.labels.admin_set') %>:</strong>
19
+ <%= @importer.admin_set_id %>
20
+ </p>
21
+ <% end %>
16
22
  <p class="bulkrax-p-align">
17
- <strong>Admin set:</strong>
18
- <%= @importer.admin_set_id %>
19
- </p>
20
- <p class="bulkrax-p-align">
21
- <strong>User:</strong>
23
+ <strong><%= t('bulkrax.importer.labels.user') %>:</strong>
22
24
  <%= @importer.user %>
23
25
  </p>
24
26
  <p class="bulkrax-p-align">
25
- <strong>Frequency:</strong>
27
+ <strong><%= t('bulkrax.importer.labels.frequency') %>:</strong>
26
28
  <%= @importer.frequency %>
27
29
  </p>
28
30
  <p class="bulkrax-p-align">
29
- <strong>Parser klass:</strong>
31
+ <strong><%= t('bulkrax.importer.labels.parser_klass') %>:</strong>
30
32
  <%= @importer.parser_klass %>
31
33
  </p>
32
34
  <p class="bulkrax-p-align">
33
- <strong>Limit:</strong>
35
+ <strong><%= t('bulkrax.importer.labels.limit') %>:</strong>
34
36
  <%= @importer.limit %>
35
37
  </p>
36
38
 
@@ -57,26 +59,26 @@
57
59
  <%= render partial: 'bulkrax/shared/bulkrax_field_mapping', locals: {item: @importer} %>
58
60
 
59
61
  <p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_works %> processed, <%= @importer.last_run&.failed_works %> failed">
60
- <strong>Total Works:</strong>
62
+ <strong><%= t('bulkrax.importer.labels.total_work_entries') %>:</strong>
61
63
  <%= @importer.last_run&.total_work_entries %>
62
64
  </p>
63
65
 
64
66
  <p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_collections %> processed, <%= @importer.last_run&.failed_collections %> failed">
65
- <strong>Total Collections:</strong>
67
+ <strong><%= t('bulkrax.importer.labels.total_collections') %>:</strong>
66
68
  <%= @importer.last_run&.total_collection_entries %>
67
69
  </p>
68
70
 
69
71
  <p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_file_sets %> processed, <%= @importer.last_run&.failed_file_sets %> failed">
70
- <strong>Total File Sets:</strong>
72
+ <strong><%= t('bulkrax.importer.labels.total_file_sets') %>:</strong>
71
73
  <%= @importer.last_run&.total_file_set_entries %>
72
74
  </p>
73
75
 
74
76
  <div class="bulkrax-nav-tab-bottom-margin">
75
77
  <!-- Nav tabs -->
76
78
  <ul class="bulkrax-nav-tab-top-margin tab-nav nav nav-tabs" role="tablist">
77
- <li role="presentation" class='active'><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab">Work Entries</a></li>
78
- <li role="presentation"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab">Collection Entries</a></li>
79
- <li role="presentation"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab">File Set Entries</a></li>
79
+ <li role="presentation" class='active'><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.work_entries') %></a></li>
80
+ <li role="presentation"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.collection_entries') %></a></li>
81
+ <li role="presentation"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.file_set_entries') %></a></li>
80
82
  </ul>
81
83
  <!-- Tab panes -->
82
84
  <div class="tab-content outline">
@@ -2,12 +2,12 @@
2
2
  <table class='table table-striped'>
3
3
  <thead>
4
4
  <tr>
5
- <th>Identifier</th>
6
- <th>Entry ID</th>
7
- <th>Status</th>
8
- <th>Errors</th>
9
- <th>Status Set At</th>
10
- <th>Actions</th>
5
+ <th><%= t('bulkrax.table_header.labels.identifier') %></th>
6
+ <th><%= t('bulkrax.table_header.labels.entry_id') %></th>
7
+ <th><%= t('bulkrax.table_header.labels.status') %></th>
8
+ <th><%= t('bulkrax.table_header.labels.errors') %></th>
9
+ <th><%= t('bulkrax.table_header.labels.status_set_at') %></th>
10
+ <th><%= t('bulkrax.table_header.labels.actions') %></th>
11
11
  </tr>
12
12
  </thead>
13
13
  <tbody>
@@ -2,12 +2,12 @@
2
2
  <table class='table table-striped'>
3
3
  <thead>
4
4
  <tr>
5
- <th>Identifier</th>
6
- <th>Entry ID</th>
7
- <th>Status</th>
8
- <th>Errors</th>
9
- <th>Status Set At</th>
10
- <th>Actions</th>
5
+ <th><%= t('bulkrax.table_header.labels.identifier') %></th>
6
+ <th><%= t('bulkrax.table_header.labels.entry_id') %></th>
7
+ <th><%= t('bulkrax.table_header.labels.status') %></th>
8
+ <th><%= t('bulkrax.table_header.labels.errors') %></th>
9
+ <th><%= t('bulkrax.table_header.labels.status_set_at') %></th>
10
+ <th><%= t('bulkrax.table_header.labels.actions') %></th>
11
11
  </tr>
12
12
  </thead>
13
13
  <tbody>
@@ -2,12 +2,12 @@
2
2
  <table class='table table-striped'>
3
3
  <thead>
4
4
  <tr>
5
- <th>Identifier</th>
6
- <th>Entry ID</th>
7
- <th>Status</th>
8
- <th>Errors</th>
9
- <th>Status Set At</th>
10
- <th>Actions</th>
5
+ <th><%= t('bulkrax.table_header.labels.identifier') %></th>
6
+ <th><%= t('bulkrax.table_header.labels.entry_id') %></th>
7
+ <th><%= t('bulkrax.table_header.labels.status') %></th>
8
+ <th><%= t('bulkrax.table_header.labels.errors') %></th>
9
+ <th><%= t('bulkrax.table_header.labels.status_set_at') %></th>
10
+ <th><%= t('bulkrax.table_header.labels.actions') %></th>
11
11
  </tr>
12
12
  </thead>
13
13
  <tbody>
@@ -27,8 +27,12 @@ en:
27
27
  start_date: Start Date
28
28
  status: Status
29
29
  total_work_entries: Total Works
30
+ total_entries: Total Entries
30
31
  user: User
31
32
  worktype: Work Type
33
+ work_entries: Work Entries
34
+ collection_entries: Collection Entries
35
+ file_set_entries: File Set Entries
32
36
  workflow_status:
33
37
  approved: "Approved"
34
38
  deleted: "Deleted"
@@ -40,3 +44,25 @@ en:
40
44
  hints:
41
45
  include_thumbnails: "These exported fields currently cannot be imported."
42
46
  generated_metadata: "These exported fields currently cannot be imported."
47
+ importer:
48
+ labels:
49
+ name: Name
50
+ user: User
51
+ admin_set: Admin set
52
+ frequency: Frequency
53
+ parser_klass: Parser klass
54
+ limit: Limit
55
+ total_work_entries: Total Works
56
+ total_collections: Total Collections
57
+ total_file_sets: Total File Sets
58
+ work_entries: Work Entries
59
+ collection_entries: Collection Entries
60
+ file_set_entries: File Set Entries
61
+ table_header:
62
+ labels:
63
+ identifier: Identifier
64
+ entry_id: Entry ID
65
+ status: Status
66
+ errors: Errors
67
+ status_set_at: Status Set At
68
+ actions: Actions
@@ -58,6 +58,23 @@ module Bulkrax
58
58
  **options)
59
59
  end
60
60
 
61
+ # @api public
62
+ #
63
+ # @param parser_class_name [String]
64
+ # @param parser_fields [Hash<String,Hash>]
65
+ #
66
+ # @return [Bulkrax::Exporter]
67
+ def self.exporter_for(parser_class_name:, parser_fields: {}, **options)
68
+ Bulkrax::Exporter.new(
69
+ name: options.fetch(:exporter_name, "Test importer for identifier"),
70
+ user: options.fetch(:exporter_user, User.new(email: "hello@world.com")),
71
+ limit: options.fetch(:exporter_limit, 1),
72
+ parser_klass: parser_class_name,
73
+ field_mapping: options.fetch(:exporter_field_mappings) { Bulkrax.field_mappings.fetch(parser_class_name) },
74
+ parser_fields: parser_fields
75
+ )
76
+ end
77
+
61
78
  ENTRY_TYPE_TO_METHOD_NAME_MAP = {
62
79
  entry: :entry_class,
63
80
  collection: :collection_entry_class,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bulkrax
4
- VERSION = '5.1.0'
4
+ VERSION = '5.2.0'
5
5
  end
data/lib/bulkrax.rb CHANGED
@@ -6,31 +6,91 @@ require 'active_support/all'
6
6
 
7
7
  # rubocop:disable Metrics/ModuleLength
8
8
  module Bulkrax
9
- class << self
10
- # @todo Move from module attribute methods to a configuration class. With module attributes,
11
- # when we make a change we are polluting the global space. This means that our tests that
12
- # modify these config values are modifying global state. Which is not desirous, as it can
13
- # introduce unexpected flakey tests.
14
- mattr_accessor :api_definition,
15
- :default_field_mapping,
16
- :default_work_type,
17
- :export_path,
18
- :field_mappings,
19
- :fill_in_blank_source_identifiers,
20
- :generated_metadata_mapping,
21
- :import_path,
22
- :multi_value_element_join_on,
23
- :multi_value_element_split_on,
24
- :object_factory,
25
- :parsers,
26
- :qa_controlled_properties,
27
- :related_children_field_mapping,
28
- :related_parents_field_mapping,
29
- :removed_image_path,
30
- :reserved_properties,
31
- :server_name
32
-
33
- self.parsers = [
9
+ extend self # rubocop:disable Style/ModuleFunction
10
+ extend Forwardable
11
+
12
+ ##
13
+ # @api public
14
+ class Configuration
15
+ attr_accessor :api_definition,
16
+ :curation_concerns,
17
+ :default_field_mapping,
18
+ :default_work_type,
19
+ :export_path,
20
+ :field_mappings,
21
+ :file_model_class,
22
+ :fill_in_blank_source_identifiers,
23
+ :generated_metadata_mapping,
24
+ :import_path,
25
+ :multi_value_element_join_on,
26
+ :multi_value_element_split_on,
27
+ :object_factory,
28
+ :parsers,
29
+ :qa_controlled_properties,
30
+ :related_children_field_mapping,
31
+ :related_parents_field_mapping,
32
+ :relationship_job_class,
33
+ :removed_image_path,
34
+ :required_elements,
35
+ :reserved_properties,
36
+ :server_name
37
+ end
38
+
39
+ def config
40
+ @config ||= Configuration.new
41
+ yield @config if block_given?
42
+ @config
43
+ end
44
+ alias setup config
45
+
46
+ def_delegators :@config,
47
+ :api_definition,
48
+ :api_definition=,
49
+ :curation_concerns,
50
+ :curation_concerns=,
51
+ :default_field_mapping,
52
+ :default_field_mapping=,
53
+ :default_work_type,
54
+ :default_work_type=,
55
+ :export_path,
56
+ :export_path=,
57
+ :field_mappings,
58
+ :field_mappings=,
59
+ :file_model_class,
60
+ :file_model_class=,
61
+ :fill_in_blank_source_identifiers,
62
+ :fill_in_blank_source_identifiers=,
63
+ :generated_metadata_mapping,
64
+ :generated_metadata_mapping=,
65
+ :import_path,
66
+ :import_path=,
67
+ :multi_value_element_join_on,
68
+ :multi_value_element_join_on=,
69
+ :multi_value_element_split_on,
70
+ :multi_value_element_split_on=,
71
+ :object_factory,
72
+ :object_factory=,
73
+ :parsers,
74
+ :parsers=,
75
+ :qa_controlled_properties,
76
+ :qa_controlled_properties=,
77
+ :related_children_field_mapping,
78
+ :related_children_field_mapping=,
79
+ :related_parents_field_mapping,
80
+ :related_parents_field_mapping=,
81
+ :relationship_job_class,
82
+ :relationship_job_class=,
83
+ :removed_image_path,
84
+ :removed_image_path=,
85
+ :required_elements,
86
+ :required_elements=,
87
+ :reserved_properties,
88
+ :reserved_properties=,
89
+ :server_name,
90
+ :server_name=
91
+
92
+ config do |conf|
93
+ conf.parsers = [
34
94
  { name: "OAI - Dublin Core", class_name: "Bulkrax::OaiDcParser", partial: "oai_fields" },
35
95
  { name: "OAI - Qualified Dublin Core", class_name: "Bulkrax::OaiQualifiedDcParser", partial: "oai_fields" },
36
96
  { name: "CSV - Comma Separated Values", class_name: "Bulkrax::CsvParser", partial: "csv_fields" },
@@ -38,16 +98,34 @@ module Bulkrax
38
98
  { name: "XML", class_name: "Bulkrax::XmlParser", partial: "xml_fields" }
39
99
  ]
40
100
 
41
- self.import_path = Bulkrax.import_path || 'tmp/imports'
42
- self.export_path = Bulkrax.export_path || 'tmp/exports'
43
- self.removed_image_path = Bulkrax::Engine.root.join('spec', 'fixtures', 'removed.png').to_s
44
- self.server_name = 'bulkrax@example.com'
101
+ conf.import_path = Bulkrax.import_path || 'tmp/imports'
102
+ conf.export_path = Bulkrax.export_path || 'tmp/exports'
103
+ conf.removed_image_path = Bulkrax::Engine.root.join('spec', 'fixtures', 'removed.png').to_s
104
+ conf.server_name = 'bulkrax@example.com'
105
+ conf.relationship_job_class = "Bulkrax::CreateRelationshipsJob"
106
+ conf.required_elements = ['title']
107
+
108
+ def conf.curation_concerns
109
+ @curation_concerns ||= defined?(::Hyrax) ? ::Hyrax.config.curation_concerns : []
110
+ end
111
+
112
+ def conf.curation_concerns=(val)
113
+ @curation_concerns = val
114
+ end
115
+
116
+ def conf.file_model_class
117
+ @file_model_class ||= defined?(::Hyrax) ? ::FileSet : File
118
+ end
119
+
120
+ def conf.file_model_class=(val)
121
+ @file_model_class = val
122
+ end
45
123
 
46
124
  # Hash of Generic field_mappings for use in the view
47
- # There must be one field_mappings hash per view parial
125
+ # There must be one field_mappings hash per view partial
48
126
  # Based on Hyrax CoreMetadata && BasicMetadata
49
127
  # Override at application level to change
50
- self.field_mappings = {
128
+ conf.field_mappings = {
51
129
  "Bulkrax::OaiDcParser" => {
52
130
  "contributor" => { from: ["contributor"] },
53
131
  # no appropriate mapping for coverage (based_near needs id)
@@ -95,7 +173,7 @@ module Bulkrax
95
173
  }
96
174
 
97
175
  # Lambda to set the default field mapping
98
- self.default_field_mapping = lambda do |field|
176
+ conf.default_field_mapping = lambda do |field|
99
177
  return if field.blank?
100
178
  {
101
179
  field.to_s =>
@@ -110,7 +188,7 @@ module Bulkrax
110
188
  end
111
189
 
112
190
  # Properties that should not be used in imports. They are reserved for use by Hyrax.
113
- self.reserved_properties = %w[
191
+ conf.reserved_properties = %w[
114
192
  create_date
115
193
  modified_date
116
194
  date_modified
@@ -133,10 +211,10 @@ module Bulkrax
133
211
  # List of Questioning Authority properties that are controlled via YAML files in
134
212
  # the config/authorities/ directory. For example, the :rights_statement property
135
213
  # is controlled by the active terms in config/authorities/rights_statements.yml
136
- self.qa_controlled_properties = %w[rights_statement license]
214
+ conf.qa_controlled_properties = %w[rights_statement license]
137
215
  end
138
216
 
139
- def self.api_definition
217
+ def api_definition
140
218
  @api_definition ||= ActiveSupport::HashWithIndifferentAccess.new(
141
219
  YAML.safe_load(
142
220
  ERB.new(
@@ -149,9 +227,9 @@ module Bulkrax
149
227
  DEFAULT_MULTI_VALUE_ELEMENT_JOIN_ON = ' | '
150
228
  # Specify the delimiter for joining an attribute's multi-value array into a string.
151
229
  #
152
- # @note the specific delimeter should likely be present in the multi_value_element_split_on
230
+ # @note the specific delimiter should likely be present in the multi_value_element_split_on
153
231
  # expression.
154
- def self.multi_value_element_join_on
232
+ def multi_value_element_join_on
155
233
  @multi_value_element_join_on ||= DEFAULT_MULTI_VALUE_ELEMENT_JOIN_ON
156
234
  end
157
235
 
@@ -161,7 +239,7 @@ module Bulkrax
161
239
  #
162
240
  # @note The "true" value is to preserve backwards compatibility.
163
241
  # @see DEFAULT_MULTI_VALUE_ELEMENT_JOIN_ON
164
- def self.multi_value_element_split_on
242
+ def multi_value_element_split_on
165
243
  if @multi_value_element_join_on.is_a?(TrueClass)
166
244
  DEFAULT_MULTI_VALUE_ELEMENT_SPLIT_ON
167
245
  else
@@ -169,29 +247,24 @@ module Bulkrax
169
247
  end
170
248
  end
171
249
 
172
- # this function maps the vars from your app into your engine
173
- def self.setup
174
- yield self
175
- end
176
-
177
250
  # Responsible for stripping hidden characters from the given string.
178
251
  #
179
252
  # @param value [#to_s]
180
253
  # @return [String] with hidden characters removed
181
254
  #
182
255
  # @see https://github.com/samvera-labs/bulkrax/issues/688
183
- def self.normalize_string(value)
256
+ def normalize_string(value)
184
257
  # Removing [Byte Order Mark (BOM)](https://en.wikipedia.org/wiki/Byte_order_mark)
185
258
  value.to_s.delete("\xEF\xBB\xBF")
186
259
  end
187
260
 
188
- def self.fallback_user_for_importer_exporter_processing
261
+ def fallback_user_for_importer_exporter_processing
189
262
  return User.batch_user if defined?(Hyrax) && User.respond_to?(:batch_user)
190
263
 
191
264
  raise "We have no fallback user available for Bulkrax.fallback_user_for_importer_exporter_processing"
192
265
  end
193
266
 
194
- # This class confirms to the Active::Support.serialze interface. It's job is to ensure that we
267
+ # This class confirms to the Active::Support.serialize interface. It's job is to ensure that we
195
268
  # don't have keys with the tricksy Byte Order Mark character.
196
269
  #
197
270
  # @see https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize