bulkrax 8.2.3 → 8.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/bulkrax/bulkrax.js +9 -7
- data/app/assets/javascripts/bulkrax/importers.js.erb +134 -99
- data/app/controllers/bulkrax/importers_controller.rb +16 -5
- data/app/controllers/concerns/bulkrax/datatables_behavior.rb +1 -1
- data/app/factories/bulkrax/object_factory.rb +1 -4
- data/app/jobs/bulkrax/export_work_job.rb +1 -1
- data/app/models/bulkrax/status.rb +1 -1
- data/app/models/concerns/bulkrax/export_behavior.rb +4 -8
- data/app/parsers/bulkrax/csv_parser.rb +2 -5
- data/app/parsers/bulkrax/parser_export_record_set.rb +1 -1
- data/app/views/bulkrax/importers/_bagit_fields.html.erb +10 -3
- data/app/views/bulkrax/importers/_csv_fields.html.erb +13 -9
- data/app/views/bulkrax/importers/_file_uploader.html.erb +37 -0
- data/app/views/bulkrax/importers/_xml_fields.html.erb +10 -4
- data/lib/bulkrax/version.rb +1 -1
- data/lib/tasks/bulkrax_tasks.rake +1 -1
- metadata +6 -7
- data/db/migrate/20241203010707_entry_error_denormalization.rb +0 -7
- data/db/migrate/20241205212513_faster_first_entry.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a409c17f35bc09ef0a8c63d06a064d01fbff68a0e4c0b91c9bfaed45d6e8169
|
4
|
+
data.tar.gz: 7fad94124795ff133b83d05030c550f2a52f808ac017fdd3a436c17ce039cd01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65280762e81baa620e73d965d5e7c58ec4ccb40d303c00cf634e7f9b3b3850e541cc9964900ce7b9aec9f6be1a7fe81dd9781db5b74209a9f8661f5f8a96f595
|
7
|
+
data.tar.gz: e91e65f6de8edc1640dd9b6e75c246fff4fd0812a3f87f6b4600dd9c95afc095be6076c9a80c5bca50ccc73c3831fc0a30c1160b46f18c483a6d68277bf762a8
|
@@ -5,18 +5,20 @@ $(document).on('turbolinks:load ready', function() {
|
|
5
5
|
$('button#err_toggle').click(function() {
|
6
6
|
$('#error_trace').toggle();
|
7
7
|
});
|
8
|
+
|
8
9
|
$('button#fm_toggle').click(function() {
|
9
10
|
$('#field_mapping').toggle();
|
10
11
|
});
|
12
|
+
|
11
13
|
$('#bulkraxItemModal').on('show.bs.modal', function (event) {
|
12
|
-
var button = $(event.relatedTarget) // Button that triggered the modal
|
13
|
-
var recipient = button.data('entry-id') // Extract info from data-* attributes
|
14
|
+
var button = $(event.relatedTarget); // Button that triggered the modal
|
15
|
+
var recipient = button.data('entry-id'); // Extract info from data-* attributes
|
14
16
|
// If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
|
15
17
|
// Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead.
|
16
|
-
var modal = $(this)
|
18
|
+
var modal = $(this);
|
17
19
|
modal.find('a').each(function() {
|
18
|
-
this.href = this.href.replace(/\d+\?/, recipient + '?')
|
19
|
-
})
|
20
|
-
return true
|
21
|
-
})
|
20
|
+
this.href = this.href.replace(/\d+\?/, recipient + '?');
|
21
|
+
});
|
22
|
+
return true;
|
23
|
+
});
|
22
24
|
});
|
@@ -2,205 +2,240 @@
|
|
2
2
|
// All this logic will automatically be available in application.js.
|
3
3
|
|
4
4
|
function prepBulkrax(event) {
|
5
|
-
var refresh_button = $('.refresh-set-source')
|
6
|
-
var base_url = $('#importer_parser_fields_base_url')
|
7
|
-
var initial_base_url = base_url.val()
|
8
|
-
var file_path_value = $('#importer_parser_fields_import_file_path').val()
|
9
|
-
handleFileToggle(file_path_value)
|
5
|
+
var refresh_button = $('.refresh-set-source');
|
6
|
+
var base_url = $('#importer_parser_fields_base_url');
|
7
|
+
var initial_base_url = base_url.val();
|
8
|
+
var file_path_value = $('#importer_parser_fields_import_file_path').val();
|
9
|
+
handleFileToggle(file_path_value);
|
10
|
+
|
11
|
+
// Initialize the uploader only if hyraxUploader is defined
|
12
|
+
if (typeof $.fn.hyraxUploader === 'function') {
|
13
|
+
// Initialize the uploader
|
14
|
+
$('.fileupload-bulkrax').hyraxUploader({ maxNumberOfFiles: 1 });
|
15
|
+
|
16
|
+
// Function to toggle 'required' attribute based on uploaded files
|
17
|
+
function toggleRequiredAttribute() {
|
18
|
+
const fileInput = $('#addfiles');
|
19
|
+
const uploadedFilesTable = $('.fileupload-bulkrax tbody.files');
|
20
|
+
|
21
|
+
if (uploadedFilesTable.find('tr.template-download').length > 0) {
|
22
|
+
// Remove 'required' if there are uploaded files
|
23
|
+
fileInput.removeAttr('required');
|
24
|
+
} else {
|
25
|
+
// Add 'required' if no uploaded files
|
26
|
+
fileInput.attr('required', 'required');
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
// Check the required attribute when a file is added or removed
|
31
|
+
$('#addfiles').on('change', function() {
|
32
|
+
toggleRequiredAttribute();
|
33
|
+
});
|
34
|
+
|
35
|
+
// Also check when an upload completes or is canceled
|
36
|
+
$('.fileupload-bulkrax').on('fileuploadcompleted fileuploaddestroyed', function() {
|
37
|
+
toggleRequiredAttribute();
|
38
|
+
});
|
39
|
+
|
40
|
+
// Ensure 'required' is only added if there are no files on form reset
|
41
|
+
$('#file-upload-cancel-btn').on('click', function() {
|
42
|
+
$('#addfiles').attr('required', 'required');
|
43
|
+
$('#addfiles').val(''); // Clear file input to ensure 'required' behavior resets
|
44
|
+
});
|
45
|
+
|
46
|
+
// Initial check in case files are already uploaded
|
47
|
+
toggleRequiredAttribute();
|
48
|
+
}
|
10
49
|
|
11
50
|
// handle refreshing/loading of external sets via button click
|
12
51
|
$('body').on('click', '.refresh-set-source', function(e) {
|
13
|
-
e.preventDefault()
|
52
|
+
e.preventDefault();
|
14
53
|
|
15
|
-
external_set_select = $("#importer_parser_fields_set")
|
16
|
-
handleSourceLoad(refresh_button, base_url, external_set_select)
|
17
|
-
})
|
54
|
+
external_set_select = $("#importer_parser_fields_set");
|
55
|
+
handleSourceLoad(refresh_button, base_url, external_set_select);
|
56
|
+
});
|
18
57
|
|
19
58
|
// handle refreshing/loading of external sets via blur event for the base_url field
|
20
59
|
$('body').on('blur', '#importer_parser_fields_base_url', function(e) {
|
21
|
-
e.preventDefault()
|
60
|
+
e.preventDefault();
|
22
61
|
|
23
62
|
// retrieve the latest base_url
|
24
|
-
base_url = $('#importer_parser_fields_base_url')
|
63
|
+
base_url = $('#importer_parser_fields_base_url');
|
25
64
|
|
26
65
|
// ensure we don't make another query if the value is the same -- this can be forced by clicking the refresh button
|
27
66
|
if (initial_base_url != base_url.val()) {
|
28
|
-
external_set_select = $("#importer_parser_fields_set")
|
29
|
-
handleSourceLoad(refresh_button, base_url, external_set_select)
|
30
|
-
initial_base_url = base_url.val()
|
67
|
+
external_set_select = $("#importer_parser_fields_set");
|
68
|
+
handleSourceLoad(refresh_button, base_url, external_set_select);
|
69
|
+
initial_base_url = base_url.val();
|
31
70
|
}
|
32
|
-
})
|
71
|
+
});
|
33
72
|
|
34
73
|
// hide and show correct parser fields depending on klass setting
|
35
74
|
$('body').on('change', '#importer_parser_klass', function(e) {
|
36
|
-
handleParserKlass()
|
37
|
-
})
|
38
|
-
handleParserKlass()
|
75
|
+
handleParserKlass();
|
76
|
+
});
|
77
|
+
handleParserKlass();
|
39
78
|
|
40
79
|
// observer for cloud files being added
|
41
80
|
var form = document.getElementById('new_importer');
|
42
81
|
if (form == null) {
|
43
|
-
|
82
|
+
form = document.getElementsByClassName('edit_importer')[0];
|
44
83
|
}
|
84
|
+
|
45
85
|
// only setup the observer on the new and edit importer pages
|
46
86
|
if (form != null) {
|
47
87
|
var config = { childList: true, attributes: true };
|
48
88
|
var callback = function(mutationsList) {
|
49
89
|
for(var mutation of mutationsList) {
|
50
|
-
|
51
90
|
if (mutation.type == 'childList') {
|
52
91
|
browseButton = document.getElementById('browse');
|
53
|
-
var exp = /selected_files\[[0-9]*\]\[url\]
|
92
|
+
var exp = /selected_files\[[0-9]*\]\[url\]/;
|
54
93
|
for (var node of mutation.addedNodes) {
|
55
94
|
if (node.attributes != undefined) {
|
56
|
-
var name = node.attributes.name.value
|
95
|
+
var name = node.attributes.name.value;
|
57
96
|
if (exp.test(name)) {
|
58
97
|
browseButton.innerHTML = 'Cloud Files Added';
|
59
98
|
browseButton.style.backgroundColor = 'green';
|
60
|
-
browseButton.after(document.createElement("br"), node.value.toString())
|
99
|
+
browseButton.after(document.createElement("br"), node.value.toString());
|
61
100
|
}
|
62
101
|
}
|
63
102
|
}
|
64
103
|
}
|
65
104
|
}
|
66
105
|
};
|
67
|
-
var observer = new MutationObserver
|
68
|
-
observer.observe
|
106
|
+
var observer = new MutationObserver(callback);
|
107
|
+
observer.observe(form, config);
|
69
108
|
}
|
70
109
|
}
|
71
110
|
|
72
111
|
function handleFileToggle(file_path) {
|
73
112
|
if (file_path === undefined || file_path.length === 0) {
|
74
|
-
$('#file_path').hide()
|
75
|
-
$('#file_upload').hide()
|
76
|
-
$('#cloud').hide()
|
77
|
-
$('#existing_options').hide()
|
78
|
-
$('#file_path input').attr('required', null)
|
79
|
-
$('#file_upload input').attr('required', null)
|
113
|
+
$('#file_path').hide();
|
114
|
+
$('#file_upload').hide();
|
115
|
+
$('#cloud').hide();
|
116
|
+
$('#existing_options').hide();
|
117
|
+
$('#file_path input').attr('required', null);
|
118
|
+
$('#file_upload input').attr('required', null);
|
80
119
|
} else {
|
81
|
-
$('#file_path').show()
|
82
|
-
$('#file_upload').hide()
|
83
|
-
$('#cloud').hide()
|
84
|
-
$('#existing_options').hide()
|
85
|
-
$('#file_path input').attr('required', 'required')
|
86
|
-
$('#file_upload input').attr('required', null)
|
87
|
-
$('#importer_parser_fields_file_style_specify_a_path_on_the_server').attr('checked', true)
|
120
|
+
$('#file_path').show();
|
121
|
+
$('#file_upload').hide();
|
122
|
+
$('#cloud').hide();
|
123
|
+
$('#existing_options').hide();
|
124
|
+
$('#file_path input').attr('required', 'required');
|
125
|
+
$('#file_upload input').attr('required', null);
|
126
|
+
$('#importer_parser_fields_file_style_specify_a_path_on_the_server').attr('checked', true);
|
88
127
|
}
|
89
128
|
|
90
129
|
$('#importer_parser_fields_file_style_upload_a_file').click(function(e){
|
91
|
-
$('#file_path').hide()
|
92
|
-
$('#file_upload').show()
|
93
|
-
$('#cloud').hide()
|
94
|
-
$('#existing_options').hide()
|
95
|
-
$('#file_path input').attr('required', null)
|
96
|
-
$('#file_upload input').attr('required', 'required')
|
97
|
-
})
|
130
|
+
$('#file_path').hide();
|
131
|
+
$('#file_upload').show();
|
132
|
+
$('#cloud').hide();
|
133
|
+
$('#existing_options').hide();
|
134
|
+
$('#file_path input').attr('required', null);
|
135
|
+
$('#file_upload input').attr('required', 'required');
|
136
|
+
});
|
98
137
|
$('#importer_parser_fields_file_style_specify_a_path_on_the_server').click(function(e){
|
99
|
-
$('#file_path').show()
|
100
|
-
$('#file_upload').hide()
|
101
|
-
$('#cloud').hide()
|
102
|
-
$('#existing_options').hide()
|
103
|
-
$('#file_path input').attr('required', 'required')
|
104
|
-
$('#file_upload input').attr('required', null)
|
105
|
-
})
|
138
|
+
$('#file_path').show();
|
139
|
+
$('#file_upload').hide();
|
140
|
+
$('#cloud').hide();
|
141
|
+
$('#existing_options').hide();
|
142
|
+
$('#file_path input').attr('required', 'required');
|
143
|
+
$('#file_upload input').attr('required', null);
|
144
|
+
});
|
106
145
|
$('#importer_parser_fields_file_style_add_cloud_file').click(function(e){
|
107
|
-
$('#file_path').hide()
|
108
|
-
$('#file_upload').hide()
|
109
|
-
$('#cloud').show()
|
110
|
-
$('#existing_options').hide()
|
111
|
-
$('#file_path input').attr('required', null)
|
112
|
-
$('#file_upload input').attr('required', null)
|
113
|
-
})
|
146
|
+
$('#file_path').hide();
|
147
|
+
$('#file_upload').hide();
|
148
|
+
$('#cloud').show();
|
149
|
+
$('#existing_options').hide();
|
150
|
+
$('#file_path input').attr('required', null);
|
151
|
+
$('#file_upload input').attr('required', null);
|
152
|
+
});
|
114
153
|
$('#importer_parser_fields_file_style_existing_entries').click(function(e){
|
115
|
-
$('#file_path').hide()
|
116
|
-
$('#file_upload').hide()
|
117
|
-
$('#cloud').hide()
|
118
|
-
$('#existing_options').show()
|
119
|
-
$('#file_path input').attr('required', null)
|
120
|
-
$('#file_upload input').attr('required', null)
|
121
|
-
})
|
122
|
-
|
154
|
+
$('#file_path').hide();
|
155
|
+
$('#file_upload').hide();
|
156
|
+
$('#cloud').hide();
|
157
|
+
$('#existing_options').show();
|
158
|
+
$('#file_path input').attr('required', null);
|
159
|
+
$('#file_upload input').attr('required', null);
|
160
|
+
});
|
123
161
|
}
|
124
162
|
|
125
163
|
function handleParserKlass() {
|
126
164
|
<% Bulkrax.parsers.map{ |p| p[:partial]}.uniq.each do |partial| %>
|
127
165
|
if($('.<%= partial %>').length > 0) {
|
128
|
-
window.<%= partial %> = $('.<%= partial %>').detach()
|
166
|
+
window.<%= partial %> = $('.<%= partial %>').detach();
|
129
167
|
}
|
130
168
|
<% end %>
|
131
169
|
|
132
|
-
var parser_klass = $("#importer_parser_klass option:selected")
|
170
|
+
var parser_klass = $("#importer_parser_klass option:selected");
|
133
171
|
if(parser_klass.length > 0 && parser_klass.data('partial') && parser_klass.data('partial').length > 0) {
|
134
|
-
$('.parser_fields').append(window[parser_klass.data('partial')])
|
172
|
+
$('.parser_fields').append(window[parser_klass.data('partial')]);
|
135
173
|
}
|
136
174
|
|
137
|
-
handleBrowseEverything()
|
138
|
-
var file_path_value = $('#importer_parser_fields_import_file_path').val()
|
139
|
-
handleFileToggle(file_path_value)
|
175
|
+
handleBrowseEverything();
|
176
|
+
var file_path_value = $('#importer_parser_fields_import_file_path').val();
|
177
|
+
handleFileToggle(file_path_value);
|
140
178
|
}
|
141
179
|
|
142
180
|
function handleBrowseEverything(){
|
143
|
-
var button = $("button[data-toggle='browse-everything']")
|
181
|
+
var button = $("button[data-toggle='browse-everything']");
|
144
182
|
if(button.length == 0) { return; }
|
145
183
|
button.browseEverything({
|
146
184
|
route: button.data('route'),
|
147
185
|
target: button.data('target')
|
148
186
|
}).done(function(data) {
|
149
187
|
var evt = { isDefaultPrevented: function() { return false; } };
|
150
|
-
$('.ev-browser.show').removeClass('show')
|
188
|
+
$('.ev-browser.show').removeClass('show');
|
151
189
|
if($('#fileupload').length > 0) {
|
152
|
-
var files = $.map(data, function(d) { return { name: d.file_name, size: d.file_size, id: d.url } });
|
190
|
+
var files = $.map(data, function(d) { return { name: d.file_name, size: d.file_size, id: d.url }; });
|
153
191
|
$.blueimp.fileupload.prototype.options.done.call($('#fileupload').fileupload(), evt, { result: { files: files }});
|
154
192
|
}
|
155
|
-
return true
|
156
|
-
// User has submitted files; data contains an array of URLs and their options
|
193
|
+
return true;
|
157
194
|
}).cancel(function() {
|
158
|
-
$('.ev-browser.show').removeClass('show')
|
159
|
-
// User cancelled the browse operation
|
195
|
+
$('.ev-browser.show').removeClass('show');
|
160
196
|
}).fail(function(status, error, text) {
|
161
|
-
$('.ev-browser.show').removeClass('show')
|
162
|
-
// URL retrieval experienced a technical failure
|
197
|
+
$('.ev-browser.show').removeClass('show');
|
163
198
|
});
|
164
199
|
}
|
165
200
|
|
166
201
|
function handleSourceLoad(refresh_button, base_url, external_set_select) {
|
167
202
|
if (base_url.val() == "") { // ignore empty base_url value
|
168
|
-
return
|
203
|
+
return;
|
169
204
|
}
|
170
205
|
|
171
|
-
var initial_button_text = refresh_button.html()
|
206
|
+
var initial_button_text = refresh_button.html();
|
172
207
|
|
173
|
-
refresh_button.html('Refreshing...')
|
174
|
-
refresh_button.attr('disabled', true)
|
208
|
+
refresh_button.html('Refreshing...');
|
209
|
+
refresh_button.attr('disabled', true);
|
175
210
|
|
176
211
|
$.post('/importers/external_sets', {
|
177
212
|
base_url: base_url.val(),
|
178
213
|
}, function(res) {
|
179
214
|
if (!res.error) {
|
180
|
-
genExternalSetOptions(external_set_select, res.sets)
|
215
|
+
genExternalSetOptions(external_set_select, res.sets);
|
181
216
|
} else {
|
182
|
-
setError(external_set_select, res.error)
|
217
|
+
setError(external_set_select, res.error);
|
183
218
|
}
|
184
219
|
|
185
|
-
refresh_button.html(initial_button_text)
|
186
|
-
refresh_button.attr('disabled', false)
|
187
|
-
})
|
220
|
+
refresh_button.html(initial_button_text);
|
221
|
+
refresh_button.attr('disabled', false);
|
222
|
+
});
|
188
223
|
}
|
189
224
|
|
190
225
|
function genExternalSetOptions(selector, sets) {
|
191
|
-
out = '<option value="">- Select One -</option>'
|
226
|
+
out = '<option value="">- Select One -</option>';
|
192
227
|
|
193
228
|
out += sets.map(function(set) {
|
194
|
-
return '<option value="'+set[1]+'">'+set[0]+'</option>'
|
195
|
-
})
|
229
|
+
return '<option value="'+set[1]+'">'+set[0]+'</option>';
|
230
|
+
});
|
196
231
|
|
197
|
-
selector.html(out)
|
198
|
-
selector.attr('disabled', false)
|
232
|
+
selector.html(out);
|
233
|
+
selector.attr('disabled', false);
|
199
234
|
}
|
200
235
|
|
201
236
|
function setError(selector, error) {
|
202
|
-
selector.html('<option value="none">Error - Please enter Base URL and try again</option>')
|
203
|
-
selector.attr('disabled', true)
|
237
|
+
selector.html('<option value="none">Error - Please enter Base URL and try again</option>');
|
238
|
+
selector.attr('disabled', true);
|
204
239
|
}
|
205
240
|
|
206
|
-
$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax})
|
241
|
+
$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax});
|
@@ -78,11 +78,13 @@ module Bulkrax
|
|
78
78
|
|
79
79
|
# POST /importers
|
80
80
|
# rubocop:disable Metrics/MethodLength
|
81
|
+
# rubocop:disable Metrics/AbcSize
|
81
82
|
def create
|
82
83
|
# rubocop:disable Style/IfInsideElse
|
83
84
|
if api_request?
|
84
85
|
return return_json_response unless valid_create_params?
|
85
86
|
end
|
87
|
+
uploads = Hyrax::UploadedFile.find(params[:uploaded_files]) if params[:uploaded_files].present?
|
86
88
|
file = file_param
|
87
89
|
cloud_files = cloud_params
|
88
90
|
|
@@ -93,7 +95,7 @@ module Bulkrax
|
|
93
95
|
# on a new import otherwise it only gets updated during the update path
|
94
96
|
@importer.parser_fields['update_files'] = true if params[:commit] == 'Create and Import'
|
95
97
|
if @importer.save
|
96
|
-
files_for_import(file, cloud_files)
|
98
|
+
files_for_import(file, cloud_files, uploads)
|
97
99
|
if params[:commit] == 'Create and Import'
|
98
100
|
Bulkrax::ImporterJob.send(@importer.parser.perform_method, @importer.id)
|
99
101
|
render_request('Importer was successfully created and import has been queued.')
|
@@ -112,6 +114,7 @@ module Bulkrax
|
|
112
114
|
end
|
113
115
|
# rubocop:enable Style/IfInsideElse
|
114
116
|
end
|
117
|
+
# rubocop:enable Metrics/AbcSize
|
115
118
|
|
116
119
|
# PATCH/PUT /importers/1
|
117
120
|
# # @todo refactor so as to not need to disable rubocop
|
@@ -120,7 +123,7 @@ module Bulkrax
|
|
120
123
|
if api_request?
|
121
124
|
return return_json_response unless valid_update_params?
|
122
125
|
end
|
123
|
-
|
126
|
+
uploads = Hyrax::UploadedFile.find(params[:uploaded_files]) if params[:uploaded_files].present?
|
124
127
|
file = file_param
|
125
128
|
cloud_files = cloud_params
|
126
129
|
|
@@ -128,7 +131,7 @@ module Bulkrax
|
|
128
131
|
field_mapping_params if params[:importer][:parser_fields].present?
|
129
132
|
|
130
133
|
if @importer.update(importer_params)
|
131
|
-
files_for_import(file, cloud_files)
|
134
|
+
files_for_import(file, cloud_files, uploads)
|
132
135
|
# do not perform the import
|
133
136
|
unless params[:commit] == 'Update Importer'
|
134
137
|
set_files_parser_fields
|
@@ -218,8 +221,9 @@ module Bulkrax
|
|
218
221
|
|
219
222
|
private
|
220
223
|
|
221
|
-
def files_for_import(file, cloud_files)
|
222
|
-
return if file.blank? && cloud_files.blank?
|
224
|
+
def files_for_import(file, cloud_files, uploads)
|
225
|
+
return if file.blank? && cloud_files.blank? && uploads.blank?
|
226
|
+
|
223
227
|
@importer[:parser_fields]['import_file_path'] = @importer.parser.write_import_file(file) if file.present?
|
224
228
|
if cloud_files.present?
|
225
229
|
@importer[:parser_fields]['cloud_file_paths'] = cloud_files
|
@@ -229,6 +233,13 @@ module Bulkrax
|
|
229
233
|
target = @importer.parser.retrieve_cloud_files(cloud_files, @importer)
|
230
234
|
@importer[:parser_fields]['import_file_path'] = target if target.present?
|
231
235
|
end
|
236
|
+
|
237
|
+
if uploads.present?
|
238
|
+
uploads.each do |upload|
|
239
|
+
@importer[:parser_fields]['import_file_path'] = @importer.parser.write_import_file(upload.file.file)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
232
243
|
@importer.save
|
233
244
|
end
|
234
245
|
|
@@ -132,7 +132,7 @@ module Bulkrax
|
|
132
132
|
status_message: status_message_for(e),
|
133
133
|
type: e.type,
|
134
134
|
updated_at: e.updated_at,
|
135
|
-
errors: e.
|
135
|
+
errors: e.latest_status&.error_class&.present? ? view_context.link_to(e.latest_status.error_class, view_context.item_entry_path(item, e), title: e.latest_status.error_message) : "",
|
136
136
|
actions: entry_util_links(e, item)
|
137
137
|
}
|
138
138
|
end
|
@@ -26,7 +26,7 @@ module Bulkrax
|
|
26
26
|
end
|
27
27
|
# rubocop:enable Rails/SkipsModelValidations
|
28
28
|
end
|
29
|
-
return entry if exporter_run.
|
29
|
+
return entry if exporter_run.enqueued_records.positive?
|
30
30
|
|
31
31
|
if exporter_run.failed_records.positive?
|
32
32
|
exporter_run.exporter.set_status_info('Complete (with failures)')
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Bulkrax
|
4
4
|
class Status < ApplicationRecord
|
5
|
-
belongs_to :statusable, polymorphic: true, denormalize: { fields: %i[status_message
|
5
|
+
belongs_to :statusable, polymorphic: true, denormalize: { fields: %i[status_message], if: :latest? }
|
6
6
|
belongs_to :runnable, polymorphic: true
|
7
7
|
serialize :error_backtrace, Array
|
8
8
|
|
@@ -26,15 +26,11 @@ module Bulkrax
|
|
26
26
|
|
27
27
|
# Prepend the file_set id to ensure a unique filename and also one that is not longer than 255 characters
|
28
28
|
def filename(file_set)
|
29
|
+
# NOTE: Will this work with Valkyrie?
|
29
30
|
return if file_set.original_file.blank?
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
else # original non valkyrie version
|
34
|
-
fn = file_set.original_file.file_name.first
|
35
|
-
mime = ::Marcel::MimeType.for(declared_type: file_set.original_file.mime_type)
|
36
|
-
end
|
37
|
-
ext_mime = ::Marcel::MimeType.for(name: fn)
|
31
|
+
fn = file_set.original_file.file_name.first
|
32
|
+
mime = ::Marcel::MimeType.for(file_set.original_file.mime_type)
|
33
|
+
ext_mime = ::Marcel::MimeType.for(file_set.original_file.file_name)
|
38
34
|
if fn.include?(file_set.id) || importerexporter.metadata_only?
|
39
35
|
filename = "#{fn}.#{mime.to_sym}"
|
40
36
|
filename = fn if mime.to_s == ext_mime.to_s
|
@@ -244,10 +244,7 @@ module Bulkrax
|
|
244
244
|
record = Bulkrax.object_factory.find(identifier)
|
245
245
|
return unless record
|
246
246
|
|
247
|
-
file_sets = Array.wrap(record)
|
248
|
-
if file_sets.nil? # for valkyrie
|
249
|
-
file_sets = record.respond_to?(:file_sets) ? record.file_sets : record.members&.select(&:file_set?)
|
250
|
-
end
|
247
|
+
file_sets = record.file_set? ? Array.wrap(record) : record.file_sets
|
251
248
|
file_sets << record.thumbnail if exporter.include_thumbnails && record.thumbnail.present? && record.work?
|
252
249
|
file_sets.each do |fs|
|
253
250
|
path = File.join(exporter_export_path, folder_count, 'files')
|
@@ -255,7 +252,7 @@ module Bulkrax
|
|
255
252
|
file = filename(fs)
|
256
253
|
next if file.blank? || fs.original_file.blank?
|
257
254
|
|
258
|
-
io =
|
255
|
+
io = open(fs.original_file.uri)
|
259
256
|
File.open(File.join(path, file), 'wb') do |f|
|
260
257
|
f.write(io.read)
|
261
258
|
f.close
|
@@ -173,7 +173,7 @@ module Bulkrax
|
|
173
173
|
# @see https://github.com/samvera/hyrax/blob/64c0bbf0dc0d3e1b49f040b50ea70d177cc9d8f6/app/indexers/hyrax/work_indexer.rb#L15-L18
|
174
174
|
def file_sets
|
175
175
|
@file_sets ||= ParserExportRecordSet.in_batches(candidate_file_set_ids) do |batch_of_ids|
|
176
|
-
fsq = "has_model_ssim
|
176
|
+
fsq = "has_model_ssim:#{Bulkrax.file_model_internal_resource} AND id:(\"" + batch_of_ids.join('" OR "') + "\")"
|
177
177
|
fsq += extra_filters if extra_filters.present?
|
178
178
|
Bulkrax.object_factory.query(
|
179
179
|
fsq,
|
@@ -41,9 +41,16 @@
|
|
41
41
|
<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>
|
42
42
|
<p>The Server Path can point to a BagIt Bag, a folder containing BagIt Bags, or a zip file containing either.</p>
|
43
43
|
|
44
|
-
|
44
|
+
<%= fi.input :file_style,
|
45
|
+
collection: ['Upload a File', 'Specify a Path on the Server'] +
|
46
|
+
(defined?(::Hyrax) && Hyrax.config.browse_everything? ? ['Add Cloud File'] : []),
|
47
|
+
as: :radio_buttons, label: false %>
|
45
48
|
<div id='file_upload'>
|
46
|
-
|
49
|
+
<% if defined?(::Hyrax) %>
|
50
|
+
<%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'application/zip' %>
|
51
|
+
<% else %>
|
52
|
+
<%= fi.input 'file', as: :file, input_html: {accept: 'application/zip'} %><br />
|
53
|
+
<% end %>
|
47
54
|
</div>
|
48
55
|
<div id='file_path'>
|
49
56
|
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
|
@@ -53,4 +60,4 @@
|
|
53
60
|
<%= render 'browse_everything', form: form %>
|
54
61
|
<% end %>
|
55
62
|
</div>
|
56
|
-
</div>
|
63
|
+
</div>
|
@@ -1,5 +1,4 @@
|
|
1
1
|
<div class='csv_fields'>
|
2
|
-
|
3
2
|
<%= fi.input :visibility,
|
4
3
|
label: 'Default Visibility',
|
5
4
|
collection: [
|
@@ -11,7 +10,6 @@
|
|
11
10
|
input_html: { class: 'form-control' },
|
12
11
|
hint: 'If your CSV includes the visibility field, it will override the default setting.'
|
13
12
|
%>
|
14
|
-
|
15
13
|
<% if defined?(::Hyrax) %>
|
16
14
|
<% rights_statements = Hyrax.config.rights_statement_service_class.new %>
|
17
15
|
<%= fi.input :rights_statement,
|
@@ -24,26 +22,32 @@
|
|
24
22
|
%>
|
25
23
|
<%= 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") } %>
|
26
24
|
<% end %>
|
27
|
-
<h4>Add CSV File to Import:</h4>
|
25
|
+
<h4>Add CSV or ZIP File to Import:</h4>
|
28
26
|
<%# accept a single file upload; data files and bags will need to be added another way %>
|
29
|
-
|
30
27
|
<% file_style_list = ['Upload a File', 'Specify a Path on the Server'] %>
|
31
28
|
<% file_style_list << 'Existing Entries' unless importer.new_record? %>
|
32
29
|
<%= fi.input :file_style, collection: file_style_list, as: :radio_buttons, label: false %>
|
30
|
+
|
33
31
|
<div id='file_upload'>
|
34
|
-
|
32
|
+
<% if defined?(::Hyrax) %>
|
33
|
+
<%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'text/csv,application/zip,application/gzip' %>
|
34
|
+
<% else %>
|
35
|
+
<%= fi.input 'file', as: :file, input_html: { accept: 'text/csv,application/zip,application/gzip' } %><br />
|
36
|
+
<% end %>
|
35
37
|
</div>
|
38
|
+
|
36
39
|
<div id='file_path'>
|
37
40
|
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
|
38
41
|
</div>
|
42
|
+
|
39
43
|
<div id='existing_options'>
|
40
44
|
<%= fi.collection_check_boxes :entry_statuses, [['Failed'], ['Pending'], ['Skipped'], ['Deleted'], ['Complete']], :first, :first %>
|
41
45
|
</div>
|
42
|
-
|
46
|
+
|
43
47
|
<% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
|
44
|
-
|
45
|
-
|
48
|
+
<h4>Add Files to Import:</h4>
|
49
|
+
<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>
|
46
50
|
<%= render 'browse_everything', form: form %>
|
47
51
|
<% end %>
|
48
52
|
<br />
|
49
|
-
</div>
|
53
|
+
</div>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<div class="fileupload-bulkrax">
|
2
|
+
<noscript><input type="hidden" name="redirect" value="<%= main_app.root_path %>" /></noscript>
|
3
|
+
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
|
4
|
+
<div class="fileupload-buttonbar">
|
5
|
+
<div class="row">
|
6
|
+
<div class="col-12">
|
7
|
+
<div class="fileinput-button" id="add-files">
|
8
|
+
<input id="addfiles" type="file" style="display:none;" name="files[]"
|
9
|
+
accept="<%= accepted_file_types || 'text/csv,application/zip,application/gzip' %>" multiple />
|
10
|
+
<button type="button" class="btn btn-success" onclick="document.getElementById('addfiles').click();">
|
11
|
+
<span class="fa fa-plus"></span>
|
12
|
+
<span>Add Files</span>
|
13
|
+
</button>
|
14
|
+
</div>
|
15
|
+
<button type="reset" id="file-upload-cancel-btn" class="btn btn-warning cancel">
|
16
|
+
<span class="fa fa-ban"></span>
|
17
|
+
<span>Cancel Upload</span>
|
18
|
+
</button>
|
19
|
+
<span class="fileupload-process"></span>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<div class="row">
|
23
|
+
<div class="col-12">
|
24
|
+
<div class="fileupload-progress fade">
|
25
|
+
<div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100">
|
26
|
+
<div class="progress-bar progress-bar-striped progress-bar-animated bg-success" style="width:0%;"></div>
|
27
|
+
</div>
|
28
|
+
<div class="progress-extended"> </div>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
<div class="dropzone">
|
34
|
+
Drop files here to upload
|
35
|
+
</div>
|
36
|
+
<%= render 'hyrax/uploads/js_templates' %>
|
37
|
+
</div>
|
@@ -47,16 +47,22 @@
|
|
47
47
|
<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>
|
48
48
|
<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>
|
49
49
|
|
50
|
-
|
50
|
+
<%= fi.input :file_style,
|
51
|
+
collection: ['Upload a File', 'Specify a Path on the Server'] +
|
52
|
+
(defined?(::Hyrax) && Hyrax.config.browse_everything? ? ['Add Cloud File'] : []),
|
53
|
+
as: :radio_buttons, label: false %>
|
51
54
|
<div id='file_upload'>
|
52
|
-
|
55
|
+
<% if defined?(::Hyrax) %>
|
56
|
+
<%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'application/zip,application/xml' %>
|
57
|
+
<% else %>
|
58
|
+
<%= fi.input 'file', as: :file, input_html: {accept: ['application/zip', 'application/xml']} %><br />
|
59
|
+
<% end%>
|
53
60
|
</div>
|
54
61
|
<div id='file_path'>
|
55
62
|
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
|
56
63
|
</div>
|
57
64
|
<div id='cloud'>
|
58
65
|
<% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
|
59
|
-
<%= render 'browse_everything', form: form %>
|
60
66
|
<% end %>
|
61
67
|
</div>
|
62
|
-
</div>
|
68
|
+
</div>
|
data/lib/bulkrax/version.rb
CHANGED
@@ -9,7 +9,7 @@ namespace :bulkrax do
|
|
9
9
|
progress_mark: ' ',
|
10
10
|
remainder_mark: "\u{FF65}")
|
11
11
|
Bulkrax::Status.latest_by_statusable.includes(:statusable).find_each do |status|
|
12
|
-
status.statusable.update(status_message: status.status_message
|
12
|
+
status.statusable.update(status_message: status.status_message)
|
13
13
|
@progress.increment
|
14
14
|
end
|
15
15
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bulkrax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Kaufman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.6
|
33
|
+
version: 0.4.6
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.6
|
40
|
+
version: 0.4.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: coderay
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -428,6 +428,7 @@ files:
|
|
428
428
|
- app/views/bulkrax/importers/_csv_fields.html.erb
|
429
429
|
- app/views/bulkrax/importers/_edit_form_buttons.html.erb
|
430
430
|
- app/views/bulkrax/importers/_edit_item_buttons.html.erb
|
431
|
+
- app/views/bulkrax/importers/_file_uploader.html.erb
|
431
432
|
- app/views/bulkrax/importers/_form.html.erb
|
432
433
|
- app/views/bulkrax/importers/_oai_fields.html.erb
|
433
434
|
- app/views/bulkrax/importers/_xml_fields.html.erb
|
@@ -486,8 +487,6 @@ files:
|
|
486
487
|
- db/migrate/20240823173525_add_error_tracking_to_pending_relationships.rb
|
487
488
|
- db/migrate/20240916182737_add_last_imported_at_to_bulkrax_importers.rb
|
488
489
|
- db/migrate/20240916182823_add_next_import_at_to_bulkrax_importers.rb
|
489
|
-
- db/migrate/20241203010707_entry_error_denormalization.rb
|
490
|
-
- db/migrate/20241205212513_faster_first_entry.rb
|
491
490
|
- lib/bulkrax.rb
|
492
491
|
- lib/bulkrax/engine.rb
|
493
492
|
- lib/bulkrax/entry_spec_helper.rb
|
@@ -520,7 +519,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
520
519
|
- !ruby/object:Gem::Version
|
521
520
|
version: '0'
|
522
521
|
requirements: []
|
523
|
-
rubygems_version: 3.
|
522
|
+
rubygems_version: 3.4.20
|
524
523
|
signing_key:
|
525
524
|
specification_version: 4
|
526
525
|
summary: Import and export tool for Hyrax and Hyku
|
@@ -1,7 +0,0 @@
|
|
1
|
-
class EntryErrorDenormalization < ActiveRecord::Migration[5.1]
|
2
|
-
def change
|
3
|
-
add_column :bulkrax_entries, :error_class, :string unless column_exists?(:bulkrax_entries, :error_class)
|
4
|
-
add_column :bulkrax_importers, :error_class, :string unless column_exists?(:bulkrax_importers, :error_class)
|
5
|
-
add_column :bulkrax_exporters, :error_class, :string unless column_exists?(:bulkrax_exporters, :error_class)
|
6
|
-
end
|
7
|
-
end
|
@@ -1,7 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
class FasterFirstEntry < ActiveRecord::Migration[5.2]
|
3
|
-
def change
|
4
|
-
add_index :bulkrax_entries, [:importerexporter_id, :importerexporter_type, :id], name: 'index_bulkrax_entries_on_importerexporter_id_type_and_id' unless index_exists?(:bulkrax_entries, [:importerexporter_id, :importerexporter_type, :id],
|
5
|
-
name: 'index_bulkrax_entries_on_importerexporter_id_type_and_id')
|
6
|
-
end
|
7
|
-
end
|