bulkrax 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
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